
Heute eröffnen wir eine Reihe von Artikeln darüber, worüber auf technischen Konferenzen und Tagungen normalerweise nicht gesprochen wird. In diesem und den folgenden Beiträgen erfahren Sie, wie der Monetarisierungsmechanismus in der in den USA beliebten iFunny iOS-Unterhaltungsanwendung funktioniert, die wir entwickeln.
Werbung ist eine der wichtigsten Möglichkeiten, um kostenlose Anwendungen zu monetarisieren. Aber welche Optionen gab es 2011, als iFunny erschien? Der Service wurde ursprünglich als starkes, nachhaltiges Unternehmen entwickelt. Daher entschied sich das Unternehmen vom ersten Tag an, nicht mit Benutzern zu flirten und sich nicht auf Spiele mit bedingter Kapitalisierung einzulassen.
Zu dieser Zeit bestand die Hauptoption für die Monetarisierung darin, eine kostenlose abgespeckte Version des Dienstes zu erstellen und dann zu versuchen, die Hauptfunktionalität zu verkaufen. Der Verbraucher war jung, unerfahren und nicht bereit, sich von Beträgen über einem Dollar zu trennen.
Einfache Mathematik hat gezeigt, dass es bei einer Umwandlung von 10% fast unmöglich ist, einen ARPU von mehr als 10 Cent zu erhalten.
Dann musste ich darüber nachdenken, wie Sie das Produkt sonst noch monetarisieren können. Das Werbemodell hat im Web bereits sehr gut funktioniert, und es ist davon auszugehen, dass es bald auch auf Handys aufblühen wird.
Im Allgemeinen kann der Beginn des mobilen Werbemodells der Monetarisierung als das Erscheinen von AdWhirl betrachtet werden - einem Dienst, mit dem Sie das SDK von Werbenetzwerken integrieren und rotieren konnten. Durch sein Erscheinen konnte FillRate auf durchschnittlich 50% des Marktes angehoben und die Einnahmen aus dem Werbemodell mindestens mit Ein-Dollar-Verkäufen vergleichbar gemacht werden. Das Prinzip der Umsetzung aller möglichen Nachfragequellen und der Organisation des Wettbewerbs zwischen ihnen ist zum Hauptwachstumstreiber in der Werbebranche geworden und wird bis heute genutzt.
Aber je komplexer das System ist, desto weniger stabil wird es, was für große Dienste der iFunny-Ebene absolut inakzeptabel ist. Das Unternehmen begann 2011, sich in diese Richtung zu bewegen, und schuf einen der effektivsten Mechanismen für die Arbeit mit mobilen Bannern und nativer Werbung. Der Umsatz pro Nutzer konnte um das 40-fache gesteigert werden, wodurch nicht nur interne Projekte entwickelt, sondern auch in andere Unternehmen investiert werden konnten.
MoPub und Firma
Seit 2012 sind wir von AdWhirl zu MoPub gewechselt.
MoPub ist eine mobile Werbeplattform mit der Möglichkeit, eigene Module hinzuzufügen, die mehrere großartige Tools enthalten:
- MoPub-Marktplatz - eigene Werbebörse;
- Vermittler von Werbenetzwerken für die Arbeit mit externen Netzwerken;
- Ein Bestellmechanismus, mit dem Sie Banner unabhängig in Ihrer eigenen Anwendung platzieren und ihre Anzeigen anpassen können.
Die Hauptvorteile von MoPub:
- in der Lage, mit den meisten Werbenetzwerken zu arbeiten;
- klarer Mechanismus für die Verbindung neuer Netzwerke von Drittanbietern;
- Open Source
- eine große Anzahl von Grundeinstellungen und Targeting;
- Als große Community rund um das Netzwerk gibt es sogar eine eigene Konferenz.
MoPub hat auch Nachteile:
- Pool-Anfragen auf GitHub werden nicht akzeptiert und es gibt überhaupt keine Reaktion darauf.
- Das Control Panel ist sehr komplex und für den Entwickler dauert es beim Debuggen einige Zeit, sich mit seiner Struktur zu befassen.
Die Kraft der Wahrheit
Wie der Held eines russischen Films sagte: "Stärke ist in Wahrheit." In diesem Teil werde ich über die Schwierigkeiten sprechen, mit denen wir als Anwendungsentwickler nach den ersten Millionen Downloads von iFunny, dem Wachstum des Publikums und dem Werbeverkehr von mehr als 100 Partnern konfrontiert waren.
Inhalt
Der Werbemarkt ist eine sehr geschlossene „Kaste“ von Technologieunternehmen, aber gleichzeitig verfügen Aggregatoren über ein großes Netzwerk von Partnern: von großen Unternehmen, die mit Millionen von Budgets arbeiten, bis zu kleinen Unternehmen, die auf bestimmte Zielgruppen zugeschnitten sind.
Diese Nähe und Fragmentierung der Partner ermöglicht es den ehrlichsten Werbeverkäufern trotz der Vormoderation der Banner und der strengen Regeln für Werbeinhalte nicht, Motive zu veröffentlichen, die verboten sind oder die Benutzererfahrung in der Anwendung beeinträchtigen.
Es gibt mehrere Hauptkategorien von „obszönen“ Inhalten in Werbebannern:
- Porno-Inhalt. In letzter Zeit erscheint es immer weniger, aber es findet dennoch statt. Wir können diesen Inhalt nicht im Artikel veröffentlichen, daher wird das Bild nicht hier sein
- Systemwarnungen in Bannern, ein Beispiel kann unter einem der Benutzer twitter.com/IfunnyStates/status/1029393804749668352 angezeigt werden
- zufrieden mit Ton. Sounds werden von Werbenetzwerken sowie Animationen nicht verboten. Wenn der Sound jedoch ohne Interaktion mit der Benutzeroberfläche abgespielt wird, wird dies von den Benutzern als Anwendungsfehler wahrgenommen und wirkt sich negativ auf die Benutzererfahrung aus
- Aufmerksamkeit erregen. Ein gutes Banner sollte die Aufmerksamkeit des Benutzers auf sich ziehen, aber dies geschieht nicht immer auf ehrliche Weise: Manchmal fallen flackernde Videos in die Banner. Eine andere unehrliche Möglichkeit, den Benutzer dazu zu bringen, auf das Banner zu tippen, besteht darin, die Anwendungsoberfläche zu simulieren, beispielsweise wie folgt:

Übrigens kann in Russland ein gewöhnliches Tippen auf dieses Banner für einige Mobilfunkbetreiber ein kostenpflichtiges Abonnement ausstellen, und Sie werden es erst erfahren, wenn Sie die Details sehen. Dies ist auch eine unehrliche Art, mit Werbung zu arbeiten, aber Betreiber in den USA haben keine solche Gelegenheit.
Automatische Klicks
Wie meine Erfahrung zeigt, ist dies ein äußerst negativer Fall für Benutzer. Mit den Funktionen von JavaScript, WKWebView oder UIWebView sowie Lücken in der Implementierung von Werbebibliotheken können Sie Anzeigen erstellen, die den Bannerinhalt selbst öffnen und den Benutzer aus der Anwendung herausführen.
Um dieses Problem am Beispiel von MoPub zu wiederholen, fügen Sie einfach den Javascript-Code des folgenden Inhalts zum Banner hinzu:
<a href="https://ifunny.co" id="testbutton">test</a> <script>document.getElementById('testbutton').click(); </script>
Dies funktionierte lange Zeit in vielen Versionen von MoPub bis zur Version 4.13.
Durch die Untersuchung der Implementierung von MoPub konnten komplexere Links generiert werden, mit denen nicht nur Anzeigen im Vollbildmodus geöffnet, sondern der Benutzer auch an den AppStore an eine bestimmte Anwendung gesendet und die Banneranzeige nicht einmal berücksichtigt werden konnte.
Übrigens gibt es in den Versionshinweisen für Version 4.13.0 des MoPub SDK für iOS keine Informationen zu diesem Fix, da es ein ziemlich schwerwiegendes Loch im SDK war und die unehrlichen Partner von MoPub es ziemlich aktiv ausnutzten. Wie die Protokolle zeigen, auf die ich später noch eingehen werde, musste ich jeden Tag bis zu 2 Millionen Versuche blockieren, das Banner ohne Benutzerinteraktion zu öffnen.
Im Fall von MoPub stellte sich heraus, dass das Problem leicht zu finden und zu wiederholen war. Andere Netzwerke, mit denen iFunny arbeitet, haben jedoch einen geschlossenen Code, und Sie müssen sich mit neu auftretenden automatischen Klicks auseinandersetzen, indem Sie Banner blockieren oder sogar Netzwerke für eine Weile trennen.
iFunny arbeitet eng mit allen Werbepartnern zusammen und informiert sie über solche Banner. Da das junge Publikum von iFunny für Werbetreibende interessant ist, treffen sich die Partner bereitwillig mit ihnen und entfernen solche Anzeigen aus der Rotation.
Absturz
Absturz ist immer schlimm. Schlimmer noch, wenn sie aufgrund einer Abhängigkeit von Closed Source auftreten und Sie sie nur indirekt beeinflussen können. Im Laufe der Jahre der Arbeit mit Werbung bei iFunnu wurden verschiedene Arten von Abstürzen identifiziert, die in mehrere Gruppen unterteilt werden können.
Dazu gehören Ausnahmen in der Netzwerkbibliothek, WKWebView (UIWebView), OpenGL.
Es ist sehr schwierig, diese Art von Abstürzen direkt zu beeinflussen, aber es war immer noch möglich, einige von ihnen zu beeinflussen, nachdem zuvor die Funktionsweise der WebView-Komponente mit WebGL untersucht worden war.
So sieht der Stackrace solcher Abstürze aus:
1 libGPUSupportMercury.dylib gpus_ReturnNotPermittedKillClient + 12
2 AGXGLDriver gldUpdateDispatch + 7132
3 libGPUSupportMercury.dylib gpusSubmitDataBuffers + 172
4 AGXGLDriver gldUpdateDispatch + 12700
5 WebCore WebCore::GraphicsContext3D::reshape(int, int) + 524
6 WebCore WebCore::WebGLRenderingContextBase::initializeNewContext() + 712
7 WebCore WebCore::WebGLRenderingContextBase::WebGLRenderingContextBase(WebCore::HTMLCanvasElement*, WTF::RefPtr<WebCore::GraphicsContext3D>&&, WebCore::GraphicsContext3D::Attributes) + 512
8 WebCore WebCore::WebGLRenderingContext::WebGLRenderingContext(WebCore::HTMLCanvasElement*, WTF::PassRefPtr<WebCore::GraphicsContext3D>, WebCore::GraphicsContext3D::Attributes) + 36
9 WebCore WebCore::WebGLRenderingContextBase::create(WebCore::HTMLCanvasElement*, WebCore::WebGLContextAttributes*, WTF::String const&) + 1272
10 WebCore WebCore::HTMLCanvasElement::getContext(WTF::String const&, WebCore::CanvasContextAttributes*) + 520
11 WebCore WebCore::JSHTMLCanvasElement::getContext(JSC::ExecState&) + 212
12 JavaScriptCore llint_entry + 27340
13 JavaScriptCore llint_entry + 24756
14 JavaScriptCore llint_entry + 24756
15 JavaScriptCore llint_entry + 24756
16 JavaScriptCore llint_entry + 25676
17 JavaScriptCore llint_entry + 24756
18 JavaScriptCore llint_entry + 24656
19 JavaScriptCore vmEntryToJavaScript + 260
20 JavaScriptCore JSC::JITCode::execute(JSC::VM*, JSC::ProtoCallFrame*) + 164
21 JavaScriptCore JSC::Interpreter::executeCall(JSC::ExecState*, JSC::JSObject*, JSC::CallType, JSC::CallData const&, JSC::JSValue, JSC::ArgList const&) + 348
22 JavaScriptCore JSC::profiledCall(JSC::ExecState*, JSC::ProfilingReason, JSC::JSValue, JSC::CallType, JSC::CallData const&, JSC::JSValue, JSC::ArgList const&, WTF::NakedPtr<JSC::Exception>&) + 160
23 WebCore WebCore::JSEventListener::handleEvent(WebCore::ScriptExecutionContext*, WebCore::Event*) + 980
24 WebCore WebCore::EventTarget::fireEventListeners(WebCore::Event&, WebCore::EventTargetData*, WTF::Vector<WebCore::RegisteredEventListener, 1ul, WTF::CrashOnOverflow, 16ul>&) + 616
25 WebCore WebCore::EventTarget::fireEventListeners(WebCore::Event&) + 324
26 WebCore WebCore::EventContext::handleLocalEvents(WebCore::Event&) const + 108
27 WebCore WebCore::EventDispatcher::dispatchEvent(WebCore::Node*, WebCore::Event&) + 876
28 WebCore non-virtual thunk to WebCore::HTMLScriptElement::dispatchLoadEvent() + 80
29 WebCore WebCore::ScriptElement::execute(WebCore::CachedScript*) + 360
30 WebCore WebCore::ScriptRunner::timerFired() + 456
31 WebCore WebCore::ThreadTimers::sharedTimerFiredInternal() + 144
32 WebCore WebCore::timerFired(__CFRunLoopTimer*, void*) + 24
33 CoreFoundation __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 24
34 CoreFoundation __CFRunLoopDoTimer + 868
35 CoreFoundation __CFRunLoopDoTimers + 240
36 CoreFoundation __CFRunLoopRun + 1568
37 CoreFoundation CFRunLoopRunSpecific + 440
38 WebCore RunWebThread(void*) + 452
39 libsystem_pthread.dylib _pthread_body + 236
40 libsystem_pthread.dylib _pthread_start + 280
41 libsystem_pthread.dylib thread_start + 0
Darüber hinaus treten sie ausschließlich beim Verlassen im Hintergrund auf. Dies liegt an der Tatsache, dass die OpenGL-Engine nicht funktionieren sollte, wenn sich die Anwendung im Hintergrund befindet.
Die Lösung hier erwies sich als recht einfach:
Wenn Sie im Hintergrund gehen, müssen Sie einen Screenshot des Banners machen.
Entfernen Sie die Werbeansicht vom Bildschirm, damit die WebView-Komponente OpenGL nicht mehr verwendet.
Wenn Sie den Hintergrund verlassen, geben Sie alles so zurück, wie es war.
Im Objective-C-Code sieht es folgendermaßen aus:
- (void)onWillResignActive { if (self.adView.superview) { UIGraphicsBeginImageContext(self.adView.bounds.size); [self.adView.layer renderInContext:UIGraphicsGetCurrentContext()]; UIImage *adViewScreenShot = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); adViewThumbView = [[UIImageView alloc] initWithImage:adViewScreenShot]; adViewThumbView.backgroundColor = [UIColor clearColor]; adViewThumbView.frame = self.adView.frame; NSInteger adIndex = [self.adView.superview.subviews indexOfObject:self.adView]; [self.adView.superview insertSubview:adViewThumbView atIndex:adIndex]; [self.adView removeFromSuperview]; } } - (void)onDidBecomeActive { if (self.adView && adViewThumbView) { NSInteger adIndex = [adViewThumbView.superview.subviews indexOfObject:adViewThumbView]; [adViewThumbView.superview insertSubview:self.adView atIndex:adIndex]; [adViewThumbView removeFromSuperview]; adViewThumbView = nil; } }
Dies sind Probleme, die an der Kreuzung von iFunny, Mopub und dem Werbeanbieter auftreten.
Sie entstehen in der Regel nach der Aktualisierung der Provider-Bibliothek und aufgrund neuer Interaktionsmöglichkeiten mit ihnen.
Der letzte derartige Fall war im Juni dieses Jahres nach dem nächsten Update einer der verwendeten Bibliotheken. Eine neue Methode zum Initialisieren der Bibliothek schlug vor, Singleton zum Konfigurieren der Netzwerkeinstellungen zu verwenden.
Wenn ich zweimal darauf zurückkam, wie es in der Implementierung der Fall war, verursachte dies regelmäßig einen Fries des Hauptthreads, sodass ich die Initialisierung in dispatch_once einschließen musste.
Die iFunny-QS-Abteilung kann Werbebibliotheken gut testen, sodass dieses Problem beim Testen des Updates festgestellt wurde.
Diese Art von Abstürzen kann überhaupt nicht kontrolliert werden, da sie ohne Änderungen im Client auftritt.
Sie sind mit der Aktualisierung des Backends von Partnern und der mangelnden Abwärtskompatibilität verbunden. Solche Abstürze treten häufig bei großen Werbeanbietern auf, werden jedoch schnell behoben, da sie eine große Anzahl von Anwendungen gleichzeitig betreffen.
Es gab Fälle, in denen der Absturz von iFunny pro Tag von 99,8% auf 80% sank und die Anzahl der verärgerten Kommentare in der Geschichte bei zehn lag.
Leistung
Bannerwerbung verwendet in der Regel WebView-Komponenten, um Werbung anzuzeigen. Jedes angezeigte Banner ist also eine Initialisierung eines neuen WebView mit all seinen Abhängigkeiten.
Darüber hinaus verwenden einige Partner WebView auch zur Kommunikation mit ihrem eigenen Backend, da Bannerwerbung auf Mobilgeräten ein Nachkomme von Werbung im Web ist.
Es kommt vor, dass nach dem Upgrade Speicherlecks in der neuen Bibliothek auftreten. Nach dem Erscheinen des Memory Graph-Tools in Xcode wurde es viel einfacher, Lecks in Bibliotheken von Drittanbietern zu finden, sodass Partner jetzt schnell darüber informiert werden können.
Unten ist das GIF von iFunny im Leerlauf, wenn keine Werbung für den Benutzer vorhanden ist:

Lösungen
Trotz aller oben beschriebenen Probleme ist iFunny stabil und sorgt jeden Tag bei Millionen seiner Benutzer für ein Lächeln.
Während der jahrelangen aktiven Arbeit mit Werbung verfügt das Entwicklungsteam über mehrere Tools, mit denen Werbeprobleme erfolgreich überwacht und rechtzeitig behoben werden können.
Protokollierungssystem
Jetzt hat sich das Ausnahmeprotokollierungssystem in iFunny auf die gesamte Anwendung ausgeweitet: Dazu verwenden wir unser eigenes Backend mit einer Basis auf ClickHouse und der Anzeige in Grafana.
Die erste Aufgabe für die Arbeit mit Protokollen in der Anwendung war jedoch genau die Protokollierung von Ausnahmesituationen in der Werbung.
Es gibt verschiedene verwandte Komponenten, um festzustellen, ob ein Anruf an iFunny weitergeleitet wird. Ich werde Ihnen mehr über jeden von ihnen erzählen.
IFAdView
Dies ist der Nachkomme der MPAdView-Klasse (sie ist für die Anzeige von Anzeigen in MoPub verantwortlich).
Die Methode hitTest: withEvent wird in dieser Klasse überschrieben:
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { UIView *hitView = [super hitTest:point withEvent:event]; if (hitView) { [[IFAdsExceptionManager instance] triggerTouchView]; } return hitView; }
Daher setzen wir den Auslöser dafür, dass der Benutzer mit der Werbung interagiert.
IFURLProtocol
Wir erben von NSURLProtocol und beschreiben die Methode:
+ (BOOL)canInitWithRequest:(NSURLRequest *)request { __weak NSString *wRequestURL = request.URL.absoluteString; dispatch_async(dispatch_get_main_queue(), ^{ if (wRequestURL == nil) return; if ([wRequestURL hasPrefix:@"itms-appss://itunes.apple.com"] || [wRequestURL hasPrefix:@"itms-apps://itunes.apple.com"] || [wRequestURL hasPrefix:@"itmss://itunes.apple.com"] || [wRequestURL hasPrefix:@"http://itunes.apple.com"] || [wRequestURL hasPrefix:@"https://itunes.apple.com"]) { [[IFAdsExceptionManager instance] adsTriggerItunesURL:wRequestURL]; } }); return NO; }
Dies ist ein Auslöser zum Öffnen des AppStore in der Anwendung. Wir listen alle verfügbaren URLs dafür auf.
IFAdsExceptionManager
Eine Klasse, die Trigger sammelt und einen Ausnahmedatensatz im Protokoll generiert.
Um zu verdeutlichen, welche Art von Triggern es gibt, werde ich jede Methode der Schnittstelle dieser Klasse beschreiben.
- (void)triggerTouchView; . <source lang="objectivec">- (void)triggerItunesURL:(NSString *)itunesURL;
Ein Auslöser, der bestimmt, ob eine Umleitung in iTunes erfolgt.
- (void)triggerResignActive;
Ein Auslöser, um den Aktivitätsverlust einer Anwendung zu bestimmen. Es vergleicht die beiden vorherigen Trigger.
- (void)resetTriggers;
Trigger zurücksetzen. Wir nennen es, wenn wir den Hintergrund verlassen oder den AppStore selbst öffnen, beispielsweise wenn wir den Benutzer zur Bewertung in älteren Versionen von iOS senden.
@property (nonatomic, strong) FNAdConfigurationInfo *lastRequestedConfiguration; @property (nonatomic, strong) FNAdConfigurationInfo *lastLoadedConfiguration; @property (nonatomic, strong) FNAdConfigurationInfo *lastFailedConfiguration;
Eigenschaften zum Aufzeichnen der zuletzt erfolgreich oder nicht erfolgreich angeforderten und heruntergeladenen Anzeigen. Muss eine Nachricht an das Protokoll senden.
Es ist ersichtlich, dass sich der Algorithmus als recht einfach, aber effektiv herausstellte. Damit können wir nicht nur automatische Entdeckungen von MoPub, sondern auch von anderen Netzwerken verfolgen.
In letzter Zeit öffnen Anzeigen mit automatischer Öffnung häufig SKStoreProductViewController. Daher arbeiten wir jetzt an der Definition der automatischen Öffnung dieses Controllers. Der Algorithmus zum Definieren dieser Ausnahme wird etwas komplizierter sein, aber Objective-C Runtime wird uns hier helfen.
Lokaler Stand
Basierend auf dem Protokollierungssystem begann iFunny auch mit der Entwicklung eines lokalen Standes, um Anzeigen zu empfangen und zu debuggen, die Benutzer in Echtzeit sehen.
Der Stand besteht aus:
- Build Agent
- Geräte
- Testsuite für jeden Anbieter
Eine der interessanten Lösungen, die am Stand eingesetzt wird, ist IDFA aus Nutzerbeschwerden für echte Werbung.
Seit etwa 2016 erhalten wir keine echten Anzeigen mehr, die nur über VPNs auf die USA ausgerichtet sind. Daher müssen wir IDFA-Geräte durch IDFAs für echte Benutzer ersetzen.
Dies geschieht ziemlich einfach mit der Objective-C-Laufzeit und dem Swizzling.
Sie müssen die AdvertisingIdentifier-Methode der ASIdentifierManager-Klasse ersetzen.
Hier machen wir es durch die Kategorie:
@interface ASIdentifierManager (IDFARewrite) @end @implementation ASIdentifierManager (IDFARewrite) + (void)load { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ if (AdsMonitorTests.customIDFA != nil) { [self swizzleIDFA]; } }); } + (void)swizzleIDFA { Class class = [self class]; SEL originalSelector = @selector(advertisingIdentifier); SEL swizzledSelector = @selector(swizzled_advertisingIdentifier); Method originalMethod = class_getInstanceMethod(class, originalSelector); Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector); BOOL didAddMethod = class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod)); if (didAddMethod) { class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod)); } else { method_exchangeImplementations(originalMethod, swizzledMethod); } } #pragma mark - Method Swizzling - (NSUUID *)swizzled_advertisingIdentifier { NSUUID *result = AdsMonitorTests.customIDFA; return result; } @end
Die im
Artikel beschriebene Methode
wird verwendet, um die Benutzer-IDFA vom Build-Agenten auf den Build zu übertragen.
Abschließend möchte ich sagen, dass Bannerwerbung in den USA gut funktioniert. Seit sieben Jahren, in denen iFunny aktiv als Hauptmethode für die Monetarisierung eingesetzt wird, hat iFunny gelernt, gut damit zu arbeiten.
Trotz der Tatsache, dass Banner 75% des Umsatzes des Unternehmens ausmachen, wird derzeit an alternativen Monetarisierungsmethoden gearbeitet, und es wurden bereits einige Erfahrungen mit einheimischer Werbung und der Verwendung von Werbeauktionen auf dem US-amerikanischen Markt gesammelt.
Im Allgemeinen gibt es etwas zu erzählen.