Zum Fußzeileninhalt springen
.NET HILFE

Deedle C# (Funktionsweise für Entwickler)

Deedle C#

Deedle is a powerful library for data manipulation and data analysis. It offers entire data frames and series, allowing you to handle structured data frames efficiently. Deedle provides tools for missing data, aligning data, and applying helper functions with static members ofNullables and ofObservations. It is widely used in data science for its flexibility and performance.

IronPDF is a library for creating and manipulating PDF documents in .NET. It helps you generate PDFs from HTML, convert images to PDFs, and extract content from PDF files. IronPDF simplifies PDF tasks in your .NET projects.

In this article, you'll learn how to get started with Deedle for C#, set it up in your .NET projects using Visual Studio, and implement key features with automatically generated documentation. You'll see code examples and explanations to help you understand how to use Deedle effectively, including how to apply a specified function.

Getting Started with Deedle C#

Setting Up Deedle in .NET Projects

To begin, create a new C# Console Application project in Visual Studio.

To use Deedle in your .NET project, you need to install the Deedle NuGet package. Run the following command in the NuGet console:

Install-Package Deedle

Once installed, you need to import the Deedle namespace into your project:

using Deedle;
using Deedle;
Imports Deedle
$vbLabelText   $csharpLabel

A Basic Code Example

Let's start with a basic example to create and manipulate a data frame. This will help you understand the basics of Deedle.

using System;
using Deedle;

class Program
{
    static void Main()
    {
        // Creating a series with integer keys and double values
        var series = new Series<int, double>(new[] { 1, 2, 3 }, new[] { 3.5, 4.2, 5.1 });
        Console.WriteLine("Series:");
        Console.WriteLine(series);

        // Creating a data frame from a 2D array
        var rowIndex = new[] { 1, 2, 3 };
        var colIndex = new[] { "A", "B" };
        var data = new double[,] { { 1.0, 3.5 }, { 2.0, 4.2 }, { 3.0, 5.1 } };
        var dataFrame = Frame.FromArray2D(data)
                             .IndexRowsWith(rowIndex)
                             .IndexColumnsWith(colIndex);
        Console.WriteLine("Data Frame:");
        Console.WriteLine(dataFrame);
    }
}
using System;
using Deedle;

class Program
{
    static void Main()
    {
        // Creating a series with integer keys and double values
        var series = new Series<int, double>(new[] { 1, 2, 3 }, new[] { 3.5, 4.2, 5.1 });
        Console.WriteLine("Series:");
        Console.WriteLine(series);

        // Creating a data frame from a 2D array
        var rowIndex = new[] { 1, 2, 3 };
        var colIndex = new[] { "A", "B" };
        var data = new double[,] { { 1.0, 3.5 }, { 2.0, 4.2 }, { 3.0, 5.1 } };
        var dataFrame = Frame.FromArray2D(data)
                             .IndexRowsWith(rowIndex)
                             .IndexColumnsWith(colIndex);
        Console.WriteLine("Data Frame:");
        Console.WriteLine(dataFrame);
    }
}
Imports System
Imports Deedle

Friend Class Program
	Shared Sub Main()
		' Creating a series with integer keys and double values
		Dim series As New Series(Of Integer, Double)( { 1, 2, 3 }, { 3.5, 4.2, 5.1 })
		Console.WriteLine("Series:")
		Console.WriteLine(series)

		' Creating a data frame from a 2D array
		Dim rowIndex = { 1, 2, 3 }
		Dim colIndex = { "A", "B" }
		Dim data = New Double(, ) {
			{ 1.0, 3.5 },
			{ 2.0, 4.2 },
			{ 3.0, 5.1 }
		}
		Dim dataFrame = Frame.FromArray2D(data).IndexRowsWith(rowIndex).IndexColumnsWith(colIndex)
		Console.WriteLine("Data Frame:")
		Console.WriteLine(dataFrame)
	End Sub
End Class
$vbLabelText   $csharpLabel

In this example, you create a series with integer row keys and double values. Then, you create a data frame using a 2D array of double values. You index the rows with integers and the columns with strings.

Implementing Features of Deedle C#

Handling Missing Values

Handling missing values is crucial in data manipulation. Deedle provides robust support for missing data. You can create a series with missing values and perform operations to handle them.

using System;
using Deedle;

