
Jeden Tag helfen uns 2GIS-Benutzer dabei, die Datengenauigkeit aufrechtzuerhalten: Sie informieren über neue Unternehmen, fügen Verkehrsereignisse hinzu, laden Fotos hoch und schreiben Bewertungen. Bisher konnten wir ihnen nur mit Worten danken oder ein Werbegeschenk arrangieren. Aber mit der Zeit werden Worte vergessen und nicht jeder bekommt Geschenke. Deshalb haben wir uns entschlossen sicherzustellen, dass alle, die sich für 2GIS interessieren, ihren Beitrag zum Produkt und unsere Dankbarkeit dafür sehen.
Es gab also Auszeichnungen - virtuelle Medaillen, die wir für verschiedene Aufgaben sammeln: Fotos auf Cafékarten hochladen, Rezensionen über Theater schreiben, Arbeitszeiten von Organisationen festlegen und so weiter. Benutzer sehen die erzielten Belohnungen in ihrem persönlichen 2GIS-Profil und auf der Registerkarte "Mein 2GIS" in der mobilen Anwendung. Dort zeigen wir, wie viel bis zum nächsten Erfolg übrig bleibt.
Um diese Funktion zu implementieren, haben wir gelernt, wie ein Ereignisstrom mit einem Volumen von 500.000 Datensätzen pro Stunde (an Orten mit bis zu 50.000 Datensätzen pro Sekunde) verarbeitet und Daten von mehreren Diensten analysiert werden. Und außerdem haben sie eine kleine Metaprogrammierung hinzugefügt, um die Konfiguration bei der Entwicklung neuer Auszeichnungen zu vereinfachen.
Zusammen mit
Rapter werden wir Ihnen sagen, was sich unter der Haube des Vergabeverfahrens befindet.
Konzept
Um die Komplexität der Funktion zu verstehen, müssen Sie verstehen, wie sich das technische Problem angehört hat. Dann - betrachten Sie die Idee der Implementierung und das allgemeine Schema der Systemkomponenten. Dies werden wir in diesem Abschnitt tun.
Anforderungen an Abstracts
Anforderungen - eine ziemlich langweilige Sache, damit wir nicht alle Nuancen malen, sondern uns auf die wichtigsten Dinge konzentrieren:
- Auszeichnungen werden nur an autorisierte Benutzer vergeben;
- Die Aktualisierung des Fortschritts bei einer Belohnung sollte so schnell wie möglich erfolgen.
- Belohnung - das Ergebnis eines Benutzers, der eine Reihe von Aktionen im Produkt ausführt: Hochladen eines Fotos, Schreiben einer Bewertung, Finden von Anweisungen usw. Es gibt viele Datenquellen.
Architektonische Idee
Die Idee der Implementierung ist nicht sehr kompliziert. Es kann theoretisch ausgedrückt werden:
- Die Auszeichnung besteht aus Aufgaben, deren Ergebnisse gemäß der bei der Konfiguration der Auszeichnung angegebenen Formel kombiniert werden.
- Die Aufgabe reagiert auf Ereignisse über Benutzeraktionen von außen, filtert sie und registriert die Änderung in Form von Zählern.
- „Externe Ereignisse“ werden von Mastersystemen (Foto-, Feedback-, Verfeinerungsdienste usw.) oder Hilfsdiensten generiert, die bereits vorhandene Ereignisflüsse transformieren oder filtern.
- Die Ereignisverarbeitung erfolgt asynchron und kann bei Bedarf jederzeit gestoppt werden.
- Der Benutzer sieht den aktuellen Status seiner Auszeichnungen.
- Alles andere sind die Details ...
Schlüsselentitäten
Das folgende Diagramm zeigt die Hauptentitäten des Themenbereichs und ihre Beziehung:

