CXXGraph ist eine umfassende C++-Bibliothek, die Diagrammalgorithmen verwaltet. Diese reine Header-Bibliothek dient als Alternative zur Boost Graph Library (BGL).
Wir suchen:
Wenn Sie Interesse haben, kontaktieren Sie uns bitte unter [email protected] oder tragen Sie zu diesem Projekt bei. Wir warten auf Sie!
Vollendet | Beschreibung | Datum der Fertigstellung |
---|---|---|
✔️ | Version 0.4.0 | 7. Okt. 2022 |
✔️ | Version 0.5.0 | 23. März 2023 |
✔️ | Erste stabile Version 1.0.0 | 28. März 2023 |
✔️ | Version 1.0.1 | 7. Mai 2023 |
✔️ | Version 1.1.0 | 8. Mai 2023 |
✔️ | Stabile Version 2.0.0 | 1. Juni 2023 |
✔️ | Stabile Version 3.0.0 | 3. November 2023 |
✔️ | Version 3.1.0 | 9. Januar 2023 |
Stellen Sie Hypergraph Nr. 122 vor | Noch offen | |
Stabile Version 4.0.0 | Noch offen |
Führen Sie zur Installation auf Unix/Linux-Systemen Folgendes über die Befehlszeile aus:
$ sudo tar xjf CXXGraph-{version}.tar.bz2
Zum Deinstallieren:
$ sudo rm -f /usr/include/Graph.hpp /usr/include/CXXGraph*
Führen Sie zur Installation auf Fedora/CentOS/RedHat-Systemen Folgendes über die Befehlszeile aus:
$ sudo rpm -ivh CXXGraph-{version}.noarch.rpm
Zum Deinstallieren:
$ sudo rpm -e CXXGraph-{version}
Um auf Debian/Ubuntu-Systemen zu installieren, führen Sie Folgendes über die Befehlszeile aus:
$ sudo dpkg -i CXXGraph_{version}.deb
Zum Deinstallieren:
$ sudo apt-get remove CXXGraph
Führen Sie bei selbstkompilierten Installationen mit CMake Folgendes über die Befehlszeile aus, sobald die Kompilierung abgeschlossen ist:
$ sudo make install
Die Klassenerklärung finden Sie im Abschnitt „Klassen“ der Doxygen-Dokumentation
Um die Bibliothek zu verwenden , platzieren Sie einfach die Header-Datei dort, wo Sie sie benötigen. So einfach ist das!
In Arbeit
Für den Unit-Test sind CMake 3.9 und höher sowie die GoogleTest -Bibliothek erforderlich.
GoogleTest
git clone https://github.com/google/googletest.git
cd googletest # Main directory of the cloned repository
mkdir -p build # Create a directory to hold the build output
cd build
cmake .. # Generate native build scripts for GoogleTest
make # Compile
sudo make install # Install in /usr/local/ by default
Aus dem Basisverzeichnis:
mkdir -p build # Create a directory to hold the build output
cd build # Enter the build folder
cmake -DTEST=ON .. # Generate native build scripts for GoogleTest,
make # Compile
Nachdem der Build kompiliert wurde, führen Sie die ausführbare Datei „test_exe“ im Verzeichnis „build“ mit dem folgenden Befehl aus:
./test_exe
Für den Benchmark sind CMake 3.9 und höher, die GoogleTest -Bibliothek und die Google Benchmark -Bibliothek erforderlich.
Google-Benchmark
# Check out the library
$ git clone https://github.com/google/benchmark.git
# Google Benchmark requires GoogleTest as a dependency. Add the source tree as a subdirectory
$ git clone https://github.com/google/googletest.git benchmark/googletest
# Go to the library's root directory
$ cd benchmark
# Make a build directory to place the build output
$ cmake -E make_directory " build "
# Generate the build system files with CMake
$ cmake -E chdir " build " cmake -DCMAKE_BUILD_TYPE=Release ../
# If starting with CMake 3.13, you can use the following:
# cmake -DCMAKE_BUILD_TYPE=Release -S . -B "build"
# Build the library
$ cmake --build " build " --config Release
# Install the library
$ sudo cmake --build " build " --config Release --target install
Aus dem Basisverzeichnis:
mkdir -p build # Create a directory to hold the build output
cd build # Enter the build folder
cmake -DBENCHMARK=ON .. # Generate native build scripts for Google Benchmark
make # Compile
Nachdem der Build kompiliert wurde, führen Sie die ausführbare Datei „benchmark“ im Verzeichnis „build“ mit dem folgenden Befehl aus:
./benchmark
Das Benchmark-Ergebnis können Sie über diesen Link überprüfen.
Um ein Tarball-Paket zu erstellen, führen Sie Folgendes über die Befehlszeile aus:
# Enter Packaging Directory
$ cd packaging
# Execute the script to generate tarballs
$ ./tarballs.sh
Um ein RPM-Paket zu erstellen, führen Sie Folgendes über die Befehlszeile aus:
# Enter Packaging Directory
$ cd packaging/rpm
# Execute the script to generate tarballs
$ ./make_rpm.sh
Um ein Deb-Paket zu erstellen, führen Sie Folgendes über die Befehlszeile aus:
# Enter Packaging Directory
$ cd packaging/deb
# Execute the script to generate tarballs
$ ./make_deb.sh
Graph Dijkstras Shortest Path Algorithm(Dijkstra's Shortest Path) [Dijkstra's Algorithm] (https://www.interviewbit.com/blog/find-shortest-path-dijkstras-algorithm/) wird verwendet, um den kürzesten Weg von einem Quellknoten zu zu finden alle anderen erreichbaren Knoten im Diagramm. Der Algorithmus geht zunächst davon aus, dass alle Knoten vom angegebenen Quellknoten aus nicht erreichbar sind, daher markieren wir die Entfernungen aller Knoten als unendlich. (unendlich) vom Quellknoten (INF/unendlich bedeutet nicht erreichbar).
Wählspezialisierung des Dijkstra-Algorithmus.
Wenn Kantengewichte kleine ganze Zahlen sind (begrenzt durch einen Parameter C ), können spezielle Warteschlangen, die sich diese Tatsache zunutze machen, verwendet werden, um den Dijkstra-Algorithmus zu beschleunigen. Der erste Algorithmus dieser Art war Dials Algorithmus (Dial 1969) für Graphen mit positiven ganzzahligen Kantengewichten, der eine Bucket-Warteschlange verwendet, um eine Laufzeit O(|E|+|V|C) zu erhalten. (Quelle Wikipedia)
Nachfolgend finden Sie den vollständigen Algorithmus:
Unter diesem Link finden Sie eine Schritt-für-Schritt-Anleitung.
Prims Algorithmus Prims Algorithmus ist ein Greedy-Algorithmus, der einen minimalen Spannbaum für einen gewichteten ungerichteten Graphen findet. Dies bedeutet, dass eine Teilmenge der Kanten gefunden wird, die einen Baum bilden, der jeden Scheitelpunkt umfasst, wobei das Gesamtgewicht aller Kanten im Baum minimiert wird. Der Algorithmus baut diesen Baum Scheitelpunkt für Punkt auf, ausgehend von einem beliebigen Startscheitelpunkt, und fügt bei jedem Schritt die günstigste mögliche Verbindung vom Baum zu einem anderen Scheitelpunkt hinzu.
Schritte:
(Breadth First Search) Algorithmus zur Breitensuche (Breadth First Search) Die Breitensuche , auch als BFS bezeichnet, ist ein Graph-Traversal-Algorithmus. Zeitkomplexität O(|V| + |E|), wobei V die Anzahl der Eckpunkte und E die Anzahl der Kanten im Diagramm sind. Anwendungen der Breitensuche sind:
Und es gibt noch viele mehr...
(Depth First Search) Depth First Search-Algorithmus (Depth First Search) Depth First Search , auch als DFS bezeichnet, ist ein Graph-Traversal-Algorithmus. Zeitkomplexität O(|V| + |E|), wobei V die Anzahl der Eckpunkte und E die Anzahl der Kanten im Diagramm ist. Anwendungen der Tiefensuche sind:
Und es gibt noch viele mehr...
Best First Search ist eine Klasse von Suchalgorithmen, die den Graphen durchsuchen, indem sie den vielversprechendsten Knoten untersuchen, der anhand einer Bewertungsfunktion ausgewählt wird. Die Zeitkomplexität im ungünstigsten Fall beträgt O(n * log n), wobei n die Anzahl der Knoten im Diagramm ist.
Zyklus (Graphentheorie)
Das Vorhandensein eines Zyklus in gerichteten und ungerichteten Graphen kann dadurch bestimmt werden, ob die Tiefensuche (DFS) eine Kante findet, die auf einen Vorfahren des aktuellen Scheitelpunkts zeigt (sie enthält eine Hinterkante). Alle Hinterkanten, die DFS überspringt, sind Teil von Zyklen. In einem ungerichteten Diagramm sollte die Kante zum übergeordneten Knoten eines Knotens nicht als Hinterkante gezählt werden, aber das Finden eines anderen bereits besuchten Knotens weist auf eine Hinterkante hin. Bei ungerichteten Graphen ist nur O(n) Zeit erforderlich, um einen Zyklus in einem n-Eckpunkt-Graphen zu finden, da höchstens n − 1 Kanten Baumkanten sein können.
Viele topologische Sortieralgorithmen erkennen auch Zyklen, da diese Hindernisse für die Existenz topologischer Ordnung darstellen. Auch wenn ein gerichteter Graph in stark zusammenhängende Komponenten unterteilt wurde, existieren Kreise nur innerhalb der Komponenten und nicht zwischen ihnen, da Kreise stark zusammenhängend sind.
Für gerichtete Graphen können verteilte nachrichtenbasierte Algorithmen verwendet werden. Diese Algorithmen basieren auf der Idee, dass eine von einem Scheitelpunkt in einem Zyklus gesendete Nachricht zu sich selbst zurückkehrt. Algorithmen zur Erkennung verteilter Zyklen sind nützlich für die Verarbeitung umfangreicher Diagramme mithilfe eines verteilten Diagrammverarbeitungssystems auf einem Computercluster (oder Supercomputer).
Zu den Anwendungen der Zykluserkennung gehört die Verwendung von Wartediagrammen zur Erkennung von Deadlocks in gleichzeitigen Systemen.
Der Bellman-Ford-Algorithmus kann verwendet werden, um die kürzeste Entfernung zwischen einem Quell- und einem Zielknoten zu ermitteln. Zeitkomplexität O(|V| . |E|), wobei V die Anzahl der Eckpunkte und E die Anzahl der Kanten im Diagramm ist, was höher ist als der Algorithmus für den kürzesten Weg von Dijkstra. Die zeitliche Komplexität des Dijkstra-Algorithmus beträgt O(|E| + |V| log |v| ). Der Vorteil von Bellman-Ford gegenüber Dijkstra besteht darin, dass es Diagramme mit negativen Kantengewichten verarbeiten kann. Wenn das Diagramm außerdem einen negativen Gewichtszyklus enthält, kann der Algorithmus das Vorhandensein eines negativen Gewichtszyklus erkennen und melden.
Dieses Video gibt einen schönen Überblick über die Algorithmusimplementierung. Dieser MIT-Vortrag liefert einen Beweis für die Richtigkeit von Bellman-Ford und seine Fähigkeit, negative Zyklen zu erkennen. Anwendungen:
Floyd Warshall-Algorithmus
Als ersten Schritt initialisieren wir die Lösungsmatrix genauso wie die Eingabediagrammmatrix. Dann aktualisieren wir die Lösungsmatrix, indem wir alle Scheitelpunkte als Zwischenscheitelpunkt betrachten. Die Idee besteht darin, nacheinander alle Scheitelpunkte auszuwählen und alle kürzesten Pfade zu aktualisieren, die den ausgewählten Scheitelpunkt als Zwischenscheitelpunkt im kürzesten Pfad enthalten. Wenn wir den Scheitelpunkt Nummer k als Zwischenscheitelpunkt auswählen, haben wir bereits die Scheitelpunkte {0, 1, 2, .. k-1} als Zwischenscheitelpunkte betrachtet. Für jedes Paar (i, j) der Quell- bzw. Zielscheitelpunkte gibt es zwei mögliche Fälle.
Transitive Reduktion
Dieser Algorithmus wird verwendet, um einen gerichteten Graphen mit der gleichen Erreichbarkeit zu erstellen und den transitiven Abschluss mit möglichst wenigen Kanten zu erfüllen. Konkreter wird ein minimaler äquivalenter Graph mit möglichst wenigen Kanten erstellt, wodurch „Kurzschlusspfade“ durch den Graphen vermieden werden.
Dazu wird jedes Knotenpaar durchlaufen und überprüft, ob zwei Kanten vorhanden sind, die aus dem ersten Knoten ODER aus dem letzten Knoten herausführen, und die Kante des Knotenpaars entfernt, falls vorhanden.
Im Pseudocode: foreach x in graph.vertices foreach y in graph.vertices foreach z in graph.vertices Kante xz löschen, wenn Kanten xy und yz existieren
Unsere Implementierung verfügt über If-Gatter, die frühzeitig an mehreren Stellen nach Kanten suchen, wodurch die Laufzeit etwas schneller ist als beim kubischen Pseudocode hier.
Der Kruskal-Algorithmus kann verwendet werden, um den minimalen Spannwald eines ungerichteten kantengewichteten Graphen zu ermitteln. Zeitkomplexität O(E log E) = O(E log V), wobei V die Anzahl der Eckpunkte und E die Anzahl der Kanten im Diagramm ist. Die Hauptgeschwindigkeitsbeschränkung für diesen Algorithmus ist das Sortieren der Kanten.
Für ein schnelles Verständnis des Algorithmusverfahrens sehen Sie sich dieses Video an. Einige der realen Anwendungen sind:
Andere Algorithmen zum Finden des minimalen Spanning Forest sind der Prim-Algorithmus oder der Borůvka-Algorithmus.
Borůvkas Algorithmus ist ein gieriger Algorithmus, der zum Finden eines minimal aufspannenden Baums in einem Diagramm oder eines minimal aufspannenden Waldes im Fall eines Diagramms, das nicht verbunden ist, verwendet werden kann.
Der Algorithmus beginnt damit, die Kante mit dem minimalen Gewicht zu finden, die zu jedem Scheitelpunkt des Diagramms gehört, und alle diese Kanten zur Gesamtstruktur hinzuzufügen. Anschließend wird ein ähnlicher Vorgang wiederholt, bei dem die Kante mit minimalem Gewicht von jedem bisher erstellten Baum zu einem anderen Baum ermittelt und alle diese Kanten zum Wald hinzugefügt werden. Jede Wiederholung dieses Prozesses reduziert die Anzahl der Bäume innerhalb jeder verbundenen Komponente des Diagramms auf höchstens die Hälfte dieses vorherigen Wertes, sodass der Prozess nach logarithmisch vielen Wiederholungen abgeschlossen ist. Wenn dies der Fall ist, bildet die Menge der hinzugefügten Kanten den minimalen Spannwald.
Es kann gezeigt werden, dass der Algorithmus von Borůvka O(log V) Iterationen der äußeren Schleife durchführt, bis sie endet, und daher in der Zeit O(E log V) läuft, wobei E die Anzahl der Kanten und V die Anzahl der Scheitelpunkte darin ist G (vorausgesetzt E ≥ V).
Mathematische Definition des Problems: Sei G die Menge der Knoten in einem Graphen und n ein gegebener Knoten in dieser Menge. Sei C die nicht-strikte Teilmenge von G, die sowohl n als auch alle von n aus erreichbaren Knoten enthält, und sei C' ihr Komplement. Es gibt eine dritte Menge M, die die nicht-strikte Teilmenge von C ist und alle Knoten enthält, die von jedem Knoten in C' aus erreichbar sind. Das Problem besteht darin, alle Knoten zu finden, die zu C, aber nicht zu M gehören.
Derzeit implementierter Algorithmus:
Anwendung:
Dieser Algorithmus wird in Garbage-Collection-Systemen verwendet, um zu entscheiden, welche anderen Objekte freigegeben werden müssen, vorausgesetzt, dass ein Objekt kurz vor der Freigabe steht.
Der Ford-Fulkerson-Algorithmus ist ein gieriger Algorithmus zum Finden eines maximalen Flusses in einem Flussnetzwerk. Die Idee hinter dem Algorithmus ist folgende: Solange es einen Pfad von der Quelle (Startknoten) zur Senke (Endknoten) gibt und an allen Kanten des Pfads Kapazität verfügbar ist, senden wir den Fluss entlang eines der Pfade. Dann finden wir einen anderen Weg und so weiter. Ein Pfad mit verfügbarer Kapazität wird als Erweiterungspfad bezeichnet.
Der Kosaraju-Algorithmus ist ein linearer Zeitalgorithmus zum Finden der stark zusammenhängenden Komponenten eines gerichteten Graphen. Es basiert auf der Idee, dass, wenn man in der Lage ist, einen Scheitelpunkt v ausgehend von Scheitelpunkt u zu erreichen, man auch in der Lage sein sollte, Scheitelpunkt u ausgehend von Scheitelpunkt v zu erreichen, und wenn dies der Fall ist, kann man sagen, dass die Scheitelpunkte u und v sind stark verbunden – sie befinden sich in einem stark verbundenen Untergraphen. Nachfolgend ein Beispiel:
1). Erstellen Sie einen leeren Stapel „S“ und führen Sie eine DFS-Durchquerung eines Diagramms durch. Bei der DFS-Durchquerung wird nach dem Aufruf von rekursivem DFS für benachbarte Scheitelpunkte eines Scheitelpunkts der Scheitelpunkt in den Stapel verschoben. 2). Kehren Sie die Richtungen aller Bögen um, um den Transponierungsgraphen zu erhalten. 3). Platzieren Sie nacheinander einen Scheitelpunkt aus S, solange S nicht leer ist. Der geknallte Scheitelpunkt sei „v“. Nehmen Sie v als Quelle und führen Sie DFS aus (rufen Sie DFSUtil(v) auf). Das DFS gibt ausgehend von v eine stark verbundene Komponente von v aus.
Kahns Algorithmus ermittelt die topologische Ordnung, indem er iterativ Knoten im Diagramm entfernt, die keine eingehenden Kanten haben. Wenn ein Knoten aus dem Diagramm entfernt wird, wird er der topologischen Reihenfolge hinzugefügt und alle seine Kanten werden entfernt, sodass der nächste Satz von Knoten ohne eingehende Kanten ausgewählt werden kann.
Der walisische Powell-Färbungsalgorithmus ist ein gieriger Vertex-Färbungsalgorithmus. Dieser Algorithmus wird auch verwendet, um die chromatische Zahl eines Graphen zu ermitteln.
Der walisische Powell-Algorithmus besteht aus folgenden Schritten:
Der Algorithmus gibt ein std::map<Node, int>-Ergebnis zurück, das jedem Knoten eine nach Ganzzahlen geordnete Farbe zuweist. Benutzer können auch die minimale chromatische Reihenfolge des Diagramms abfragen, indem sie den höchsten Wert aus der resultierenden Karte abfragen.
std::map<Node, int > result = graph.welshPowellColoring();
auto chromatic_color = std::max_element(result.begin(), result.end(),
[]( const auto & lhs, const auto & rhs) {
return lhs. second < rhs. second ;
}
Die Mindestfärbung beginnt bei 1 statt bei 0.
Der Algorithmus geht davon aus, dass der Graph ungerichtet ist. Alle Quellen und Inspirationen sind in der Deklaration des Algorithmus und der Testfälle verlinkt.
Eine Vertex-Cut-Partitionierung unterteilt die Kanten eines Diagramms in gleich große Partitionen. Die Scheitelpunkte, die die Endpunkte einer Kante enthalten, werden ebenfalls in derselben Partition wie die Kante selbst platziert. Allerdings sind die Scheitelpunkte in allen Partitionen nicht eindeutig und müssen möglicherweise aufgrund der Verteilung ihrer Kanten auf verschiedene Partitionen repliziert (geschnitten) werden.
Der Replikationsfaktor quantifiziert, wie viele Scheitelpunkte über Computer repliziert werden, verglichen mit der Anzahl der Scheitelpunkte des ursprünglichen Eingabediagramms.
Dieser Algorithmus ist ein einfacher Vertex-Cut im Round-Robin-Verfahren. Es nimmt die ursprünglichen Diagrammkanten, weist sie den Partitionen zu und teilt sie in gleiche (oder ähnliche) Größen auf. Dieser Algorithmus kümmert sich nicht um die Optimierung bei der Vertex-Replikation (Replikationsfaktor), sondern gleicht nur die Kante in den Partitionen aus.
Greedy-Partitionierungsalgorithmen nutzen den gesamten Verlauf der Kantenzuweisungen, um die nächste Entscheidung zu treffen. Der Algorithmus speichert die Menge der Partitionen A(v), denen jeder bereits beobachtete Scheitelpunkt v zugeordnet wurde, sowie die aktuellen Partitionsgrößen. Bei der Verarbeitung der Kante e ∈ E, die die Eckpunkte vi, vj ∈ V verbindet, folgt der Greedy-Algorithmus diesem einfachen Regelsatz:
Der High Degree (are) Replicated First (HDRF)-Algorithmus ist ein Greedy-Vertex-Cut-Algorithmus, wie in diesem Artikel beschrieben. Dieser Algorithmus versucht, den Replikationsfaktor zu optimieren, indem er den Verlauf der Kantenzuweisungen und den inkrementellen Scheitelpunktgrad verwendet. Mit einer Funktion, die diese beiden Faktoren berücksichtigt, wird die beste Partition für die Zuweisung der analysierten Kante berechnet. Die erstellten Replikate basieren auf dem Grad der Scheitelpunkte, und die replizierten Scheitelpunkte sind wahrscheinlich sogenannte „Hub-Knoten“, also die Scheitelpunkte mit höherem Grad.
Efficient and Balanced Vertex-cut (EBV) ist ein Offline-Vertex-Cut-Algorithmus, wie in diesem Artikel beschrieben. Dieser Algorithmus versucht, die Partitionen im Hinblick auf die Anzahl der Kanten und Scheitelpunkte jeder Partition und den Replikationsfaktor auszugleichen. Es wendet eine Formel an, um die Partition auszuwerten, in der die Kante zugewiesen wird, wobei auch die Gesamtzahl der Kanten und Scheitelpunkte des Diagramms berücksichtigt wird. Die Bewertungsformel lautet wie folgt:
Der niedrigste Wert wird als Partitions-ID verwendet.
Die Gradmatrix ist eine quadratische Matrix, die Einblicke in die Konnektivität von Knoten in einem Diagramm bietet. Bei gerichteten Graphen spiegelt es die Anzahl der eingehenden und ausgehenden Kanten für jeden Knoten wider, während es bei ungerichteten Graphen die Anzahl der Kanten darstellt, die auf jeden Knoten fallen.
Die Laplace-Matrix ist eine quadratische Matrix, die aus der Adjazenzmatrix und der Gradmatrix eines Graphen abgeleitet wird. Es ist hilfreich bei der Analyse verschiedener Eigenschaften des Diagramms, wie z. B. der Verbundenheit, der Anzahl aufspannender Bäume und anderer spektraler Eigenschaften.
Die Übergangsmatrix wird häufig bei der Untersuchung von Markov-Ketten und stochastischen Prozessen verwendet. Im Kontext eines Diagramms bezeichnet es die Wahrscheinlichkeiten des Übergangs von einem Knoten zu einem anderen, oft basierend auf den Kantengewichten oder vorgegebenen Kriterien. Diese Matrix findet Anwendungen in verschiedenen Bereichen wie Netzwerkanalyse, maschinelles Lernen und Optimierung.
Wenn Sie Ihre Unterstützung geben möchten, können Sie eine Pull-Anfrage erstellen oder ein Problem melden. Wenn Sie den Code ändern, ein Problem beheben oder eine neue Funktion implementieren möchten, lesen Sie bitte unseren Beitragsleitfaden.
Wenn Sie neue Funktionen besprechen möchten oder Fragen oder Anregungen zur Bibliothek haben, eröffnen Sie bitte eine Diskussion oder chatten Sie einfach weiter
CXXGraph-Site
E-Mail: [email protected]
GitHub-Profil
Um mich zu unterstützen, fügen Sie dem Projekt einen Stern hinzu oder folgen Sie mir
Um auf dem Laufenden zu bleiben, schauen Sie sich das Projekt an
Wir werden referenziert von:
Vielen Dank an die Community von TheAlgorithms für die Inspiration zu Algorithmen.
Vielen Dank an GeeksForGeeks für die Inspiration zum Algorithmus.
Vielen Dank an alle Menschen, die bereits zu CXXGraph beigetragen haben!
Wenn Sie diese Software verwenden, befolgen Sie bitte die CITATION-Anweisungen. Danke schön!
Wir haben am Hacktoberfest 2021 teilgenommen. Vielen Dank an alle Mitwirkenden!
Wir haben am Hacktoberfest 2022 teilgenommen. Vielen Dank an alle Mitwirkenden!
Wir haben am Hacktoberfest 2023 teilgenommen. Vielen Dank an alle Mitwirkenden!
Sehen Sie sich den geschätzten Wert des Projekts an
@ZigRazor |
---|