class Program
{
    static void Main()
    {
        // Creating a series with nullable doubles to represent missing values
        var series = new Series<int, double?>(
            new[] { 75, 8, 47, 5 },
            new double?[] { 75.0, null, 47.0, 5.0 }
        );
        Console.WriteLine("Original Series with Missing Values:");
        Console.WriteLine(series);

        // Fill missing values with a specified value (e.g., 0.0)
        var filledSeries = series.FillMissing(0.0);
        Console.WriteLine("Series after Filling Missing Values:");
        Console.WriteLine(filledSeries);
    }
}
using System;
using Deedle;

class Program
{
    static void Main()
    {
        // Creating a series with nullable doubles to represent missing values
        var series = new Series<int, double?>(
            new[] { 75, 8, 47, 5 },
            new double?[] { 75.0, null, 47.0, 5.0 }
        );
        Console.WriteLine("Original Series with Missing Values:");
        Console.WriteLine(series);

        // Fill missing values with a specified value (e.g., 0.0)
        var filledSeries = series.FillMissing(0.0);
        Console.WriteLine("Series after Filling Missing Values:");
        Console.WriteLine(filledSeries);
    }
}
Imports System
Imports Deedle

Friend Class Program
	Shared Sub Main()
		' Creating a series with nullable doubles to represent missing values
		Dim series As New Series(Of Integer, Double?)( { 75, 8, 47, 5 }, New Double?() { 75.0, Nothing, 47.0, 5.0 })
		Console.WriteLine("Original Series with Missing Values:")
		Console.WriteLine(series)

		' Fill missing values with a specified value (e.g., 0.0)
		Dim filledSeries = series.FillMissing(0.0)
		Console.WriteLine("Series after Filling Missing Values:")
		Console.WriteLine(filledSeries)
	End Sub
End Class
$vbLabelText   $csharpLabel

This example creates a series with missing values and fills them with a specified value. You can also use static member methods like ofOptionalObservations and ofValues for more complex scenarios.

Data Manipulation

Deedle allows you to perform various data manipulation tasks. You can filter, transform, and aggregate data in data frames.

using System;
using Deedle;

class Program
{
    static void Main()
    {
        // Creating a data frame
        var rowIndex = new[] { 1, 2, 3 };
        var colIndex = new[] { "A", "B" };
        var data = new double[,] { { 1.0, 3.5 }, { 2.0, 4.2 }, { 3.0, 5.1 } };
        var dataFrame = Frame.FromArray2D(data)
                             .IndexRowsWith(rowIndex)
                             .IndexColumnsWith(colIndex);
        Console.WriteLine("Original Data Frame:");
        Console.WriteLine(dataFrame);

        // Filter rows where column 'A' is greater than 1.5
        var filteredFrame = dataFrame.Where(row => row.Value.GetAs<double>("A") > 1.5);
        Console.WriteLine("Filtered Data Frame:");
        Console.WriteLine(filteredFrame);

        // Add a new column 'C' which is the sum of columns 'A' and 'B'
        dataFrame.AddColumn("C", dataFrame["A"] + dataFrame["B"]);
        Console.WriteLine("Transformed Data Frame with New Column 'C':");
        Console.WriteLine(dataFrame);
    }
}
using System;
using Deedle;

class Program
{
    static void Main()
    {
        // Creating a data frame
        var rowIndex = new[] { 1, 2, 3 };
        var colIndex = new[] { "A", "B" };
        var data = new double[,] { { 1.0, 3.5 }, { 2.0, 4.2 }, { 3.0, 5.1 } };
        var dataFrame = Frame.FromArray2D(data)
                             .IndexRowsWith(rowIndex)
                             .IndexColumnsWith(colIndex);
        Console.WriteLine("Original Data Frame:");
        Console.WriteLine(dataFrame);

        // Filter rows where column 'A' is greater than 1.5
        var filteredFrame = dataFrame.Where(row => row.Value.GetAs<double>("A") > 1.5);
        Console.WriteLine("Filtered Data Frame:");
        Console.WriteLine(filteredFrame);

        // Add a new column 'C' which is the sum of columns 'A' and 'B'
        dataFrame.AddColumn("C", dataFrame["A"] + dataFrame["B"]);
        Console.WriteLine("Transformed Data Frame with New Column 'C':");
        Console.WriteLine(dataFrame);
    }
}
Imports System
Imports Deedle

