
Ein Tool für statische Codeanalyse für CFML.
Lizenz: BSD
Aktuelle Version: 1.5.x
Weitere Informationen finden Sie unter changelog.md.
Cflint ist ein Projekt, an dem Freiwillige entwickelt und bearbeitet werden. Wenn Sie Probleme protokollieren, seien Sie bitte nett und rücksichtsvoll. Wir sind hier, um zu helfen. Wir schätzen die Korrekturen und Verbesserungen sehr.
/src/main enthält den Quellcode. Tests finden Sie in /src/test . CFLINT ist stark auf das CFParser-Projekt sowie eine Reihe von Java-Bibliotheken von Drittanbietern angewiesen.
Der Master -Zweig gilt als unsere stabile Codebasis. Der größte Teil der Entwicklung erfolgt im Dev -Zweig. Lokale Entwicklungszweige für bestimmte Themen.
Geben Sie das Repository in Ihr Konto ein und klonen oder laden Sie die Codebasis als Zip-Datei herunter.
Installieren Sie die Werkzeuge Ihrer Wahl und bauen Sie sie über Gradle oder Maven (veraltet). Cflint benötigt Java 8.
A. Gradle: Ausführen
gradlew build
im CFLINT -Verzeichnis
B. Maven: Ausführen
mvn clean install
im CFLINT -Verzeichnis
Importieren Sie alternativ die CFLINT -Codebasis in die IDE Ihrer Wahl und verwenden Sie die Integration von Gradle/Maven. Dies sollte für Eclipse- und IntelliJ -Nutzer nicht funktionieren.
Holen Sie sich die neueste Version von Maven Central oder der CFLINT GitHub Release -Seite oder erstellen Sie das Projekt.
Wenn Sie CFLINT aus einem anderen Maven -Projekt verwenden möchten, verwenden Sie:
< dependency >
< groupId >com.github.cflint</ groupId >
< artifactId >CFLint</ artifactId >
< version >1.4.0</ version >
</ dependency >Oder verwenden Sie immer die neuesten:
< dependency >
< groupId >com.github.cflint</ groupId >
< artifactId >CFLint</ artifactId >
< version >LATEST</ version >
</ dependency >Wenn die Binärdateien eine oder andere Weise abgerufen haben, können Sie jetzt CFLINT in der Befehlszeile verwenden.
CFLint-1.5.0-all.jar
java -jar CFLint-1.5.0-all.jar -folder <baseFolder>
java -jar CFLint-1.5.0-all.jar -file <fullPathToFile>
java -jar CFLint-1.5.0-all.jar -help
Hinweis: Dies ist eine laufende Arbeit. Wir sammeln derzeit Informationen aus einer Vielzahl von Quellen.
Die einfachsten Optionen für die Ausführung von CFLINT sind die Befehlszeile. CFLINT verfügt derzeit über einen UI -Modus (ausgelöst von -UI in der Befehlszeile), der vom neuesten für CFLint 2.0 entfernt wird - siehe Ausgabe Nr. 316. Wenn Sie sich auf den UI -Modus verlassen, sind Sie leider auf eigene Faust - von hier aus werden keine Arbeiten mehr darauf eingehen.
Alternativ zur Befehlszeile können Sie .cflintrc -Dateien in bestimmte Verzeichnisse einfügen. Durch Konfigurieren von CFlint auf diese Weise können Sie konzeptionell bestimmte Regeln in bestimmten Teilen Ihrer Anwendung ausführen.
CFLINT unterstützt derzeit die JSON- und XML-basierte Konfiguration. Die XML-basierte Konfiguration ist in CFLINT 1.3.0 veraltet und wird in Cflint 2.0 entfernt.
Wenn Cflint ausgeführt wird, scannt und analysiert es Ihren Code (mit CFParser). Der Syntaxbaum wird dann gegen eine Reihe von integrierten Regeln untersucht.
In Cflint werden diese Regeln als Plugins aufgerufen und implementiert (sie leben in /src/main/java/com/cflint/plugins ). Standardmäßig werden alle Regeln gegen Ihre Codebasis verwendet. Dies ist, was viele Menschen tun, aber mit der Konfiguration können Sie ein benutzerdefiniertes Szenario erstellen, um Ihren Code zu testen. Weitere Informationen zu Regeln und ihrer Bedeutung finden Sie in Regeln.md.
CFLINT ist überlegen und jede Veröffentlichung nach 1.3.0 wird in Verzeichnissen niemals mit a gescannt . Um die Zeitverschwendung von versteckten Verzeichnissen wie Erstellungskonfiguration, Modul-/Bibliothekspeicher oder Versionskontrollinformationen zu verhindern.
Die Standard- und globale Konfigurationsdatei ist /src/main/resources/cflint.definition.json . Die übliche Verwendung von CFLint erfordert normalerweise nicht, dass diese Datei ersetzt wird.
Wenn Sie eine .cflintrc -Datei in ein Verzeichnis einfügen, können Sie bestimmte Regeln angeben, die für dieses Verzeichnis und seine Kinder ausgeführt werden sollten. Darüber hinaus können Sie eine Handvoll anderer Eigenschaften angeben.
Ein Beispiel .cflintrc -Datei ist unten dargestellt:
{
"rule" : [ ],
"excludes" : [ ],
"includes" : [ {
"code" : " FUNCTION_HINT_MISSING "
} ],
"inheritParent" : false ,
"parameters" : { }
} rule können Sie ein Plugin für diesen Ordner hinzufügen, der in der globalen Konfiguration nicht aufgeführt ist. ruleImpl finden Sie in cflint.definition.json .
excludes und includes können Sie ein Array von Objekten angeben, die Regeln beschreiben, die Sie für dieses Verzeichnis und seine Kinder angewendet werden möchten. Im obigen Beispiel ist die einzige Regel, auf die man überprüft werden muss, function_hint_miss.
inheritParent -Konfiguration, wenn die in der globalen oder einer übergeordneten Konfiguration festgelegten Regeln als Basissatz von Regeln vererbt werden sollten.
parameters ermöglichen die Konfiguration von Regeln. Siehe Regeln.MD für die Parameter jeder Regel und deren Standardeinstellungen. Sie müssen dem Parameternamen mit dem durch einen Punkt getrennten Regelnamen vorangehen.
Bitte beachten Sie: inheritPlugins und output wurden in CFLint 1.2.0 markiert und in 1.4.0 entfernt. Das Plugin -Vererbung wird jetzt immer als wahr behandelt, da das Team keinen Anwendungsfall sehen kann, in dem es deaktiviert werden sollte. Der Ausgangstyp kann an anderer Stelle gesteuert werden, z. B. Befehlszeilenflags.
Wir bieten ein Schema mit den veralteten Eigenschaften aus.
In den Rezepten finden Sie einige Verwendungsbeispiele von .cflintrc . Beispieldateien finden Sie durch das Durchsuchen der Projekttestdateien.
Sehr oft gibt es Szenarien, in denen Sie im Allgemeinen eine bestimmte Reihe von Regeln gegen Ihren Code ausführen möchten, in bestimmten Fällen jedoch einen ansonsten gültigen Verstoß ignorieren müssen.
Ein häufiges Beispiel sind Verstöße gegen cfqueryparam_req, die nicht durch Anwenden <cfqueryparam> behoben werden können, da Ihr DB -Server in bestimmten Positionen keine Parameter zulässt (zum Beispiel in einer SELECT something FROM #application.config.linkedServerName#.DefaultDatabase.dbo.Comment Szenario). Weitere Beispiele finden Sie in Ausgabe 282.
CFLINT bietet eine Annotations-basierte Konfiguration für diese und ähnliche Szenarien. Annotationen können auf der Komponenten- oder Funktionsebene in einem CFC oder Inline mit Code platziert werden.
<!---
@CFLintIgnore SOMETHINGELSE,MISSING_VAR,ANOTHERTHINGTOIGNORE
--->
Ignorieren Sie alle Regeln in der aktuellen Zeile:
//cflint ignore:line
Ignorieren Sie eine bestimmte Regel (oder eine von Kommas getrennte Liste von Regeln) in der aktuellen Zeile:
//cflint ignore:MISSING_VAR
Multiline ignorieren Anmerkungen:
/*
@CFLintIgnore SOMETHINGELSE,MISSING_VAR,ANOTHERTHINGTOIGNORE
*/
Innerhalb von SQL können Sie auch verwenden
<!--- @CFLintIgnore CFQUERYPARAM_REQ --->
eine Regelverletzung in der nächsten Zeile zu ignorieren.
Die Konfiguration, welche Plugins ausgeführt werden und welche Regeln enthalten sind, beginnt mit der globalen Konfiguration und fließt über die Befehlszeilenparameter, die Ordnerebene und bis zu den Anmerkungen innerhalb der Quelle.
-configfile , wir empfehlen diese Option nicht , in den täglichen Operationen von CFLint verwendet zu werden.-rulegroups , Standardverhalten sind -ReleGroups! Experimental)-includeRule und -excludeRule ) aus)Die Konfigurationsregel, die der Regel am nächsten ist, ist diejenige, die wirksam wird.
.cflintrc , fügt sie jedoch wieder in den Quelldateien in diesem Teil des Quellbaums ab.-includeRule "MISSING_VAR,CFQUERYPARAM_REQ" CFLINT unterstützt eine Vielzahl von Berichterungs- und Ausgabeoptionen, die Sie über Befehlszeilenflags steuern können. Über die gezielten Ausgangsformate von Text, XML, JSON oder HTML können Sie CFLint auch mit Optionen für die Ausgabe von Ruhe, ausführlich und Debuggen ausführen.
Wenn überhaupt kein gezielter Ausgangsformat angegeben ist, erstellt CFLINT standardmäßig einen HTML-Bericht in der Datei cflint-result.html .
Sie können das Ausgangsverhalten von CFLINT in STDOut und Stderr erzwingen, indem Sie Optionen für Ruhe, ausführliche und debuggen angeben. Wenn Sie auch nicht angeben, gibt CFLINT die grundlegenden internen Informationen und die Fehlerausgabe an stdout und stderr zurück.
Der ruhige Modus ( -quiet <boolean> ) unterdrückt den größten Teil des Ausgangs -Cflint beim Linieren. Dies kann tatsächliche Fehler und Ausnahmen enthalten, aber auch Informationen wie die Beendigung der rekursiven Vorlage analysieren oder bestimmte Konfigurationsprobleme. Führen Sie nicht den ruhigen Modus aus, wenn Sie wahrscheinlich Unterstützung bei Fehlermeldungen benötigen oder besser verstehen möchten, was CFLINT tut.
Dies ist der minimale Ausgangsmodus, in dem Sie Cflint ausführen können, und die Funktion wurde ursprünglich von Ausgabe 4 inspiriert.
In diesem Stadium können gelegentliche Nachrichten von CFParser und Antlr in Stderr geschoben werden - obwohl CFLINT im ruhigen Modus läuft. Dies ist ein bekanntes Problem und wird in Zukunft angesprochen.
Der ausführliche Modus ( -verbose <boolean> ) ermöglicht die ausführliche Ausgabe aus der ausführlichen Linie. Dies enthält Informationen zu ausgewählten Ausgabeformaten und Konfigurationsdateien, die gefunden und verarbeitet werden, sowie die aktuell verarbeitete Datei, an der CFLINT funktioniert (angezeigt nur Dateien, die tatsächlich gescannt werden).
Wenn Sie weitere Informationen über die inneren Arbeiten von CFLint während der Ausführung wünschen, ist der ausführliche Modus das Minimum, in dem Sie CFLint ausführen sollten.
Debug -Modus ( -debug <boolean> ) ermöglicht die Debug -Ausgabe. Der Debug -Modus impliziert den ausführlichen Modus, fügt jedoch zusätzliche Informationen wie die Parser -Token und jede verarbeitete Datei (unabhängig davon, ob Sie von Ihrer oder der Standard -Erweiterungsliste unterstützt werden) in die Ausgabestreams hinzu.
Es ist möglich, gleichzeitig ruhige, ausführliche und debuggierte Modi einzuschalten und zusammenzuführen. Dies ist teilweise beabsichtigt, da Sie möglicherweise nicht feststellen möchten, dass Fehlerinformationen im ruhigen Modus unterdrückt werden, aber dennoch sehen möchten, dass bestimmte Informationen im ausführlichen Modus angezeigt werden. Bitte nehmen Sie dieses Verhalten jedoch mit einem Salzkörnchen an -es könnte das seltsame Szenario geben, in dem das Kombination von -quiet , -verbose und -debug eine ungewöhnliche Leistung verursacht.
Die Ausnahme ist der Debug -Modus. Im Debug -Modus ignoriert CFLINT die Benutzereinstellungen immer für ausführliche und ruhige und setzt aus, die true und quiet bis false verbose .
Das Flag -html weist Cflint an, ein HTML -Dokument zu erstellen. Die vollständige Syntax ist:
-html -html <outputFileName>
Das Flag -xml weist Cflint an, XML zu erstellen. Es gibt zwei Optionen für die XML -Berichterstattung.
Die erste Option ist das, was wir Cflint XML nennen. Es ist ein internes Format, das hier ein grundlegendes Schema hält. Sie können dieses Format dann als IS verwenden oder eine weitere Verarbeitung Ihrer Wahl durchführen.
Die zweite Option ist Findbugs XML. Das resultierende XML-Dokument hält die aktuelle Version der FindBugs Bugcollection XML-Schema-Definition an und kann in den meisten CII/Build-Server-Produkten verwendet werden. JetBrains TeamCity 10+ kann dieses Format außerhalb der Box importieren.
Bitte beachten Sie : Derzeit ist es nicht möglich, beide Geschmacksrichtungen von XML -Berichten gleichzeitig zu erstellen. Dies ist eine bekannte Einschränkung. Diese Einschränkung wird im Rahmen von Cflint 2.0 entfernt (siehe Ausgabe Nr. 331).
So erstellen Sie CFLint XML, geben Sie die folgenden Befehlszeilenargumente an:
-xml -xmlstyle cflint -xmlfile <outputFileName>
Beispiel für Cflint XML:
<? xml version = " 1.0 " encoding = " UTF-8 " ?>
< issues version = " 1.2.1 " timestamp = " 1500107134 " >
< issue severity = " WARNING " id = " CFQUERYPARAM_REQ " message = " CFQUERYPARAM_REQ " category = " CFLint " abbrev = " CR " >
< location file = " /Users/kai/Documents/Code/paypal.cfc " fileName = " paypal.cfc " function = " doSomething " column = " 0 " line = " 325 " message = " < cfquery > should use < cfqueryparam/ > for variable 'arguments.PaymentType'. " variable = " arguments.PaymentType " >
< Expression > <![CDATA[ <cfquery name="doPayment" datasource="#paymentDatasource#">...some more Details... ]]> </ Expression >
</ location >
</ issue >
< issue severity = " WARNING " id = " CFQUERYPARAM_REQ " message = " CFQUERYPARAM_REQ " category = " CFLint " abbrev = " CR " >
< location file = " /Users/kai/Documents/Code/paypal.cfc " fileName = " paypal.cfc " function = " doSomethingElse " column = " 0 " line = " 432 " message = " < cfquery > should use < cfqueryparam/ > for variable 'arguments.something'. " variable = " arguments.something " >
< Expression > <![CDATA[ <cfquery name="doPayment" datasource="#paymentDatasource#">...some more Details... ]]> </ Expression >
</ location >
</ issue >
...
< counts totalfiles = " 108 " totallines = " 55596 " >
< count code = " CFQUERYPARAM_REQ " count = " 39 " ></ count >
< count severity = " WARNING " count = " 39 " ></ count >
</ counts >
</ issues >So erstellen Sie FindBugs XML, geben Sie die folgenden Befehlszeilenargumente an:
-xml -xmlstyle findbugs -xmlfile <outputFileName>
Das FindBugs XML-Format wird derzeit mit einem XSLT-Dokument erstellt, wodurch der CFLINT-Bericht in Findbugs XML ( /src/main/resources/findbugs/cflint-to-findbugs.xsl ) verwandelt wird.
JSON -Ausgabe kann erstellt werden mit
-json -jsonfile <outputFileName>
Beispiel von Cflint JSON:
{
"version" : " 1.2.1 " ,
"timestamp" : 1501202128 ,
"issues" : [ {
"severity" : " ERROR " ,
"id" : " MISSING_VAR " ,
"message" : " MISSING_VAR " ,
"category" : " CFLINT " ,
"abbrev" : " MV " ,
"locations" : [ {
"file" : " src/test/resources/com/cflint/tests/Ignores/ignoreCFMLAny2.cfc " ,
"fileName" : " ignoreCFMLAny2.cfc " ,
"function" : " testFunction " ,
"column" : 6 ,
"line" : 14 ,
"message" : " Variable someVar is not declared with a var statement. " ,
"variable" : " someVar " ,
"expression" : " someVar "
} ]
} ],
"counts" : {
"totalFiles" : 7 ,
"totalLines" : 49 ,
"countByCode" : [ {
"code" : " MISSING_VAR " ,
"count" : 1
} ],
"countBySeverity" : [ {
"severity" : " ERROR " ,
"count" : 1
} ]
}
}Das JSON -Schema ist hier verfügbar.
Einfacher Textausgabe kann erstellt werden mit
-text -textfile <outputFileName>
Beispiel für einen einfachen Textausgang:
Issue
Severity:WARNING
Message code:CFQUERYPARAM_REQ
File:/Users/kai/Documents/Code/paypal.cfc
Column:0
Line:79
Message:<cfquery> should use <cfqueryparam/> for variable 'arguments.something'.
Variable:'arguments.something' in function:
Expression:<cfquery name="qry" datasource="#variables.dsn#" cachedwithin="#createTimeSpan(0,0,arguments.cacheInMins,0)#">rn...some Details...
Severity:WARNING
Message code:CFQUERYPARAM_REQ
File:/Users/kai/Documents/Code/paypal.cfc
Column:0
Line:145
Message:<cfquery> should use <cfqueryparam/> for variable 'arguments.something'.
Variable:'arguments.something' in function:
Expression:<cfquery name="qry" datasource="#variables.dsn#" cachedwithin="#createTimeSpan(0,0,arguments.cacheInMins,0)#">rn...some Details...
...
Total files:108
Total lines:55690
Issue counts:1
CFQUERYPARAM_REQ:4
Total issues:4
Total warnings:4
Um direkt mit Cflint innerhalb des JVM zu interagieren, verwenden Sie die Cflint -API.
import com . cflint . api . CFLintAPI ;
import com . cflint . api . CFLintResult ;
CFLintAPI api = new CFLintAPI ();
CFLintResult result = api . scan ( filename );
String jsonResult = result . getJSON ();Für Jenkins schauen Sie sich bitte das unten erwähnte Jenkins/Hudson -Plugin an.
Das TeamCity von JetBrains bietet Unterstützung für Findbugs XML -Code -Inspektionsberichte. Sie können ab 1.2.0 aus dem Box produziert werden (siehe oben im Abschnitt "FindBugs XML).
Sonarqube unterstützt das Sonar Coldfusion -Plugin von Stepstone, das unten weiter unten erwähnt wird.
Für Azure DevOps/TFS schauen Sie sich bitte die weiter unten erwähnte Azure -Pipeline/TFS -Erweiterung an.
Es gibt einen NPM -Wrapper für Cflint unten. Bitte beachten Sie, dass die Wrapper mit einem eigenen gebündelten Cflint-Binary zu kommen scheint, der möglicherweise nicht auf dem neuesten Stand ist und außerhalb unserer Kontrolle liegt.
Andere Produkte in der Kategorie Integration/Build Server können ebenfalls funktionieren. Wenn Sie ein bestimmtes Produkt verwenden, das für Sie mit Cflint funktioniert, teilen Sie uns dies bitte mit. Wenn Sie CFLINT nicht dazu bringen können, in einer Umgebung zu arbeiten, die Sie verwenden, teilen Sie uns bitte auch mit - wir können möglicherweise helfen.
Es gibt mehrere IDE -Integrationen für Cflint, die verfügbar sind. Im Folgenden finden Sie einige kurze Beschreibungen, aber wenn Sie mehr wissen möchten, sehen Sie interessante Projekte von Drittanbietern.
Es gibt IDE-Unterstützung für Sublime Text 3 durch ein Projekt von Drittanbietern, bei dem Sublimelinter verwendet wird.
Es gibt auch Unterstützung für den Adobe Coldfusion Builder durch ein Projekt von Drittanbietern. Benutzer von CFBuilder sehen bitte auch die Diskussion in Ausgabe Nr. 327.
Benutzer von Atom können sich über ein Atomlinter über ein Projekt von Drittanbietern integrieren.
Eine Erweiterung für Visual Studio-Code ist auch als Drittanbieterprojekt erhältlich.
Die Unterstützung für JetBrains ' Intellij ist als Drittanbieter-Plugin erhältlich.
package com . cflint . plugins . core ;
import net . htmlparser . jericho . Element ;
import cfml . parsing . cfscript . script . CFFuncDeclStatement ;
import cfml . parsing . cfscript . script . CFFunctionParameter ;
import cfml . parsing . cfscript . script . CFScriptStatement ;
import com . cflint . BugList ;
import com . cflint . plugins . CFLintScannerAdapter ;
import com . cflint . plugins . Context ;
import com . cflint . tools . CFTool ;
public class ArgDefChecker extends CFLintScannerAdapter {
@ Override
public void expression ( final CFScriptStatement expression , final Context context , final BugList bugs ) {
if ( expression instanceof CFFuncDeclStatement ) {
final CFFuncDeclStatement function = ( CFFuncDeclStatement ) expression ;
for ( final CFFunctionParameter argument : function . getFormals ()) {
// handler.addArgument(param.getName());
final String name = argument . getName ();
if (! argument . toString (). contains ( "required" ) && ! argument . toString (). contains ( "=" )) {
function . getLine ();
function . getColumn ();
context . addMessage ( "ARG_DEFAULT_MISSING" , name );
}
}
}
}
@ Override
public void element ( final Element element , final Context context , final BugList bugs ) {
if ( element . getName (). equals ( "cfargument" )) {
final String name = element . getAttributeValue ( "name" );
final boolean required = CFTool . toBoolean ( element . getAttributeValue ( "required" ));
final String defaultExpr = element . getAttributeValue ( "default" );
if (! required && defaultExpr == null ) {
element . getSource (). getRow ( element . getBegin ());
element . getSource (). getColumn ( element . getBegin ());
context . addMessage ( "ARG_DEFAULT_MISSING" , name );
}
}
}
} Wenn Sie sich das element ansehen, sind die Argumente:
element - das aktuelle CFML -Tagcontext - Die aktuelle Datei wird überprüftbugs - das angemessene Objekt von Verstößen Der einfachste Weg, dies zu erreichen, ist eine benutzerdefinierte .cflintrc -Datei:
Das Feld includes das Feld wird ignoriert, wenn es sich um eine leere Liste handelt. Fügen Sie ihm einfach ein einzelnes Element hinzu, für den nichts übereinstimmt.
{
"code" : " NOTHING "
}oder einfacher:
{}Im Folgenden wird alle Regeln im aktuellen Ordner und unten ignoriert.
{
"rule" : [ ],
"excludes" : [ ],
"includes" : [ {} ],
"inheritParent" : false ,
"parameters" : {}
} Dies kann anhand der Standardwerte einer .cflintrc -Datei vereinfacht werden:
{
"includes" : [{}],
"inheritParent" : false
}Weitere Informationen finden Sie in der Diskussion in Ausgabe Nr. 290.
Parameter innerhalb der Regeln können in den .cflintrc -Dateien überschrieben werden. Verwenden Sie den Regelnamen und den Parameter mit einem Punkt.
{
"parameters" : {
"VariableNameChecker.maxLength" : " 15 "
}
} Geben Sie in der Befehlszeile eine cflintexclude.json -Datei mit dem Argument für -FilterFile an.
Fügen cflintexclude.json die folgenden Fügen
[
other exclude rules...,
{"file":".*some\\package\\location\\.*","code":"GLOBAL_VAR"}
]
Hinweis: Die hinteren Schrägstriche müssen zweimal für JSON entkommen, einmal für reguläre Ausdrücke
[
other exclude rules...,
{"file":".*some/package/location/.*","code":"GLOBAL_VAR"}
]
Lebe hier auf Github Probleme und wir werden sie mir ansehen.
Das CFML Slack -Team verfügt über einen #cflint -Kanal, an dem Sie die meisten regulären Mitarbeiter und anderen Benutzer sprechen können.
Weitere Informationen finden Sie unter Beitrags.md.
Bitte beachten Sie, dass die Mehrheit der hier genannten Bibliotheken und Projekte nicht direkt mit dem CFLINT -Team zusammenhängt und sie verwaltet. Bitte beachten Sie die Autoren und Betreuer des jeweiligen Projekts, um zuerst die Unterstützung der Bibliotheken zu unterstützen.
Wenn Sie an einem Projekt, das sich mit CFLint bezieht, an einem Projekt gearbeitet (oder darüber nachdenken), lassen Sie es uns bitte wissen. Wir freuen uns, relevante Projekte von Drittanbietern in die obige Liste aufzunehmen.