Im Diagramm werden zwei Zonen unterschieden:
- Schema - eine Zone zur Beschreibung der Struktur von Auszeichnungen und der Regeln für deren Abgrenzung;
- Daten - Auszeichnungsbereich für bestimmte Benutzer und Daten zu ihrem aktuellen Status.
Die Entitäten im Diagramm:
- Erhalten - Informationen über die Auszeichnung, die erhalten werden können. Enthält Metainformationen und eine Beschreibung, wie die Ergebnisse von Aufgaben kombiniert werden können - eine Strategie.
- Ziel - eine Aufgabe, deren Bedingungen erfüllt sein müssen, um eine Auszeichnung zu erhalten.
- UserAchieve - Der aktuelle Status der Belohnung für einen bestimmten Benutzer.
- UserObjective - Der aktuelle Status des Belohnungsjobs des Benutzers.
- Benutzer - Informationen über den Benutzer, die für Benachrichtigungen und das Verständnis seines aktuellen Status erforderlich sind (entfernte und gesperrte Belohnungen sind nicht erforderlich).
- ProcessingLog - Ein Protokoll der Rückstellungen für Aufgaben. Enthält Informationen darüber, wie eine bestimmte Aktion den Fortschritt der Zuweisung beeinflusst hat.
- Ereignis - Die minimal erforderlichen Informationen zu einem Ereignis, die den Fortschritt der Aufgaben des Benutzers irgendwie beeinflusst haben.
Servicestruktur
Betrachten Sie nun die Hauptkomponenten des Dienstes und ihre Abhängigkeiten:

- Ereignisbus - Ein Ereignisbus, mit dem Aufgaben erledigt werden können. Wir verwenden Apache Kafka.
- Master- und Slave-DBs sind das Haupt-Data-Warehouse. In diesem Fall ein PostgreSQL-Cluster.
- ConsumingWorkers - Handler für Busereignisse. Die Hauptaufgabe besteht darin, Ereignisse aus einer bestimmten Quelle (Fotos, Rezensionen usw.) zu lesen, sie auf Benutzeraufgaben anzuwenden und das Ergebnis zu speichern.
- AchievesWorker - zeigt den Fortschritt der Benutzerbelohnungen entsprechend dem Status der Aufgaben an.
- NotificationWorkers - eine Reihe von Handlern zum Planen und Senden von Benachrichtigungen über den Erhalt von Auszeichnungen, Ankündigungen neuer möglicher Erfolge usw.
- Öffentliche API - eine öffentliche REST-Schnittstelle für Web- und mobile Anwendungen.
- Private API - REST-Schnittstelle für das Admin-Panel, die bei der Untersuchung von Vorfällen und der Serviceunterstützung hilft. Es steht Entwicklern und Supportteams zur Verfügung.
Jede der Komponenten ist in Bezug auf Logik und Verantwortungsbereiche isoliert, wodurch unnötige Integrationen und Deadlocks beim Ändern von Daten vermieden werden. Im Folgenden betrachten wir nur einen Teil des Schemas, das mit der Verarbeitung von Ereignissen und deren Umwandlung in Belohnungen verbunden ist.
Ereignisbehandlung
Inhalt
Belohnungen sind in erster Linie ein Datenaggregationsdienst. Jedes Mastersystem generiert verschiedene Arten von Ereignissen. In der Regel hängt jeder Ereignistyp eng mit dem Status des Inhalts und seinem Statusmodell zusammen. So kann ein Foto moderiert, gelöscht, blockiert, ausgeblendet oder aktiv werden. All dies sind unterschiedliche Ereignisse, die von einem separaten Mitarbeiter behandelt werden, der sich auf eine bestimmte Quelle spezialisiert hat. Derzeit besteht eine Interaktion mit folgenden Quellen (Mastersystemen):
- Foto - Erzeugt verschiedene Ereignisse, die sich auf Vorgänge beziehen, die Benutzer an Fotos ausführen.
- Überprüfungen - Ereignisse im Zusammenhang mit Vorgängen für Benutzerüberprüfungen.
- Datenfeedback - Ereignisse im Zusammenhang mit Verfeinerungsvorgängen. Klarstellung ist eine Änderung der Informationen über ein Objekt auf einer Karte, sei es eine Firma oder ein Denkmal.
- Check - Ereignisse, die sich auf die 2GIS Check-Anwendung beziehen.
- BSS sind Analyseereignisse, die 2GIS-Anwendungen generieren. Zum Beispiel die Eröffnung eines bestimmten Unternehmens, Fahrten mit dem Navigator usw.