Friend Class Program
	Shared Sub Main()
		' Creating a data frame
		Dim rowIndex = { 1, 2, 3 }
		Dim colIndex = { "A", "B" }
		Dim data = New Double(, ) {
			{ 1.0, 3.5 },
			{ 2.0, 4.2 },
			{ 3.0, 5.1 }
		}
		Dim dataFrame = Frame.FromArray2D(data).IndexRowsWith(rowIndex).IndexColumnsWith(colIndex)
		Console.WriteLine("Original Data Frame:")
		Console.WriteLine(dataFrame)

		' Filter rows where column 'A' is greater than 1.5
		Dim filteredFrame = dataFrame.Where(Function(row) row.Value.GetAs(Of Double)("A") > 1.5)
		Console.WriteLine("Filtered Data Frame:")
		Console.WriteLine(filteredFrame)

		' Add a new column 'C' which is the sum of columns 'A' and 'B'
		dataFrame.AddColumn("C", dataFrame("A") + dataFrame("B"))
		Console.WriteLine("Transformed Data Frame with New Column 'C':")
		Console.WriteLine(dataFrame)
	End Sub
End Class
$vbLabelText   $csharpLabel

This example demonstrates filtering rows based on a condition and adding a new column with transformed data. Deedle implements standard frame extension methods to make data analysis straightforward.

Statistical Functions

Deedle provides standard statistical functions to analyze data. Using the statistical functions, you can calculate the mean, standard deviation, and other statistical measures.

using System;
using Deedle;

class Program
{
    static void Main()
    {
        // Creating a series with integer keys and double values
        var series = new Series<int, double>(
            new[] { 1, 2, 3, 4 },
            new[] { 1.0, 2.0, 3.0, 4.0 }
        );
        Console.WriteLine("Series:");
        Console.WriteLine(series);

        // Calculate the mean of the series
        var mean = series.Mean();
        Console.WriteLine($"Mean: {mean}");

        // Calculate the standard deviation of the series
        var stddev = series.StdDev();
        Console.WriteLine($"Standard Deviation: {stddev}");
    }
}
using System;
using Deedle;

class Program
{
    static void Main()
    {
        // Creating a series with integer keys and double values
        var series = new Series<int, double>(
            new[] { 1, 2, 3, 4 },
            new[] { 1.0, 2.0, 3.0, 4.0 }
        );
        Console.WriteLine("Series:");
        Console.WriteLine(series);

        // Calculate the mean of the series
        var mean = series.Mean();
        Console.WriteLine($"Mean: {mean}");

        // Calculate the standard deviation of the series
        var stddev = series.StdDev();
        Console.WriteLine($"Standard Deviation: {stddev}");
    }
}
Imports System
Imports Deedle

Friend Class Program
	Shared Sub Main()
		' Creating a series with integer keys and double values
		Dim series As New Series(Of Integer, Double)( { 1, 2, 3, 4 }, { 1.0, 2.0, 3.0, 4.0 })
		Console.WriteLine("Series:")
		Console.WriteLine(series)

		' Calculate the mean of the series
		Dim mean = series.Mean()
		Console.WriteLine($"Mean: {mean}")

		' Calculate the standard deviation of the series
		Dim stddev = series.StdDev()
		Console.WriteLine($"Standard Deviation: {stddev}")
	End Sub
End Class
$vbLabelText   $csharpLabel

This Deedle code example implements standard statistical functions Mean() and StdDev() to calculate the mean and standard deviation of a series respectively.

Creating Data Frames from CSV

Deedle allows you to create data frames from CSV files easily. This is helpful for loading and analyzing structured data.

using System;
using Deedle;

class Program
{
    static void Main()
    {
        // Load a data frame from a CSV file
        var dataFrame = Frame.ReadCsv("data.csv");
        Console.WriteLine("Data Frame from CSV:");
        Console.WriteLine(dataFrame);

        // Aggregate rows by a specified column and compute sum
        var summary = dataFrame.AggregateRowsBy<string, double>(
            new[] { "ColumnName" }, // rowKeys
            null, // columnKeys, you can pass null if not required
            v => v.Sum() // aggFunc
        );
        Console.WriteLine("Summary of Data Frame:");
        Console.WriteLine(summary);
    }
}
using System;
using Deedle;

class Program
{
    static void Main()
    {
        // Load a data frame from a CSV file
        var dataFrame = Frame.ReadCsv("data.csv");
        Console.WriteLine("Data Frame from CSV:");
        Console.WriteLine(dataFrame);

        // Aggregate rows by a specified column and compute sum
        var summary = dataFrame.AggregateRowsBy<string, double>(
            new[] { "ColumnName" }, // rowKeys
            null, // columnKeys, you can pass null if not required
            v => v.Sum() // aggFunc
        );
        Console.WriteLine("Summary of Data Frame:");
        Console.WriteLine(summary);
    }
}
Imports System
Imports Deedle

Friend Class Program
	Shared Sub Main()
		' Load a data frame from a CSV file
		Dim dataFrame = Frame.ReadCsv("data.csv")
		Console.WriteLine("Data Frame from CSV:")
		Console.WriteLine(dataFrame)

		' Aggregate rows by a specified column and compute sum
		Dim summary = dataFrame.AggregateRowsBy(Of String, Double)( { "ColumnName" }, Nothing, Function(v) v.Sum())
		Console.WriteLine("Summary of Data Frame:")
		Console.WriteLine(summary)
	End Sub
End Class
$vbLabelText   $csharpLabel

This example reads a CSV file into a data frame and performs a summary operation on the data.

Integrating Deedle with IronPDF

Introduction of IronPDF

Deedle C# (How It Works For Developers): Figure 1 - IronPDF for .NET: The C# PDF Library

IronPDF is a powerful library that allows you to create, manipulate, and extract content from PDF files in .NET applications. It's highly versatile and can handle various PDF-related tasks such as generating PDFs from HTML, extracting text, merging PDFs, and much more. Integrating IronPDF with Deedle can be particularly useful for data analysis and reporting scenarios where you need to generate dynamic reports from data frames.

Installation of IronPDF

To install IronPDF in your .NET project using NuGet Package Manager Console, add the following command:

Install-Package IronPdf

Or you can also install IronPDF by using NuGet Package Manager for Solutions. Look for the IronPDF package on NuGet in the search results, select it, and then click on the "Install" button. Visual Studio will handle the download and installation automatically.

After installation is complete, IronPDF can be utilized for your project.

Use Case of Merging IronPDF with Deedle

Imagine you have a data frame with some statistical data that you want to present in a PDF report. Deedle can handle the data manipulation and analysis part, while IronPDF can be used to format and generate the final report. For instance, you can generate a PDF that includes tables, charts, and descriptive statistics, making the data easy to share and present.

Code Example of Use Case

Here's a complete code example demonstrating how to integrate Deedle with IronPDF. We'll create a simple report from a Deedle data frame and generate a PDF using IronPDF.

using System;
using System.Linq;
using Deedle;
using IronPdf;

namespace DeedleIronPDFIntegration
{
    class Program
    {
        static void Main(string[] args)
        {
            // Set IronPDF license key
            IronPdf.License.LicenseKey = "License-Key";

            // Create a sample data frame from in-memory records
            var data = new[]
            {
                new { Name = "Robert", Age = 30, City = "New York" },
                new { Name = "Johnny", Age = 25, City = "San Francisco" },
                new { Name = "Charlie", Age = 35, City = "Los Angeles" }
            };
            var frame = Frame.FromRecords(data);

            // Convert the data frame to an HTML table format
            var htmlTable = "<table border='1' cellpadding='5' cellspacing='0'><thead><tr><th>Name</th><th>Age</th><th>City</th></tr></thead><tbody>" +
                            string.Join("", frame.Rows.Select(row =>
                                $"<tr><td>{row.Value.GetAs<string>("Name")}</td><td>{row.Value.GetAs<int>("Age")}</td><td>{row.Value.GetAs<string>("City")}</td></tr>")
                            ) +
                            "</tbody></table>";

            // Wrap the HTML table in basic HTML structure with CSS styling
            var htmlContent = $@"
            <html>
            <head>
                <style>
                    table {{
                        width: 100%;
                        border-collapse: collapse;
                    }}
                    th, td {{
                        border: 1px solid black;
                        padding: 8px;
                        text-align: left;
                    }}
                    th {{
                        background-color: #f2f2f2;
                    }}
                </style>
            </head>
            <body>
                {htmlTable}
            </body>
            </html>";

            // Create a PDF from the HTML content
            var renderer = new ChromePdfRenderer();
            var pdfDocument = renderer.RenderHtmlAsPdf(htmlContent);

            // Save the generated PDF to a file
            pdfDocument.SaveAs("f:\\DeedleReport.pdf");
            Console.WriteLine("PDF report created successfully!");
        }
    }
}
using System;
using System.Linq;
using Deedle;
using IronPdf;