Vom Mastersystem generierte Ereignisse fallen in der Reihenfolge der Änderung ihres Status in das Kafka-Thema. Dadurch kann der Fortschritt der Auszeichnung für den Benutzer nicht nur vorwärts, sondern auch rückwärts verschoben werden. Wenn sich das Foto beispielsweise im Status "aktiv" befand und dann aus irgendeinem Grund den Status "blockiert" erhielt, sollte sich der Fortschritt bei der Auszeichnung nach unten ändern. Der Preisfortschritt ist eine Interpretation interner Objekte, die als Inhaltszähler bezeichnet werden.
Die Zähler können für verschiedene Daten variieren. Bei Ereignissen zum Foto sind dies beispielsweise die folgenden: die Anzahl der genehmigten, die Anzahl der moderierten, die Anzahl der blockierten Ereignisse und bei Ereignissen beim Öffnen von Karten müssen Sie nur die Anzahl der vom Benutzer geöffneten Karten berücksichtigen. Basierend auf den aktuellen Werten der Inhaltszähler für einen bestimmten Benutzer werden im Rahmen einer bestimmten Auszeichnung die Antworten auf die folgenden Fragen festgelegt:
- Hat die Auszeichnung begonnen?
- Was ist der Fortschritt
- Ist die Belohnung vollständig abgeschlossen?
Filter und Regeln
Die Jobzähler einer bestimmten Auszeichnung werden nur geändert, wenn eine Veranstaltung mit dem gewünschten Inhaltstyp sowie den für den Erhalt der Auszeichnung erforderlichen Daten eingetroffen ist.
Um nur den Inhalt zu überspringen, der für die Auszeichnung geeignet ist, führen wir jede Veranstaltung durch eine Reihe von Filtern und Regeln.
Ein Filter ist eine bestimmte Einschränkung, die dem Inhalt auferlegt wird. Es geht ihm nur um die Beantwortung der Frage: "Passt ein neues Ereignis zu dieser Bedingung oder nicht?"
Eine Regel ist ein spezieller Filter, dessen Zweck lautet: "Wenn ein Ereignis der Bedingung entspricht, wie sollten sich dann die Zähler ändern?" Die Regel enthält einen Algorithmus zum Ändern von Zählern. Jede Auszeichnung enthält nur eine Regel.
Die Implementierung von Filtern und Regeln befindet sich im Projektcode, und die Beschreibung, welche Filter (Regeln) zu einer bestimmten Auszeichnung gehören, befindet sich in der Datenbank im JSON-Format. Wir sind nicht sofort zu einer solchen Entscheidung gekommen. Anfänglich konnten Filter und Regeln nicht mithilfe der Konfiguration über die Datenbank festgelegt werden. Die Auszeichnung wurde vollständig im Code beschrieben, nur die Kennung wurde in der Tabelle gespeichert. Diese Entscheidung brachte eine Reihe wesentlicher Nachteile mit sich:
- Das Problem der Unterstützung mehrerer Umgebungen. Wenn Sie einen Status der Liste der Auszeichnungen für die Testumgebung bereitstellen und einen anderen in den Kampf schicken möchten, müssen Sie die Umgebung im Projektcode kennen oder über eine Konfigurationsdatei mit der Liste der Auszeichnungen verfügen. Gleichzeitig ist es nicht möglich, unterschiedliche Datenbanken für diese Aufgabe zu verwenden, obwohl diese bereits für jede Umgebung vorhanden sind.
- Möglichkeit, die Filterung nur vom Entwickler zu konfigurieren. Da alles im Code beschrieben ist und nur eine Person, die das Projekt und die Programmiersprache kennt, Änderungen vornehmen kann, möchte ich, dass dies einfach über die private API oder Datenbank möglich ist.
- Der Nachteil der Betrachtung. Es gibt viele Belohnungen, manchmal müssen Sie die Filter sehen, die sie verwenden. Jedes Mal ist es ziemlich mühsam, dies durch Anzeigen des Codes zu tun.
Zu Beginn der Anwendung stimmen wir mit dem Namen der aus der Datenbank geladenen Filter überein und setzen sie in eine bestimmte Belohnung ein. Beispiel für eine Filterbeschreibung:
[ { "name":"SourceFilter", "config":{ "sources":["reviews"] } }, { "name": "ReviewsLengthFilter", "config": { "allowed_length": 100 } } ]
In diesem Fall nehmen wir nur die Überprüfungen (dies wird durch das erste Beschreibungsobjekt aus dem Filterarray angezeigt), deren Text mehr als 100 Zeichen enthält (der zweite Filter in der Liste).
Beispiel für eine Regelbeschreibung:
{"name": "ReviewUniqueByObjectRule","config":{}}
Mit dieser Regel können Sie die Zähler nur ändern, wenn der Benutzer eine Bewertung für das Objekt geschrieben hat, während nur eine Bewertung für ein Objekt berücksichtigt wird.
Bss
Lassen Sie uns separat auf die Arbeit mit dem Strom von BSS-Ereignissen eingehen. Dafür gibt es mindestens drei Gründe:
- Analytics-Ereignisse können nicht zurückgesetzt werden, da sie kein Statusmodell enthalten. Dies ist im Allgemeinen logisch, da das Durchfahren eines Navigators oder das Erstellen einer Route nicht abgebrochen werden kann. Die Aktion war entweder da oder nicht.
- Bände. Ich möchte Sie daran erinnern, dass das Gesamtpublikum von 2GIS mehr als 50 Millionen Benutzer pro Monat beträgt. Zusammen führen sie mehr als 1,5 Milliarden Suchanfragen sowie viele andere Aktionen durch: Starten der Anwendung, Anzeigen der Objektkarte usw. In der Spitze kann die Anzahl der Ereignisse 50.000 pro Sekunde erreichen. Wir müssen all diese Informationen durch Filter weitergeben, um dem Benutzer eine Belohnung zu geben.
- Analytics-Ereignisse haben Funktionen: verschiedene Formate, eine Vielzahl von Typen.
All dies hat die Verarbeitung von Daten aus dem BSS-Thema stark beeinflusst, da wir, wenn wir Echtzeit benötigen, eine sehr enge Verarbeitungszeit benötigen.
Um die beschriebenen Unterschiede zu verringern, wurde ein separater Dienst erstellt, der solche Ereignisse vorbereitet. Der Dienst kann mit der Vielzahl von Nachrichtenformaten arbeiten, die aus der Analyse stammen. Das Wesentliche seiner Arbeit ist wie folgt: Der gesamte BSS-Veranstaltungsstrom wird gelesen, aus dem nur diejenigen entnommen werden, die für die Auszeichnungen benötigt werden. Ein solcher Servicefilter reduziert die Last (nach dem Filtern beträgt die Flussrate 300 Ereignisse pro Sekunde) durch die Belohnungen des BSS-Stream-Prozessors erheblich und generiert auch Ereignisse in einem einzigen Format, wodurch der mit der Historie der internen Analyse verbundene Nachteil ausgeglichen wird.
Auszeichnungen
Also haben wir herausgefunden, wie wir mit Ereignissen umgehen und den Fortschritt bei Aufgaben berechnen können. Jetzt ist es an der Zeit, einen Blick auf den Prozess der Ausgabe von Belohnungen an Benutzer zu werfen.
Die erste Frage, die sich stellt, lautet: Warum sollte die Ausgabe einem separaten Mitarbeiter zugewiesen werden? Kann sie bei der Verarbeitung jedes Ereignisses nicht nachgezählt werden? Antwort: möglich, aber es lohnt sich nicht.
Es gibt mehrere Gründe, die Auslieferung einem separaten Verfahren zuzuweisen:
- Wenn wir die Nachzählung an jeden ConsumingWorker übertragen, erhalten wir die Race-Bedingung für die Aktualisierung des Fortschritts durch Belohnung, da jeder Handler versucht, den Fortschritt basierend auf dem bekannten Status der Aufgaben zu aktualisieren, und andere diesen Status aktiv ändern.
- Jeder ConsumingWorker-Stapel verarbeitet Ereignisse von Kafka in einer Transaktion. Durch Hinzufügen einer Einfügung zur Belohnungstabelle des Benutzers werden zusätzliche Sperren auf Datenbankebene aufgerufen, wodurch andere Handler gesperrt werden.
- Bei der Vergabe von Prämien gibt es eine Logik zum Senden von Benachrichtigungen, die die Verarbeitung des Ereignisflusses nur verlangsamt, was unerwünscht ist.
Die Gründe für die Entstehung eines separaten AchievesWorker (Handler für die Vergabe von Auszeichnungen) wurden geklärt. Jetzt müssen Sie sich mit zwei wichtigen Teilen der Verarbeitung befassen:
- Die Belohnung enthält eine Reihe von Quests. Für diese Aufgaben gibt es eine Reihe von Zählern. Wie kann man verstehen, wie viel die Auszeichnung verdient und wie man sie im Code ausdrückt?
Beispiel: Sie müssen 3 Bewertungen schreiben oder 3 Fotos hochladen. Der Benutzer hat 1 Bewertung und 2 Fotos. Wie ist der Fortschritt der Auszeichnung? Antwort: 3, da der Benutzer definitiv sicher sein wird, dass Sie insgesamt 3 benötigen. - Wir haben einen separaten Handler für die Vergabe von Auszeichnungen. Es ist unwahrscheinlich, dass jedes Mal mehrere Dutzend Auszeichnungen für jeden autorisierten Benutzer, dh mehrere zehn Millionen, schnell erfolgreich sind. Wie kann er erfahren, welche Fortschritte bestimmte Benutzer haben und welche Aufgaben sich seit der letzten Verarbeitung geändert haben?
Wir werden jedes Teil separat betrachten.
Fluss des Fortschritts
Um besser zu verstehen, wie Sie beschreiben können, wie Sie den Fortschritt von Aufgaben durch Belohnung in Fortschritt umwandeln können, teilen wir die Belohnungen in Kategorien ein und betrachten die Transformationen.
"Erfülle eine Aufgabe pro X Einheit." Beispiel: Fahren Sie 10 km mit dem Navigator.
"Erledige mehrere Aufgaben für jeweils X Einheiten." Beispiel: Laden Sie 5 Fotos hoch und schreiben Sie 5 Bewertungen in Karten - nur 10 Inhaltseinheiten.
"Erfülle mehrere Aufgaben für insgesamt X Einheiten." Beispiel: Schreiben Sie 5 Bewertungen oder laden Sie 5 Fotos hoch.
"Führen Sie mehrere Aufgaben nach Typ gruppiert aus." Beispiel: Laden Sie 5 Inhaltseinheiten (Fotos oder Bewertungen) hoch und fahren Sie 10 km mit dem Navigator.