namespace DeedleIronPDFIntegration
{
    class Program
    {
        static void Main(string[] args)
        {
            // Set IronPDF license key
            IronPdf.License.LicenseKey = "License-Key";

            // Create a sample data frame from in-memory records
            var data = new[]
            {
                new { Name = "Robert", Age = 30, City = "New York" },
                new { Name = "Johnny", Age = 25, City = "San Francisco" },
                new { Name = "Charlie", Age = 35, City = "Los Angeles" }
            };
            var frame = Frame.FromRecords(data);

            // Convert the data frame to an HTML table format
            var htmlTable = "<table border='1' cellpadding='5' cellspacing='0'><thead><tr><th>Name</th><th>Age</th><th>City</th></tr></thead><tbody>" +
                            string.Join("", frame.Rows.Select(row =>
                                $"<tr><td>{row.Value.GetAs<string>("Name")}</td><td>{row.Value.GetAs<int>("Age")}</td><td>{row.Value.GetAs<string>("City")}</td></tr>")
                            ) +
                            "</tbody></table>";

            // Wrap the HTML table in basic HTML structure with CSS styling
            var htmlContent = $@"
            <html>
            <head>
                <style>
                    table {{
                        width: 100%;
                        border-collapse: collapse;
                    }}
                    th, td {{
                        border: 1px solid black;
                        padding: 8px;
                        text-align: left;
                    }}
                    th {{
                        background-color: #f2f2f2;
                    }}
                </style>
            </head>
            <body>
                {htmlTable}
            </body>
            </html>";

            // Create a PDF from the HTML content
            var renderer = new ChromePdfRenderer();
            var pdfDocument = renderer.RenderHtmlAsPdf(htmlContent);

            // Save the generated PDF to a file
            pdfDocument.SaveAs("f:\\DeedleReport.pdf");
            Console.WriteLine("PDF report created successfully!");
        }
    }
}
Imports System
Imports System.Linq
Imports Deedle
Imports IronPdf

Namespace DeedleIronPDFIntegration
	Friend Class Program
		Shared Sub Main(ByVal args() As String)
			' Set IronPDF license key
			IronPdf.License.LicenseKey = "License-Key"

			' Create a sample data frame from in-memory records
			Dim data = {
				New With {
					Key .Name = "Robert",
					Key .Age = 30,
					Key .City = "New York"
				},
				New With {
					Key .Name = "Johnny",
					Key .Age = 25,
					Key .City = "San Francisco"
				},
				New With {
					Key .Name = "Charlie",
					Key .Age = 35,
					Key .City = "Los Angeles"
				}
			}
			Dim frame = Frame.FromRecords(data)

			' Convert the data frame to an HTML table format
			Dim htmlTable = "<table border='1' cellpadding='5' cellspacing='0'><thead><tr><th>Name</th><th>Age</th><th>City</th></tr></thead><tbody>" & String.Join("", frame.Rows.Select(Function(row) $"<tr><td>{row.Value.GetAs(Of String)("Name")}</td><td>{row.Value.GetAs(Of Integer)("Age")}</td><td>{row.Value.GetAs(Of String)("City")}</td></tr>")) & "</tbody></table>"

			' Wrap the HTML table in basic HTML structure with CSS styling
			Dim htmlContent = $"
            <html>
            <head>
                <style>
                    table {{
                        width: 100%;
                        border-collapse: collapse;
                    }}
                    th, td {{
                        border: 1px solid black;
                        padding: 8px;
                        text-align: left;
                    }}
                    th {{
                        background-color: #f2f2f2;
                    }}
                </style>
            </head>
            <body>
                {htmlTable}
            </body>
            </html>"

			' Create a PDF from the HTML content
			Dim renderer = New ChromePdfRenderer()
			Dim pdfDocument = renderer.RenderHtmlAsPdf(htmlContent)

			' Save the generated PDF to a file
			pdfDocument.SaveAs("f:\DeedleReport.pdf")
			Console.WriteLine("PDF report created successfully!")
		End Sub
	End Class
End Namespace
$vbLabelText   $csharpLabel

Output

Deedle C# (How It Works For Developers): Figure 2 - Output PDF generated using IronPDF and Deedle

And that's it! You've just created a fully functional application that takes complex data from Deedle and turns it into a formatted PDF report using IronPDF's .NET PDF Library. It's a powerful way to communicate your data analysis results in a professional format.

Conclusion

In this article, we've explored how to integrate Deedle with IronPDF to create dynamic PDF reports from data frames. Using Deedle, you can efficiently manipulate and analyze data, while IronPDF handles the creation and formatting of the final PDF document. This combination allows you to generate professional reports with ease, automating the process from data analysis to presentation.

IronPDF offers detailed documentation on features and usage along with various IronPDF code examples to guide you on how to get started and effectively use its extensive features.

Explore IronPDF licensing options starting from $799. Give it a try and see how it can enhance your reporting capabilities.

Häufig gestellte Fragen

Wofür wird Deedle C# verwendet?

Deedle C# wird zur Datenmanipulation und -analyse verwendet und bietet Werkzeuge zur effizienten Handhabung von strukturierten Datenrahmen und Serien. Es ist besonders in Datenwissenschaftsanwendungen nützlich, da es fehlende Daten verwalten, Daten ausrichten und Funktionen anwenden kann.

Wie kann ich Deedle mit der PDF-Erstellung in .NET integrieren?

Sie können Deedle mit IronPDF integrieren, um dynamische PDF-Berichte aus Datenrahmen zu erstellen. Deedle übernimmt die Datenmanipulation, während IronPDF verwendet wird, um den endgültigen PDF-Bericht zu formatieren und zu generieren, komplett mit Tabellen, Diagrammen und Statistiken.

Wie installiert man Deedle in einem .NET-Projekt?

Um Deedle in einem .NET-Projekt zu installieren, können Sie Visual Studio verwenden, um eine neue C#-Konsolenanwendung zu erstellen, dann das Deedle NuGet-Paket mit dem Befehl Install-Package Deedle installieren und es mit using Deedle; in Ihr Projekt einbinden.

Wie erstellt man Datenrahmen aus CSV-Dateien mit Deedle?

Um Datenrahmen aus CSV-Dateien mit Deedle zu erstellen, können Sie die Methode Frame.ReadCsv() verwenden. Dies ermöglicht Ihnen das Laden strukturierter Daten aus CSV-Dateien in Datenrahmen zur Analyse und Manipulation.

Kann Deedle mit fehlenden Werten in Datenrahmen umgehen?

Ja, Deedle bietet robuste Unterstützung für den Umgang mit fehlenden Werten in Datenrahmen. Sie können Funktionen wie FillMissing() verwenden, um fehlende Daten innerhalb einer Serie oder eines Datenrahmens angemessen zu verwalten und zu füllen.

Wie kann ich eine statistische Analyse mit Deedle durchführen?

Deedle bietet eingebaute statistische Funktionen, die es Ihnen ermöglichen, Datenanalysen durchzuführen, einschließlich Berechnungen von Mittelwert, Standardabweichung und anderen statistischen Kennzahlen direkt auf Datenrahmen und Serien.

Wie erzeugt man PDF-Berichte aus Datenrahmen in .NET?

Um PDF-Berichte aus Datenrahmen in .NET zu erzeugen, können Sie Deedle für die Datenmanipulation und IronPDF für die PDF-Erstellung verwenden. Nach der Datenmanipulation mit Deedle verwenden Sie IronPDF, um die Daten in einen professionell gestalteten PDF-Bericht zu formatieren und auszugeben.

Curtis Chau
Technischer Autor

Curtis Chau hat einen Bachelor-Abschluss in Informatik von der Carleton University und ist spezialisiert auf Frontend-Entwicklung mit Expertise in Node.js, TypeScript, JavaScript und React. Leidenschaftlich widmet er sich der Erstellung intuitiver und ästhetisch ansprechender Benutzerschnittstellen und arbeitet gerne mit modernen Frameworks sowie der Erstellung gut strukturierter, optisch ansprechender ...

Weiterlesen