Theoretisch könnte es komplexere verschachtelte Kombinationen geben. Unter realen Bedingungen ist es jedoch nicht möglich, dem Benutzer in zwei oder drei Sätzen die komplexe logische Kombination zu erklären, die ausgeführt werden muss, um die Auszeichnung zu erhalten. Daher sind diese Optionen in den meisten Fällen ausreichend.
Wir haben die Konvertierungsmethode als Strategie bezeichnet und versucht, sie mehr oder weniger universell zu gestalten, indem wir eine formale Beschreibung in Form eines JSON-Objekts ausgearbeitet haben. Sie könnten natürlich daran denken, in Form einer Formel zu schreiben, aber dann müssten Sie Ähnlichkeiten verwenden, um die Grammatik zu bewerten oder zu beschreiben und umzusetzen, und dies ist eindeutig eine Überkomplikation. Das Speichern der Strategie im Quellcode für jede Auszeichnung ist nicht sehr praktisch, da die Beschreibung der Auszeichnung (Teil in der Datenbank und Teil im Code) reißt und es auch in Zukunft nicht möglich ist, Auszeichnungen von vorgefertigten Komponenten ohne Teilnahme an der Entwicklung zu sammeln.
Die Strategie wird in Form eines Baums dargestellt, wobei jeder Knoten:
- Bezieht sich auf den aktuellen Zuweisungsfortschritt oder ist eine Gruppe anderer Knoten.
- Kann eine Top-Einschränkung haben - in der Tat ein Hinweis auf die Notwendigkeit, min () zu verwenden.
- Kann einen Normalisierungskoeffizienten haben. Wird für einfache Konvertierungen benötigt, indem das Ergebnis mit einer Zahl multipliziert wird. Wir haben uns als nützlich erwiesen, um Meter in Kilometer umzurechnen.
Um die obigen Beispiele zu beschreiben, reicht eine Operation aus - Summe. Die Summe ist ideal, um den Benutzerfortschritt mit einer einzelnen Zahl klar darzustellen. Auf Wunsch können jedoch auch andere Vorgänge verwendet werden.
Hier ist eine beispielhafte Strategiebeschreibung für die letzte Kategorie:
{ "goal": 15, "operation": "sum", "strategy": [ { "goal": 5, "operation": "sum", "strategy": [ { "objective_id": "photo" }, { "objective_id": "reviews" } ] }, { "goal": 10, "operation": "sum", "strategy": [ { "objective_id": "navi", "normalization_factor": 0.001 } ] } ] }
Erforderliche Updates
Es gibt mehrere Handler, die Ereignisse von Benutzern unermüdlich analysieren und Änderungen am Fortschritt von Aufgaben vornehmen. Eine regelmäßige Suche aller Benutzer mit jeder Auszeichnung führt zu einer Analyse von mehreren zehn Millionen Auszeichnungen - nicht sehr ermutigend, vorausgesetzt, dass echte Aktualisierungen in Tausenden gemessen werden. Wie kann man nur über Tausende lernen und nicht Millionen von CPU verschwenden?
Die Idee, den Fortschritt nur bei den tatsächlich geänderten Auszeichnungen neu zu berechnen, kam ziemlich schnell. Es basiert auf der Verwendung von Vektoruhren.
Vor der Beschreibung werde ich an Entitäten erinnern:
- UserObjective - Daten zum Fortschritt des Benutzers durch Festlegen der Auszeichnung.
- UserAchieve - Belohnt Benutzerfortschrittsdaten.
Die Implementierung sieht folgendermaßen aus:
- Wir erhalten das Versionsfeld für UserObjective und UserAchieve and Sequence in PostgreSQL.
- Jedes Update der UserObjective-Entität ändert ihre Version. Der Wert wird aus der Sequenz entnommen (wir haben ihn allen Datensätzen gemeinsam).
- Der Versionswert für UserAchieve wird als Maximum der Versionen des zugeordneten UserObjective festgelegt.
- Bei jedem Verarbeitungszyklus sucht AchievesWorker nach einem solchen UserObjective, für das es kein UserAchieve oder UserAchieve.version <UserObjective.version gibt. Das Problem wird durch eine einzelne Abfrage an die Datenbank gelöst.
Es ist erwähnenswert, dass die Lösung Einschränkungen hinsichtlich der Anzahl der Einträge in den Tabellen mit Auszeichnungen und Aufgaben sowie der Häufigkeit von Änderungen bei den Aufgaben aufweist. Mit einigen zehn Millionen Auszeichnungen und einer Anzahl von Aktualisierungen von weniger als tausend pro Minute ist es jedoch durchaus möglich, mit einer solchen Lösung zu leben. Irgendwie werden wir separat darüber berichten, wie wir die Ausgabe für den Wettbewerb „
2GIS Agents “ optimiert haben.
Schlussfolgerungen
Trotz der Tatsache, dass sich der Artikel als ziemlich umfangreich herausstellte, blieben viele Nuancen hinter den Kulissen, da es nicht möglich wäre, kurz darüber zu sprechen.
Welche Schlussfolgerungen haben wir dank der Auszeichnungen gezogen:
- Das Prinzip "Teilen und Erobern" spielte uns in diesem Fall in die Hände. Die Zuordnung von Ereignishandlern zu jeder Quelle hilft uns bei Bedarf bei der Skalierung. Ihre Arbeit ist nach Daten isoliert und schneidet sich nur in kleinen Bereichen. Durch Hervorheben der Belohnungslogik können Sie den Overhead in Ereignishandlern reduzieren.
- Wenn Sie viele Daten verarbeiten müssen und die Verarbeitung recht teuer ist, sollten Sie sofort darüber nachdenken, wie Sie herausfiltern können, was definitiv nicht benötigt wird. Die Erfahrung mit dem Filtern eines BSS-Streams ist ein Beispiel.
- Wir waren erneut davon überzeugt, dass die Integration von Diensten über einen gemeinsamen Ereignisbus sehr bequem ist und es Ihnen ermöglicht, unnötige Belastungen anderer Dienste zu vermeiden. Wenn der Rewards-Dienst Daten von Foto-, Überprüfungs- usw. Diensten über http-Anforderungen erhalten würde, müssten mehrere Dienste für eine zusätzliche Belastung vorbereitet werden.
- Ein bisschen Metaprogrammierung kann dabei helfen, die Integrität der Datenkonfiguration aufrechtzuerhalten und Umgebungen willkürlich zu trennen. Das Speichern von Filtern, Regeln und Strategien in der Datenbank vereinfachte das Entwickeln und Freigeben neuer Auszeichnungen.