diff --git a/.gitignore b/.gitignore index 9222a118..215b253f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -.classpath +asspath .project .settings .DS_Store @@ -12,4 +12,4 @@ spring-social-core/src/test/java/exploration **/.settings **/bin /.idea -*.iml \ No newline at end of file +*.iml diff --git a/alerts.txt b/alerts.txt new file mode 100644 index 00000000..e69de29b diff --git a/build.gradle b/build.gradle index 3e94e94d..255491bc 100644 --- a/build.gradle +++ b/build.gradle @@ -25,12 +25,12 @@ configure(allprojects - docProjects) { group = 'org.springframework.social' compileJava { - sourceCompatibility=1.5 - targetCompatibility=1.5 + sourceCompatibility=1.8 + targetCompatibility=1.8 } compileTestJava { - sourceCompatibility=1.7 - targetCompatibility=1.7 + sourceCompatibility=1.8 + targetCompatibility=1.8 } [compileJava, compileTestJava]*.options*.compilerArgs = [ @@ -197,7 +197,6 @@ project('spring-social-twitter') { compile ("org.springframework.social:spring-social-security:$springSocialVersion", optional) compile ("com.fasterxml.jackson.core:jackson-core:$jacksonVersion") compile ("com.fasterxml.jackson.core:jackson-databind:$jacksonVersion") - compile ("com.fasterxml.jackson.core:jackson-annotations:$jacksonVersion") compile ("org.springframework.security:spring-security-crypto:$springSecurityCryptoVersion") compile ("javax.servlet:javax.servlet-api:$servletApiVersion", provided) testCompile ("org.springframework:spring-test:$springVersion") diff --git a/docs/manual/.gitignore b/docs/manual/.gitignore new file mode 100644 index 00000000..ae3c1726 --- /dev/null +++ b/docs/manual/.gitignore @@ -0,0 +1 @@ +/bin/ diff --git a/gradle.properties b/gradle.properties index b5e09e2c..94209514 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,4 +8,4 @@ version=1.1.3.BUILD-SNAPSHOT jacksonVersion=2.6.1 servletApiVersion=3.0.1 springReleaseVersion=latest.release -mockitoVersion=1.9.5 +mockitoVersion=1.9.5 \ No newline at end of file diff --git a/report.xml b/report.xml new file mode 100644 index 00000000..5bf8b2b2 --- /dev/null +++ b/report.xml @@ -0,0 +1,44 @@ + + + + Feature Extraction + + + TCPFLOW + 1.4.4 + + 4.8.2 (4.8.2 20140110 (prerelease) [ibm/gcc-4_8-branch merged from gcc-4_8-branch, revision 205847]) + -pthread -I/usr/local/include -D_FORTIFY_SOURCE=2 -DUTC_OFFSET=+0000 + -g -pthread -g -O3 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security -MD -D_FORTIFY_SOURCE=2 -Wpointer-arith -Wmissing-declarations -Wmissing-prototypes -Wshadow -Wwrite-strings -Wcast-align -Waggregate-return -Wbad-function-cast -Wcast-qual -Wundef -Wredundant-decls -Wdisabled-optimization -Wfloat-equal -Wmultichar -Wc++-compat -Wmissing-noreturn -Wall -Wstrict-prototypes + -g -pthread -g -O3 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security -std=c++11 -Wall -MD -D_FORTIFY_SOURCE=2 -Wpointer-arith -Wshadow -Wwrite-strings -Wcast-align -Wredundant-decls -Wdisabled-optimization -Wfloat-equal -Wmultichar -Wmissing-noreturn -Woverloaded-virtual -Wsign-promo -funit-at-a-time -Wstrict-null-sentinel -Weffc++ + -L/usr/local/lib -Wl,-Bsymbolic-functions -Wl,-z,relro + -lpcap -lcairo -lfontconfig -lfreetype -lpixman-1 -lexpat -lssl -lcrypto -lz -lssl -lcrypto + 2014-01-13T17:14:40 + + + + Linux + 3.13.0-55-generic + #94-Ubuntu SMP Thu Jun 18 00:27:10 UTC 2015 + oohm-bdev-02 + x86_64 + tcpflow -i any -C -J port 9003 + 0 + 2015-07-23T09:56:11Z + + + + + 0 + + + 0 + + + + 0 + + diff --git a/spring-social-twitter/.gitignore b/spring-social-twitter/.gitignore new file mode 100644 index 00000000..ae3c1726 --- /dev/null +++ b/spring-social-twitter/.gitignore @@ -0,0 +1 @@ +/bin/ diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/AbstractStreamParameters.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/AbstractStreamParameters.java index 60cd8871..c2eb0e27 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/AbstractStreamParameters.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/AbstractStreamParameters.java @@ -23,7 +23,7 @@ * Subclassed by {@link UserStreamParameters} and {@link FilterStreamParameters}. * @author Craig Walls */ -abstract class AbstractStreamParameters { +public abstract class AbstractStreamParameters { protected StringBuffer track = new StringBuffer(); diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/AccountSettings.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/AccountSettings.java index 1369e226..1ad4ac36 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/AccountSettings.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/AccountSettings.java @@ -22,7 +22,7 @@ * @author Craig Walls */ public class AccountSettings extends TwitterObject { - + private static final long serialVersionUID = 1L; private boolean alwaysUseHttps; private boolean discoverableByEmail; private boolean discoverableByMobilePhone; diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/DirectMessage.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/DirectMessage.java index 5d97bcad..0d536930 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/DirectMessage.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/DirectMessage.java @@ -22,6 +22,7 @@ * @author Craig Walls */ public class DirectMessage extends TwitterObject { + private static final long serialVersionUID = 1L; private final long id; private final String text; private final TwitterProfile sender; diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/MediaEntity.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/MediaEntity.java index a4d0ee15..bb38354b 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/MediaEntity.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/MediaEntity.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -19,134 +19,144 @@ import java.util.Arrays; /** - *

A representation of embedded media entity.

+ *

+ * A representation of embedded media entity. + *

+ * * @author bowen */ public class MediaEntity extends TwitterObject implements Serializable { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; + + private final long id; + + private final String mediaHttp; + + private final String mediaHttps; + + private final String url; + + private final String display; - private long id; + private final String expanded; - private String mediaHttp; + private final String type; - private String mediaHttps; + private final int[] indices; - private String url; + private final VideoInfoMediaEntity videoInfo; - private String display; + public MediaEntity( + long id, + String mediaHttp, + String mediaHttps, + String url, + String display, + String expanded, + String type, + int[] indices, + VideoInfoMediaEntity videoInfo) { - private String expanded; + this.id = id; + this.mediaHttp = mediaHttp; + this.mediaHttps = mediaHttps; + this.url = url; + this.display = display; + this.expanded = expanded; + this.type = type; + this.indices = indices; + this.videoInfo = videoInfo; + } - private String type; - private int[] indices; + public long getId() { + return id; + } - public MediaEntity(long id, String mediaHttp, String mediaHttps, String url, String display, String expanded, String type, int[] indices) { - this.id = id; - this.mediaHttp = mediaHttp; - this.mediaHttps = mediaHttps; - this.url = url; - this.display = display; - this.expanded = expanded; - this.type = type; - this.indices = indices; - } + public String getMediaUrl() { + return mediaHttp; + } - public long getId() { - return this.id; - } + public String getMediaSecureUrl() { + return mediaHttps; + } - public String getMediaUrl() { - return this.mediaHttp; - } + public String getType() { + return type; + } - public String getMediaSecureUrl() { - return this.mediaHttps; - } + public String getDisplayUrl() { + return display; + } - public String getType() { - return this.type; - } + public String getExpandedUrl() { + return expanded; + } - public String getDisplayUrl() { - return display; - } + public String getUrl() { + return url; + } - public String getExpandedUrl() { - return this.expanded; - } + public int[] getIndices() { + if (indices == null || indices.length <= 0) + return new int[0]; + return indices; + } - public String getUrl() { - return this.url; - } + public VideoInfoMediaEntity getVideoInfo() { + return videoInfo; + } - public int[] getIndices() { - if (this.indices == null || this.indices.length <= 0) { - return new int[0]; - } - return this.indices; - } + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } + final MediaEntity that = (MediaEntity) o; - MediaEntity that = (MediaEntity) o; + if (id != that.id) + return false; + if (display != null ? !display.equals(that.display) : that.display != null) + return false; + if (expanded != null ? !expanded.equals(that.expanded) : that.expanded != null) + return false; + if (!Arrays.equals(indices, that.indices)) + return false; + if (mediaHttp != null ? !mediaHttp.equals(that.mediaHttp) : that.mediaHttp != null) + return false; + if (mediaHttps != null ? !mediaHttps.equals(that.mediaHttps) : that.mediaHttps != null) + return false; + if (type != null ? !type.equals(that.type) : that.type != null) + return false; + if (url != null ? !url.equals(that.url) : that.url != null) + return false; - if (id != that.id) { - return false; - } - if (display != null ? !display.equals(that.display) : that.display != null) { - return false; - } - if (expanded != null ? !expanded.equals(that.expanded) : that.expanded != null) { - return false; - } - if (!Arrays.equals(indices, that.indices)) { - return false; - } - if (mediaHttp != null ? !mediaHttp.equals(that.mediaHttp) : that.mediaHttp != null) { - return false; - } - if (mediaHttps != null ? !mediaHttps.equals(that.mediaHttps) : that.mediaHttps != null) { - return false; - } - if (type != null ? !type.equals(that.type) : that.type != null) { - return false; - } - if (url != null ? !url.equals(that.url) : that.url != null) { - return false; - } - - return true; - } - - - @Override - public int hashCode() { - int result = (int) (id ^ (id >>> 32)); - result = 31 * result + (mediaHttp != null ? mediaHttp.hashCode() : 0); - result = 31 * result + (mediaHttps != null ? mediaHttps.hashCode() : 0); - result = 31 * result + (url != null ? url.hashCode() : 0); - result = 31 * result + (display != null ? display.hashCode() : 0); - result = 31 * result + (expanded != null ? expanded.hashCode() : 0); - result = 31 * result + (type != null ? type.hashCode() : 0); - result = 31 * result + (indices != null ? Arrays.hashCode(indices) : 0); - return result; - } + return true; + } + + + @Override + public int hashCode() { + int result = (int) (id ^ (id >>> 32)); + result = 31 * result + (mediaHttp != null ? mediaHttp.hashCode() : 0); + result = 31 * result + (mediaHttps != null ? mediaHttps.hashCode() : 0); + result = 31 * result + (url != null ? url.hashCode() : 0); + result = 31 * result + (display != null ? display.hashCode() : 0); + result = 31 * result + (expanded != null ? expanded.hashCode() : 0); + result = 31 * result + (type != null ? type.hashCode() : 0); + result = 31 * result + (indices != null ? Arrays.hashCode(indices) : 0); + return result; + } } diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/OEmbedOptions.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/OEmbedOptions.java index 2b4f6505..a563d00a 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/OEmbedOptions.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/OEmbedOptions.java @@ -1,12 +1,12 @@ /* * Copyright 2014 the original author or authors. - * + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * + * + * http://www.apache.org/licenses/LICENSE-2.0 + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -20,110 +20,117 @@ public class OEmbedOptions { - private Integer maxWidth; - private boolean hideMedia; - private boolean hideThread; - private boolean omitScript; - private String align; - private String related; - private String lang; - - /** - * Specify the maximum width in pixels that the embedded tweet should be rendered at. - * @param maxWidth the maximum width. Must be between 250 and 550. - * @return the same OEmbedOptions for additional configuration - */ - public OEmbedOptions maxWidth(int maxWidth) { - this.maxWidth = maxWidth; - return this; - } + private Integer maxWidth; + private boolean hideMedia; + private boolean hideThread; + private boolean omitScript; + private String align; + private String related; + private String lang; - /** - * Specify that the embedded Tweet should not show images that were posted with the tweet. - * By default, images will be shown. - * @return the same OEmbedOptions for additional configuration - */ - public OEmbedOptions hideMedia() { - this.hideMedia = true; - return this; - } + /** + * Specify the maximum width in pixels that the embedded tweet should be rendered at. + * + * @param maxWidth the maximum width. Must be between 250 and 550. + * @return the same OEmbedOptions for additional configuration + */ + public OEmbedOptions maxWidth(int maxWidth) { + this.maxWidth = maxWidth; + return this; + } - /** - * Specify that the embedded Tweet should not show the original message if the tweet is a reply. - * By default, the thread will be shown. - * @return the same OEmbedOptions for additional configuration - */ - public OEmbedOptions hideThread() { - this.hideThread = true; - return this; - } + /** + * Specify that the embedded Tweet should not show images that were posted with the tweet. + * By default, images will be shown. + * + * @return the same OEmbedOptions for additional configuration + */ + public OEmbedOptions hideMedia() { + this.hideMedia = true; + return this; + } - /** - * Specify that the embedded Tweet should not include a <script> element pointing to widgets.js. - * This avoids the script from being redundantly loaded in the case that 2 or more embedded tweets are rendered on a page. - * By default, the script will be included. - * @return the same OEmbedOptions for additional configuration - */ - public OEmbedOptions omitScript() { - this.omitScript = true; - return this; - } - - /** - * Specifies how the embedded tweet should be aligned. - * @param align The alignment value. Either left, right, center, or none. Defaults to none. - * @return the same OEmbedOptions for additional configuration - */ - public OEmbedOptions align(String align) { - this.align = align; - return this; - } - - /** - * Suggested Twitter accounts that might be related to the embedded tweet. - * Used by Web Intents (https://dev.twitter.com/docs/intents) to render suggestions to the reader. - * @param related A comma-separated list of Twitter screen names to recommend. - * @return the same OEmbedOptions for additional configuration - */ - public OEmbedOptions related(String related) { - this.related = related; - return this; - } - - /** - * Specifies the language code for the embedded tweet. - * @param lang The language code. Example: "fr" - * @return the same OEmbedOptions for additional configuration - */ - public OEmbedOptions language(String lang) { - this.lang = lang; - return this; - } + /** + * Specify that the embedded Tweet should not show the original message if the tweet is a reply. + * By default, the thread will be shown. + * + * @return the same OEmbedOptions for additional configuration + */ + public OEmbedOptions hideThread() { + this.hideThread = true; + return this; + } - public MultiValueMap toRequestParameters() { - MultiValueMap params = new LinkedMultiValueMap(); - if (maxWidth != null) { - params.set("maxwidth", String.valueOf(maxWidth)); - } - if (hideMedia) { - params.set("hide_media", "true"); - } - if (hideThread) { - params.set("hide_thread", "true"); - } - if (omitScript) { - params.set("omit_script", "true"); - } - if (align != null) { - params.set("align", align); - } - if (related != null) { - params.set("related", related); - } - if (lang != null) { - params.set("lang", lang); - } - return params; - } + /** + * Specify that the embedded Tweet should not include a <script> element pointing to widgets.js. + * This avoids the script from being redundantly loaded in the case that 2 or more embedded tweets are rendered on a page. + * By default, the script will be included. + * + * @return the same OEmbedOptions for additional configuration + */ + public OEmbedOptions omitScript() { + this.omitScript = true; + return this; + } + + /** + * Specifies how the embedded tweet should be aligned. + * + * @param align The alignment value. Either left, right, center, or none. Defaults to none. + * @return the same OEmbedOptions for additional configuration + */ + public OEmbedOptions align(String align) { + this.align = align; + return this; + } + + /** + * Suggested Twitter accounts that might be related to the embedded tweet. + * Used by Web Intents (https://dev.twitter.com/docs/intents) to render suggestions to the reader. + * + * @param related A comma-separated list of Twitter screen names to recommend. + * @return the same OEmbedOptions for additional configuration + */ + public OEmbedOptions related(String related) { + this.related = related; + return this; + } + + /** + * Specifies the language code for the embedded tweet. + * + * @param lang The language code. Example: "fr" + * @return the same OEmbedOptions for additional configuration + */ + public OEmbedOptions language(String lang) { + this.lang = lang; + return this; + } + + public MultiValueMap toRequestParameters() { + MultiValueMap params = new LinkedMultiValueMap(); + if (maxWidth != null) { + params.set("maxwidth", String.valueOf(maxWidth)); + } + if (hideMedia) { + params.set("hide_media", "true"); + } + if (hideThread) { + params.set("hide_thread", "true"); + } + if (omitScript) { + params.set("omit_script", "true"); + } + if (align != null) { + params.set("align", align); + } + if (related != null) { + params.set("related", related); + } + if (lang != null) { + params.set("lang", lang); + } + return params; + } } diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/OEmbedTweet.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/OEmbedTweet.java index 55dcc8c1..bb4bbacf 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/OEmbedTweet.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/OEmbedTweet.java @@ -15,6 +15,8 @@ */ package org.springframework.social.twitter.api; + + /** * Represents an oEmbed Tweet object. * Useful for embedding content in a page using provider-defined HTML and/or data. @@ -22,6 +24,7 @@ * @author Craig Walls */ public class OEmbedTweet extends TwitterObject { + private static final long serialVersionUID = 1L; private String type; private String version; diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/Place.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/Place.java index b6eaae06..986a226b 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/Place.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/Place.java @@ -22,6 +22,7 @@ * @author Craig Walls */ public class Place extends TwitterObject { + private static final long serialVersionUID = 1L; private final String id; diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/PlacePrototype.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/PlacePrototype.java index 52381673..dc794b73 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/PlacePrototype.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/PlacePrototype.java @@ -15,6 +15,7 @@ */ package org.springframework.social.twitter.api; + /** * Represents a new place that could be created. * This is the type returned from calls to {@link GeoOperations#findSimilarPlaces(double, double, String)}. diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/SavedSearch.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/SavedSearch.java index 95764ba4..f29fc88b 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/SavedSearch.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/SavedSearch.java @@ -22,6 +22,7 @@ * @author Craig Walls */ public class SavedSearch extends TwitterObject { + private static final long serialVersionUID = 1L; private final long id; private final String name; diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/SearchResults.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/SearchResults.java index 0398dbf2..ecd4973c 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/SearchResults.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/SearchResults.java @@ -17,6 +17,8 @@ import java.util.List; +import org.springframework.social.twitter.api.impl.SearchMetadata; + /** * Represents the results of a Twitter search, including matching {@link Tweet}s * and any metadata associated with that search. @@ -24,6 +26,7 @@ * @author Craig Walls */ public class SearchResults extends TwitterObject { + private static final long serialVersionUID = 1L; private List tweets; private SearchMetadata metadata; private boolean lastPage; diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/Settings.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/Settings.java new file mode 100644 index 00000000..00f5561f --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/Settings.java @@ -0,0 +1,8 @@ +package org.springframework.social.twitter.api; + +public interface Settings { + + public String hostForStandardApi(); + + public String hostForAdsApi(); +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/StreamDeleteEvent.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/StreamDeleteEvent.java index d4410694..f055317a 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/StreamDeleteEvent.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/StreamDeleteEvent.java @@ -15,11 +15,14 @@ */ package org.springframework.social.twitter.api; + + /** * A stream event indicating that a tweet should be removed from the client. * @author Craig Walls */ public class StreamDeleteEvent extends TwitterObject { + private static final long serialVersionUID = 1L; private final long tweetId; diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/StreamListener.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/StreamListener.java index 3508998b..ec86846f 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/StreamListener.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/StreamListener.java @@ -15,6 +15,8 @@ */ package org.springframework.social.twitter.api; + + /** * Listener interface for clients consuming data from a Twitter stream. * @author Craig Walls diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/StreamWarningEvent.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/StreamWarningEvent.java index 4d10df7c..f88cadf7 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/StreamWarningEvent.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/StreamWarningEvent.java @@ -15,11 +15,14 @@ */ package org.springframework.social.twitter.api; + + /** * A stream event warning that the client is stalling and is in danger of being disconnected. * @author Craig Walls */ public class StreamWarningEvent extends TwitterObject { + private static final long serialVersionUID = 1L; private final String code; diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/SuggestionCategory.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/SuggestionCategory.java index a1a90886..7337f7d2 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/SuggestionCategory.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/SuggestionCategory.java @@ -15,11 +15,14 @@ */ package org.springframework.social.twitter.api; + + /** * Represents a suggestion category; a category of users that Twitter may suggest that a user follow. * @author Craig Walls */ public class SuggestionCategory extends TwitterObject { + private static final long serialVersionUID = 1L; private final String name; private final String slug; private final int size; diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/Trend.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/Trend.java index 2638ab93..c96701d5 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/Trend.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/Trend.java @@ -15,11 +15,14 @@ */ package org.springframework.social.twitter.api; + + /** * Represents a single trending topic. * @author Craig Walls */ public class Trend extends TwitterObject { + private static final long serialVersionUID = 1L; private final String name; private final String query; diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/Trends.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/Trends.java index 8d0c49ac..79d86dec 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/Trends.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/Trends.java @@ -24,6 +24,7 @@ * @author Craig Walls */ public class Trends extends TwitterObject { + private static final long serialVersionUID = 1L; private final Date time; private final List trends; diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/Tweet.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/Tweet.java index 03a8d359..5ac8dde7 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/Tweet.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/Tweet.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -20,367 +20,418 @@ /** * Represents a Twitter status update (e.g., a "tweet"). + * * @author Craig Walls */ public class Tweet extends TwitterObject implements Serializable { - private static final long serialVersionUID = 1L; - - private final long id; - private final String idStr; - private final String text; - private final Date createdAt; - private String fromUser; - private String profileImageUrl; - private Long toUserId; - private Long inReplyToStatusId; - private Long inReplyToUserId; - private String inReplyToScreenName; - private long fromUserId; - private String languageCode; - private String source; - private Integer retweetCount; - private boolean retweeted; - private Tweet retweetedStatus; - private boolean favorited; - private Integer favoriteCount; - private Entities entities; - private TwitterProfile user; - - /** - * Constructs a Tweet - * - * @param id The tweet's ID - * @param text The tweet's text - * @param createdAt Date Tweet was created - * @param fromUser The username of the author of the tweet. - * @param profileImageUrl The URL to the profile picture of the tweet's author. - * @param toUserId The user ID of the user to whom the tweet is targeted. - * @param fromUserId The user ID of the tweet's author. - * @param languageCode The language code - * @param source The source of the tweet. - * - * @deprecated Use other constructor with String ID instead. - */ - @Deprecated - public Tweet(long id, String text, Date createdAt, String fromUser, String profileImageUrl, Long toUserId, long fromUserId, String languageCode, String source) { - this(id, String.valueOf(id), text, createdAt, fromUser, profileImageUrl, toUserId, fromUserId, languageCode, source); - } - - /** - * Constructs a Tweet - * - * @param id The tweet's ID - * @param idStr The tweet's ID as a String - * @param text The tweet's text - * @param createdAt Date Tweet was created - * @param fromUser The username of the author of the tweet. - * @param profileImageUrl The URL to the profile picture of the tweet's author. - * @param toUserId The user ID of the user to whom the tweet is targeted. - * @param fromUserId The user ID of the tweet's author. - * @param languageCode The language code - * @param source The source of the tweet. - * - * @deprecated Use other constructor with String ID instead. - */ - public Tweet(long id, String idStr, String text, Date createdAt, String fromUser, String profileImageUrl, Long toUserId, long fromUserId, String languageCode, String source) { - this.id = id; - this.idStr = idStr; - this.text = text; - this.createdAt = createdAt; - this.fromUser = fromUser; - this.profileImageUrl = profileImageUrl; - this.toUserId = toUserId; - this.fromUserId = fromUserId; - this.languageCode = languageCode; - this.source = source; - } - - /** - * The text of the tweet. If this tweet is a retweet of another tweet, the text may be preceeded with "RT \@someuser" and may be truncated at the end. - * To get the raw, unmodified text of the original tweet, use {@link #getUnmodifiedText()}. - * @return The text of the tweet. - */ - public String getText() { - return text; - } - - /** - * Returns the unmodified text of the tweet. - * If this tweet is a retweet, it returns the text of the original tweet. - * If it is not a retweet, then this method will return the same value as {@link #getText()}. - * @return The unmodified text of the tweet. - */ - public String getUnmodifiedText() { - return isRetweet() ? retweetedStatus.getText() : getText(); - } - - public Date getCreatedAt() { - return createdAt; - } - - public String getFromUser() { - return fromUser; - } - - public void setFromUser(String fromUser) { - this.fromUser = fromUser; - } - - public long getId() { - return id; - } - - public String getIdStr() { - return idStr; - } - - public String getProfileImageUrl() { - return profileImageUrl; - } - - public void setProfileImageUrl(String profileImageUrl) { - this.profileImageUrl = profileImageUrl; - } - - public Long getToUserId() { - return toUserId; - } - - public void setToUserId(Long toUserId) { - this.toUserId = toUserId; - } - - public long getFromUserId() { - return fromUserId; - } - - public void setInReplyToStatusId(Long inReplyToStatusId) { - this.inReplyToStatusId = inReplyToStatusId; - } - - public Long getInReplyToStatusId() { - return inReplyToStatusId; - } - - public void setFromUserId(long fromUserId) { - this.fromUserId = fromUserId; - } - - public String getLanguageCode() { - return languageCode; - } - - public void setLanguageCode(String languageCode) { - this.languageCode = languageCode; - } - - public String getSource() { - return source; - } - - public void setSource(String source) { - this.source = source; - } - - public void setRetweetCount(Integer retweetCount) { - this.retweetCount = retweetCount; - } - - /** - * The number of times this tweet has been retweeted. - * Only available in timeline results. - * getRetweetCount() will return null for Tweet objects returned in search results. - * @return the number of times the tweet has been retweeted or null if that information is unavailable - */ - public Integer getRetweetCount() { - return retweetCount; - } - - public void setRetweeted(boolean retweeted) { - this.retweeted = retweeted; - } - - public boolean isRetweeted() { - return retweeted; - } - - public Tweet getRetweetedStatus() { - return this.retweetedStatus; - } - - public void setRetweetedStatus(final Tweet tweet) { - this.retweetedStatus = tweet; - } - - public boolean isRetweet() { - return this.retweetedStatus != null; - } - - public void setFavorited(boolean favorited) { - this.favorited = favorited; - } - - public boolean isFavorited() { - return favorited; - } - - public void setFavoriteCount(Integer favoriteCount) { - this.favoriteCount = favoriteCount; - } - - public Integer getFavoriteCount() { - return favoriteCount; - } - - public Entities getEntities() { - return this.entities; - } - - public void setEntities(final Entities ent) { - this.entities = ent; - } - - public boolean hasMentions() { - if (this.entities == null) { - return false; - } - return !this.entities.getMentions().isEmpty(); - } - - public boolean hasMedia() { - if (this.entities == null) { - return false; - } - return !this.entities.getMedia().isEmpty(); - } - - public boolean hasUrls() { - if (this.entities == null) { - return false; - } - return !this.entities.getUrls().isEmpty(); - } - - public boolean hasTags() { - if (this.entities == null) { - return false; - } - return !this.entities.getHashTags().isEmpty(); - } - - public TwitterProfile getUser() { - return this.user; - } - - public void setUser(final TwitterProfile prof) { - this.user = prof; - } - - public Long getInReplyToUserId() { - return inReplyToUserId; - } - - public void setInReplyToUserId(final Long inReplyToUserId) { - this.inReplyToUserId = inReplyToUserId; - } - - public String getInReplyToScreenName() { - return inReplyToScreenName; - } - - public void setInReplyToScreenName(final String inReplyToScreenName) { - this.inReplyToScreenName = inReplyToScreenName; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - Tweet tweet = (Tweet) o; - - if (fromUserId != tweet.fromUserId) { - return false; - } - if (id != tweet.id) { - return false; - } - if (idStr != null ? !idStr.equals(tweet.idStr) : tweet.idStr != null) { - return false; - } - if (retweeted != tweet.retweeted) { - return false; - } - if (createdAt != null ? !createdAt.equals(tweet.createdAt) : tweet.createdAt != null) { - return false; - } - if (entities != null ? !entities.equals(tweet.entities) : tweet.entities != null) { - return false; - } - if (fromUser != null ? !fromUser.equals(tweet.fromUser) : tweet.fromUser != null) { - return false; - } - if (inReplyToScreenName != null ? !inReplyToScreenName.equals(tweet.inReplyToScreenName) : tweet.inReplyToScreenName != null) { - return false; - } - if (inReplyToStatusId != null ? !inReplyToStatusId.equals(tweet.inReplyToStatusId) : tweet.inReplyToStatusId != null) { - return false; - } - if (inReplyToUserId != null ? !inReplyToUserId.equals(tweet.inReplyToUserId) : tweet.inReplyToUserId != null) { - return false; - } - if (languageCode != null ? !languageCode.equals(tweet.languageCode) : tweet.languageCode != null) { - return false; - } - if (profileImageUrl != null ? !profileImageUrl.equals(tweet.profileImageUrl) : tweet.profileImageUrl != null) { - return false; - } - if (retweetCount != null ? !retweetCount.equals(tweet.retweetCount) : tweet.retweetCount != null) { - return false; - } - if (retweetedStatus != null ? !retweetedStatus.equals(tweet.retweetedStatus) : tweet.retweetedStatus != null) { - return false; - } - if (source != null ? !source.equals(tweet.source) : tweet.source != null) { - return false; - } - if (text != null ? !text.equals(tweet.text) : tweet.text != null) { - return false; - } - if (toUserId != null ? !toUserId.equals(tweet.toUserId) : tweet.toUserId != null) { - return false; - } - if (user != null ? !user.equals(tweet.user) : tweet.user != null) { - return false; - } - - return true; - } - - @Override - public int hashCode() { - int result = (int) (id ^ (id >>> 32)); - result = 31 * result + (idStr != null ? idStr.hashCode() : 0); - result = 31 * result + (text != null ? text.hashCode() : 0); - result = 31 * result + (createdAt != null ? createdAt.hashCode() : 0); - result = 31 * result + (fromUser != null ? fromUser.hashCode() : 0); - result = 31 * result + (profileImageUrl != null ? profileImageUrl.hashCode() : 0); - result = 31 * result + (toUserId != null ? toUserId.hashCode() : 0); - result = 31 * result + (inReplyToStatusId != null ? inReplyToStatusId.hashCode() : 0); - result = 31 * result + (inReplyToUserId != null ? inReplyToUserId.hashCode() : 0); - result = 31 * result + (inReplyToScreenName != null ? inReplyToScreenName.hashCode() : 0); - result = 31 * result + (int) (fromUserId ^ (fromUserId >>> 32)); - result = 31 * result + (languageCode != null ? languageCode.hashCode() : 0); - result = 31 * result + (source != null ? source.hashCode() : 0); - result = 31 * result + (retweetCount != null ? retweetCount.hashCode() : 0); - result = 31 * result + (retweeted ? 1 : 0); - result = 31 * result + (retweetedStatus != null ? retweetedStatus.hashCode() : 0); - result = 31 * result + (entities != null ? entities.hashCode() : 0); - result = 31 * result + (user != null ? user.hashCode() : 0); - return result; - } -} + private static final long serialVersionUID = 1L; + + private final long id; + private final String idStr; + private final String text; + private final Date createdAt; + private String fromUser; + private String profileImageUrl; + private Long toUserId; + private Long inReplyToStatusId; + private Long inReplyToUserId; + private String inReplyToScreenName; + private long fromUserId; + private String languageCode; + private String source; + private Integer retweetCount; + private boolean retweeted; + private Tweet retweetedStatus; + private boolean favorited; + private Integer favoriteCount; + private Boolean truncated; + private Boolean possiblySensitive; + private Entities entities; + private Entities extendedEntities; + private TwitterProfile user; + + /** + * Constructs a Tweet + * + * @param id The tweet's ID + * @param text The tweet's text + * @param createdAt Date Tweet was created + * @param fromUser The username of the author of the tweet. + * @param profileImageUrl The URL to the profile picture of the tweet's author. + * @param toUserId The user ID of the user to whom the tweet is targeted. + * @param fromUserId The user ID of the tweet's author. + * @param languageCode The language code + * @param source The source of the tweet. + * + * @deprecated Use other constructor with String ID instead. + */ + @Deprecated + public Tweet( + long id, + String text, + Date createdAt, + String fromUser, + String profileImageUrl, + Long toUserId, + long fromUserId, + String languageCode, + String source) { + this(id, String.valueOf(id), text, createdAt, fromUser, profileImageUrl, toUserId, fromUserId, languageCode, source); + } + + /** + * Constructs a Tweet + * + * @param id The tweet's ID + * @param idStr The tweet's ID as a String + * @param text The tweet's text + * @param createdAt Date Tweet was created + * @param fromUser The username of the author of the tweet. + * @param profileImageUrl The URL to the profile picture of the tweet's author. + * @param toUserId The user ID of the user to whom the tweet is targeted. + * @param fromUserId The user ID of the tweet's author. + * @param languageCode The language code + * @param source The source of the tweet. + * + * @deprecated Use other constructor with String ID instead. + */ + public Tweet( + long id, + String idStr, + String text, + Date createdAt, + String fromUser, + String profileImageUrl, + Long toUserId, + long fromUserId, + String languageCode, + String source) { + this.id = id; + this.idStr = idStr; + this.text = text; + this.createdAt = createdAt; + this.fromUser = fromUser; + this.profileImageUrl = profileImageUrl; + this.toUserId = toUserId; + this.fromUserId = fromUserId; + this.languageCode = languageCode; + this.source = source; + } + + /** + * The text of the tweet. If this tweet is a retweet of another tweet, the text may be preceeded with "RT \@someuser" and may be truncated at the + * end. + * To get the raw, unmodified text of the original tweet, use {@link #getUnmodifiedText()}. + * + * @return The text of the tweet. + */ + public String getText() { + return text; + } + + /** + * Returns the unmodified text of the tweet. + * If this tweet is a retweet, it returns the text of the original tweet. + * If it is not a retweet, then this method will return the same value as {@link #getText()}. + * + * @return The unmodified text of the tweet. + */ + public String getUnmodifiedText() { + return isRetweet() ? retweetedStatus.getText() : getText(); + } + + public Date getCreatedAt() { + return createdAt; + } + + public String getFromUser() { + return fromUser; + } + + public void setFromUser(String fromUser) { + this.fromUser = fromUser; + } + + public long getId() { + return id; + } + + public String getIdStr() { + return idStr; + } + + public String getProfileImageUrl() { + return profileImageUrl; + } + + public void setProfileImageUrl(String profileImageUrl) { + this.profileImageUrl = profileImageUrl; + } + + public Long getToUserId() { + return toUserId; + } + + public void setToUserId(Long toUserId) { + this.toUserId = toUserId; + } + + public long getFromUserId() { + return fromUserId; + } + + public void setInReplyToStatusId(Long inReplyToStatusId) { + this.inReplyToStatusId = inReplyToStatusId; + } + + public Long getInReplyToStatusId() { + return inReplyToStatusId; + } + + public void setFromUserId(long fromUserId) { + this.fromUserId = fromUserId; + } + + public String getLanguageCode() { + return languageCode; + } + + public void setLanguageCode(String languageCode) { + this.languageCode = languageCode; + } + + public String getSource() { + return source; + } + + public void setSource(String source) { + this.source = source; + } + + public void setRetweetCount(Integer retweetCount) { + this.retweetCount = retweetCount; + } + + /** + * The number of times this tweet has been retweeted. + * Only available in timeline results. + * getRetweetCount() will return null for Tweet objects returned in search results. + * + * @return the number of times the tweet has been retweeted or null if that information is unavailable + */ + public Integer getRetweetCount() { + return retweetCount; + } + + public void setRetweeted(boolean retweeted) { + this.retweeted = retweeted; + } + + public boolean isRetweeted() { + return retweeted; + } + + public Tweet getRetweetedStatus() { + return this.retweetedStatus; + } + + public void setRetweetedStatus(final Tweet tweet) { + this.retweetedStatus = tweet; + } + + public boolean isRetweet() { + return this.retweetedStatus != null; + } + + public void setFavorited(boolean favorited) { + this.favorited = favorited; + } + + public boolean isFavorited() { + return favorited; + } + + public void setFavoriteCount(Integer favoriteCount) { + this.favoriteCount = favoriteCount; + } + + public Integer getFavoriteCount() { + return favoriteCount; + } + + public void setTruncated(Boolean truncated) { + this.truncated = truncated; + } + + public Boolean isTruncated() { + return truncated; + } + + public void setPossiblySensitive(Boolean possiblySensitive) { + this.possiblySensitive = possiblySensitive; + } + + public Boolean isPossiblySensitive() { + return possiblySensitive; + } + + public Entities getEntities() { + return this.entities; + } + + public void setEntities(final Entities ent) { + this.entities = ent; + } + + public void setExtendedEntities(Entities extendedEntities) { + this.extendedEntities = extendedEntities; + } + + public Entities getExtendedEntities() { + return extendedEntities; + } + + public boolean hasMentions() { + if (this.entities == null) { + return false; + } + return !this.entities.getMentions().isEmpty(); + } + + public boolean hasMedia() { + if (this.entities == null) { + return false; + } + return !this.entities.getMedia().isEmpty(); + } + + public boolean hasUrls() { + if (this.entities == null) { + return false; + } + return !this.entities.getUrls().isEmpty(); + } + + public boolean hasTags() { + if (this.entities == null) { + return false; + } + return !this.entities.getHashTags().isEmpty(); + } + + public TwitterProfile getUser() { + return this.user; + } + + public void setUser(final TwitterProfile prof) { + this.user = prof; + } + + public Long getInReplyToUserId() { + return inReplyToUserId; + } + + public void setInReplyToUserId(final Long inReplyToUserId) { + this.inReplyToUserId = inReplyToUserId; + } + + public String getInReplyToScreenName() { + return inReplyToScreenName; + } + + public void setInReplyToScreenName(final String inReplyToScreenName) { + this.inReplyToScreenName = inReplyToScreenName; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + Tweet tweet = (Tweet) o; + + if (fromUserId != tweet.fromUserId) { + return false; + } + if (id != tweet.id) { + return false; + } + if (idStr != null ? !idStr.equals(tweet.idStr) : tweet.idStr != null) { + return false; + } + if (retweeted != tweet.retweeted) { + return false; + } + if (createdAt != null ? !createdAt.equals(tweet.createdAt) : tweet.createdAt != null) { + return false; + } + if (entities != null ? !entities.equals(tweet.entities) : tweet.entities != null) { + return false; + } + if (fromUser != null ? !fromUser.equals(tweet.fromUser) : tweet.fromUser != null) { + return false; + } + if (inReplyToScreenName != null ? !inReplyToScreenName.equals(tweet.inReplyToScreenName) : tweet.inReplyToScreenName != null) { + return false; + } + if (inReplyToStatusId != null ? !inReplyToStatusId.equals(tweet.inReplyToStatusId) : tweet.inReplyToStatusId != null) { + return false; + } + if (inReplyToUserId != null ? !inReplyToUserId.equals(tweet.inReplyToUserId) : tweet.inReplyToUserId != null) { + return false; + } + if (languageCode != null ? !languageCode.equals(tweet.languageCode) : tweet.languageCode != null) { + return false; + } + if (profileImageUrl != null ? !profileImageUrl.equals(tweet.profileImageUrl) : tweet.profileImageUrl != null) { + return false; + } + if (retweetCount != null ? !retweetCount.equals(tweet.retweetCount) : tweet.retweetCount != null) { + return false; + } + if (retweetedStatus != null ? !retweetedStatus.equals(tweet.retweetedStatus) : tweet.retweetedStatus != null) { + return false; + } + if (source != null ? !source.equals(tweet.source) : tweet.source != null) { + return false; + } + if (text != null ? !text.equals(tweet.text) : tweet.text != null) { + return false; + } + if (toUserId != null ? !toUserId.equals(tweet.toUserId) : tweet.toUserId != null) { + return false; + } + if (user != null ? !user.equals(tweet.user) : tweet.user != null) { + return false; + } + + return true; + } + + @Override + public int hashCode() { + int result = (int) (id ^ (id >>> 32)); + result = 31 * result + (idStr != null ? idStr.hashCode() : 0); + result = 31 * result + (text != null ? text.hashCode() : 0); + result = 31 * result + (createdAt != null ? createdAt.hashCode() : 0); + result = 31 * result + (fromUser != null ? fromUser.hashCode() : 0); + result = 31 * result + (profileImageUrl != null ? profileImageUrl.hashCode() : 0); + result = 31 * result + (toUserId != null ? toUserId.hashCode() : 0); + result = 31 * result + (inReplyToStatusId != null ? inReplyToStatusId.hashCode() : 0); + result = 31 * result + (inReplyToUserId != null ? inReplyToUserId.hashCode() : 0); + result = 31 * result + (inReplyToScreenName != null ? inReplyToScreenName.hashCode() : 0); + result = 31 * result + (int) (fromUserId ^ (fromUserId >>> 32)); + result = 31 * result + (languageCode != null ? languageCode.hashCode() : 0); + result = 31 * result + (source != null ? source.hashCode() : 0); + result = 31 * result + (retweetCount != null ? retweetCount.hashCode() : 0); + result = 31 * result + (retweeted ? 1 : 0); + result = 31 * result + (retweetedStatus != null ? retweetedStatus.hashCode() : 0); + result = 31 * result + (entities != null ? entities.hashCode() : 0); + result = 31 * result + (user != null ? user.hashCode() : 0); + return result; + } +} \ No newline at end of file diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/Twitter.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/Twitter.java index 17bd948f..37c9d050 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/Twitter.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/Twitter.java @@ -1,12 +1,12 @@ /* * Copyright 2014 the original author or authors. - * + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * + * + * http://www.apache.org/licenses/LICENSE-2.0 + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -16,6 +16,16 @@ package org.springframework.social.twitter.api; import org.springframework.social.ApiBinding; +import org.springframework.social.twitter.api.advertising.AdvertisingOperations; +import org.springframework.social.twitter.api.advertising.CampaignOperations; +import org.springframework.social.twitter.api.advertising.LineItemOperations; +import org.springframework.social.twitter.api.advertising.PromotionOperations; +import org.springframework.social.twitter.api.advertising.StatisticsOperations; +import org.springframework.social.twitter.api.advertising.TailoredAudienceOperations; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryOperations; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaOperations; +import org.springframework.social.twitter.api.ton.TonOperations; +import org.springframework.social.twitter.api.upload.UploadOperations; import org.springframework.web.client.RestOperations; @@ -26,57 +36,116 @@ * @author Craig Walls */ public interface Twitter extends ApiBinding { - - /** - * @return the portion of the Twitter API containing the block operations. - */ - BlockOperations blockOperations(); - - /** - * @return the portion of the Twitter API containing the direct message operations. - */ - DirectMessageOperations directMessageOperations(); - - /** - * @return the portion of the Twitter API containing the friends and followers operations. - */ - FriendOperations friendOperations(); - - /** - * @return the portion of the Twitter API containing the geo location operations. - */ - GeoOperations geoOperations(); - - /** - * @return the portion of the Twitter API containing the user list operations. - */ - ListOperations listOperations(); - - /** - * @return the portion of the Twitter API containing the search operations. - */ - SearchOperations searchOperations(); - - /** - * @return the portion of the Twitter API containing the streaming operations. - */ - StreamingOperations streamingOperations(); - - /** - * @return the portion of the Twitter API containing the tweet and timeline operations. - */ - TimelineOperations timelineOperations(); - - /** - * @return the portion of the Twitter API containing the user operations. - */ - UserOperations userOperations(); - - /** - * Returns the underlying {@link RestOperations} object allowing for consumption of Twitter endpoints that may not be otherwise covered by the API binding. - * The RestOperations object returned is configured to include an OAuth "Authorization" header on all requests. - * @return a RestOperations object instrumented for including an OAuth Authorization header on requests. - */ - RestOperations restOperations(); - -} + + /** + * @return the portion of the Twitter API containing the block operations. + */ + BlockOperations blockOperations(); + + /** + * @return the portion of the Twitter API containing the direct message operations. + */ + DirectMessageOperations directMessageOperations(); + + /** + * @return the portion of the Twitter API containing the friends and followers operations. + */ + FriendOperations friendOperations(); + + /** + * @return the portion of the Twitter API containing the geo location operations. + */ + GeoOperations geoOperations(); + + /** + * @return the portion of the Twitter API containing the user list operations. + */ + ListOperations listOperations(); + + /** + * @return the portion of the Twitter API containing the search operations. + */ + SearchOperations searchOperations(); + + /** + * @return the portion of the Twitter API containing the streaming operations. + */ + StreamingOperations streamingOperations(); + + /** + * @return the portion of the Twitter API containing the tweet and timeline operations. + */ + TimelineOperations timelineOperations(); + + /** + * @return the portion of the Twitter API containing the user operations. + */ + UserOperations userOperations(); + + /** + * @return the portion of the Twitter ADS API containing the advertising operations. + */ + AdvertisingOperations advertisingOperations(); + + /** + * @return the portion of the Twitter ADS API containing the promoted tweet operations. + */ + PromotionOperations promotionOperations(); + + /** + * + * @return the portion of the Twitter ADS API containing operations for advertising statistics. + */ + StatisticsOperations statisticsOperations(); + + /** + * @return the portion of the Twitter ADS API containing the campaign operations. + */ + CampaignOperations campaignOperations(); + + /** + * @return the portion of the Twitter ADS API containing the line items operations. + */ + LineItemOperations lineItemOperations(); + + /** + * @return the portion of the Twitter ADS API containing the targeting criteria operations. + */ + TargetingCriteriaOperations targetingCriteriaOperations(); + + /** + * @return the portion of the Twitter ADS API containing the targeting criteria discovery operations. + */ + TargetingCriteriaDiscoveryOperations targetingCriteriaDiscoveryOperations(); + + /** + * @return the portion of the Twitter ADS API containing the tailored audience operations. + */ + TailoredAudienceOperations tailoredAudienceOperations(); + + /** + * @return the Twitter Object Nest operations. + */ + TonOperations tonOperations(); + + /** + * @return operations for uploading non-chunked media. + */ + UploadOperations uploadOperations(); + + /** + * Returns the underlying {@link RestOperations} object allowing for consumption of Twitter endpoints that may not be otherwise covered by the API + * binding. + * The RestOperations object returned is configured to include an OAuth "Authorization" header on all requests. + * + * @return a RestOperations object instrumented for including an OAuth Authorization header on requests. + */ + RestOperations restOperations(); + + /** + * Retrieve dynamic settings inherent to the setup of the twitter api. + * + * @return an implementation of {@link Settings} responsible for communicating the settings + */ + Settings settings(); +} \ No newline at end of file diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/TwitterForm.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/TwitterForm.java new file mode 100644 index 00000000..0262a729 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/TwitterForm.java @@ -0,0 +1,33 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api; + +import org.springframework.util.MultiValueMap; + +/** + * Generic data transfering contract that can be used to build + * request parameters transfering data specially for POST and PUT + * operations in Api endpoints. + * + * This helps eliminate dependencies that the "api" package may + * have to the "api.impl" package since contracts by definition + * should not be coupled to implementations. + * + * @author Hudson mendes + */ +public interface TwitterForm { + public MultiValueMap toRequestBody(); +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/TwitterObject.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/TwitterObject.java index 06b18cb5..34c34e02 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/TwitterObject.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/TwitterObject.java @@ -15,6 +15,7 @@ */ package org.springframework.social.twitter.api; +import java.io.Serializable; import java.util.HashMap; import java.util.Map; @@ -25,7 +26,8 @@ * Offers an extraData property for carrying any data in response from Twitter that won't be otherwise mapped to any properties of the subclass. * @author Craig Walls */ -public class TwitterObject { +public class TwitterObject implements Serializable { + private static final long serialVersionUID = 1L; private Map extraData; diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/TwitterProfile.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/TwitterProfile.java index 9d3e9af7..c8871017 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/TwitterProfile.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/TwitterProfile.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -24,489 +24,507 @@ * @author Craig Walls */ public class TwitterProfile extends TwitterObject implements Serializable { - private static final long serialVersionUID = 1L; - - private final long id; - private final String screenName; - private final String name; - private final String url; - private final String profileImageUrl; - private final String description; - private final String location; - private final Date createdDate; - private String language; - private int statusesCount; - private int friendsCount; - private int followersCount; - private int favoritesCount; - private int listedCount; - private boolean following; - private boolean followRequestSent; - private boolean isProtected; - private boolean notificationsEnabled; - private boolean verified; - private boolean geoEnabled; - private boolean contributorsEnabled; - private boolean translator; - private String timeZone; - private int utcOffset; - private String sidebarBorderColor; - private String sidebarFillColor; - private String backgroundColor; - private boolean useBackgroundImage; - private String backgroundImageUrl; - private boolean backgroundImageTiled; - private String textColor; - private String linkColor; - private boolean showAllInlineMedia; + private static final long serialVersionUID = 1L; + + private final long id; + private final String screenName; + private final String name; + private final String url; + private final String profileImageUrl; + private final String description; + private final String location; + private final Date createdDate; + private String language; + private int statusesCount; + private int friendsCount; + private int followersCount; + private int favoritesCount; + private int listedCount; + private boolean following; + private boolean followRequestSent; + private boolean isProtected; + private boolean notificationsEnabled; + private boolean verified; + private boolean geoEnabled; + private boolean contributorsEnabled; + private boolean translator; + private String timeZone; + private int utcOffset; + private String sidebarBorderColor; + private String sidebarFillColor; + private String backgroundColor; + private boolean useBackgroundImage; + private String backgroundImageUrl; + private boolean backgroundImageTiled; + private String textColor; + private String linkColor; + private boolean showAllInlineMedia; private String profileBannerUrl; - - public static long getSerialversionuid() { - return serialVersionUID; - } - - public TwitterProfile(long id, String screenName, String name, String url, String profileImageUrl, String description, String location, Date createdDate) { - this.id = id; - this.screenName = screenName; - this.name = name; - this.url = url; - this.profileImageUrl = profileImageUrl; - this.description = description; - this.location = location; - this.createdDate = createdDate; - } - - /** - * The user's Twitter ID - * - * @return The user's Twitter ID - */ - public long getId() { - return id; - } - - /** - * The user's Twitter screen name - * - * @return The user's Twitter screen name - */ - public String getScreenName() { - return screenName; - } - - /** - * The user's full name - * - * @return The user's full name - */ - public String getName() { - return name; - } - - /** - * The user's URL - * - * @return The user's URL - */ - public String getUrl() { - return url; - } - - /** - * The user's description - * - * @return The user's description - */ - public String getDescription() { - return description; - } - - /** - * The user's location - * - * @return The user's location - */ - public String getLocation() { - return location; - } - - /** - *

- * The URL of the user's profile image in "normal" size (48x48). - *

- * - * @return The URL of the user's normal-sized profile image. - */ - public String getProfileImageUrl() { - return profileImageUrl; - } - - /** - *

- * The URL of the user's profile. - *

- * - * @return The URL of the user's profile. - */ - public String getProfileUrl() { - return "http://twitter.com/" + screenName; - } - - /** - * The date that the Twitter profile was created. - * - * @return The date that the Twitter profile was created. - */ - public Date getCreatedDate() { - return createdDate; - } - - /** - * Whether or not the user has mobile notifications enabled. - * @return true if the user has mobile notifications enabled - */ - public boolean isNotificationsEnabled() { - return notificationsEnabled; - } - - /** - * Whether or not the user is verified with Twitter. - * See http://support.twitter.com/groups/31-twitter-basics/topics/111-features/articles/119135-about-verified-accounts. - * @return true if the user is verified - */ - public boolean isVerified() { - return verified; - } - - /** - * Whether or not the user has enabled their account with geo location. - * @return true if geo-location is enabled - */ - public boolean isGeoEnabled() { - return geoEnabled; - } - - /** - * @return the user's preferred language. - */ - public String getLanguage() { - return language; - } - - /** - * @return the number of tweets this user has posted. - */ - public int getStatusesCount() { - return statusesCount; - } - - /** - * @return the number of lists the user is listed on. - */ - public int getListedCount() { - return listedCount; - } - - /** - * @return the number of friends the user has (the number of users this user follows). - */ - public int getFriendsCount() { - return friendsCount; - } - - /** - * @return the number of followers the user has. - */ - public int getFollowersCount() { - return followersCount; - } - - /** - * Whether or not the authenticated user is following this user. - * @return true if the authenticated user is following this user - */ - public boolean isFollowing() { - return following; - } - - /** - * Whether or not a request has been sent by the authenticating user to follow this user. - * @return true if a follow request has been sent to this user - */ - public boolean isFollowRequestSent() { - return followRequestSent; - } - - /** - * @return the number of tweets that the user has marked as favorites. - */ - public int getFavoritesCount() { - return favoritesCount; - } - - /** - * Whether or not the user's tweets are protected. - * @return true if the user's tweets are protected - */ - public boolean isProtected() { - return isProtected; - } - - /** - * @return the user's time zone. - */ - public String getTimeZone() { - return timeZone; - } - - /** - * @return the user's UTC offset in seconds. - */ - public int getUtcOffset() { - return utcOffset; - } - - /** - * Whether or not this profile is enabled for contributors. - * @return true if contributors are enabled - */ - public boolean isContributorsEnabled() { - return contributorsEnabled; - } - - /** - * Whether or not this user is a translator. - * @return true if the user is a translator - */ - public boolean isTranslator() { - return translator; - } - - /** - * @return the color of the sidebar border on the user's Twitter profile page. - */ - public String getSidebarBorderColor() { - return sidebarBorderColor; - } - - /** - * @return the color of the sidebar fill on the user's Twitter profile page. - */ - public String getSidebarFillColor() { - return sidebarFillColor; - } - - /** - * @return the color of the background of the user's Twitter profile page. - */ - public String getBackgroundColor() { - return backgroundColor; - } - - /** - * Whether or not the user's Twitter profile page uses a background image. - * @return true if the user's profile page uses a background image - */ - public boolean useBackgroundImage() { - return useBackgroundImage; - } - - /** - * @return the URL to a background image shown on the user's Twitter profile page. - */ - public String getBackgroundImageUrl() { - return backgroundImageUrl; - } - - /** - * Whether or not the background image is tiled. - * @return true if the background images is tiled - */ - public boolean isBackgroundImageTiled() { - return backgroundImageTiled; - } - - /** - * @return the text color on the user's Twitter profile page. - */ - public String getTextColor() { - return textColor; - } - - /** - * @return the link color on the user's Twitter profile page. - */ - public String getLinkColor() { - return linkColor; - } - - /** - * The URL to the banner image shown on the user's Twitter profile page + + public static long getSerialversionuid() { + return serialVersionUID; + } + + public TwitterProfile( + long id, + String screenName, + String name, + String url, + String profileImageUrl, + String description, + String location, + Date createdDate) { + this.id = id; + this.screenName = screenName; + this.name = name; + this.url = url; + this.profileImageUrl = profileImageUrl; + this.description = description; + this.location = location; + this.createdDate = createdDate; + } + + /** + * The user's Twitter ID + * + * @return The user's Twitter ID + */ + public long getId() { + return id; + } + + /** + * The user's Twitter screen name + * + * @return The user's Twitter screen name + */ + public String getScreenName() { + return screenName; + } + + /** + * The user's full name + * + * @return The user's full name + */ + public String getName() { + return name; + } + + /** + * The user's URL + * + * @return The user's URL + */ + public String getUrl() { + return url; + } + + /** + * The user's description + * + * @return The user's description + */ + public String getDescription() { + return description; + } + + /** + * The user's location + * + * @return The user's location + */ + public String getLocation() { + return location; + } + + /** + *

+ * The URL of the user's profile image in "normal" size (48x48). + *

+ * + * @return The URL of the user's normal-sized profile image. + */ + public String getProfileImageUrl() { + return profileImageUrl; + } + + /** + *

+ * The URL of the user's profile. + *

+ * + * @return The URL of the user's profile. + */ + public String getProfileUrl() { + return "http://twitter.com/" + screenName; + } + + /** + * The date that the Twitter profile was created. + * + * @return The date that the Twitter profile was created. + */ + public Date getCreatedDate() { + return createdDate; + } + + /** + * Whether or not the user has mobile notifications enabled. + * + * @return true if the user has mobile notifications enabled + */ + public boolean isNotificationsEnabled() { + return notificationsEnabled; + } + + /** + * Whether or not the user is verified with Twitter. + * See http://support.twitter.com/groups/31-twitter-basics/topics/111-features/articles/119135-about-verified-accounts. + * + * @return true if the user is verified + */ + public boolean isVerified() { + return verified; + } + + /** + * Whether or not the user has enabled their account with geo location. + * + * @return true if geo-location is enabled + */ + public boolean isGeoEnabled() { + return geoEnabled; + } + + /** + * @return the user's preferred language. + */ + public String getLanguage() { + return language; + } + + /** + * @return the number of tweets this user has posted. + */ + public int getStatusesCount() { + return statusesCount; + } + + /** + * @return the number of lists the user is listed on. + */ + public int getListedCount() { + return listedCount; + } + + /** + * @return the number of friends the user has (the number of users this user follows). + */ + public int getFriendsCount() { + return friendsCount; + } + + /** + * @return the number of followers the user has. + */ + public int getFollowersCount() { + return followersCount; + } + + /** + * Whether or not the authenticated user is following this user. + * + * @return true if the authenticated user is following this user + */ + public boolean isFollowing() { + return following; + } + + /** + * Whether or not a request has been sent by the authenticating user to follow this user. + * + * @return true if a follow request has been sent to this user + */ + public boolean isFollowRequestSent() { + return followRequestSent; + } + + /** + * @return the number of tweets that the user has marked as favorites. + */ + public int getFavoritesCount() { + return favoritesCount; + } + + /** + * Whether or not the user's tweets are protected. + * + * @return true if the user's tweets are protected + */ + public boolean isProtected() { + return isProtected; + } + + /** + * @return the user's time zone. + */ + public String getTimeZone() { + return timeZone; + } + + /** + * @return the user's UTC offset in seconds. + */ + public int getUtcOffset() { + return utcOffset; + } + + /** + * Whether or not this profile is enabled for contributors. + * + * @return true if contributors are enabled + */ + public boolean isContributorsEnabled() { + return contributorsEnabled; + } + + /** + * Whether or not this user is a translator. + * + * @return true if the user is a translator + */ + public boolean isTranslator() { + return translator; + } + + /** + * @return the color of the sidebar border on the user's Twitter profile page. + */ + public String getSidebarBorderColor() { + return sidebarBorderColor; + } + + /** + * @return the color of the sidebar fill on the user's Twitter profile page. + */ + public String getSidebarFillColor() { + return sidebarFillColor; + } + + /** + * @return the color of the background of the user's Twitter profile page. + */ + public String getBackgroundColor() { + return backgroundColor; + } + + /** + * Whether or not the user's Twitter profile page uses a background image. + * + * @return true if the user's profile page uses a background image + */ + public boolean useBackgroundImage() { + return useBackgroundImage; + } + + /** + * @return the URL to a background image shown on the user's Twitter profile page. + */ + public String getBackgroundImageUrl() { + return backgroundImageUrl; + } + + /** + * Whether or not the background image is tiled. + * + * @return true if the background images is tiled + */ + public boolean isBackgroundImageTiled() { + return backgroundImageTiled; + } + + /** + * @return the text color on the user's Twitter profile page. + */ + public String getTextColor() { + return textColor; + } + + /** + * @return the link color on the user's Twitter profile page. + */ + public String getLinkColor() { + return linkColor; + } + + /** + * @return The URL to the banner image shown on the user's Twitter profile page */ public String getProfileBannerUrl() { return profileBannerUrl; } - /** - * Whether or not the user has selected to see all inline media from everyone. - * If false, they will only see inline media from the users they follow. - * @return true if the user wats to see all inline media - */ - public boolean showAllInlineMedia() { - return showAllInlineMedia; - } + /** + * Whether or not the user has selected to see all inline media from everyone. + * If false, they will only see inline media from the users they follow. + * + * @return true if the user wats to see all inline media + */ + public boolean showAllInlineMedia() { + return showAllInlineMedia; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + TwitterProfile that = (TwitterProfile) o; + + if (backgroundImageTiled != that.backgroundImageTiled) { + return false; + } + if (contributorsEnabled != that.contributorsEnabled) { + return false; + } + if (favoritesCount != that.favoritesCount) { + return false; + } + if (followRequestSent != that.followRequestSent) { + return false; + } + if (followersCount != that.followersCount) { + return false; + } + if (following != that.following) { + return false; + } + if (friendsCount != that.friendsCount) { + return false; + } + if (geoEnabled != that.geoEnabled) { + return false; + } + if (id != that.id) { + return false; + } + if (isProtected != that.isProtected) { + return false; + } + if (listedCount != that.listedCount) { + return false; + } + if (notificationsEnabled != that.notificationsEnabled) { + return false; + } + if (showAllInlineMedia != that.showAllInlineMedia) { + return false; + } + if (statusesCount != that.statusesCount) { + return false; + } + if (translator != that.translator) { + return false; + } + if (useBackgroundImage != that.useBackgroundImage) { + return false; + } + if (utcOffset != that.utcOffset) { + return false; + } + if (verified != that.verified) { + return false; + } + if (backgroundColor != null ? !backgroundColor.equals(that.backgroundColor) : that.backgroundColor != null) { + return false; + } + if (backgroundImageUrl != null ? !backgroundImageUrl.equals(that.backgroundImageUrl) : that.backgroundImageUrl != null) { + return false; + } + if (createdDate != null ? !createdDate.equals(that.createdDate) : that.createdDate != null) { + return false; + } + if (description != null ? !description.equals(that.description) : that.description != null) { + return false; + } + if (language != null ? !language.equals(that.language) : that.language != null) { + return false; + } + if (linkColor != null ? !linkColor.equals(that.linkColor) : that.linkColor != null) { + return false; + } + if (location != null ? !location.equals(that.location) : that.location != null) { + return false; + } + if (name != null ? !name.equals(that.name) : that.name != null) { + return false; + } + if (profileImageUrl != null ? !profileImageUrl.equals(that.profileImageUrl) : that.profileImageUrl != null) { + return false; + } + if (screenName != null ? !screenName.equals(that.screenName) : that.screenName != null) { + return false; + } + if (sidebarBorderColor != null ? !sidebarBorderColor.equals(that.sidebarBorderColor) : that.sidebarBorderColor != null) { + return false; + } + if (sidebarFillColor != null ? !sidebarFillColor.equals(that.sidebarFillColor) : that.sidebarFillColor != null) { + return false; + } + if (textColor != null ? !textColor.equals(that.textColor) : that.textColor != null) { + return false; + } + if (timeZone != null ? !timeZone.equals(that.timeZone) : that.timeZone != null) { + return false; + } + if (url != null ? !url.equals(that.url) : that.url != null) { + return false; + } + + return true; + } @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - TwitterProfile that = (TwitterProfile) o; - - if (backgroundImageTiled != that.backgroundImageTiled) { - return false; - } - if (contributorsEnabled != that.contributorsEnabled) { - return false; - } - if (favoritesCount != that.favoritesCount) { - return false; - } - if (followRequestSent != that.followRequestSent) { - return false; - } - if (followersCount != that.followersCount) { - return false; - } - if (following != that.following) { - return false; - } - if (friendsCount != that.friendsCount) { - return false; - } - if (geoEnabled != that.geoEnabled) { - return false; - } - if (id != that.id) { - return false; - } - if (isProtected != that.isProtected) { - return false; - } - if (listedCount != that.listedCount) { - return false; - } - if (notificationsEnabled != that.notificationsEnabled) { - return false; - } - if (showAllInlineMedia != that.showAllInlineMedia) { - return false; - } - if (statusesCount != that.statusesCount) { - return false; - } - if (translator != that.translator) { - return false; - } - if (useBackgroundImage != that.useBackgroundImage) { - return false; - } - if (utcOffset != that.utcOffset) { - return false; - } - if (verified != that.verified) { - return false; - } - if (backgroundColor != null ? !backgroundColor.equals(that.backgroundColor) : that.backgroundColor != null) { - return false; - } - if (backgroundImageUrl != null ? !backgroundImageUrl.equals(that.backgroundImageUrl) : that.backgroundImageUrl != null) { - return false; - } - if (createdDate != null ? !createdDate.equals(that.createdDate) : that.createdDate != null) { - return false; - } - if (description != null ? !description.equals(that.description) : that.description != null) { - return false; - } - if (language != null ? !language.equals(that.language) : that.language != null) { - return false; - } - if (linkColor != null ? !linkColor.equals(that.linkColor) : that.linkColor != null) { - return false; - } - if (location != null ? !location.equals(that.location) : that.location != null) { - return false; - } - if (name != null ? !name.equals(that.name) : that.name != null) { - return false; - } - if (profileImageUrl != null ? !profileImageUrl.equals(that.profileImageUrl) : that.profileImageUrl != null) { - return false; - } - if (screenName != null ? !screenName.equals(that.screenName) : that.screenName != null) { - return false; - } - if (sidebarBorderColor != null ? !sidebarBorderColor.equals(that.sidebarBorderColor) : that.sidebarBorderColor != null) { - return false; - } - if (sidebarFillColor != null ? !sidebarFillColor.equals(that.sidebarFillColor) : that.sidebarFillColor != null) { - return false; - } - if (textColor != null ? !textColor.equals(that.textColor) : that.textColor != null) { - return false; - } - if (timeZone != null ? !timeZone.equals(that.timeZone) : that.timeZone != null) { - return false; - } - if (url != null ? !url.equals(that.url) : that.url != null) { - return false; - } - - return true; - } - - - @Override - public int hashCode() { - int result = (int) (id ^ (id >>> 32)); - result = 31 * result + (screenName != null ? screenName.hashCode() : 0); - result = 31 * result + (name != null ? name.hashCode() : 0); - result = 31 * result + (url != null ? url.hashCode() : 0); - result = 31 * result + (profileImageUrl != null ? profileImageUrl.hashCode() : 0); - result = 31 * result + (description != null ? description.hashCode() : 0); - result = 31 * result + (location != null ? location.hashCode() : 0); - result = 31 * result + (createdDate != null ? createdDate.hashCode() : 0); - result = 31 * result + (language != null ? language.hashCode() : 0); - result = 31 * result + statusesCount; - result = 31 * result + friendsCount; - result = 31 * result + followersCount; - result = 31 * result + favoritesCount; - result = 31 * result + listedCount; - result = 31 * result + (following ? 1 : 0); - result = 31 * result + (followRequestSent ? 1 : 0); - result = 31 * result + (isProtected ? 1 : 0); - result = 31 * result + (notificationsEnabled ? 1 : 0); - result = 31 * result + (verified ? 1 : 0); - result = 31 * result + (geoEnabled ? 1 : 0); - result = 31 * result + (contributorsEnabled ? 1 : 0); - result = 31 * result + (translator ? 1 : 0); - result = 31 * result + (timeZone != null ? timeZone.hashCode() : 0); - result = 31 * result + utcOffset; - result = 31 * result + (sidebarBorderColor != null ? sidebarBorderColor.hashCode() : 0); - result = 31 * result + (sidebarFillColor != null ? sidebarFillColor.hashCode() : 0); - result = 31 * result + (backgroundColor != null ? backgroundColor.hashCode() : 0); - result = 31 * result + (useBackgroundImage ? 1 : 0); - result = 31 * result + (backgroundImageUrl != null ? backgroundImageUrl.hashCode() : 0); - result = 31 * result + (backgroundImageTiled ? 1 : 0); - result = 31 * result + (textColor != null ? textColor.hashCode() : 0); - result = 31 * result + (linkColor != null ? linkColor.hashCode() : 0); - result = 31 * result + (showAllInlineMedia ? 1 : 0); - return result; - } + public int hashCode() { + int result = (int) (id ^ (id >>> 32)); + result = 31 * result + (screenName != null ? screenName.hashCode() : 0); + result = 31 * result + (name != null ? name.hashCode() : 0); + result = 31 * result + (url != null ? url.hashCode() : 0); + result = 31 * result + (profileImageUrl != null ? profileImageUrl.hashCode() : 0); + result = 31 * result + (description != null ? description.hashCode() : 0); + result = 31 * result + (location != null ? location.hashCode() : 0); + result = 31 * result + (createdDate != null ? createdDate.hashCode() : 0); + result = 31 * result + (language != null ? language.hashCode() : 0); + result = 31 * result + statusesCount; + result = 31 * result + friendsCount; + result = 31 * result + followersCount; + result = 31 * result + favoritesCount; + result = 31 * result + listedCount; + result = 31 * result + (following ? 1 : 0); + result = 31 * result + (followRequestSent ? 1 : 0); + result = 31 * result + (isProtected ? 1 : 0); + result = 31 * result + (notificationsEnabled ? 1 : 0); + result = 31 * result + (verified ? 1 : 0); + result = 31 * result + (geoEnabled ? 1 : 0); + result = 31 * result + (contributorsEnabled ? 1 : 0); + result = 31 * result + (translator ? 1 : 0); + result = 31 * result + (timeZone != null ? timeZone.hashCode() : 0); + result = 31 * result + utcOffset; + result = 31 * result + (sidebarBorderColor != null ? sidebarBorderColor.hashCode() : 0); + result = 31 * result + (sidebarFillColor != null ? sidebarFillColor.hashCode() : 0); + result = 31 * result + (backgroundColor != null ? backgroundColor.hashCode() : 0); + result = 31 * result + (useBackgroundImage ? 1 : 0); + result = 31 * result + (backgroundImageUrl != null ? backgroundImageUrl.hashCode() : 0); + result = 31 * result + (backgroundImageTiled ? 1 : 0); + result = 31 * result + (textColor != null ? textColor.hashCode() : 0); + result = 31 * result + (linkColor != null ? linkColor.hashCode() : 0); + result = 31 * result + (showAllInlineMedia ? 1 : 0); + return result; + } } diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/TwitterQueryForData.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/TwitterQueryForData.java new file mode 100644 index 00000000..f55fde4e --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/TwitterQueryForData.java @@ -0,0 +1,36 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api; + +import org.springframework.util.MultiValueMap; + +/** + * Generic data query builder contract that can be used to build + * request parameters transfering data specially for GET + * operations in Api endpoints. + * + * This helps eliminate dependencies that the "api" package may + * have to the "api.impl" package since contracts by definition + * should not be coupled to implementations. + * + * @author Hudson mendes + */ +public interface TwitterQueryForData> { + + public TBuilderInterface includeDeleted(Boolean include); + + public MultiValueMap toQueryParameters(); +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/TwitterQueryForEntity.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/TwitterQueryForEntity.java new file mode 100644 index 00000000..2c6b8860 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/TwitterQueryForEntity.java @@ -0,0 +1,35 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api; + + +/** + * Generic data query builder contract that can be used to build + * request parameters transfering data specially for GET + * operations in Api endpoints. + * + * This helps eliminate dependencies that the "api" package may + * have to the "api.impl" package since contracts by definition + * should not be coupled to implementations. + * + * @author Hudson mendes + */ +public interface TwitterQueryForEntity> extends + TwitterQueryForData { + + public TBuilderInterface pagedBy(String cursor, Integer pageSize); + public TBuilderInterface withQuery(String query); +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/TwitterQueryForSortableEntity.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/TwitterQueryForSortableEntity.java new file mode 100644 index 00000000..30edb0f5 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/TwitterQueryForSortableEntity.java @@ -0,0 +1,37 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api; + +import org.springframework.social.twitter.api.advertising.SortDirection; + + +/** + * Generic data query builder contract that can be used to build + * request parameters transfering data specially for GET + * operations in Api endpoints. + * + * This helps eliminate dependencies that the "api" package may + * have to the "api.impl" package since contracts by definition + * should not be coupled to implementations. + * + * @author Hudson mendes + */ +public interface TwitterQueryForSortableEntity, TSort> extends + TwitterQueryForEntity { + + public TBuilderInterface sortBy(TSort sort); + public TBuilderInterface sortBy(TSort sort, SortDirection direction); +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/TwitterQueryForStats.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/TwitterQueryForStats.java new file mode 100644 index 00000000..f288f74e --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/TwitterQueryForStats.java @@ -0,0 +1,50 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api; + +import java.time.LocalDateTime; + +import org.springframework.social.twitter.api.advertising.StatisticsGranularity; +import org.springframework.social.twitter.api.advertising.StatisticsMetric; +import org.springframework.social.twitter.api.advertising.StatisticsSegmentationType; +import org.springframework.util.MultiValueMap; + +/** + * Generic data query builder contract that can be used to build + * request parameters transfering data specially for GET + * operations in Api endpoints. + * + * This helps eliminate dependencies that the "api" package may + * have to the "api.impl" package since contracts by definition + * should not be coupled to implementations. + * + * @author Hudson mendes + */ +public interface TwitterQueryForStats> { + public TBuilderInterface activeUntil(LocalDateTime endTime); + + public TBuilderInterface activeFrom(LocalDateTime startTime); + + public TBuilderInterface activeBetween(LocalDateTime startTime, LocalDateTime endTime); + + public TBuilderInterface withGranularity(StatisticsGranularity granularity); + + public TBuilderInterface withStatisticalMetric(StatisticsMetric... metrics); + + public TBuilderInterface withSegmentationType(StatisticsSegmentationType segmentation); + + public MultiValueMap toQueryParameters(); +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/UserList.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/UserList.java index 32c6a298..d1dca4cc 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/UserList.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/UserList.java @@ -15,11 +15,14 @@ */ package org.springframework.social.twitter.api; + + /** * Represents a user-defined list. * @author Craig Walls */ public class UserList extends TwitterObject { + private static final long serialVersionUID = 1L; private final long id; private final String name; private final String fullName; diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/UserOperations.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/UserOperations.java index 3c914b1c..93bf9605 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/UserOperations.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/UserOperations.java @@ -76,6 +76,7 @@ public interface UserOperations { /** * Retrieves a list of Twitter profiles for the given list of user IDs. * Supports either user or application authorization. + * @param userIds identifies the ids of users which will be fetch from the authenticating twitter account. * @return a list of Twitter profiles * @throws ApiException if there is an error while communicating with Twitter. * @throws MissingAuthorizationException if TwitterTemplate was not created with OAuth credentials or an application access token. @@ -85,6 +86,7 @@ public interface UserOperations { /** * Retrieves a list of Twitter profiles for the given list of screen names. * Supports either user or application authorization. + * @param screenNames identifies the screen names of users which will be fetch from the authenticating twitter account. * @return a list of Twitter profiles * @throws ApiException if there is an error while communicating with Twitter. * @throws MissingAuthorizationException if TwitterTemplate was not created with OAuth credentials or an application access token. @@ -93,6 +95,7 @@ public interface UserOperations { /** * Searches for up to 20 users that match a given query. + * @param query defines the query against which users will be retrieved. * @return a list of Twitter profiles * @throws ApiException if there is an error while communicating with Twitter. * @throws MissingAuthorizationException if TwitterTemplate was not created with OAuth credentials. @@ -101,6 +104,7 @@ public interface UserOperations { /** * Searches for users that match a given query. + * @param query defines the query against which users will be retrieved. * @param page the page of search results to return * @param pageSize the number of {@link TwitterProfile}s per page. Maximum of 20 per page. * @return a list of Twitter profiles diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/VideoInfoMediaEntity.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/VideoInfoMediaEntity.java new file mode 100644 index 00000000..0deb03f1 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/VideoInfoMediaEntity.java @@ -0,0 +1,52 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api; + +import java.util.ArrayList; +import java.util.List; + +/** + * Represents the video info of a particular media + * brought back in the entities or extended_entities. + * + * @author Hudson Mendes + * + */ +public class VideoInfoMediaEntity extends TwitterObject { + private static final long serialVersionUID = 1L; + + private final List aspectRatio = new ArrayList<>(); + private final List variants = new ArrayList<>(); + + public VideoInfoMediaEntity( + List aspectRatio, + List variants) { + + if (aspectRatio != null) + this.aspectRatio.addAll(aspectRatio); + + if (variants != null) + this.variants.addAll(variants); + } + + public List getAspectRatio() { + return aspectRatio; + } + + public List getVariants() { + return variants; + } +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/VideoInfoVariantMediaEntity.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/VideoInfoVariantMediaEntity.java new file mode 100644 index 00000000..520a358e --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/VideoInfoVariantMediaEntity.java @@ -0,0 +1,65 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api; + + +/** + * Represents the possible video variants. + * + * @author Hudson Mendes + * + */ +public class VideoInfoVariantMediaEntity extends TwitterObject { + private static final long serialVersionUID = 1L; + + private Long bitrate; + private String contentType; + private String url; + + public VideoInfoVariantMediaEntity( + Long bitrate, + String contentType, + String url) { + + this.bitrate = bitrate; + this.contentType = contentType; + this.url = url; + } + + public Long getBitrate() { + return bitrate; + } + + public void setBitrate(Long bitrate) { + this.bitrate = bitrate; + } + + public String getContentType() { + return contentType; + } + + public void setContentType(String contentType) { + this.contentType = contentType; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/AdvertisingAccount.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/AdvertisingAccount.java new file mode 100644 index 00000000..ea869a2c --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/AdvertisingAccount.java @@ -0,0 +1,106 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import java.time.LocalDateTime; +import java.util.TimeZone; + +import org.springframework.social.twitter.api.TwitterObject; + +/** + * Represents an Advertising Account + * + * Source: https://dev.twitter.com/ads/campaigns/getting-started + * Advertising accounts are registered on ads.twitter.com and + * identified in the API by account_id. Advertising accounts + * link directly to funding sources and leverage content from + * one or more Twitter user accounts as promotable users. + * Each advertising account can grant permission to one or more + * Twitter user accounts. The advertising account, or current account, + * is represented in nearly every URL executed as an in-line:account_id + * parameter. + * + * @author Hudson Mendes + */ +public class AdvertisingAccount extends TwitterObject { + private static final long serialVersionUID = 1L; + private final String id; + private final String name; + private final String salt; + private final TimeZone timeZone; + private final LocalDateTime timeZoneSwitchAt; + private final LocalDateTime createdAt; + private final LocalDateTime updatedAt; + private final ApprovalStatus approvalStatus; + private final Boolean deleted; + + public AdvertisingAccount( + String id, + String name, + String salt, + TimeZone timeZone, + LocalDateTime timeZoneSwitchAt, + LocalDateTime createdAt, + LocalDateTime updatedAt, + ApprovalStatus approvalStatus, + Boolean deleted) { + this.id = id; + this.name = name; + this.salt = salt; + this.timeZone = timeZone; + this.timeZoneSwitchAt = timeZoneSwitchAt; + this.createdAt = createdAt; + this.updatedAt = updatedAt; + this.approvalStatus = approvalStatus; + this.deleted = deleted; + } + + public String getId() { + return id; + } + + public String getName() { + return name; + } + + public String getSalt() { + return salt; + } + + public TimeZone getTimeZone() { + return timeZone; + } + + public LocalDateTime getTimeZoneSwitchAt() { + return timeZoneSwitchAt; + } + + public LocalDateTime getCreatedAt() { + return createdAt; + } + + public LocalDateTime getUpdatedAt() { + return updatedAt; + } + + public ApprovalStatus getApprovalStatus() { + return approvalStatus; + } + + public Boolean isDeleted() { + return deleted; + } +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/AdvertisingAccountFeatureQuery.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/AdvertisingAccountFeatureQuery.java new file mode 100644 index 00000000..c87c8934 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/AdvertisingAccountFeatureQuery.java @@ -0,0 +1,27 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.twitter.api.TwitterQueryForEntity; + +/** + * Defines the contract for any feature query. + * + * @author Hudson Mendes + */ +public interface AdvertisingAccountFeatureQuery extends TwitterQueryForEntity { + public AdvertisingAccountFeatureQuery withFeatureKey(FeatureKey... featureKeys); +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/AdvertisingAccountPermissions.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/AdvertisingAccountPermissions.java new file mode 100644 index 00000000..32fb954b --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/AdvertisingAccountPermissions.java @@ -0,0 +1,48 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import java.util.List; + +import org.springframework.social.twitter.api.TwitterObject; + +/** + * Represents an Advertising Account's Permissions + * + * Source: https://dev.twitter.com/ads/reference/get/accounts/%3Aaccount_id/authenticated_user_access + * Retrieve the permissions of the currently authenticated user (access_token) as they relate to this ads account. + * + * @author Chris Latko + */ +public class AdvertisingAccountPermissions extends TwitterObject { + private static final long serialVersionUID = 1L; + private final Long userId; + private final List permissions; + + public AdvertisingAccountPermissions(Long userId, List permissions) { + this.userId = userId; + this.permissions = permissions; + } + + public Long getUserId() { + return userId; + } + + public List getPermissions() { + return permissions; + } + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/AdvertisingAccountQuery.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/AdvertisingAccountQuery.java new file mode 100644 index 00000000..81cb9214 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/AdvertisingAccountQuery.java @@ -0,0 +1,25 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.twitter.api.TwitterQueryForSortableEntity; + +/** + * Defines the contract for any {@link AdvertisingAccount} query. + * @author Hudson Mendes + */ +public interface AdvertisingAccountQuery extends TwitterQueryForSortableEntity { +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/AdvertisingAccountSorting.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/AdvertisingAccountSorting.java new file mode 100644 index 00000000..b9410d24 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/AdvertisingAccountSorting.java @@ -0,0 +1,27 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +/** + * All sorting options for {@link AdvertisingAccountQuery}. + * @author Hudson Mendes + */ +public enum AdvertisingAccountSorting { + created_at, + updated_at, + deleted, + name +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/AdvertisingObjective.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/AdvertisingObjective.java new file mode 100644 index 00000000..b045aae5 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/AdvertisingObjective.java @@ -0,0 +1,30 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +/** + * @author Hudson Mendes + */ +public enum AdvertisingObjective { + APP_ENGAGEMENTS, + APP_INSTALLS, + FOLLOWERS, + LEAD_GENERATION, + TWEET_ENGAGEMENTS, + VIDEO_VIEWS, + WEBSITE_CLICKS, + CUSTOM +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/AdvertisingOperations.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/AdvertisingOperations.java new file mode 100644 index 00000000..781ad835 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/AdvertisingOperations.java @@ -0,0 +1,92 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.ApiException; +import org.springframework.social.MissingAuthorizationException; +import org.springframework.social.twitter.api.impl.DataListHolder; + +/** + * Interface defining the operations for advertising operations. + * + * @author Hudson Mendes + */ +public interface AdvertisingOperations { + + /** + * Retrieves a list of all {@link AdvertisingAccount} to which the authenticating user has access. + * + * @param query The query parameters that will filter the request + * @return a list of {@link AdvertisingAccount} + * @throws ApiException if there is an error while communicating with Twitter. + * @throws MissingAuthorizationException if TwitterTemplate was not created with OAuth credentials. + */ + DataListHolder getAccounts(AdvertisingAccountQuery query); + + /** + * Retrieves a single {@link AdvertisingAccount} to which the authenticating user has access. + * + * @param id identifies the {@link AdvertisingAccount} that will be returned + * @return the {@link AdvertisingAccount} + * @throws ApiException if there is an error while communicating with Twitter. + * @throws MissingAuthorizationException if TwitterTemplate was not created with OAuth credentials. + */ + AdvertisingAccount getAccount(String id); + + /** + * Retrieves a list of all {@link FundingInstrument} linked to a particular {@link AdvertisingAccount}. + * + * @param accountId identifies the account for which we want to get the funding instruments. + * @param query The query parameters that will filter the request + * @return a list of {@link FundingInstrument} + * @throws ApiException if there is an error while communicating with Twitter. + * @throws MissingAuthorizationException if TwitterTemplate was not created with OAuth credentials. + */ + DataListHolder getFundingInstruments(String accountId, FundingInstrumentQuery query); + + /** + * Retrieves a single {@link FundingInstrument} from its identifier. + * + * @param accountId identifies the account for which we want to get the funding instruments. + * @param fundingInstrumentId identifies the funding source. + * @return an instance of {@link FundingInstrument} + * @throws ApiException if there is an error while communicating with Twitter. + * @throws MissingAuthorizationException if TwitterTemplate was not created with OAuth credentials. + */ + FundingInstrument getFundingInstrument(String accountId, String fundingInstrumentId); + + /** + * Retrieves a list of all {@link FeatureKey} linked to a particular {@link AdvertisingAccount}. + * + * @param accountId identifies the account for which we want to get the feature keys. + * @param query The query parameters that will filter the request + * @return a list of {@link FeatureKey} + * @throws ApiException if there is an error while communicating with Twitter. + * @throws MissingAuthorizationException if TwitterTemplate was not created with OAuth credentials. + */ + DataListHolder getAccountFeatures(String accountId, AdvertisingAccountFeatureQuery query); + + /** + * Retrieves a list of all {@link AdvertisingPermission} linked to a particular {@link AdvertisingAccount}. + * + * @param accountId identifies the account for which we want to get the permissions. + * @return a single {@link AdvertisingPermission} + * @throws ApiException if there is an error while communicating with Twitter. + * @throws MissingAuthorizationException if TwitterTemplate was not created with OAuth credentials. + */ + AdvertisingAccountPermissions getAccountPermissions(String accountId); + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/AdvertisingPermission.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/AdvertisingPermission.java new file mode 100644 index 00000000..0ebcfaaa --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/AdvertisingPermission.java @@ -0,0 +1,15 @@ +package org.springframework.social.twitter.api.advertising; + +/** + * More information at: https://dev.twitter.com/ads/overview/enums + * Enumeration: product_type + * + * @author Hudson Mendes + * + */ +public enum AdvertisingPermission { + ACCOUNT_ADMIN, + AD_MANAGER, + TWEET_COMPOSER, + ANALYST; +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/AdvertisingPlacement.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/AdvertisingPlacement.java new file mode 100644 index 00000000..ba4def38 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/AdvertisingPlacement.java @@ -0,0 +1,27 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +/** + * @author Hudson Mendes + */ +public enum AdvertisingPlacement { + ALL_ON_TWITTER, + TWITTER_SEARCH, + TWITTER_TIMELINE, + TWITTER_PROFILE, + PUBLISHER_NETWORK +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/AdvertisingProductType.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/AdvertisingProductType.java new file mode 100644 index 00000000..3d255e60 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/AdvertisingProductType.java @@ -0,0 +1,13 @@ +package org.springframework.social.twitter.api.advertising; + +/** + * More information at: https://dev.twitter.com/ads/overview/enums + * Enumeration: product_type + * + * @author Hudson Mendes + * + */ +public enum AdvertisingProductType { + PROMOTED_ACCOUNT, + PROMOTED_TWEETS +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/AdvertisingSentiment.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/AdvertisingSentiment.java new file mode 100644 index 00000000..81e50ef7 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/AdvertisingSentiment.java @@ -0,0 +1,24 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +/** + * @author Hudson Mendes + */ +public enum AdvertisingSentiment { + POSITIVE_ONLY, + ALL +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/AppStore.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/AppStore.java new file mode 100644 index 00000000..4234fa60 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/AppStore.java @@ -0,0 +1,24 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +/** + * @author Hudson Mendes + */ +public enum AppStore { + IOS_APP_STORE, + GOOGLE_PLAY; +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/ApprovalStatus.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/ApprovalStatus.java new file mode 100644 index 00000000..75b2801b --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/ApprovalStatus.java @@ -0,0 +1,26 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +/** + * Enumeration of stats that an Advertising account may be in. + * @author Hudson Mendes + */ +public enum ApprovalStatus { + ACCEPTED, + UNDER_REVIEW, + REJECTED +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/BidUnit.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/BidUnit.java new file mode 100644 index 00000000..dde869c6 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/BidUnit.java @@ -0,0 +1,11 @@ +package org.springframework.social.twitter.api.advertising; + +public enum BidUnit { + APP_CLICK, + APP_INSTALL, + ENGAGEMENT, + FOLLOW, + LEAD, + LINK_CLICK, + VIEW +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/Campaign.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/Campaign.java new file mode 100644 index 00000000..36f68c71 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/Campaign.java @@ -0,0 +1,155 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.ArrayList; +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import java.util.List; + +import org.springframework.social.twitter.api.TwitterObject; + +/** + * Represents an Advertising Campaign run for a particular {@link AdvertisingAccount}. + * @author Hudson Mendes + */ +public class Campaign extends TwitterObject { + private static final long serialVersionUID = 1L; + private final String id; + private final String accountId; + private final String name; + private final String currency; + private final String fundingInstrumentId; + private final BigDecimal totalBudget; + private final BigDecimal dailyBudget; + private final LocalDateTime startTime; + private final LocalDateTime endTime; + private final List reasonsNotServable; + private final Boolean standardDelivery; + private final Boolean paused; + private final Boolean deleted; + private final LocalDateTime createdAt; + private final LocalDateTime updatedAt; + + public Campaign( + String id, String name, String accountId, String currency, + String fundingInstrumentId, BigDecimal totalBudget, BigDecimal dailyBudget, + LocalDateTime startTime, LocalDateTime endTime, + LocalDateTime createdAt, LocalDateTime updatedAt, + List reasonsNotServable, + Boolean standardDelivery, Boolean paused, Boolean deleted) { + + this.id = id; + this.name = name; + this.accountId = accountId; + this.currency = currency; + this.fundingInstrumentId = fundingInstrumentId; + + this.totalBudget = totalBudget; + this.dailyBudget = dailyBudget; + + this.startTime = startTime; + this.endTime = endTime; + this.createdAt = createdAt; + this.updatedAt = updatedAt; + + this.reasonsNotServable = reasonsNotServable != null ? reasonsNotServable : new ArrayList(); + + this.standardDelivery = standardDelivery; + this.paused = paused; + this.deleted = deleted; + } + + public String getId() { + return id; + } + + public String getName() { + return name; + } + + public String getAccountId() { + return accountId; + } + + public String getCurrency() { + return currency; + } + + public String getFundingInstrumentId() { + return fundingInstrumentId; + } + + public BigDecimal getTotalBudget() { + return totalBudget; + } + + public BigDecimal getDailyBudget() { + return dailyBudget; + } + + public LocalDateTime getStartTime() { + return startTime; + } + + public LocalDateTime getEndTime() { + return endTime; + } + + public LocalDateTime getCreatedAt() { + return createdAt; + } + + public LocalDateTime getUpdatedAt() { + return updatedAt; + } + + public List getReasonsNotServable() { + return reasonsNotServable; + } + + public Boolean isStandardDelivery() { + return standardDelivery; + } + + public Boolean isPaused() { + return paused; + } + + public Boolean isServable() { + Boolean servable = reasonsNotServable.isEmpty(); + return servable; + } + + public Boolean isDeleted() { + return deleted; + } +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/CampaignForm.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/CampaignForm.java new file mode 100644 index 00000000..3ef0c7d0 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/CampaignForm.java @@ -0,0 +1,131 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import java.time.LocalDateTime; + +import org.springframework.social.twitter.api.TwitterForm; + +/** + * Describes the contract for the builder of {@link Campaign}'s + * data that will be posted / patched to the endpoint. + * + * @author Hudson Mendes + */ +public interface CampaignForm extends TwitterForm { + + /** + * The name of the {@link Campaign}. + * + * @param name is the name of the {@link Campaign}. + * @return the fluent builder + */ + public CampaignForm withName(String name); + + /** + * The default currency in which linked {@link LineItem} will consume the budget. + * + * @param currency of the {@link Campaign}. + * @return the fluent loader. + */ + public CampaignForm withCurrency(String currency); + + /** + * The {@link FundingInstrument} of the {@link Campaign} + * + * @param fundingInstrumentId defines which {@link FundingInstrument} will fund the {@link Campaign}. + * @return the fluent builder + */ + public CampaignForm withFundingInstrument(String fundingInstrumentId); + + /** + * The budget (total and daily) that the {@link Campaign} is allowed to spend. + * + * @param totalBudget describes the total budget. + * @param dailyBudget describes the daily budget. + * @return the fluent builder + */ + public CampaignForm withBudget(String totalBudget, String dailyBudget); + + /** + * Defines the activity period of the {@link Campaign}. + * + * @param endTime is when the campaign will be stoped. + * @return the fluent builder + */ + public CampaignForm activeUntil(LocalDateTime endTime); + + /** + * Defines the activity period of the {@link Campaign} + * + * @param startTime is when the campaign will start + * @return the fluent builder + */ + public CampaignForm activeFrom(LocalDateTime startTime); + + /** + * Defines the activity period of the {@link Campaign} + * + * @param startTime is when the campaign will start + * @param endTime is when the campaign will be stoped. + * @return the fluent builder + */ + public CampaignForm activeBetween(LocalDateTime startTime, LocalDateTime endTime); + + /** + * Defines the reasons for which the {@link Campaign} cannot be served. + * + * @param reasons for which the campaigns cannot be served. + * @return the fluent loader + */ + public CampaignForm thatCantBeServedDueTo(ReasonNotServable... reasons); + + /** + * Defines if the {@link Campaign} uses the standard delivery mechanism or not. + * + * @param standardDelivery is true if the campaign should use the standard mechanism; otherwise, it's false. + * @return the fluent loader + */ + public CampaignForm withStandardDelivery(Boolean standardDelivery); + + /** + * Set the {@link Campaign} to paused. + * + * @return the fluent loader + */ + public CampaignForm paused(); + + /** + * Unpause the {@link Campaign}. + * + * @return the fluent loader + */ + public CampaignForm unpaused(); + + /** + * Set the {@link Campaign} to deleted. + * + * @return the fluent loader + */ + public CampaignForm deleted(); + + /** + * Make a {@link Campaign} active again. + * + * @return the fluent loader + */ + public CampaignForm active(); +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/CampaignOperations.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/CampaignOperations.java new file mode 100644 index 00000000..eaf143d7 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/CampaignOperations.java @@ -0,0 +1,81 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.ApiException; +import org.springframework.social.MissingAuthorizationException; +import org.springframework.social.twitter.api.impl.DataListHolder; + +/** + * Interface defining the operations for campaign operations. + * + * @author Hudson Mendes + */ +public interface CampaignOperations { + /** + * Retrieves a {@link Campaign} linked to a particular {@link AdvertisingAccount}. + * + * @param accountId identifies the account for which we are attempting to get the campaign + * @param id identifies the campaign + * @return an instance of {@link Campaign} + * @throws ApiException if there is an error while communicating with Twitter. + * @throws MissingAuthorizationException if TwitterTemplate was not created with OAuth credentials. + */ + Campaign getCampaign(String accountId, String id); + + /** + * Retrieves a list of all {@link Campaign} linked to a particular {@link AdvertisingAccount}. + * + * @param accountId identifies the account for which we are attempting to get the campaigns + * @param query The query parameters that will filter the request + * @return a list of {@link Campaign} + * @throws ApiException if there is an error while communicating with Twitter. + * @throws MissingAuthorizationException if TwitterTemplate was not created with OAuth credentials. + */ + DataListHolder getCampaigns(String accountId, CampaignQuery query); + + /** + * Creates a {@link Campaign} for a {@link AdvertisingAccount} referenced by its 'accountId'. + * + * @param accountId identifies the account for which we are attempting to create the campaign. + * @param data is the request data builder that will generate the request body for the operation. + * @return an instance of {@link Campaign} which refers to the campaign created in the procedure. + * @throws ApiException if there is an error while communicating with Twitter. + * @throws MissingAuthorizationException if TwitterTemplate was not created with OAuth credentials. + */ + Campaign createCampaign(String accountId, CampaignForm data); + + /** + * Updates a {@link Campaign} for a {@link AdvertisingAccount} found by its campaignId. + * + * @param accountId identifies the account for which we are attempting to update the campaign. + * @param id identifies the campaign that we wish to update. + * @param data is the request data builder that will generate the request body for the operation. + * @throws ApiException if there is an error while communicating with Twitter. + * @throws MissingAuthorizationException if TwitterTemplate was not created with OAuth credentials. + */ + void updateCampaign(String accountId, String id, CampaignForm data); + + /** + * Deletes a {@link Campaign} related to an {@link AdvertisingAccount} found by its campaignId. + * + * @param accountId identifies the account of which campaign we wish to delete. + * @param id identifies the campaign that we desire to delete. + * @throws ApiException if there is an error while communicating with Twitter. + * @throws MissingAuthorizationException if TwitterTemplate was not created with OAuth credentials. + */ + void deleteCampaign(String accountId, String id); +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/CampaignQuery.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/CampaignQuery.java new file mode 100644 index 00000000..9e053fe9 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/CampaignQuery.java @@ -0,0 +1,29 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.twitter.api.TwitterQueryForSortableEntity; + +/** + * Defines the contract for any {@link Campaign} query. + * @author Hudson Mendes + */ +public interface CampaignQuery extends TwitterQueryForSortableEntity { + public CampaignQuery withCampaigns(String... campaignIds); + public CampaignQuery withFundingInstruments(String... fundingInstrumentIds); + public CampaignQuery withCount(Integer count); + public CampaignQuery withCursor(Integer cursor); +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/CampaignSorting.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/CampaignSorting.java new file mode 100644 index 00000000..baba729d --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/CampaignSorting.java @@ -0,0 +1,31 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +/** + * All sorting options for querying {@link CampaignQuery}. + * @author Hudson Mendes + */ +public enum CampaignSorting { + created_at, + updated_at, + deleted, name, + start_time, + end_time, + daily_budget_amount_local_micro, + total_budget_amount_local_micro, + standard_delivery +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/EventType.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/EventType.java new file mode 100644 index 00000000..a17df14c --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/EventType.java @@ -0,0 +1,27 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +/** + * @author Hudson Mendes + */ +public enum EventType { + SPORTS, + MUSIC_AND_ENTERTAINMENT, + HOLIDAY, + CONFERENCE, + OTHER; +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/FeatureKey.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/FeatureKey.java new file mode 100644 index 00000000..0fbfbe6e --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/FeatureKey.java @@ -0,0 +1,30 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +/** + * @author Hudson Mendes + */ +public enum FeatureKey { + AGE_TARGETING, + BRAND_TPN, + CPI_CHARGING, + INSTALLED_APP_CATEGORY_TARGETING, + MOBILE_CONVERSION_TRANSACTION_VALUE, + OPTIMIZED_ACTION_BIDDING, + OPTIMIZED_WEBSITE_CONVERSION, + VIDEO_VIEWS_OBJECTIVE; +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/FundingInstrument.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/FundingInstrument.java new file mode 100644 index 00000000..8993d699 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/FundingInstrument.java @@ -0,0 +1,135 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +import org.springframework.social.twitter.api.TwitterObject; + +/** + * Represents a Funding instrument related to an {@link AdvertisingAccount}. + * + * Source: https://dev.twitter.com/ads/campaigns/funding-instruments + * Funding Instruments are the source of campaign budget. + * Funding Instruments can not be created via the Ads API, + * they have to be already established by the advertiser’s + * account manager at Twitter (for credit lines) or via + * ads.twitter.com (for credit cards) to be available. + * + * @author Hudson Mendes + */ +public class FundingInstrument extends TwitterObject { + private static final long serialVersionUID = 1L; + private final String id; + private final FundingInstrumentType type; + private final String accountId; + private final String currency; + private final String description; + private final Boolean cancelled; + private final Boolean deleted; + private final BigDecimal creditLimit; + private final BigDecimal creditRemaining; + private final BigDecimal fundedAmount; + private final LocalDateTime startTime; + private final LocalDateTime endTime; + private final LocalDateTime createdAt; + private final LocalDateTime updatedAt; + + public FundingInstrument( + String id, FundingInstrumentType type, + String accountId, String currency, String description, + Boolean cancelled, Boolean deleted, + BigDecimal creditLimit, BigDecimal creditRemaining, BigDecimal fundedAmount, + LocalDateTime startTime, LocalDateTime endTime, + LocalDateTime createdAt, LocalDateTime updatedAt) { + + this.id = id; + this.type = type; + + this.accountId = accountId; + this.currency = currency; + this.description = description; + + this.cancelled = cancelled; + this.deleted = deleted; + + this.creditLimit = creditLimit; + this.creditRemaining = creditRemaining; + this.fundedAmount = fundedAmount; + + this.startTime = startTime; + this.endTime = endTime; + this.createdAt = createdAt; + this.updatedAt = updatedAt; + } + + public String getId() { + return id; + } + + public FundingInstrumentType getType() { + return type; + } + + public String getAccountId() { + return accountId; + } + + public String getCurrency() { + return currency; + } + + public String getDescription() { + return description; + } + + public Boolean isCancelled() { + return cancelled; + } + + public Boolean isDeleted() { + return deleted; + } + + public BigDecimal getCreditLimit() { + return creditLimit; + } + + public BigDecimal getCreditRemaining() { + return creditRemaining; + } + + public BigDecimal getFundedAmount() { + return fundedAmount; + } + + public LocalDateTime getStartTime() { + return startTime; + } + + public LocalDateTime getEndTime() { + return endTime; + } + + public LocalDateTime getCreatedAt() { + return createdAt; + } + + public LocalDateTime getUpdatedAt() { + return updatedAt; + } +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/FundingInstrumentQuery.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/FundingInstrumentQuery.java new file mode 100644 index 00000000..b2819696 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/FundingInstrumentQuery.java @@ -0,0 +1,26 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.twitter.api.TwitterQueryForSortableEntity; + +/** + * Defines the contract for any {@link FundingInstrumentQuery}. + * @author Hudson Mendes + */ +public interface FundingInstrumentQuery extends TwitterQueryForSortableEntity { + public FundingInstrumentQuery withFundingInstruments(String... fundingInstrumentIds); +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/FundingInstrumentSorting.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/FundingInstrumentSorting.java new file mode 100644 index 00000000..7c3530c1 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/FundingInstrumentSorting.java @@ -0,0 +1,29 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +/** + * All sorting options for {@link FundingInstrumentQuery}. + * @author Hudson Mendes + */ +public enum FundingInstrumentSorting { + created_at, + updated_at, + deleted, + funded_amount_local_micro, + start_time, + end_time +} \ No newline at end of file diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/FundingInstrumentType.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/FundingInstrumentType.java new file mode 100644 index 00000000..95616393 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/FundingInstrumentType.java @@ -0,0 +1,28 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +/** + * Types of {@link FundingInstrument} + * @author Hudson Mendes + */ +public enum FundingInstrumentType { + INSERTION_ORDER, + CREDIT_LINE, + AGENCY_CREDIT_LINE, + CREDIT_CARD, + PARTNER_MANAGED +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/GlobalOptOut.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/GlobalOptOut.java new file mode 100644 index 00000000..588c32c1 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/GlobalOptOut.java @@ -0,0 +1,45 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +/** + * Represents the resulting entity of an attempt to mark + * customers to be excluded from tailored audiences do + * to their opt-out. + * + * @author Hudson Mendes + * + */ +public class GlobalOptOut { + private final String inputFilePath; + private final TailoredAudienceListType listType; + + public GlobalOptOut( + String inputFilePath, + TailoredAudienceListType listType) { + + this.inputFilePath = inputFilePath; + this.listType = listType; + } + + public String getInputFilePath() { + return inputFilePath; + } + + public TailoredAudienceListType getListType() { + return listType; + } +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/GlobalOptOutForm.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/GlobalOptOutForm.java new file mode 100644 index 00000000..9ab031f1 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/GlobalOptOutForm.java @@ -0,0 +1,44 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.twitter.api.TwitterForm; + +/** + * Describes the contract for the builder of {@link GlobalOptOut}'s + * data that will be posted / patched to the endpoint. + * + * @author Hudson Mendes + */ +public interface GlobalOptOutForm extends TwitterForm { + + /** + * The TON file path that will be linked with the opt-out operation. + * + * @param tonFilePath in TON. + * @return the fluent builder. + */ + public abstract GlobalOptOutForm withInputFilePath(String tonFilePath); + + /** + * The list type of the data in the TON file. + * + * @param listType of the data in the TON file. + * @return the fluent builder. + */ + public abstract GlobalOptOutForm withListType(TailoredAudienceListType listType); + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/LineItem.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/LineItem.java new file mode 100644 index 00000000..807d7032 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/LineItem.java @@ -0,0 +1,183 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +import org.springframework.social.twitter.api.TwitterObject; + +/** + * Represents an Advertising Group (also known as Line Item). + * + * Source: https://dev.twitter.com/ads/campaigns + * Line items spend the budget defined by a campaign. + * Line items pull together the per-engagement bid, + * the Tweet or account to promote, and the targeting rules. + * + * Source: https://dev.twitter.com/ads/reference/post/accounts/:account_id/line_items + * Create a line item associated with the specified campaign belonging to the current account. + * Note that for PROMOTED_ACCOUNT campaigns, associating a Promoted Tweet to the line_item will + * add timeline placements on mobile in addition to the standard PROMOTED_ACCOUNT placement. + * + * @author Hudson Mendes + */ +public class LineItem extends TwitterObject { + private static final long serialVersionUID = 1L; + private final String id; + private final String accountId; + private final String campaignId; + private final String name; + + private final BidUnit bidUnit; + private final LineItemOptimization optimization; + private final AdvertisingObjective objective; + private final AdvertisingSentiment includeSentiment; + + private final AdvertisingProductType productType; + private final List placements = new ArrayList<>(); + + private final String currency; + private final BigDecimal totalBudgetAmount; + private final BigDecimal bidAmount; + + private final Boolean paused; + private final Boolean deleted; + private final Boolean automaticallySelectBid; + private final LocalDateTime createdAt; + private final LocalDateTime updatedAt; + + public LineItem( + String id, + String accountId, + String campaignId, + String name, + BidUnit bidUnit, + LineItemOptimization optimization, + AdvertisingObjective objective, + AdvertisingSentiment includeSentiment, + AdvertisingProductType productType, + AdvertisingPlacement[] placements, + String currency, + BigDecimal totalBudgetAmount, + BigDecimal bidAmount, + Boolean automaticallySelectBid, + Boolean paused, + Boolean deleted, + LocalDateTime createdAt, + LocalDateTime updatedAt) { + + this.id = id; + this.accountId = accountId; + this.campaignId = campaignId; + this.name = name; + + this.productType = productType; + if (placements != null) + for (AdvertisingPlacement placement : placements) + this.placements.add(placement); + + this.bidUnit = bidUnit; + this.objective = objective; + this.includeSentiment = includeSentiment; + this.optimization = optimization; + + this.currency = currency; + this.totalBudgetAmount = totalBudgetAmount; + this.bidAmount = bidAmount; + + this.paused = paused; + this.deleted = deleted; + this.automaticallySelectBid = automaticallySelectBid; + + this.createdAt = createdAt; + this.updatedAt = updatedAt; + } + + public String getId() { + return id; + } + + public String getAccountId() { + return accountId; + } + + public String getCampaignId() { + return campaignId; + } + + public String getName() { + return name; + } + + public AdvertisingProductType getProductType() { + return productType; + } + + public BidUnit getBidUnit() { + return bidUnit; + } + + public LineItemOptimization getOptimization() { + return optimization; + } + + public AdvertisingObjective getObjective() { + return objective; + } + + public AdvertisingSentiment getIncludeSentiment() { + return includeSentiment; + } + + public List getPlacements() { + return placements; + } + + public String getCurrency() { + return currency; + } + + public BigDecimal getTotalBudgetAmount() { + return totalBudgetAmount; + } + + public BigDecimal getBidAmount() { + return bidAmount; + } + + public Boolean isPaused() { + return paused; + } + + public Boolean isDeleted() { + return deleted; + } + + public Boolean isAutomaticallySetBid() { + return automaticallySelectBid; + } + + public LocalDateTime getCreatedAt() { + return createdAt; + } + + public LocalDateTime getUpdatedAt() { + return updatedAt; + } +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/LineItemForm.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/LineItemForm.java new file mode 100644 index 00000000..8d435161 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/LineItemForm.java @@ -0,0 +1,147 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.twitter.api.TwitterForm; + + +/** + * Describes the contract for the builder of {@link LineItem}'s + * data that will be posted / patched to the endpoint. + * + * @author Hudson Mendes + */ +public interface LineItemForm extends TwitterForm { + + /** + * The {@link Campaign} that the {@link LineItem} is related to. + * + * @param campaignId is the id of the {@link Campaign} related to the {@link LineItem}. + * @return the fluent builder + */ + public abstract LineItemForm forCampaign(String campaignId); + + /** + * Name of the {@link LineItem} + * + * @param name is the name of the {@link LineItem}. + * @return the fluent builder + */ + public abstract LineItemForm named(String name); + + /** + * The type of product that will be advertised {@link AdvertisingProductType} + * + * @param productType is the type of advertising product that we are using for the {@link LineItem}. + * @return the fluent builder + */ + public abstract LineItemForm productType(AdvertisingProductType productType); + + /** + * The type of placement for ads of a {@link LineItem} + * + * @param placements is where the items will be advertised. + * @return the fluent builder + */ + public abstract LineItemForm placedOn(AdvertisingPlacement... placements); + + /** + * The objective of this {@link LineItem} + * + * @param objective is the objective set for this particular {@link LineItem}. + * @return the fluent builder + */ + public abstract LineItemForm objective(AdvertisingObjective objective); + + /** + * The sentiment of the {@link LineItem} amongst the ones + * set out in {@link AdvertisingSentiment}. + * + * @param sentiment can be either POSITIVE_ONLY, ALL (check {@link AdvertisingSentiment}) + * @return the fluent builder + */ + public abstract LineItemForm includingSentiment(AdvertisingSentiment sentiment); + + /** + * The sentiment of the {@link LineItem} amongst the ones + * set out in {@link LineItemOptimization} + * + * @param optimization can be either DEFAULT, WEBSITE_CONVERSIONS (check {@link LineItemOptimization}) + * @return the fluent builder + */ + public abstract LineItemForm optimizedFor(LineItemOptimization optimization); + + /** + * The total budget for the {@link LineItem}. + * + * @param totalBudgetAmount of the {@link LineItem} + * @return the fluent builder + */ + public abstract LineItemForm totalBudget(String totalBudgetAmount); + + /** + * The bid amount for the {@link LineItem}. + * + * @param bidAmount of the {@link LineItem} + * @return the fluent builder + */ + public abstract LineItemForm bidAmount(String bidAmount); + + /** + * The {@link BidUnit} for the {@link LineItem}. + * + * @param bidUnit is the unit that will be used for the {@link LineItem}. + * @return the fluent builder + */ + public abstract LineItemForm bidUnit(BidUnit bidUnit); + + /** + * Defines wether the bid should be automatically selected or not + * + * @param auto true means yes, it should be automatic; false says otherwise. + * @return the fluent builder + */ + public abstract LineItemForm automaticallySelectBid(Boolean auto); + + /** + * Set the {@link LineItem} to paused. + * + * @return the fluent builder + */ + public abstract LineItemForm paused(); + + /** + * Unpause the {@link LineItem}. + * + * @return the fluent builder + */ + public abstract LineItemForm unpaused(); + + /** + * Set the {@link LineItem} to deleted. + * + * @return the fluent builder + */ + public abstract LineItemForm deleted(); + + /** + * Undelete the {@link LineItem}. + * + * @return the fluent builder + */ + public abstract LineItemForm active(); + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/LineItemOperations.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/LineItemOperations.java new file mode 100644 index 00000000..7c6b266a --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/LineItemOperations.java @@ -0,0 +1,93 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.ApiException; +import org.springframework.social.MissingAuthorizationException; +import org.springframework.social.twitter.api.impl.DataListHolder; + +/** + * Interface defining the operations for line item (Ads API). + * + * @author Hudson Mendes + */ +public interface LineItemOperations { + + /** + * Retrieves a {@link LineItem} linked to a particular {@link AdvertisingAccount} referred to by its id. + * + * @param query Scope the results by a specific product type. + * @return a list of {@link LineItemPlacements} + * @throws ApiException if there is an error while communicating with Twitter. + * @throws MissingAuthorizationException if TwitterTemplate was not created with OAuth credentials. + */ + DataListHolder getLineItemPlacements(LineItemPlacementsQuery query); + + /** + * Retrieves a {@link LineItem} linked to a particular {@link AdvertisingAccount} referred to by its id. + * + * @param accountId identifies the account for which we wish to get the particular line item. + * @param id identifies which line id we wish to retrieve. + * @return an instance of {@link LineItem} + * @throws ApiException if there is an error while communicating with Twitter. + * @throws MissingAuthorizationException if TwitterTemplate was not created with OAuth credentials. + */ + LineItem getLineItem(String accountId, String id); + + /** + * Retrieves a list of all {@link LineItem} linked to a particular {@link AdvertisingAccount}. + * + * @param accountId identifies the account for which we want to get the line items. + * @param query The query parameters that will filter the request + * @return a list of {@link LineItem} + * @throws ApiException if there is an error while communicating with Twitter. + * @throws MissingAuthorizationException if TwitterTemplate was not created with OAuth credentials. + */ + DataListHolder getLineItems(String accountId, LineItemQuery query); + + /** + * Creates {@link LineItem} linked to a particular {@link AdvertisingAccount}. + * + * @param accountId identifies the account for which we want to create a line item. + * @param data is the request data builder that will generate the request body for the operation. + * @return an instance of {@link LineItem} + * @throws ApiException if there is an error while communicating with Twitter. + * @throws MissingAuthorizationException if TwitterTemplate was not created with OAuth credentials. + */ + LineItem createLineItem(String accountId, LineItemForm data); + + /** + * Updates {@link LineItem} linked to a particular {@link AdvertisingAccount} referred to by its id. + * + * @param accountId identifies the account for which we want to update a line item. + * @param id identifies which line id we wish to update. + * @param data is the request data builder that will generate the request body for the operation. + * @throws ApiException if there is an error while communicating with Twitter. + * @throws MissingAuthorizationException if TwitterTemplate was not created with OAuth credentials. + */ + void updateLineItem(String accountId, String id, LineItemForm data); + + /** + * Deletes a {@link LineItem} related to an {@link AdvertisingAccount} found by its campaignId. + * + * @param accountId identifies the account of which line item we wish to delete. + * @param id identifies the line item that we desire to delete. + * @throws ApiException if there is an error while communicating with Twitter. + * @throws MissingAuthorizationException if TwitterTemplate was not created with OAuth credentials. + */ + void deleteLineItem(String accountId, String id); + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/LineItemOptimization.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/LineItemOptimization.java new file mode 100644 index 00000000..cd1173c6 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/LineItemOptimization.java @@ -0,0 +1,25 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +/** + * All {@link LineItem} optimization options. + * @author Hudson Mendes + */ +public enum LineItemOptimization { + DEFAULT, + WEBSITE_CONVERSIONS +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/LineItemPlacements.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/LineItemPlacements.java new file mode 100644 index 00000000..5d895f64 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/LineItemPlacements.java @@ -0,0 +1,47 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import java.util.List; + +import org.springframework.social.twitter.api.TwitterObject; + +/** + * Represents valid Line Item Placements + * + * Source: https://dev.twitter.com/ads/reference/get/line_items/placements + * + * @author Chris Latko + */ +public class LineItemPlacements extends TwitterObject { + private static final long serialVersionUID = 1L; + private final List> placements; + private final AdvertisingProductType productType; + + public LineItemPlacements(List> placements, AdvertisingProductType productType) { + this.placements = placements; + this.productType = productType; + } + + public List> getPlacements() { + return placements; + } + + public AdvertisingProductType getProductType() { + return productType; + } + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/LineItemPlacementsQuery.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/LineItemPlacementsQuery.java new file mode 100644 index 00000000..8cd00c10 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/LineItemPlacementsQuery.java @@ -0,0 +1,29 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import java.util.List; + +import org.springframework.social.twitter.api.TwitterQueryForEntity; + +/** + * Defines the contract for any feature query. + * + * @author Hudson Mendes + */ +public interface LineItemPlacementsQuery extends TwitterQueryForEntity { + public LineItemPlacementsQuery withProductTypes(List productTypes); +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/LineItemQuery.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/LineItemQuery.java new file mode 100644 index 00000000..60a97099 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/LineItemQuery.java @@ -0,0 +1,41 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import java.time.LocalDateTime; + +import org.springframework.social.twitter.api.TwitterQueryForSortableEntity; + +/** + * Defines the contract for any {@link LineItemQuery}. + * + * @author Hudson Mendes + */ +public interface LineItemQuery extends TwitterQueryForSortableEntity { + public LineItemQuery withCampaigns(String... campaignIds); + + public LineItemQuery withFundingInstruments(String... fundingInstrumentIds); + + public LineItemQuery withLineItems(String... lineItemIds); + + public LineItemQuery withCount(Integer count); + + public LineItemQuery withCursor(Integer cursor); + + public LineItemQuery activeFrom(LocalDateTime time); + + public LineItemQuery activeBeetween(LocalDateTime from, LocalDateTime until); +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/LineItemSorting.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/LineItemSorting.java new file mode 100644 index 00000000..ab59443a --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/LineItemSorting.java @@ -0,0 +1,27 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +/** + * All sorting options for {@link LineItemQuery}. + * @author Hudson Mendes + */ +public enum LineItemSorting { + created_at, + updated_at, + deleted, + bid_amount_local_micro +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/LocationType.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/LocationType.java new file mode 100644 index 00000000..1b9fc999 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/LocationType.java @@ -0,0 +1,26 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +/** + * @author Hudson Mendes + */ +public enum LocationType { + COUNTRY, + REGION, + CITY, + POSTAL_CODE; +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/PromotableUser.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/PromotableUser.java new file mode 100644 index 00000000..36c49b96 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/PromotableUser.java @@ -0,0 +1,62 @@ +package org.springframework.social.twitter.api.advertising; + +import java.time.LocalDateTime; + +import org.springframework.social.twitter.api.TwitterObject; + +public class PromotableUser extends TwitterObject { + private static final long serialVersionUID = 1987591937358157578L; + private final Long userId; + private final String id; + private final String accountId; + private final String promotableUserType; + private final LocalDateTime createdAt; + private final LocalDateTime updatedAt; + private final Boolean deleted; + + public PromotableUser( + Long userId, + String id, + String accountId, + String promotableUserType, + LocalDateTime createdAt, + LocalDateTime updatedAt, + Boolean deleted) { + + this.userId = userId; + this.id = id; + this.promotableUserType = promotableUserType; + this.accountId = accountId; + this.createdAt = createdAt; + this.updatedAt = updatedAt; + this.deleted = deleted; + } + + public Long getUserId() { + return userId; + } + + public String getId() { + return id; + } + + public String getAccountId() { + return accountId; + } + + public LocalDateTime getCreatedAt() { + return createdAt; + } + + public LocalDateTime getUpdatedAt() { + return updatedAt; + } + + public Boolean isDeleted() { + return deleted; + } + + public String getPromotableUserType() { + return promotableUserType; + } +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/PromotableUserQuery.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/PromotableUserQuery.java new file mode 100644 index 00000000..897bb050 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/PromotableUserQuery.java @@ -0,0 +1,7 @@ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.twitter.api.TwitterQueryForData; + +public interface PromotableUserQuery extends TwitterQueryForData { + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/PromotedTweetReference.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/PromotedTweetReference.java new file mode 100644 index 00000000..2468adf5 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/PromotedTweetReference.java @@ -0,0 +1,91 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import java.time.LocalDateTime; + +import org.springframework.social.twitter.api.Tweet; +import org.springframework.social.twitter.api.TwitterObject; + +/** + * Represents a link between {@link LineItem} and {@link Tweet}, + * part of the creative namespace of the Twitter Ads Api. + * + * @author Hudson Mendes + */ +public class PromotedTweetReference extends TwitterObject { + private static final long serialVersionUID = 1L; + private final String id; + private final String lineItemId; + private final Long tweetId; + private final Boolean paused; + private final Boolean deleted; + private final LocalDateTime createdAt; + private final LocalDateTime updatedAt; + private final ApprovalStatus approvalStatus; + + public PromotedTweetReference( + String id, + String lineItemId, + Long tweetId, + Boolean paused, + Boolean deleted, + LocalDateTime createdAt, + LocalDateTime updatedAt, + ApprovalStatus approvalStatus) { + + this.id = id; + this.lineItemId = lineItemId; + this.tweetId = tweetId; + this.paused = paused; + this.deleted = deleted; + this.createdAt = createdAt; + this.updatedAt = updatedAt; + this.approvalStatus = approvalStatus; + } + + public String getId() { + return id; + } + + public String getLineItemId() { + return lineItemId; + } + + public Long getTweetId() { + return tweetId; + } + + public Boolean isPaused() { + return paused; + } + + public Boolean isDeleted() { + return deleted; + } + + public LocalDateTime getCreatedAt() { + return createdAt; + } + + public LocalDateTime getUpdatedAt() { + return updatedAt; + } + + public ApprovalStatus getApprovalStatus() { + return approvalStatus; + } +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/PromotedTweetReferenceForm.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/PromotedTweetReferenceForm.java new file mode 100644 index 00000000..fed22f0d --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/PromotedTweetReferenceForm.java @@ -0,0 +1,29 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.twitter.api.TwitterForm; + +/** + * Input form through which we can create {@link PromotedTweetReference}. + * + * @author Hudson Mendes + */ +public interface PromotedTweetReferenceForm extends TwitterForm { + public PromotedTweetReferenceForm onLineItem(String lineItemId); + + public PromotedTweetReferenceForm forTweets(Long... tweetIds); +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/PromotedTweetReferenceQuery.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/PromotedTweetReferenceQuery.java new file mode 100644 index 00000000..f3545dba --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/PromotedTweetReferenceQuery.java @@ -0,0 +1,27 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.twitter.api.TwitterQueryForEntity; + +/** + * Query builder for LineItem x Tweet links. + * + * @author Hudson Mendes + */ +public interface PromotedTweetReferenceQuery extends TwitterQueryForEntity { + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/PromotedUserReference.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/PromotedUserReference.java new file mode 100644 index 00000000..2bddfc57 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/PromotedUserReference.java @@ -0,0 +1,90 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import java.time.LocalDateTime; + +import org.springframework.social.twitter.api.TwitterObject; + +/** + * Represents a {@link PromotableUser} account that has been actually + * promoted through the Twitter Ads Api creatives namespace. + * + * @author Hudson Mendes + */ +public class PromotedUserReference extends TwitterObject { + private static final long serialVersionUID = 1L; + private final String id; + private final String lineItemId; + private final String userId; + private final Boolean paused; + private final Boolean deleted; + private final LocalDateTime createdAt; + private final LocalDateTime updatedAt; + private final ApprovalStatus approvalStatus; + + public PromotedUserReference( + String id, + String lineItemId, + String userId, + Boolean paused, + Boolean deleted, + LocalDateTime createdAt, + LocalDateTime updatedAt, + ApprovalStatus approvalStatus) { + + this.id = id; + this.lineItemId = lineItemId; + this.userId = userId; + this.paused = paused; + this.deleted = deleted; + this.createdAt = createdAt; + this.updatedAt = updatedAt; + this.approvalStatus = approvalStatus; + } + + public String getId() { + return id; + } + + public String getLineItemId() { + return lineItemId; + } + + public String getUserId() { + return userId; + } + + public Boolean isDeleted() { + return deleted; + } + + public Boolean isPaused() { + return paused; + } + + public LocalDateTime getCreatedAt() { + return createdAt; + } + + public LocalDateTime getUpdatedAt() { + return updatedAt; + } + + public ApprovalStatus getApprovalStatus() { + return approvalStatus; + } +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/PromotedUserReferenceForm.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/PromotedUserReferenceForm.java new file mode 100644 index 00000000..a39dd984 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/PromotedUserReferenceForm.java @@ -0,0 +1,30 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.twitter.api.TwitterForm; + +/** + * Allow posting data for the {@link PromotedUserReference} entity. + * + * @author Hudson Mendes + */ +public interface PromotedUserReferenceForm extends TwitterForm { + + public PromotedUserReferenceForm onLineItem(String lineItemId); + + public PromotedUserReferenceForm forUser(String userId); +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/PromotedUserReferenceQuery.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/PromotedUserReferenceQuery.java new file mode 100644 index 00000000..32f123ec --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/PromotedUserReferenceQuery.java @@ -0,0 +1,26 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.twitter.api.TwitterQueryForSortableEntity; + +/** + * Allows querying through {@link PromotedUserReference} + * + * @author Hudson Mendes + */ +public interface PromotedUserReferenceQuery extends TwitterQueryForSortableEntity { +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/PromotedUserReferenceSorting.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/PromotedUserReferenceSorting.java new file mode 100644 index 00000000..ad19ae6d --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/PromotedUserReferenceSorting.java @@ -0,0 +1,27 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +/** + * Sorting option for {@link PromotedUserReferenceQuery} + * + * @author Hudson Mendes + */ +public enum PromotedUserReferenceSorting { + created_at, + updated_at, + deleted +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/PromotionOperations.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/PromotionOperations.java new file mode 100644 index 00000000..969ed927 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/PromotionOperations.java @@ -0,0 +1,118 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.twitter.api.Tweet; +import org.springframework.social.twitter.api.impl.DataListHolder; + +/** + * Interface defining the operations for promoted tweets (Ads API). + * + * @author Hudson Mendes + */ +public interface PromotionOperations { + + /** + * Retrieves a of {@link PromotableUser}. + * + * @param accountId identifies the account for which we are trying to promote users. + * @param query are the parameters used to query the user + * @return a cursored list of {@link PromotableUser} + */ + DataListHolder getPromotableUsers(String accountId, PromotableUserQuery query); + + + /** + * Retrieves a sequence of of promoted-only {@link Tweet} + * + * @param accountId identifies the account for which we want to retrieve promoted-only tweets. + * @param query are the parameters for which we want to retrieve tweets. + * @return a cursored list of {@link Tweet}. + */ + DataListHolder getSponsoredTweets(String accountId, SponsoredTweetQuery query); + + /** + * Creates a {@link Tweet} that is a promoted-only tweet. + * + * @param accountId identifies the account for which the promoted-only tweet will be created. + * @param input is the data of the tweet. + * @return the {@link Tweet} that has been created. + */ + Tweet createSponsoredTweet(String accountId, SponsoredTweetForm input); + + /** + * Queries links between {@link Tweet} and {@link LineItem}. + * Essential to advertise for targetted people. + * + * @param accountId identifies the account for which we will query links. + * @param lineItemId is the line item for which we will query. + * @param query responsible for aditional parameters of the query, such as pagination. + * @return a cursored list of {@link PromotedTweetReference} + */ + DataListHolder getPromotedTweetReferences(String accountId, String lineItemId, PromotedTweetReferenceQuery query); + + /** + * Queries links between {@link Tweet} and {@link LineItem}. + * Essential to advertise for targetted people. + * + * @param accountId identifies the account for which we will query links. + * @param query responsible for aditional parameters of the query, such as pagination. + * @return a cursored list of {@link PromotedTweetReference} + */ + DataListHolder getPromotedTweetReferences(String accountId, PromotedTweetReferenceQuery query); + + /** + * Creates a {@link PromotedTweetReference} that links a {@link LineItem} to a {@link Tweet}. + * + * @param accountId identifies the account for which we will create a link. + * @param input is the information of the link that we will create. + * @return a list of all {@link PromotedTweetReference} created for all the {@link Tweet} passed. + */ + DataListHolder createPromotedTweetReference(String accountId, PromotedTweetReferenceForm input); + + /** + * Deletes a {@link PromotedTweetReference} by its reference. + * + * @param accountId identifies the account for which we will create a link. + * @param promotedTweetId identifies the id of the promoted_tweet to be deleted. + */ + void deletePromotedTweetReference(String accountId, String promotedTweetId); + + /** + * Retrieves all {@link PromotedUserReference} that links a {@link LineItem} to a {@link PromotableUser} existing in the Twitter Ads system. + * + * @param accountId identifies the account for which we will retrieve the links + * @param lineItemId is the line item for which we will query. + * @param query responsible for aditional parameters of the query, such as pagination. + * @return a cursored list of {@link PromotedUserReference} + */ + DataListHolder getPromotedUserReferences(String accountId, String lineItemId, PromotedUserReferenceQuery query); + + /** + * + * @param accountId identifies the account for which we will create a link. + * @param input is the information of the link that we will create. + * @return a {@link PromotedUserReference} created for all {@link PromotableUser} passed. + */ + PromotedUserReference createPromotedUserReferences(String accountId, PromotedUserReferenceForm input); + + /** + * + * @param accountId identifies the account for which we will delete the link. + * @param promotedUserId the link that shall be deleted. + */ + void deletePromotedUserReference(String accountId, String promotedUserId); +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/ReasonNotServable.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/ReasonNotServable.java new file mode 100644 index 00000000..06e48498 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/ReasonNotServable.java @@ -0,0 +1,34 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +/** + * Reasons for which a {@link Campaign} may not be servable. + * @author Hudson Mendes + */ +public enum ReasonNotServable { + ACCOUNT_REJECTED, + ACCOUNT_UNDER_REVIEW, + AWAITING_APPROVAL_BY_ADVERTISER, + BUDGET_EXHAUSTED, + CONTENT_REVIEW_PROBLEM, + DELETED, + EXPIRED, + FUNDING_PROBLEM, + INCOMPLETE, + PAUSED_BY_ADVERTISER, + STARTS_IN_FUTURE +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/RetargetingEngagementType.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/RetargetingEngagementType.java new file mode 100644 index 00000000..f96a8ce7 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/RetargetingEngagementType.java @@ -0,0 +1,27 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +/** + * The type of engagement for Retargeting + * For more information, check: https://dev.twitter.com/ads/campaigns/targeting#tweet-engager-retargeting + * + * @author Hudson Mendes + */ +public enum RetargetingEngagementType { + IMPRESSION, + ENGAGEMENT +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/SortDirection.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/SortDirection.java new file mode 100644 index 00000000..03304fb4 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/SortDirection.java @@ -0,0 +1,6 @@ +package org.springframework.social.twitter.api.advertising; + +public enum SortDirection { + asc, + desc +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/SponsoredTweetForm.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/SponsoredTweetForm.java new file mode 100644 index 00000000..cfe07103 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/SponsoredTweetForm.java @@ -0,0 +1,37 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.twitter.api.TwitterForm; + +/** + * Create Promoted-Only Tweets. The Tweets posted via this + * endpoint can be used in Promoted Tweets campaigns but will + * not appear on the public timeline and are not served to + * followers (see https://dev.twitter.com/ads/reference/post/accounts/%3Aaccount_id/tweet) + * + * @author Hudson Mendes + */ +public interface SponsoredTweetForm extends TwitterForm { + + public SponsoredTweetForm withStatus(String text); + + public SponsoredTweetForm asUser(Long userId); + + public SponsoredTweetForm trimUser(Boolean trimUser); + + public SponsoredTweetForm withMediaIds(Long... mediaIds); +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/SponsoredTweetQuery.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/SponsoredTweetQuery.java new file mode 100644 index 00000000..ccd66582 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/SponsoredTweetQuery.java @@ -0,0 +1,30 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.twitter.api.TwitterQueryForEntity; + +/** + * @author Hudson Mendes + */ +public interface SponsoredTweetQuery extends TwitterQueryForEntity { + + public SponsoredTweetQuery ofUsers(Long... userIds); + + public SponsoredTweetQuery withObjective(AdvertisingObjective objective); + + public SponsoredTweetQuery trimUser(Boolean trimUser); +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/StatisticsGranularity.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/StatisticsGranularity.java new file mode 100644 index 00000000..69f17699 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/StatisticsGranularity.java @@ -0,0 +1,27 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +/** + * Represents the granularity for which the statistics + * have been requested and therefore responded by the twitter ads api. + * @author Hudson Mendes + */ +public enum StatisticsGranularity { + TOTAL, + DAY, + HOUR +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/StatisticsMetric.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/StatisticsMetric.java new file mode 100644 index 00000000..b792f186 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/StatisticsMetric.java @@ -0,0 +1,778 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +/** + * Possible metrics that can be retrieved in a {@link StatisticsSnapshot}. + * + * @author Hudson Mendes + * + */ +public enum StatisticsMetric { + conversion_custom( + StatisticsMetricFamily.CONVERSION, + StatisticsSegmentationType.PLATFORMS, + true, + Integer.class, + "Count of conversions of type CUSTOM"), + + conversion_downloads( + StatisticsMetricFamily.CONVERSION, + StatisticsSegmentationType.PLATFORMS, + true, + Integer.class, + "Count of conversions of type DOWNLOAD"), + + conversion_order_quantity( + StatisticsMetricFamily.CONVERSION, + StatisticsSegmentationType.CONVERSION_TAGS, + true, + Integer.class, + "Count of tw_sale_quantity from web event tag"), + + conversion_purchases( + StatisticsMetricFamily.CONVERSION, + StatisticsSegmentationType.PLATFORMS, + true, + Integer.class, + "Count of conversions of type PURCHASE"), + + conversion_sale_amount( + StatisticsMetricFamily.CONVERSION, + StatisticsSegmentationType.CONVERSION_TAGS, + true, + Integer.class, + "Count of tw_sale_amount from web event tag"), + + conversion_sign_ups( + StatisticsMetricFamily.CONVERSION, + StatisticsSegmentationType.PLATFORMS, + true, + Integer.class, + "Count of conversions of type SIGN_UP"), + + conversion_site_visits( + StatisticsMetricFamily.CONVERSION, + StatisticsSegmentationType.PLATFORMS, + true, + Integer.class, + "Count of conversions of type SITE_VISIT"), + + promotion_card_responses( + StatisticsMetricFamily.ENGAGEMENT, + null, + true, + Integer.class, + "Card engagements"), + + promoted_account_follows( + StatisticsMetricFamily.ENGAGEMENT, + null, + true, + Integer.class, + "Total follows for Promoted Account campaigns"), + + billed_engagements( + StatisticsMetricFamily.ENGAGEMENT, + null, + true, + Integer.class, + "Total count of billed engagements"), + + billed_follows( + StatisticsMetricFamily.ENGAGEMENT, + null, + true, + Integer.class, + "Total count of billed follows"), + + promoted_tweet_profile_clicks( + StatisticsMetricFamily.ENGAGEMENT, + null, + true, + Integer.class, + "Catch-all clicks for Promoted Tweet in Profile inventory. Includes any click within the tweet, including favorites and other engagements."), + + promoted_tweet_profile_engagements( + StatisticsMetricFamily.ENGAGEMENT, + null, + true, + Integer.class, + "Total count of engagements for Promoted Tweet in Profiles"), + + promoted_tweet_profile_favorites( + StatisticsMetricFamily.ENGAGEMENT, + null, + true, + Integer.class, + "Count of favorites of Promoted Tweet in Profiles"), + + promoted_tweet_profile_follows( + StatisticsMetricFamily.ENGAGEMENT, + null, + true, + Integer.class, + "Count of follows for Promoted Tweet in Profiles"), + + promoted_tweet_profile_replies( + StatisticsMetricFamily.ENGAGEMENT, + null, + true, + Integer.class, + "Count of replies for Promoted Tweet in Profiles"), + + promoted_tweet_profile_retweets( + StatisticsMetricFamily.ENGAGEMENT, + null, + true, + Integer.class, + "Count of Retweets for Promoted Tweet in Profiles"), + + promoted_tweet_profile_url_clicks( + StatisticsMetricFamily.ENGAGEMENT, + null, + true, + Integer.class, + "Count of URL clicks on Promoted Tweet in Profiles"), + + promoted_tweet_search_clicks( + StatisticsMetricFamily.ENGAGEMENT, + null, + true, + Integer.class, + "Catch-all clicks for Promoted Tweet in Search inventory. Includes any click within the tweet, including favorites and other engagements."), + + promoted_tweet_search_engagements( + StatisticsMetricFamily.ENGAGEMENT, + null, + true, + Integer.class, + "Total count of engagements for Promoted Tweet in Search"), + + promoted_tweet_search_favorites( + StatisticsMetricFamily.ENGAGEMENT, + null, + true, + Integer.class, + "Count of favorites of Promoted Tweet in Search"), + + promoted_tweet_search_follows( + StatisticsMetricFamily.ENGAGEMENT, + null, + true, + Integer.class, + "Count of follows for Promoted Tweet in Search"), + + promoted_tweet_search_replies( + StatisticsMetricFamily.ENGAGEMENT, + null, + true, + Integer.class, + "Count of replies for Promoted Tweet in Search"), + + promoted_tweet_search_retweets( + StatisticsMetricFamily.ENGAGEMENT, + null, + true, + Integer.class, + "Count of Retweets for Promoted Tweet in Search"), + + promoted_tweet_search_url_clicks( + StatisticsMetricFamily.ENGAGEMENT, + null, + true, + Integer.class, + "Count of URL clicks on Promoted Tweet in Search"), + + promoted_tweet_timeline_clicks( + StatisticsMetricFamily.ENGAGEMENT, + null, + true, + Integer.class, + "Catch-all clicks for Promoted Tweet in Timeline inventory. Includes any click within the tweet, including favorites and other engagements."), + + promoted_tweet_timeline_engagements( + StatisticsMetricFamily.ENGAGEMENT, + null, + true, + Integer.class, + "Count of overall engagements for Promoted Tweet in Timeline"), + + promoted_tweet_timeline_favorites( + StatisticsMetricFamily.ENGAGEMENT, + null, + true, + Integer.class, + "Count of favorites of Promoted Tweet in Timeline"), + + promoted_tweet_timeline_follows( + StatisticsMetricFamily.ENGAGEMENT, + null, + true, + Integer.class, + "Count of follows for Promoted Tweet in Timeline"), + + promoted_tweet_timeline_replies( + StatisticsMetricFamily.ENGAGEMENT, + null, + true, + Integer.class, + "Count of replies for Promoted Tweet in Timeline"), + + promoted_tweet_timeline_retweets( + StatisticsMetricFamily.ENGAGEMENT, + null, + true, + Integer.class, + "Count of Retweets for Promoted Tweet in Timeline"), + + promoted_tweet_timeline_url_clicks( + StatisticsMetricFamily.ENGAGEMENT, + null, + true, + Integer.class, + "Count of URL clicks of Promoted Tweet in Timeline"), + + mobile_conversion_achievement_unlocked( + StatisticsMetricFamily.MAP, + null, + true, + Integer.class, + ""), + + mobile_conversion_add_to_cart( + StatisticsMetricFamily.MAP, + null, + true, + Integer.class, + ""), + + mobile_conversion_added_payment_infos( + StatisticsMetricFamily.MAP, + null, + true, + Integer.class, + ""), + + mobile_conversion_add_to_wishlist( + StatisticsMetricFamily.MAP, + null, + true, + Integer.class, + ""), + + mobile_conversion_checkout_initiated( + StatisticsMetricFamily.MAP, + null, + true, + Integer.class, + ""), + + mobile_conversion_content_views( + StatisticsMetricFamily.MAP, + null, + true, + Integer.class, + ""), + + mobile_conversion_installs( + StatisticsMetricFamily.MAP, + null, + true, + Integer.class, + "install conversion events"), + + mobile_conversion_invites( + StatisticsMetricFamily.MAP, + null, + true, + Integer.class, + ""), + + mobile_conversion_level_achieved( + StatisticsMetricFamily.MAP, + null, + true, + Integer.class, + ""), + + mobile_conversion_logins( + StatisticsMetricFamily.MAP, + null, + true, + Integer.class, + "login conversion events"), + + mobile_conversion_purchases( + StatisticsMetricFamily.MAP, + null, + true, + Integer.class, + "purchase conversion events"), + + mobile_conversion_re_engages( + StatisticsMetricFamily.MAP, + null, + true, + Integer.class, + "re-engagement conversion events"), + + mobile_conversion_sign_ups( + StatisticsMetricFamily.MAP, + null, + true, + Integer.class, + "sign-up conversion events"), + + mobile_conversion_rated( + StatisticsMetricFamily.MAP, + null, + true, + Integer.class, + ""), + + mobile_conversion_reservations( + StatisticsMetricFamily.MAP, + null, + true, + Integer.class, + ""), + + mobile_conversion_searches( + StatisticsMetricFamily.MAP, + null, + true, + Integer.class, + ""), + + mobile_conversion_shares( + StatisticsMetricFamily.MAP, + null, + true, + Integer.class, + ""), + + mobile_conversion_spent_credits( + StatisticsMetricFamily.MAP, + null, + true, + Integer.class, + ""), + + mobile_conversion_tutorial_completes( + StatisticsMetricFamily.MAP, + null, + true, + Integer.class, + ""), + + mobile_conversion_updates( + StatisticsMetricFamily.MAP, + null, + true, + Integer.class, + ""), + + promoted_tweet_app_install_attempts( + StatisticsMetricFamily.MAP, + null, + true, + Integer.class, + "tracks install attempts within the twitter app"), + + promoted_tweet_app_open_attempts( + StatisticsMetricFamily.MAP, + null, + true, + Integer.class, + "tracks open attempts within the twitter app"), + + mobile_conversion_achievement_unlocked_breakdown( + StatisticsMetricFamily.MAP, + null, + false, + Object.class, + "Provides a breakdown where total = post-view + post-engagement + assisted"), + + mobile_conversion_add_to_cart_breakdown( + StatisticsMetricFamily.MAP, + null, + false, + Object.class, + "Provides a breakdown where total = post-view + post-engagement + assisted"), + + mobile_conversion_add_to_wishlist_breakdown( + StatisticsMetricFamily.MAP, + null, + false, + Object.class, + "Provides a breakdown where total = post-view + post-engagement + assisted"), + + mobile_conversion_added_payment_infos_breakdown( + StatisticsMetricFamily.MAP, + null, + false, + Object.class, + "Provides a breakdown where total = post-view + post-engagement + assisted"), + + mobile_conversion_checkout_initiated_breakdown( + StatisticsMetricFamily.MAP, + null, + false, + Object.class, + "Provides a breakdown where total = post-view + post-engagement + assisted"), + + mobile_conversion_content_views_breakdown( + StatisticsMetricFamily.MAP, + null, + false, + Object.class, + "Provides a breakdown where total = post-view + post-engagement + assisted"), + + mobile_conversion_installs_breakdown( + StatisticsMetricFamily.MAP, + null, + false, + Object.class, + "Provides a breakdown where total = post-view + post-engagement + assisted"), + + mobile_conversion_invites_breakdown( + StatisticsMetricFamily.MAP, + null, + false, + Object.class, + "Provides a breakdown where total = post-view + post-engagement + assisted"), + + mobile_conversion_level_achieved_breakdown( + StatisticsMetricFamily.MAP, + null, + false, + Object.class, + "Provides a breakdown where total = post-view + post-engagement + assisted"), + + mobile_conversion_logins_breakdown( + StatisticsMetricFamily.MAP, + null, + false, + Object.class, + "Provides a breakdown where total = post-view + post-engagement + assisted"), + + mobile_conversion_order_quantity( + StatisticsMetricFamily.MAP, + null, + false, + Object.class, + "order quantity conversion events"), + + mobile_conversion_purchases_breakdown( + StatisticsMetricFamily.MAP, + null, + false, + Object.class, + "Provides a breakdown where total = post-view + post-engagement + assisted"), + + mobile_conversion_rated_breakdown( + StatisticsMetricFamily.MAP, + null, + false, + Object.class, + "Provides a breakdown where total = post-view + post-engagement + assisted"), + + mobile_conversion_re_engages_breakdown( + StatisticsMetricFamily.MAP, + null, + false, + Object.class, + "Provides a breakdown where total = post-view + post-engagement + assisted"), + + mobile_conversion_reservations_breakdown( + StatisticsMetricFamily.MAP, + null, + false, + Object.class, + "Provides a breakdown where total = post-view + post-engagement + assisted"), + + mobile_conversion_sale_amount_local_micro( + StatisticsMetricFamily.MAP, + null, + false, + Object.class, + "sale amount conversion events"), + + mobile_conversion_searches_breakdown( + StatisticsMetricFamily.MAP, + null, + false, + Object.class, + "Provides a breakdown where total = post-view + post-engagement + assisted"), + + mobile_conversion_shares_breakdown( + StatisticsMetricFamily.MAP, + null, + false, + Object.class, + "Provides a breakdown where total = post-view + post-engagement + assisted"), + + mobile_conversion_sign_ups_breakdown( + StatisticsMetricFamily.MAP, + null, + false, + Object.class, + "Provides a breakdown where total = post-view + post-engagement + assisted"), + + mobile_conversion_spent_credits_breakdown( + StatisticsMetricFamily.MAP, + null, + false, + Object.class, + "Provides a breakdown where total = post-view + post-engagement + assisted"), + + mobile_conversion_tutorial_completes_breakdown( + StatisticsMetricFamily.MAP, + null, + false, + Object.class, + "Provides a breakdown where total = post-view + post-engagement + assisted"), + + mobile_conversion_updates_breakdown( + StatisticsMetricFamily.MAP, + null, + false, + Object.class, + "Provides a breakdown where total = post-view + post-engagement + assisted"), + + promoted_video_cta_clicks( + StatisticsMetricFamily.VIDEO, + null, + true, + Integer.class, + "Total CTA clicks."), + + promoted_video_replays( + StatisticsMetricFamily.VIDEO, + null, + true, + Integer.class, + "Number of times a user elects to re-watch a video."), + + promoted_video_total_views( + StatisticsMetricFamily.VIDEO, + null, + true, + Integer.class, + "Total non-unique views for a promoted video where at least 3 seconds was viewed."), + + promoted_video_views_100( + StatisticsMetricFamily.VIDEO, + null, + true, + Integer.class, + "Total number of views where 100% of the video was viewed."), + + promoted_video_views_25( + StatisticsMetricFamily.VIDEO, + null, + true, + Integer.class, + "Total number of views where at least 25% of the video was viewed."), + + promoted_video_views_50( + StatisticsMetricFamily.VIDEO, + null, + true, + Integer.class, + "Total number of views where at least 50% of the video was viewed."), + + promoted_video_views_75( + StatisticsMetricFamily.VIDEO, + null, + true, + Integer.class, + "Total number of views where at least 75% of the video was viewed."), + + promoted_account_follow_rate( + StatisticsMetricFamily.OTHER, + null, + true, + Integer.class, + "Follow rate for Promoted Account campaigns. This is promoted_account_follows / promoted_account_impressions"), + + promoted_account_impressions( + StatisticsMetricFamily.OTHER, + null, + true, + Integer.class, + "Total impressions for Promoted Account campaigns"), + + promoted_account_profile_visits( + StatisticsMetricFamily.OTHER, + null, + true, + Integer.class, + "Total profile visits for Promoted Account campaigns"), + + promoted_tweet_search_engagement_rate( + StatisticsMetricFamily.OTHER, + null, + true, + Integer.class, + "Engagement rate for Promoted Tweet in Search. This is promoted_tweet_search_engagements / promoted_tweet_search_impressions"), + + promoted_tweet_profile_impressions( + StatisticsMetricFamily.OTHER, + null, + true, + Integer.class, + "Count of impressions for Promoted Tweet in Profiles"), + + promoted_tweet_search_impressions( + StatisticsMetricFamily.OTHER, + null, + true, + Integer.class, + "Count of impressions for Promoted Tweet in Search"), + + promoted_tweet_timeline_engagement_rate( + StatisticsMetricFamily.OTHER, + null, + true, + Integer.class, + "Engagement rate for Promoted Tweet in Timeline. This is promoted_tweet_timeline_engagements / promoted_tweet_timeline_impressions"), + + promoted_tweet_timeline_impressions( + StatisticsMetricFamily.OTHER, + null, + true, + Integer.class, + "Count of impressions for Promoted Tweet in Timeline"), + + billed_charge_local_micro( + StatisticsMetricFamily.SPEND, + null, + true, + Integer.class, + "Spend"), + + promoted_tweet_tpn_card_engagements( + StatisticsMetricFamily.TPN, + null, + true, + Integer.class, + "Card engagements from TPN"), + + promoted_tweet_tpn_engagement_rate( + StatisticsMetricFamily.TPN, + null, + true, + Integer.class, + "Engagement rate from TPN"), + + promoted_tweet_tpn_engagements( + StatisticsMetricFamily.TPN, + null, + true, + Integer.class, + "Total engagements from TPN"), + + promoted_tweet_tpn_clicks( + StatisticsMetricFamily.TPN, + null, + true, + Integer.class, + "Total clicks from Twitter Publisher Network (TPN)"), + + promoted_tweet_tpn_favorites( + StatisticsMetricFamily.TPN, + null, + true, + Integer.class, + "Total favorites from TPN"), + + promoted_tweet_tpn_follows( + StatisticsMetricFamily.TPN, + null, + true, + Integer.class, + "Total follows from TPN"), + + promoted_tweet_tpn_impressions( + StatisticsMetricFamily.TPN, + null, + true, + Integer.class, + "Total impressions from TPN"), + + promoted_tweet_tpn_replies( + StatisticsMetricFamily.TPN, + null, + true, + Integer.class, + "Total replies from TPN"), + + promoted_tweet_tpn_retweets( + StatisticsMetricFamily.TPN, + null, + true, + Integer.class, + "Total retweets from TPN"), + + promoted_tweet_tpn_url_clicks( + StatisticsMetricFamily.TPN, + null, + true, + Integer.class, + ""); + + private final StatisticsMetricFamily family; + private final StatisticsSegmentationType onlyForSegmentation; + private final Boolean availableForPromotedAccounts; + private final Class valueType; + private final String description; + + StatisticsMetric( + StatisticsMetricFamily family, + StatisticsSegmentationType onlyForSegmentation, + Boolean availableForPromotedAccounts, + Class valueType, + String description) { + + this.family = family; + this.onlyForSegmentation = onlyForSegmentation; + this.availableForPromotedAccounts = availableForPromotedAccounts; + this.valueType = valueType; + this.description = description; + } + + public StatisticsMetricFamily getFamily() { + return family; + } + + public StatisticsSegmentationType getOnlyForSegmentation() { + return onlyForSegmentation; + } + + public Boolean getAvailableForPromotedAccounts() { + return availableForPromotedAccounts; + } + + public Class getValueType() { + return valueType; + } + + public String getDescription() { + return description; + } +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/StatisticsMetricFamily.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/StatisticsMetricFamily.java new file mode 100644 index 00000000..adffc7b4 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/StatisticsMetricFamily.java @@ -0,0 +1,11 @@ +package org.springframework.social.twitter.api.advertising; + +public enum StatisticsMetricFamily { + CONVERSION, + ENGAGEMENT, + MAP, + VIDEO, + OTHER, + SPEND, + TPN +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/StatisticsOfAccountQuery.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/StatisticsOfAccountQuery.java new file mode 100644 index 00000000..bfc750a0 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/StatisticsOfAccountQuery.java @@ -0,0 +1,25 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.twitter.api.TwitterQueryForStats; + +/** + * Defines the contract for any {@link StatisticsOfAccountQuery}. + * @author Hudson Mendes + */ +public interface StatisticsOfAccountQuery extends TwitterQueryForStats { +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/StatisticsOfCampaignQuery.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/StatisticsOfCampaignQuery.java new file mode 100644 index 00000000..d50553cb --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/StatisticsOfCampaignQuery.java @@ -0,0 +1,29 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.twitter.api.TwitterQueryForStats; + +/** + * Defines the contract for any {@link StatisticsOfCampaignQuery}. + * @author Hudson Mendes + */ +public interface StatisticsOfCampaignQuery extends TwitterQueryForStats { + + public abstract StatisticsOfCampaignQuery withCampaigns( + String... campaignIds); + +} \ No newline at end of file diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/StatisticsOfFundingInstrumentQuery.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/StatisticsOfFundingInstrumentQuery.java new file mode 100644 index 00000000..d7a2b732 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/StatisticsOfFundingInstrumentQuery.java @@ -0,0 +1,29 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.twitter.api.TwitterQueryForStats; + +/** + * Defines the contract for any {@link StatisticsOfFundingInstrumentQuery}. + * @author Hudson Mendes + */ +public interface StatisticsOfFundingInstrumentQuery extends TwitterQueryForStats { + + public abstract StatisticsOfFundingInstrumentQuery withFundingInstruments( + String... fundingInstrumentIds); + +} \ No newline at end of file diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/StatisticsOfLineItemQuery.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/StatisticsOfLineItemQuery.java new file mode 100644 index 00000000..1ddf0e15 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/StatisticsOfLineItemQuery.java @@ -0,0 +1,29 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.twitter.api.TwitterQueryForStats; + +/** + * Defines the contract for any {@link StatisticsOfLineItemQuery}. + * @author Hudson Mendes + */ +public interface StatisticsOfLineItemQuery extends TwitterQueryForStats { + + public abstract StatisticsOfLineItemQuery withLineItems( + String... lineItemIds); + +} \ No newline at end of file diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/StatisticsOfPromotedAccountQuery.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/StatisticsOfPromotedAccountQuery.java new file mode 100644 index 00000000..6d161b73 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/StatisticsOfPromotedAccountQuery.java @@ -0,0 +1,10 @@ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.twitter.api.TwitterQueryForStats; + +public interface StatisticsOfPromotedAccountQuery extends TwitterQueryForStats { + + public abstract StatisticsOfPromotedAccountQuery withPromotedAccounts( + String... promotedAccountIds); + +} \ No newline at end of file diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/StatisticsOfPromotedTweetQuery.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/StatisticsOfPromotedTweetQuery.java new file mode 100644 index 00000000..3622b943 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/StatisticsOfPromotedTweetQuery.java @@ -0,0 +1,7 @@ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.twitter.api.TwitterQueryForStats; + +public interface StatisticsOfPromotedTweetQuery extends TwitterQueryForStats { + +} \ No newline at end of file diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/StatisticsOperations.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/StatisticsOperations.java new file mode 100644 index 00000000..dcbb39cc --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/StatisticsOperations.java @@ -0,0 +1,133 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import java.util.List; + +import org.springframework.social.twitter.api.Tweet; + + +/** + * Interface defining the operations for advertising statistical operations. + * + * @author Hudson Mendes + */ +public interface StatisticsOperations { + + /** + * Snapshot of Advertising Statistics for Multiple {@link AdvertisingAccount}. + * + * @param accountId The id of the account for which we want to retrieve the statistics. + * @param query The query for which we shall retrieve statistics. + * @return a list of {@link StatisticsSnapshot} + */ + List byAccounts(String accountId, StatisticsOfAccountQuery query); + + /** + * Snapshot of Advertising Statistics for Multiple {@link Campaign}. + * + * @param accountId The id of the account for which we want to retrieve the statistics. + * @param query The query for which we shall retrieve statistics. + * @return a list of {@link StatisticsSnapshot} + */ + List byCampaigns(String accountId, StatisticsOfCampaignQuery query); + + /** + * Snapshot of Advertising Statistics by {@link Campaign}. + * + * @param accountId The id of the account for which we want to retrieve the statistics. + * @param campaignId The id of the campaign for which we want to retrieve the statistics. + * @param query The query for which we shall retrieve statistics. + * @return an instance of {@link StatisticsSnapshot} + */ + List byCampaign(String accountId, String campaignId, StatisticsOfCampaignQuery query); + + /** + * Snapshot of Advertising Statistics for Multiple {@link FundingInstrument}. + * + * @param accountId The id of the account for which we want to retrieve the statistics. + * @param query The query for which we shall retrieve statistics. + * @return a list of {@link StatisticsSnapshot} + */ + List byFundingInstruments(String accountId, StatisticsOfFundingInstrumentQuery query); + + /** + * Snapshot of Advertising Statistics by {@link Campaign}. + * + * @param accountId The id of the account for which we want to retrieve the statistics. + * @param fundingInstrumentId The id of the funding instrument for which we want to retrieve the statistics. + * @param query The query for which we shall retrieve statistics. + * @return an instance of {@link StatisticsSnapshot} + */ + List byFundingInstrument(String accountId, String fundingInstrumentId, StatisticsOfFundingInstrumentQuery query); + + /** + * Snapshot of Advertising Statistics for Multiple {@link LineItem}. + * + * @param accountId The id of the account for which we want to retrieve the statistics. + * @param query The query for which we shall retrieve statistics. + * @return a list of {@link StatisticsSnapshot} + */ + List byLineItems(String accountId, StatisticsOfLineItemQuery query); + + /** + * Snapshot of Advertising Statistics by {@link LineItem}. + * + * @param accountId The id of the account for which we want to retrieve the statistics. + * @param lineItemId The id of the line item for which we want to retrieve the statistics. + * @param query The query for which we shall retrieve statistics. + * @return an instance of {@link StatisticsSnapshot} + */ + List byLineItem(String accountId, String lineItemId, StatisticsOfLineItemQuery query); + + /** + * Snapshot of Advertising Statistics for Multiple promoted accounts. + * + * @param accountId The id of the account for which we want to retrieve the statistics. + * @param query The query for which we shall retrieve statistics. + * @return a list of {@link StatisticsSnapshot} + */ + List byPromotedAccounts(String accountId, StatisticsOfPromotedAccountQuery query); + + /** + * Snapshot of Advertising Statistics for a promoted accounts. + * + * @param accountId The id of the account for which we want to retrieve the statistics. + * @param promotedAccountId The id of the promoted account for which we want to retrieve the statistics. + * @param query The query for which we shall retrieve statistics. + * @return an instance of {@link StatisticsSnapshot} + */ + List byPromotedAccount(String accountId, String promotedAccountId, StatisticsOfPromotedAccountQuery query); + + /** + * Snapshot of Advertising Statistics for Multiple promoted {@link Tweet}. + * + * @param accountId The id of the account for which we want to retrieve the statistics. + * @param query The query for which we shall retrieve statistics. + * @return a list of {@link StatisticsSnapshot} + */ + List byPromotedTweets(String accountId, StatisticsOfPromotedTweetQuery query); + + /** + * Snapshot of Advertising Statistics for a promoted {@link Tweet}. + * + * @param accountId The id of the account for which we want to retrieve the statistics. + * @param promotedTweetId The id of the promoted tweet for which we want to retrieve the statistics. + * @param query The query for which we shall retrieve statistics. + * @return an instance of {@link StatisticsSnapshot} + */ + List byPromotedTweet(String accountId, String promotedTweetId, StatisticsOfPromotedTweetQuery query); +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/StatisticsSegmentation.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/StatisticsSegmentation.java new file mode 100644 index 00000000..4527404c --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/StatisticsSegmentation.java @@ -0,0 +1,29 @@ +package org.springframework.social.twitter.api.advertising; + +public class StatisticsSegmentation { + private final StatisticsSegmentationType type; + private final String value; + private final String description; + + public StatisticsSegmentation( + StatisticsSegmentationType type, + String value, + String description) { + + this.type = type; + this.value = value; + this.description = description; + } + + public StatisticsSegmentationType getType() { + return type; + } + + public String getValue() { + return value; + } + + public String getDescription() { + return description; + } +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/StatisticsSegmentationType.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/StatisticsSegmentationType.java new file mode 100644 index 00000000..91724c93 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/StatisticsSegmentationType.java @@ -0,0 +1,36 @@ +package org.springframework.social.twitter.api.advertising; + +public enum StatisticsSegmentationType { + APP_STORE_CATEGORY(false, false), + CITIES(true, false), + CONVERSION_TAGS(false, false), + DEVICES(false, true), + GENDER(false, false), + INTERESTS(false, false), + KEYWORDS(false, false), + LANGUAGE(false, false), + LOCATIONS(false, false), + PLATFORMS(false, false), + PLATFORM_VERSIONS(false, true), + POSTAL_CODES(true, false), + REGIONS(true, false); + + private final Boolean countryRequired; + private final Boolean platformRequired; + + StatisticsSegmentationType( + Boolean countryRequired, + Boolean platformRequired) { + + this.countryRequired = countryRequired; + this.platformRequired = platformRequired; + } + + public Boolean getCountryRequired() { + return countryRequired; + } + + public Boolean getPlatformRequired() { + return platformRequired; + } +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/StatisticsSnapshot.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/StatisticsSnapshot.java new file mode 100644 index 00000000..6513595a --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/StatisticsSnapshot.java @@ -0,0 +1,98 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import java.time.LocalDateTime; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import org.springframework.social.twitter.api.TwitterObject; + +/** + * Represents a snapshot of the statistics on advertising + * for any of the perspectives requested to the twitter ads api. + * + * @author Hudson Mendes + */ +public class StatisticsSnapshot extends TwitterObject { + private static final long serialVersionUID = 1L; + private final String id; + private final StatisticsSegmentation segmentation; + private final StatisticsGranularity granularity; + private final Map metrics = new HashMap(); + private final LocalDateTime startTime; + private final LocalDateTime endTime; + + public StatisticsSnapshot( + String id, + StatisticsSegmentation segmentation, + StatisticsGranularity granularity, + Map metrics, + LocalDateTime startTime, + LocalDateTime endTime) { + + this.id = id; + this.segmentation = segmentation; + this.granularity = granularity; + this.metrics.putAll(metrics); + this.startTime = startTime; + this.endTime = endTime; + } + + public String getId() { + return id; + } + + public StatisticsSegmentation getSegmentation() { + return segmentation; + } + + public StatisticsGranularity getGranularity() { + return granularity; + } + + public LocalDateTime getStartTime() { + return startTime; + } + + public LocalDateTime getEndTime() { + return endTime; + } + + public StatisticsSnapshotMetric getMetric(StatisticsMetric key) { + return metrics.get(key); + } + + public StatisticsSnapshotMetric[] getMetrics() { + final Collection metrics = this.metrics.values(); + return metrics.toArray(new StatisticsSnapshotMetric[metrics.size()]); + } + + public Boolean hasMetrics(StatisticsMetric... metrics) { + if (metrics == null) + return false; + + if (metrics.length == 0) + return false; + + for (final StatisticsMetric metric : metrics) + if (!this.metrics.containsKey(metric)) + return false; + + return true; + } +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/StatisticsSnapshotMetric.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/StatisticsSnapshotMetric.java new file mode 100644 index 00000000..f3a10d20 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/StatisticsSnapshotMetric.java @@ -0,0 +1,56 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.social.twitter.api.TwitterObject; + +/** + * Represents a metric that has been retrieved by the Ads statistics endpoint. + * + * @author Hudson Mendes + */ +public class StatisticsSnapshotMetric extends TwitterObject { + private static final long serialVersionUID = 1L; + private final StatisticsMetric name; + private final List entries; + + public StatisticsSnapshotMetric(StatisticsMetric name, List entries) { + this.name = name; + this.entries = new ArrayList<>(entries); + } + + public StatisticsMetricFamily getFamily() { + return this.name.getFamily(); + } + + public StatisticsMetric getName() { + return name; + } + + public String getDescription() { + return name.getDescription(); + } + + @SuppressWarnings("unchecked") + public List entries() { + List casted = new ArrayList<>(); + this.entries.forEach(i -> casted.add((TEntry) i)); + return casted; + } +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TailoredAudience.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TailoredAudience.java new file mode 100644 index 00000000..547dc8f3 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TailoredAudience.java @@ -0,0 +1,126 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import java.time.LocalDateTime; + +import org.springframework.social.twitter.api.TwitterObject; + +/** + * Represents a Tailored Audience. + * + * Source: https://support.twitter.com/articles/20172017-tailored-audiences + * Tailored audiences are a way to target your existing users and customers + * to create highly relevant campaigns. + * + * @author Hudson Mendes + */ +public class TailoredAudience extends TwitterObject { + private static final long serialVersionUID = 1L; + private final String id; + private final String name; + private final TailoredAudienceType audienceType; + private final TailoredAudienceListType listType; + private final Integer audienceSize; + private final String partnerSource; + private final Boolean deleted; + private final Boolean targetable; + private final String[] reasonsNotTargetable; + private final String[] targetableTypes; + private final LocalDateTime createdAt; + private final LocalDateTime updatedAt; + + public TailoredAudience( + String id, + String name, + TailoredAudienceListType listType, + TailoredAudienceType audienceType, + Integer audienceSize, + String partnerSource, + Boolean deleted, + Boolean targetable, + String[] reasonsNotTargetable, + String[] targetableTypes, + LocalDateTime createdAt, + LocalDateTime updatedAt) { + + this.id = id; + this.name = name; + + this.audienceType = audienceType; + this.listType = listType; + + this.audienceSize = audienceSize; + this.partnerSource = partnerSource; + + this.deleted = deleted; + this.targetable = targetable; + + this.reasonsNotTargetable = reasonsNotTargetable; + this.targetableTypes = targetableTypes; + + this.createdAt = createdAt; + this.updatedAt = updatedAt; + } + + public String getId() { + return id; + } + + public String getName() { + return name; + } + + public TailoredAudienceType getAudienceType() { + return audienceType; + } + + public TailoredAudienceListType getListType() { + return listType; + } + + public Integer getAudienceSize() { + return audienceSize; + } + + public String getPartnerSource() { + return partnerSource; + } + + public Boolean isDeleted() { + return deleted; + } + + public Boolean isTargetable() { + return targetable; + } + + public String[] getReasonsNotTargetable() { + return reasonsNotTargetable; + } + + public String[] getTargetableTypes() { + return targetableTypes; + } + + public LocalDateTime getCreatedAt() { + return createdAt; + } + + public LocalDateTime getUpdatedAt() { + return updatedAt; + } +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TailoredAudienceChange.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TailoredAudienceChange.java new file mode 100644 index 00000000..b32ded54 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TailoredAudienceChange.java @@ -0,0 +1,68 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.twitter.api.TwitterObject; + +/** + * Represents a tailored audience file, used to update the + * lists available for twitter of the audience that the + * advertiser whishes to advertise to. + * + * @author Hudson Mendes + */ +public class TailoredAudienceChange extends TwitterObject { + private static final long serialVersionUID = 1L; + private final String id; + private final String tailoredAudienceId; + private final String inputFilePath; + private final TailoredAudienceChangeOperation operation; + private final TailoredAudienceChangeState state; + + public TailoredAudienceChange( + String id, + String tailoredAudienceId, + String inputFilePath, + TailoredAudienceChangeOperation operation, + TailoredAudienceChangeState state) { + + this.id = id; + this.tailoredAudienceId = tailoredAudienceId; + this.inputFilePath = inputFilePath; + this.operation = operation; + this.state = state; + } + + public String getId() { + return id; + } + + public String getTailoredAudienceId() { + return tailoredAudienceId; + } + + public String getInputFilePath() { + return inputFilePath; + } + + public TailoredAudienceChangeOperation getOperation() { + return operation; + } + + public TailoredAudienceChangeState getState() { + return state; + } +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TailoredAudienceChangeForm.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TailoredAudienceChangeForm.java new file mode 100644 index 00000000..fbaf0923 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TailoredAudienceChangeForm.java @@ -0,0 +1,32 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.twitter.api.TwitterForm; + +/** + * Describes the contract for the builder of {@link TailoredAudienceChange}'s + * data that will be posted / patched to the endpoint. + * + * @author Hudson Mendes + */ +public interface TailoredAudienceChangeForm extends TwitterForm { + public TailoredAudienceChangeForm withTailoredAudience(String tailoredAudienceId); + + public TailoredAudienceChangeForm withInputFilePath(String inputFilePath); + + public TailoredAudienceChangeForm withOperation(TailoredAudienceChangeOperation operation); +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TailoredAudienceChangeOperation.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TailoredAudienceChangeOperation.java new file mode 100644 index 00000000..6259a95a --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TailoredAudienceChangeOperation.java @@ -0,0 +1,27 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +/** + * Define the operations that can be run for a {@link TailoredAudienceChange}. + * + * @author Hudson Mendes + */ +public enum TailoredAudienceChangeOperation { + ADD, + REMOVE, + REPLACE +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TailoredAudienceChangeState.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TailoredAudienceChangeState.java new file mode 100644 index 00000000..c8aaa5cd --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TailoredAudienceChangeState.java @@ -0,0 +1,28 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +/** + * Defines the status in which a {@link TailoredAudienceChange} can be. + * + * @author Hudson Mendes + */ +public enum TailoredAudienceChangeState { + UPLOADING, + PROCESSING, + COMPLETED, + FAILED +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TailoredAudienceForm.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TailoredAudienceForm.java new file mode 100644 index 00000000..416f72ad --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TailoredAudienceForm.java @@ -0,0 +1,42 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.twitter.api.TwitterForm; + +/** + * Defines the contract for the input form builder of {@link TailoredAudience}. + * + * @author Hudson Mendes + */ +public interface TailoredAudienceForm extends TwitterForm { + + /** + * Defines the type of the list for the {@link TailoredAudience} + * + * @param listType is one amongst the set out in {@link TailoredAudienceListType} + * @return the fluent builder + */ + public TailoredAudienceForm ofListType(TailoredAudienceListType listType); + + /** + * Defines the name of the tailored {@link TailoredAudience} + * + * @param name of the {@link TailoredAudience}. + * @return the fluent builder + */ + public TailoredAudienceForm named(String name); +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TailoredAudienceListType.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TailoredAudienceListType.java new file mode 100644 index 00000000..503532e6 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TailoredAudienceListType.java @@ -0,0 +1,32 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +/** + * Represents the types of lists you can use for a + * Tailored Audience file. That will define which + * type of data the tailored audience (or the opt-out) + * file will contain. + * + * @author Hudson Mendes + */ +public enum TailoredAudienceListType { + EMAIL, + DEVICE_ID, + TWITTER_ID, + HANDLE, + PHONE_NUMBER +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TailoredAudienceOperations.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TailoredAudienceOperations.java new file mode 100644 index 00000000..15f23a93 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TailoredAudienceOperations.java @@ -0,0 +1,103 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.ApiException; +import org.springframework.social.MissingAuthorizationException; +import org.springframework.social.twitter.api.impl.DataListHolder; + +/** + * Interface defining the operations for targeting audience operations. + * + * @author Hudson Mendes + */ +public interface TailoredAudienceOperations { + + /** + * Retrieves a {@link TailoredAudience} linked to a particular {@link AdvertisingAccount} referred to by its id. + * + * @param accountId identifies the account for which we wish to get the particular {@link TailoredAudience}. + * @param id identifies which {@link TailoredAudience} we wish to retrieve. + * @return an instance of {@link TailoredAudience} + * @throws ApiException if there is an error while communicating with Twitter. + * @throws MissingAuthorizationException if TwitterTemplate was not created with OAuth credentials. + */ + TailoredAudience getTailoredAudience(String accountId, String id); + + /** + * Retrieves a list of all {@link TailoredAudience} linked to a particular {@link AdvertisingAccount}. + * + * @param accountId identifies the account for which we want to get the {@link TailoredAudience}. + * @param query The query parameters that will filter the request + * @return a list of {@link TailoredAudience} + * @throws ApiException if there is an error while communicating with Twitter. + * @throws MissingAuthorizationException if TwitterTemplate was not created with OAuth credentials. + */ + DataListHolder getTailoredAudiences(String accountId, TailoredAudienceQuery query); + + /** + * Creates {@link TailoredAudience} linked to a particular {@link AdvertisingAccount}. + * + * @param accountId identifies the account for which we want to create a {@link TailoredAudience}. + * @param input is the request data builder that will generate the request body for the operation. + * @return an instance of {@link TailoredAudience} + * @throws ApiException if there is an error while communicating with Twitter. + * @throws MissingAuthorizationException if TwitterTemplate was not created with OAuth credentials. + */ + TailoredAudience createTailoredAudience(String accountId, TailoredAudienceForm input); + + /** + * Deletes a {@link TailoredAudience} related to an {@link AdvertisingAccount} found by its campaignId. + * + * @param accountId identifies the account of which {@link TailoredAudience} we wish to delete. + * @param id identifies the {@link TailoredAudience} that we desire to delete. + * @throws ApiException if there is an error while communicating with Twitter. + * @throws MissingAuthorizationException if TwitterTemplate was not created with OAuth credentials. + */ + void deleteTailoredAudience(String accountId, String id); + + /** + * Updates a {@link TailoredAudience} indicating a TON file and a {@link TailoredAudienceChangeOperation} to a tailored_audience_change + * (https://dev.twitter.com/ads/reference/post/accounts/%3Aaccount_id/tailored_audience_change) + * + * @param accountId identifies the account for which we sending the change. + * @param input defines the data used for this tailored audience change. + * @return a {@link TailoredAudienceChange} describing what the change posted was. + */ + TailoredAudienceChange createTailoredAudienceChange(String accountId, TailoredAudienceChangeForm input); + + /** + * Retrieves a {@link TailoredAudienceChange} with information about the file, + * the operation and its status. + * (https://dev.twitter.com/ads/reference/get/accounts/%3Aaccount_id/tailored_audience_change/%3Aid) + * + * @param accountId identifies the account for which we sending the change. + * @param id identifies the file (or change) in the {@link TailoredAudience}. + * @return the matching {@link TailoredAudienceChange} + */ + TailoredAudienceChange getTailoredAudienceChange(String accountId, String id); + + /** + * Creates an entry in the global opt-out list that points + * to a file of people who will be ignored even if sent + * as part of tailored audiences. + * + * @param accountId defines the id of the account for which this opt-out post will function. + * @param input defines the parameters that will be posted. + * @return the instance of {@link GlobalOptOut} that has been just created. + */ + GlobalOptOut createGlobalOptOut(String accountId, GlobalOptOutForm input); +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TailoredAudienceQuery.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TailoredAudienceQuery.java new file mode 100644 index 00000000..a9391d28 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TailoredAudienceQuery.java @@ -0,0 +1,36 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.twitter.api.TwitterQueryForData; + +/** + * Defines the data that will be used to query a list of {@link TailoredAudience}. + * + * @author Hudson Mendes + */ +public interface TailoredAudienceQuery extends TwitterQueryForData { + + /** + * The parameters that shall set the page and the pageSize + * and set the amount of results and which results will be returned. + * + * @param cursor defines the cursor (from which entry) we will start counting + * @param pageSize defines the maximum number of entries that shall be retrieved. + * @return itself, allowing you to keep defining your query parameters. + */ + public TailoredAudienceQuery pagedBy(String cursor, Integer pageSize); +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TailoredAudienceType.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TailoredAudienceType.java new file mode 100644 index 00000000..28fab7ad --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TailoredAudienceType.java @@ -0,0 +1,31 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +/** + * Defines the channel of {@link TailoredAudience} that will + * be created / updated or, in any way, managed. + * + * @author Hudson Mendes + */ +public enum TailoredAudienceType { + WEB, + CRM, + MOBILE, + EXCLUDED_WEB, + EXCLUDED_CRM, + EXCLUDED_MOBILE +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForAppStoreCategories.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForAppStoreCategories.java new file mode 100644 index 00000000..347831aa --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForAppStoreCategories.java @@ -0,0 +1,62 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.twitter.api.TwitterObject; + + +/** + * Data discovery for targeting criterias based on app store categories. + * + * @author Hudson Mendes + */ +public class TargetingCriteriaDiscoveryForAppStoreCategories extends TwitterObject { + private static final long serialVersionUID = 1L; + private final String name; + private final String osType; + private final String targetingType; + private final String targetingValue; + + public TargetingCriteriaDiscoveryForAppStoreCategories( + String name, + String osType, + String targetingType, + String targetingValue) { + + this.name = name; + this.osType = osType; + this.targetingType = targetingType; + this.targetingValue = targetingValue; + } + + public String getName() { + return name; + } + + public String getOsType() { + return osType; + } + + public String getTargetingType() { + return targetingType; + } + + public String getTargetingValue() { + return targetingValue; + } + + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForAppStoreCategoriesQuery.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForAppStoreCategoriesQuery.java new file mode 100644 index 00000000..f849f9ac --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForAppStoreCategoriesQuery.java @@ -0,0 +1,27 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.twitter.api.TwitterQueryForEntity; + +/** + * Defines the data that will be used to query a list of {@link TargetingCriteriaDiscoveryForAppStoreCategories}. + * + * @author Hudson Mendes + */ +public interface TargetingCriteriaDiscoveryForAppStoreCategoriesQuery extends TwitterQueryForEntity { + public TargetingCriteriaDiscoveryForAppStoreCategoriesQuery inAppStore(AppStore appStore); +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForBehaviorTaxonomies.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForBehaviorTaxonomies.java new file mode 100644 index 00000000..79796e88 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForBehaviorTaxonomies.java @@ -0,0 +1,69 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.twitter.api.TwitterObject; + + +/** + * Data discovery for targeting criterias based in behavior taxonomies. + * + * @author Hudson Mendes + */ +public class TargetingCriteriaDiscoveryForBehaviorTaxonomies extends TwitterObject { + private static final long serialVersionUID = 1L; + private final String createdAt; + private final String id; + private final String name; + private final String parentId; + private final String updatedAt; + + public TargetingCriteriaDiscoveryForBehaviorTaxonomies( + String createdAt, + String id, + String name, + String parentId, + String updatedAt) { + + this.createdAt = createdAt; + this.id = id; + this.name = name; + this.parentId = parentId; + this.updatedAt = updatedAt; + } + + public String getCreatedAt() { + return createdAt; + } + + public String getId() { + return id; + } + + public String getName() { + return name; + } + + public String getParentId() { + return parentId; + } + + public String getUpdatedAt() { + return updatedAt; + } + + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForBehaviorTaxonomiesQuery.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForBehaviorTaxonomiesQuery.java new file mode 100644 index 00000000..6ff592d7 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForBehaviorTaxonomiesQuery.java @@ -0,0 +1,28 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.twitter.api.TwitterQueryForEntity; + +/** + * Defines the data that will be used to query a list of {@link TargetingCriteriaDiscoveryForBehaviorTaxonomies}. + * + * @author Hudson Mendes + */ +public interface TargetingCriteriaDiscoveryForBehaviorTaxonomiesQuery extends TwitterQueryForEntity { + public TargetingCriteriaDiscoveryForBehaviorTaxonomiesQuery ofTaxonomyIds(String... taxonomyIds); + public TargetingCriteriaDiscoveryForBehaviorTaxonomiesQuery ofParentTaxonomyIds(String... parentIds); +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForBehaviors.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForBehaviors.java new file mode 100644 index 00000000..3ce52bd4 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForBehaviors.java @@ -0,0 +1,78 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import java.util.List; + +import org.springframework.social.twitter.api.TwitterObject; + + +/** + * Data discovery for targeting criterias based on behaviors. + * + * @author Hudson Mendes + */ +public class TargetingCriteriaDiscoveryForBehaviors extends TwitterObject { + private static final long serialVersionUID = 1L; + private final String audienceSize; + private final String behaviorTaxonomyId; + private final String id; + private final String name; + private final String partnerSource; + private final List targetableTypes; + + public TargetingCriteriaDiscoveryForBehaviors( + String audienceSize, + String behaviorTaxonomyId, + String id, + String name, + String partnerSource, + List targetableTypes) { + + this.audienceSize = audienceSize; + this.behaviorTaxonomyId = behaviorTaxonomyId; + this.id = id; + this.name = name; + this.partnerSource = partnerSource; + this.targetableTypes = targetableTypes; + } + + public String getAudienceSize() { + return audienceSize; + } + + public String getBehaviorTaxonomyId() { + return behaviorTaxonomyId; + } + + public String getId() { + return id; + } + + public String getName() { + return name; + } + + public String getPartnerSource() { + return partnerSource; + } + + public List getTargetableTypes() { + return targetableTypes; + } + + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForBehaviorsQuery.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForBehaviorsQuery.java new file mode 100644 index 00000000..9c265ae6 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForBehaviorsQuery.java @@ -0,0 +1,28 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.twitter.api.TwitterQueryForEntity; + +/** + * Defines the data that will be used to query a list of {@link TargetingCriteriaDiscoveryForBehaviors}. + * + * @author Hudson Mendes + */ +public interface TargetingCriteriaDiscoveryForBehaviorsQuery extends TwitterQueryForEntity { + public TargetingCriteriaDiscoveryForBehaviorsQuery ofBehaviors(String... behaviorIds); + public TargetingCriteriaDiscoveryForBehaviorsQuery sortBy(String field, SortDirection direction); +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForDevices.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForDevices.java new file mode 100644 index 00000000..aaacf6a0 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForDevices.java @@ -0,0 +1,69 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.twitter.api.TwitterObject; + + +/** + * Data discovery for targeting criterias based in devices. + * + * @author Hudson Mendes + */ +public class TargetingCriteriaDiscoveryForDevices extends TwitterObject { + private static final long serialVersionUID = 1L; + private final String targetingValue; + private final String targetingType; + private final String platform; + private final String manufacturer; + private final String name; + + public TargetingCriteriaDiscoveryForDevices( + String targetingValue, + String targetingType, + String platform, + String manufacturer, + String name) { + + this.targetingValue = targetingValue; + this.targetingType = targetingType; + this.platform = platform; + this.manufacturer = manufacturer; + this.name = name; + } + + public String getTargetingValue() { + return targetingValue; + } + + public String getTargetingType() { + return targetingType; + } + + public String getPlatform() { + return platform; + } + + public String getManufacturer() { + return manufacturer; + } + + public String getName() { + return name; + } + + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForDevicesQuery.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForDevicesQuery.java new file mode 100644 index 00000000..38510d41 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForDevicesQuery.java @@ -0,0 +1,26 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.twitter.api.TwitterQueryForEntity; + +/** + * Defines the data that will be used to query a list of {@link TargetingCriteriaDiscoveryForDevices}. + * + * @author Hudson Mendes + */ +public interface TargetingCriteriaDiscoveryForDevicesQuery extends TwitterQueryForEntity { +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForEvents.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForEvents.java new file mode 100644 index 00000000..397f15e0 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForEvents.java @@ -0,0 +1,139 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.springframework.social.twitter.api.TwitterObject; + + +/** + * Data discovery for targeting criterias based on events. + * + * @author Hudson Mendes + */ +public class TargetingCriteriaDiscoveryForEvents extends TwitterObject { + private static final long serialVersionUID = 1L; + + private final Map countryBreakdownPercentage = new HashMap(); + private final String countryCode; + private final Map deviceBreakdownPercentage = new HashMap(); + private final String endTime; + private final EventType eventType; + private final Map genderBreakdownPercentage = new HashMap(); + private final String id; + private final boolean isGlobal; + private final String name; + private final Map reach = new HashMap(); + private final String startTime; + private final List topHashTags = new ArrayList(); + private final List topTweets = new ArrayList(); + private final List topUsers = new ArrayList(); + + public TargetingCriteriaDiscoveryForEvents( + final Map countryBreakdownPercentage, + final String countryCode, + final Map deviceBreakdownPercentage, + final String endTime, + final EventType eventType, + final Map genderBreakdownPercentage, + final String id, + final boolean isGlobal, + final String name, + final Map reach, + final String startTime, + final List topHashTags, + final List topTweets, + final List topUsers) { + + this.countryBreakdownPercentage.putAll(countryBreakdownPercentage); + this.countryCode = countryCode; + this.deviceBreakdownPercentage.putAll(deviceBreakdownPercentage); + this.endTime = endTime; + this.eventType = eventType; + this.genderBreakdownPercentage.putAll(genderBreakdownPercentage); + this.id = id; + this.isGlobal = isGlobal; + this.name = name; + this.reach.putAll(reach); + this.startTime = startTime; + this.topHashTags.addAll(topHashTags); + this.topTweets.addAll(topTweets); + this.topUsers.addAll(topUsers); + } + + public Map getCountryBreakdownPercentage() { + return countryBreakdownPercentage; + } + + public String getCountryCode() { + return countryCode; + } + + public Map getDeviceBreakdownPercentage() { + return deviceBreakdownPercentage; + } + + public String getEndTime() { + return endTime; + } + + public EventType getEventType() { + return eventType; + } + + public Map getGenderBreakdownPercentage() { + return genderBreakdownPercentage; + } + + public String getId() { + return id; + } + + public boolean isGlobal() { + return isGlobal; + } + + public String getName() { + return name; + } + + public Map getReach() { + return reach; + } + + public String getStartTime() { + return startTime; + } + + public List getTopHashTags() { + return topHashTags; + } + + public List getTopTweets() { + return topTweets; + } + + public List getTopUsers() { + return topUsers; + } + + + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForEventsQuery.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForEventsQuery.java new file mode 100644 index 00000000..afb8d923 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForEventsQuery.java @@ -0,0 +1,34 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import java.time.LocalDateTime; +import java.util.List; + +import org.springframework.social.twitter.api.TwitterQueryForEntity; + +/** + * Defines the data that will be used to query a list of {@link TargetingCriteriaDiscoveryForEvents}. + * + * @author Hudson Mendes + */ +public interface TargetingCriteriaDiscoveryForEventsQuery extends TwitterQueryForEntity { + public TargetingCriteriaDiscoveryForEventsQuery withEventIds(List eventIds); + public TargetingCriteriaDiscoveryForEventsQuery withEventTypes(List eventTypes); + public TargetingCriteriaDiscoveryForEventsQuery withCountryCodes(List countryCodes); + public TargetingCriteriaDiscoveryForEventsQuery withStartTime(LocalDateTime startTime); + public TargetingCriteriaDiscoveryForEventsQuery withEndTime(LocalDateTime endTime); +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForInterests.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForInterests.java new file mode 100644 index 00000000..f72b7b25 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForInterests.java @@ -0,0 +1,55 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.twitter.api.TwitterObject; + + +/** + * Data discovery for targeting criterias based on interests. + * + * @author Hudson Mendes + */ +public class TargetingCriteriaDiscoveryForInterests extends TwitterObject { + private static final long serialVersionUID = 1L; + private final String name; + private final String targetingType; + private final String targetingValue; + + public TargetingCriteriaDiscoveryForInterests( + String name, + String targetingType, + String targetingValue) { + + this.name = name; + this.targetingType = targetingType; + this.targetingValue = targetingValue; + } + + public String getName() { + return name; + } + + public String getTargetingType() { + return targetingType; + } + + public String getTargetingValue() { + return targetingValue; + } + + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForInterestsQuery.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForInterestsQuery.java new file mode 100644 index 00000000..073bfdbe --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForInterestsQuery.java @@ -0,0 +1,27 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.twitter.api.TwitterQueryForEntity; + +/** + * Defines the data that will be used to query a list of {@link TargetingCriteriaDiscoveryForInterests}. + * + * @author Hudson Mendes + */ +public interface TargetingCriteriaDiscoveryForInterestsQuery extends TwitterQueryForEntity { + public TargetingCriteriaDiscoveryForInterestsQuery withLanguage(String language); +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForLanguages.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForLanguages.java new file mode 100644 index 00000000..2e27b982 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForLanguages.java @@ -0,0 +1,55 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.twitter.api.TwitterObject; + + +/** + * Data discovery for targeting criterias based on languages. + * + * @author Hudson Mendes + */ +public class TargetingCriteriaDiscoveryForLanguages extends TwitterObject { + private static final long serialVersionUID = 1L; + private final String name; + private final String targetingType; + private final String targetingValue; + + public TargetingCriteriaDiscoveryForLanguages( + String name, + String targetingType, + String targetingValue) { + + this.name = name; + this.targetingType = targetingType; + this.targetingValue = targetingValue; + } + + public String getName() { + return name; + } + + public String getTargetingType() { + return targetingType; + } + + public String getTargetingValue() { + return targetingValue; + } + + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForLanguagesQuery.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForLanguagesQuery.java new file mode 100644 index 00000000..2e641c1d --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForLanguagesQuery.java @@ -0,0 +1,26 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.twitter.api.TwitterQueryForEntity; + +/** + * Defines the data that will be used to query a list of {@link TargetingCriteriaDiscoveryForLanguages}. + * + * @author Hudson Mendes + */ +public interface TargetingCriteriaDiscoveryForLanguagesQuery extends TwitterQueryForEntity { +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForLocations.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForLocations.java new file mode 100644 index 00000000..dbc8c474 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForLocations.java @@ -0,0 +1,63 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.twitter.api.TwitterObject; + + +/** + * Data discovery for targeting criterias based on locations. + * + * @author Hudson Mendes + */ +public class TargetingCriteriaDiscoveryForLocations extends TwitterObject { + private static final long serialVersionUID = 1L; + + private final String locationType; + private final String name; + private final String targetingType; + private final String targetingValue; + + public TargetingCriteriaDiscoveryForLocations( + String locationType, + String name, + String targetingType, + String targetingValue) { + + this.locationType = locationType; + this.name = name; + this.targetingType = targetingType; + this.targetingValue = targetingValue; + } + + public String getName() { + return name; + } + + public String getLocationType() { + return locationType; + } + + public String getTargetingType() { + return targetingType; + } + + public String getTargetingValue() { + return targetingValue; + } + + +} \ No newline at end of file diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForLocationsQuery.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForLocationsQuery.java new file mode 100644 index 00000000..4bf35522 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForLocationsQuery.java @@ -0,0 +1,28 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.twitter.api.TwitterQueryForEntity; + +/** + * Defines the data that will be used to query a list of {@link TargetingCriteriaDiscoveryForLocations}. + * + * @author Hudson Mendes + */ +public interface TargetingCriteriaDiscoveryForLocationsQuery extends TwitterQueryForEntity { + public TargetingCriteriaDiscoveryForLocationsQuery withLocation(LocationType location); + public TargetingCriteriaDiscoveryForLocationsQuery withCountryCode(String countryCode); +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForNetworkOperators.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForNetworkOperators.java new file mode 100644 index 00000000..3d451055 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForNetworkOperators.java @@ -0,0 +1,61 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.twitter.api.TwitterObject; + + +/** + * Data discovery for targeting criterias based on network operators. + * + * @author Hudson Mendes + */ +public class TargetingCriteriaDiscoveryForNetworkOperators extends TwitterObject { + private static final long serialVersionUID = 1L; + private final String countryCode; + private final String name; + private final String targetingType; + private final String targetingValue; + + public TargetingCriteriaDiscoveryForNetworkOperators( + String countryCode, + String name, + String targetingType, + String targetingValue) { + + this.countryCode = countryCode; + this.name = name; + this.targetingType = targetingType; + this.targetingValue = targetingValue; + } + + public String getName() { + return name; + } + + public String getCountryCode() { + return countryCode; + } + + public String getTargetingType() { + return targetingType; + } + + public String getTargetingValue() { + return targetingValue; + } + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForNetworkOperatorsQuery.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForNetworkOperatorsQuery.java new file mode 100644 index 00000000..c6dd7082 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForNetworkOperatorsQuery.java @@ -0,0 +1,27 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.twitter.api.TwitterQueryForEntity; + +/** + * Defines the data that will be used to query a list of {@link TargetingCriteriaDiscoveryForNetworkOperators}. + * + * @author Hudson Mendes + */ +public interface TargetingCriteriaDiscoveryForNetworkOperatorsQuery extends TwitterQueryForEntity { + public TargetingCriteriaDiscoveryForNetworkOperatorsQuery withCountryCode(String countryCode); +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForPlatformVersions.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForPlatformVersions.java new file mode 100644 index 00000000..b31abcc0 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForPlatformVersions.java @@ -0,0 +1,69 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.twitter.api.TwitterObject; + + +/** + * Data discovery for targeting criterias based on platform versions. + * + * @author Hudson Mendes + */ +public class TargetingCriteriaDiscoveryForPlatformVersions extends TwitterObject { + private static final long serialVersionUID = 1L; + private final String name; + private final String number; + private final String platform; + private final String targetingType; + private final String targetingValue; + + public TargetingCriteriaDiscoveryForPlatformVersions( + String name, + String number, + String platform, + String targetingType, + String targetingValue) { + + this.name = name; + this.number = number; + this.platform = platform; + this.targetingType = targetingType; + this.targetingValue = targetingValue; + } + + public String getName() { + return name; + } + + public String getNumber() { + return number; + } + + public String getPlatform() { + return platform; + } + + public String getTargetingType() { + return targetingType; + } + + public String getTargetingValue() { + return targetingValue; + } + + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForPlatformVersionsQuery.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForPlatformVersionsQuery.java new file mode 100644 index 00000000..887cffd0 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForPlatformVersionsQuery.java @@ -0,0 +1,26 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.twitter.api.TwitterQueryForEntity; + +/** + * Defines the data that will be used to query a list of {@link TargetingCriteriaDiscoveryForPlatformVersions}. + * + * @author Hudson Mendes + */ +public interface TargetingCriteriaDiscoveryForPlatformVersionsQuery extends TwitterQueryForEntity { +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForPlatforms.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForPlatforms.java new file mode 100644 index 00000000..e0a64c39 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForPlatforms.java @@ -0,0 +1,54 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.twitter.api.TwitterObject; + + +/** + * Data discovery for targeting criterias based on platforms. + * + * @author Hudson Mendes + */ +public class TargetingCriteriaDiscoveryForPlatforms extends TwitterObject { + private static final long serialVersionUID = 1L; + private final String name; + private final String targetingType; + private final String targetingValue; + + public TargetingCriteriaDiscoveryForPlatforms( + String name, + String targetingType, + String targetingValue) { + + this.name = name; + this.targetingType = targetingType; + this.targetingValue = targetingValue; + } + + public String getName() { + return name; + } + + public String getTargetingType() { + return targetingType; + } + + public String getTargetingValue() { + return targetingValue; + } + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForPlatformsQuery.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForPlatformsQuery.java new file mode 100644 index 00000000..76683c7a --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForPlatformsQuery.java @@ -0,0 +1,27 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.twitter.api.TwitterQueryForEntity; + +/** + * Defines the data that will be used to query a list of {@link TargetingCriteriaDiscoveryForPlatforms}. + * + * @author Hudson Mendes + */ +public interface TargetingCriteriaDiscoveryForPlatformsQuery extends TwitterQueryForEntity { + public TargetingCriteriaDiscoveryForPlatformsQuery withLanguage(String language); +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForTvChannel.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForTvChannel.java new file mode 100644 index 00000000..c8a18fa9 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForTvChannel.java @@ -0,0 +1,46 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.twitter.api.TwitterObject; + + +/** + * Data discovery for targeting criterias based in tv-channels. + * + * @author Hudson Mendes + */ +public class TargetingCriteriaDiscoveryForTvChannel extends TwitterObject { + private static final long serialVersionUID = 1L; + private final Long id; + private final String name; + + public TargetingCriteriaDiscoveryForTvChannel( + Long id, + String name) { + + this.id = id; + this.name = name; + } + + public Long getId() { + return id; + } + + public String getName() { + return name; + } +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForTvChannelQuery.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForTvChannelQuery.java new file mode 100644 index 00000000..c83edc7f --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForTvChannelQuery.java @@ -0,0 +1,26 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.twitter.api.TwitterQueryForEntity; + +/** + * Defines the data that will be used to query a list of {@link TargetingCriteriaDiscoveryForTvChannel}. + * + * @author Hudson Mendes + */ +public interface TargetingCriteriaDiscoveryForTvChannelQuery extends TwitterQueryForEntity { +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForTvGenre.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForTvGenre.java new file mode 100644 index 00000000..9047ae7c --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForTvGenre.java @@ -0,0 +1,46 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.twitter.api.TwitterObject; + + +/** + * Data discovery for targeting criterias based in tv-genres. + * + * @author Hudson Mendes + */ +public class TargetingCriteriaDiscoveryForTvGenre extends TwitterObject { + private static final long serialVersionUID = 1L; + private final Long id; + private final String name; + + public TargetingCriteriaDiscoveryForTvGenre( + Long id, + String name) { + + this.id = id; + this.name = name; + } + + public Long getId() { + return id; + } + + public String getName() { + return name; + } +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForTvGenreQuery.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForTvGenreQuery.java new file mode 100644 index 00000000..1ca9768b --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForTvGenreQuery.java @@ -0,0 +1,26 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.twitter.api.TwitterQueryForEntity; + +/** + * Defines the data that will be used to query a list of {@link TargetingCriteriaDiscoveryForTvGenre}. + * + * @author Hudson Mendes + */ +public interface TargetingCriteriaDiscoveryForTvGenreQuery extends TwitterQueryForEntity { +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForTvMarket.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForTvMarket.java new file mode 100644 index 00000000..cfcf3ab7 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForTvMarket.java @@ -0,0 +1,60 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.twitter.api.TwitterObject; + + +/** + * Data discovery for targeting criterias based in tv-markets. + * + * @author Hudson Mendes + */ +public class TargetingCriteriaDiscoveryForTvMarket extends TwitterObject { + private static final long serialVersionUID = 1L; + private final String id; + private final String name; + private final String countryCode; + private final String locale; + + public TargetingCriteriaDiscoveryForTvMarket( + String id, + String name, + String countryCode, + String locale) { + + this.id = id; + this.name = name; + this.countryCode = countryCode; + this.locale = locale; + } + + public String getCountryCode() { + return countryCode; + } + + public String getId() { + return id; + } + + public String getName() { + return name; + } + + public String getLocale() { + return locale; + } +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForTvMarketQuery.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForTvMarketQuery.java new file mode 100644 index 00000000..31d10229 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForTvMarketQuery.java @@ -0,0 +1,26 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.twitter.api.TwitterQueryForEntity; + +/** + * Defines the data that will be used to query a list of {@link TargetingCriteriaDiscoveryForTvMarket}. + * + * @author Hudson Mendes + */ +public interface TargetingCriteriaDiscoveryForTvMarketQuery extends TwitterQueryForEntity { +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForTvShow.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForTvShow.java new file mode 100644 index 00000000..d1633252 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForTvShow.java @@ -0,0 +1,61 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.twitter.api.TwitterObject; + + +/** + * Data discovery for targeting criterias based in tv-shows. + * + * @author Hudson Mendes + */ +public class TargetingCriteriaDiscoveryForTvShow extends TwitterObject { + private static final long serialVersionUID = 1L; + private final Long id; + private final Long estimatedUsers; + private final String name; + private final String genre; + + public TargetingCriteriaDiscoveryForTvShow( + Long id, + Long estimatedUsers, + String name, + String genre) { + + this.id = id; + this.estimatedUsers = estimatedUsers; + this.name = name; + this.genre = genre; + + } + + public Long getId() { + return id; + } + + public Long getEstimatedUsers() { + return estimatedUsers; + } + + public String getName() { + return name; + } + + public String getGenre() { + return genre; + } +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForTvShowQuery.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForTvShowQuery.java new file mode 100644 index 00000000..6b9835ca --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryForTvShowQuery.java @@ -0,0 +1,27 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.twitter.api.TwitterQueryForEntity; + +/** + * Defines the data that will be used to query a list of {@link TargetingCriteriaDiscoveryForTvShow}. + * + * @author Hudson Mendes + */ +public interface TargetingCriteriaDiscoveryForTvShowQuery extends TwitterQueryForEntity { + TargetingCriteriaDiscoveryForTvShowQuery withLocale(String tvMarketLocale); +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryOperations.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryOperations.java new file mode 100644 index 00000000..5d2d2a54 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaDiscoveryOperations.java @@ -0,0 +1,116 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.twitter.api.impl.DataListHolder; + +/** + * Interface defining the operations for advertising statistical operations. + * + * @author Hudson Mendes + */ +public interface TargetingCriteriaDiscoveryOperations { + + /** + * @param query builds the query for querying of {@link TargetingCriteriaDiscoveryForAppStoreCategories} + * @return an instance of {@link TargetingCriteriaDiscoveryForAppStoreCategories} + */ + DataListHolder appStoreCategories(TargetingCriteriaDiscoveryForAppStoreCategoriesQuery query); + + /** + * @param query builds the query for querying of {@link TargetingCriteriaDiscoveryForDevices} + * @return an instance of {@link TargetingCriteriaDiscoveryForDevices} + */ + DataListHolder devices(TargetingCriteriaDiscoveryForDevicesQuery query); + + /** + * @param query builds the query for querying of {@link TargetingCriteriaDiscoveryForEvents} + * @return an instance of {@link TargetingCriteriaDiscoveryForEvents} + */ + DataListHolder events(TargetingCriteriaDiscoveryForEventsQuery query); + + /** + * @param query builds the query for querying of {@link TargetingCriteriaDiscoveryForBehaviorTaxonomiesQuery} + * @return an instance of {@link TargetingCriteriaDiscoveryForBehaviorTaxonomies} + */ + DataListHolder behaviorTaxonomies(TargetingCriteriaDiscoveryForBehaviorTaxonomiesQuery query); + + /** + * @param query builds the query for querying of {@link TargetingCriteriaDiscoveryForBehaviorsQuery} + * @return an instance of {@link TargetingCriteriaDiscoveryForBehaviors} + */ + DataListHolder behaviors(TargetingCriteriaDiscoveryForBehaviorsQuery query); + + /** + * @param query builds the query for querying of {@link TargetingCriteriaDiscoveryForInterestsQuery} + * @return an instance of {@link TargetingCriteriaDiscoveryForInterests} + */ + DataListHolder interests(TargetingCriteriaDiscoveryForInterestsQuery query); + + /** + * @param query builds the query for querying of {@link TargetingCriteriaDiscoveryForLanguagesQuery} + * @return an instance of {@link TargetingCriteriaDiscoveryForLanguages} + */ + DataListHolder languages(TargetingCriteriaDiscoveryForLanguagesQuery query); + + /** + * @param query builds the query for querying of {@link TargetingCriteriaDiscoveryForLocationsQuery} + * @return an instance of {@link TargetingCriteriaDiscoveryForLocations} + */ + DataListHolder locations(TargetingCriteriaDiscoveryForLocationsQuery query); + + /** + * @param query builds the query for querying of {@link TargetingCriteriaDiscoveryForNetworkOperatorsQuery} + * @return an instance of {@link TargetingCriteriaDiscoveryForNetworkOperators} + */ + DataListHolder networkOperators(TargetingCriteriaDiscoveryForNetworkOperatorsQuery query); + + /** + * @param query builds the query for querying of {@link TargetingCriteriaDiscoveryForPlatformVersionsQuery} + * @return an instance of {@link TargetingCriteriaDiscoveryForPlatformVersions} + */ + DataListHolder platformVersions(TargetingCriteriaDiscoveryForPlatformVersionsQuery query); + + /** + * @param query builds the query for querying of {@link TargetingCriteriaDiscoveryForPlatformsQuery} + * @return an instance of {@link TargetingCriteriaDiscoveryForPlatforms} + */ + DataListHolder platforms(TargetingCriteriaDiscoveryForPlatformsQuery query); + + /** + * @param query builds the query for querying of {@link TargetingCriteriaDiscoveryForTvShowQuery} + * @return an instance of {@link TargetingCriteriaDiscoveryForTvShow} + */ + DataListHolder tvShow(TargetingCriteriaDiscoveryForTvShowQuery query); + + /** + * @param query builds the query for querying of {@link TargetingCriteriaDiscoveryForTvMarketQuery} + * @return an instance of {@link TargetingCriteriaDiscoveryForTvMarket} + */ + DataListHolder tvMarkets(TargetingCriteriaDiscoveryForTvMarketQuery query); + + /** + * @param query builds the query for querying of {@link TargetingCriteriaDiscoveryForTvGenreQuery} + * @return an instance of {@link TargetingCriteriaDiscoveryForTvGenre} + */ + DataListHolder tvGenres(TargetingCriteriaDiscoveryForTvGenreQuery query); + + /** + * @param query builds the query for querying of {@link TargetingCriteriaDiscoveryForTvChannelQuery} + * @return an instance of {@link TargetingCriteriaDiscoveryForTvChannel} + */ + DataListHolder tvChannels(TargetingCriteriaDiscoveryForTvChannelQuery query); +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaForm.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaForm.java new file mode 100644 index 00000000..ab39634d --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaForm.java @@ -0,0 +1,382 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.twitter.api.TwitterForm; + +/** + * Allow setting then entire set of {@link TargetingCriterion} for + * a particular {@link LineItem} all at once + * + * @author Hudson Mendes + */ +public interface TargetingCriteriaForm extends TwitterForm { + + /** + * A reference to the line item you are operating with in the request. + * Example Values: 43853bh6lk3n + * + * @param lineItemId identifies the {@link LineItem} + * @return the fluent builder + */ + public TargetingCriteriaForm forLineItem(String lineItemId); + + /** + * An event id to scope targeting to audiences associated with the event. + * Only one event can be targeted per line item. + * Example Values: aj12b + * + * @param eventId identifies the event + * @return the fluent builder + */ + public TargetingCriteriaForm forEvent(String eventId); + + /** + * The {@link Campaign} ID for use with Tweet Engager Retargeting. + * Example Values: 7ako2 + * + * @param campaignId identifies the campaign + * @return the fluent builder + */ + public TargetingCriteriaForm forRetargetingEngagementOfCampaign(String campaignId); + + /** + * The {@link PromotedUserReference} ID for use with Tweet Engager Retargeting. + * + * @param userId identifies the link between {@link PromotableUser} and {@link LineItem} + * @return the fluent builder + */ + public TargetingCriteriaForm forRetargetingEngagementOfPromotedUser(Long userId); + + /** + * The engagement type for use with Tweet Engager Retargeting. + * Valid values include IMPRESSION or ENGAGEMENT + * Example Values: IMPRESSION + * + * @param type identifies the type of engagement + * @return the fluent builder + */ + public TargetingCriteriaForm forRetargetingEngagementType(RetargetingEngagementType type); + + /** + * A comma-separated string of Twitter User identifiers to scope targeting to followers of on this line item. + * 100 users can be associated with a line item and the user IDs must correspond to promotable users + * for the current advertising account. Targeting deleted or invalid users will return an error block + * with an INVALID_TWITTER_USER_ID message. + * Example Values: 6253282, 7588892 + * + * @param followedUserIds identifies the ids of the users for whose followers we want to advertise. + * @return the fluent builder + */ + public TargetingCriteriaForm followersOfUsers(Long... followedUserIds); + + /** + * A comma-separated string of Twitter User identifiers to scope targeting to similar followers of on this line item. + * 100 users can be associated with a line item. Targeting deleted or invalid users will return an error block with + * an INVALID_TWITTER_USER_ID message + * Example Values: 6253282, 7588892 + * + * @param similiarUserIds the ids of the users for whose similars we want to advertise. + * @return the fluent builder. + */ + public TargetingCriteriaForm similarToUsers(Long... similiarUserIds); + + /** + * A comma-separated string of broad keywords to target. These are typically used to match expandable words appearing + * in any order within search queries for PROMOTED_TWEETS_IN_SEARCH. A maximum of 1,000 keywords may be attached to a + * line item. + * Example Values: good, bad, happy, shiny, people + * + * @param keywords to be advertised against + * @return the fluent builder + */ + public TargetingCriteriaForm withBroadKeywords(String... keywords); + + /** + * A comma-separated string of exact match keywords to target. These are typically used to match a very specific search + * query for PROMOTED_TWEETS_IN_SEARCH. A maximum of 1,000 keywords may be attached to a line item. + * Example Values: %23freebandnames, http%3A%2F%2Fen.wikipedia.org%2Fwiki%2FIn_Watermelon_Sugar + * + * @param keywords to be advertised against + * @return the fluent builder + */ + public TargetingCriteriaForm withExactKeywords(String... keywords); + + /** + * A comma-separated string of “unorderedâ€� keywords to target. These are typically used to match words appearing in any order + * within search queries for PROMOTED_TWEETS_IN_SEARCH. A maximum of 1,000 keywords may be attached to a line item. + * Example Values: good, bad, happy, shiny, people + * + * @param keywords to be advertised against + * @return the fluent builder + */ + public TargetingCriteriaForm withUnorderedKeywords(String... keywords); + + /** + * A comma-separated string of “phraseâ€� keywords to target. These are typically used to match phrases appearing within search queries for + * PROMOTED_TWEETS_IN_SEARCH. A maximum of 1,000 keywords may be attached to a line item. * + * Example Values: happy shiny people + * + * @param keywords to be advertised against + * @return the fluent builder + */ + public TargetingCriteriaForm withPhraseKeywords(String... keywords); + + /** + * A comma-separated string of “negative exact matchâ€� keywords to target. These are typically used to restrict a very specific search query + * for + * PROMOTED_TWEETS_IN_SEARCH. A maximum of 1,000 keywords may be attached to a line item. + * + * Example Values: %23freebandnames, http%3A%2F%2Fen.wikipedia.org%2Fwiki%2FIn_Watermelon_Sugar + * + * @param keywords not to be advertised against. + * @return the fluent builder + */ + public TargetingCriteriaForm withNegativeExactKeywords(String... keywords); + + /** + * A comma-separated string of “negative unorderedâ€� keywords to target. These are typically used to restrict matching keywords appearing in + * any + * order within search queries for PROMOTED_TWEETS_IN_SEARCH. A maximum of 1,000 keywords may be attached to a line item. + * Example Values: good, bad, happy, shiny, people + * + * @param keywords not to be advertised against. + * @return the fluent builder + */ + public TargetingCriteriaForm withNegativeUnorderedKeywords(String... keywords); + + /** + * A comma-separated string of “negative phraseâ€� keywords to target. These are typically used to restrict specific phrases from matching + * within + * search queries for PROMOTED_TWEETS_IN_SEARCH. A maximum of 1,000 keywords may be attached to a line item. + * Example Values: happy shiny people + * + * @param keywords not to be advertised against. + * @return the fluent builder + */ + public TargetingCriteriaForm withNegativePhraseKeywords(String... keywords); + + /** + * A comma-separated string of location identifiers to scope targeting to on this line item. 250 locations may be associated with a line item. + * Example Values: b6b8d75a320f81d9, 6c6fd550ac2d3d60 + * + * @param locations to which we want to advertise. + * @return the fluent builder + */ + public TargetingCriteriaForm withLocations(String... locations); + + /** + * A comma-separated string of interest identifiers to scope targeting to on this line item. 100 interests may be associated with a line item. + * Example Values: 19004, 19002 + * + * @param interests to which we want to advertise. + * @return the fluent builder + */ + public TargetingCriteriaForm withInterests(String... interests); + + /** + * A comma-separated string of gender identifiers to scope targeting to on this line item. Use “1â€� to limit to males, or “2â€�, to limit to + * females. + * Example Values: 1 (MALE, in our ENUM) + * + * @param gender to which we want to advertise. + * @return the fluent builder + */ + public TargetingCriteriaForm withGender(TargetingCriterionGender gender); + + /** + * A comma-separated string of age bucket identifiers to scope targeting to on this line item, only required when using targeting_type=AGE. See + * the age_buckets enum for a list of possible values. + * Example Values: AGE_25_TO_34 + * + * @param ageBuckets to which we want to advertise + * @return the fluent builder + */ + public TargetingCriteriaForm withAgeBuckets(TargetingCriterionAgeBucket... ageBuckets); + + /** + * A comma-separated string of Platform identifiers to scope targeting to on this line item. + * Example Values: 0, 4 + * + * @param platforms to which we want to advertise + * @return the fluent builder + */ + public TargetingCriteriaForm withPlatforms(String... platforms); + + /** + * A comma-separated string of platform version identifiers to scope targeting to on this line item. + * Example Values: 10, 14 + * + * @param versions to which we want to advertise + * @return the fluent builder + */ + public TargetingCriteriaForm withPlatformVersions(String... versions); + + /** + * A comma-separated string of device identifiers to scope targeting to on this line item. + * Example Values: 7, 23 + * + * @param devices to which we want to advertise + * @return the fluent builder + */ + public TargetingCriteriaForm withDevices(String... devices); + + /** + * If true, will only target users of mobile devices using wifi connections. If false, will target mobile consumers on carrier networks as well. + * Use targeting_value 1 for true, and 0 for false. + * Example Values: 1 + * + * @param wifiOnly true says to only advertise to wifi users; false states to anyone. Default is false. + * @return the fluent builder + */ + public TargetingCriteriaForm onlyWify(Boolean wifiOnly); + + /** + * A comma-separated string of TV channel identifiers to scope targeting to on this line item. + * Example Values: 3113,6945 + * + * @param channels to which we want to advertise + * @return the fluent builder + */ + public TargetingCriteriaForm withTvChannels(String... channels); + + /** + * A comma-separated string of TV genre identifiers to scope targeting to on this line item. + * Example Values: 9,15 + * + * @param genres to which we want to advertise + * @return the fluent builder + */ + public TargetingCriteriaForm withTvGenres(String... genres); + + /** + * A comma-separated string of TV show identifiers to scope targeting to on this line item. + * Example Values: 10024849207,10000271509 + * + * @param shows to which we want to advertise + * @return the fluent builder + */ + public TargetingCriteriaForm withTvShows(String... shows); + + /** + * A comma-separated string of tailored audience identifiers to scope targeting to on this line item. + * Example Values: b6b8d, 6c + * + * @param tailoredAudiences to which we want to advertise + * @return the fluent builder + */ + public TargetingCriteriaForm withTailoredAudiences(String... tailoredAudiences); + + /** + * A comma-separated string of tailored audience identifiers that should be expanded and to scope targeting to on this line item. + * Example Values: b6b8d, 6c6fd + * + * @param tailoredAudiencesExpanded to which we want to advertise + * @return the fluent builder + */ + public TargetingCriteriaForm withTailoredAudiencesExpanded(String... tailoredAudiencesExpanded); + + /** + * A comma-separated string of tailored audience identifiers to scope targeting to on this line item. Excluding audiences is available for + * tailored_audience_type CRM and WEB. + * Example Values: b6b8d, 6c6fd + * + * @param tailoredAudienceExclusions to which we want to advertise + * @return the fluent builder + */ + public TargetingCriteriaForm withTailoredAudiencesExclusion(String... tailoredAudienceExclusions); + + /** + * A comma-separated string of behavior identifiers to scope targeting to on this line item. + * Example Values: lfmj, lfrr + * + * @param behaviors to which we want to advertise + * @return the fluent builder + */ + public TargetingCriteriaForm withBehaviors(String... behaviors); + + /** + * A comma-separated string of behavior identifiers that should be expanded and to scope targeting to on this line item. + * Example Values: lfmj, lfrr + * + * @param behaviorsExpanded to which we want to advertise + * @return the fluent builder + */ + public TargetingCriteriaForm withBehaviorsExpaned(String... behaviorsExpanded); + + /** + * A comma-separated string of behavior identifiers scope targeting to on this line item. + * Example Values: lfmj, lfrr + * + * @param behavioursNegative to which we want to advertise + * @return the fluent builder + */ + public TargetingCriteriaForm withBehaviorsNegative(String... behavioursNegative); + + /** + * A comma-separated string of language identifiers to scope targeting to on this line item. + * Example Values: en, fi + * + * @param languages to which we want to advertise + * @return the fluent builder + */ + public TargetingCriteriaForm withLanguages(String... languages); + + /** + * A comma-separated string of network operator identifiers to scope targeting to on this line item. + * Example Values: lfmj, lfrr + * + * @param operators to which we want to advertise + * @return the fluent builder + */ + public TargetingCriteriaForm withNetworkOperators(String... operators); + + /** + * An integer in months, less-than, for network activation duration. + * Example Values: 3 + * + * @param months to which we want to advertise + * @return the fluent builder + */ + public TargetingCriteriaForm withNetworkActivationDurationLess(Integer months); + + /** + * An integer in months, greater-than-or-equal-to, for network activation duration. + * Example Values: 3 + * + * @param months to which we want to advertise + * @return the fluent builder + */ + public TargetingCriteriaForm withNetworkActivationDurationMoreOrEqualsTo(Integer months); + + /** + * A comma-separated string of app store category identifiers to scope targeting to on this line item. + * Example Values: lfmj, lfrr + * + * @param categories to which we want to advertise + * @return the fluent builder + */ + public TargetingCriteriaForm withAppStoreCategories(String... categories); + + /** + * A comma-separated string of app store category identifiers. Targeting will be scoped to lookalike app store categories on this line item. + * Example Values: lfmj, lfrr + * + * @param categories to which we want to advertise + * @return the fluent builder + */ + public TargetingCriteriaForm withAppStoreCategiresLookAlike(String... categories); +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaOperations.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaOperations.java new file mode 100644 index 00000000..7dc39098 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriteriaOperations.java @@ -0,0 +1,68 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.ApiException; +import org.springframework.social.MissingAuthorizationException; +import org.springframework.social.twitter.api.impl.DataListHolder; + +/** + * Interface defining the operations for targeting criterias (Ads API). + * + * @author Hudson Mendes + */ +public interface TargetingCriteriaOperations { + + /** + * Retrieves a {@link TargetingCriterion} related to an {@link AdvertisingAccount} referred to by its id. + * + * @param accountId identifies the account of which target criteria we wish to fetch. + * @param id identifies the target criteria that will be retrieved. + * @return an instance of {@link TargetingCriterion} + */ + TargetingCriterion getTargetingCriterion(String accountId, String id); + + /** + * Retrieves a list of {@link TargetingCriterion} related to an {@link AdvertisingAccount}. + * + * @param accountId identifies the account for which we want to retrieve targeting criteria. + * @param query The query parameters that will filter the request + * @return a list of {@link TargetingCriterion}. + */ + DataListHolder getTargetingCriterions(String accountId, TargetingCriterionQuery query); + + /** + * Creates a {@link TargetingCriterion} related to an {@link AdvertisingAccount} + * + * @param accountId identifies the account for which the targeting criteria will be created. + * @param data defines the parameters that we shall use to generate the targeting criteria + * @return an instance of {@link TargetingCriterion} + */ + TargetingCriterion createTargetingCriterion(String accountId, TargetingCriterionForm data); + + DataListHolder setTargetingCriteria(String accountId, TargetingCriteriaForm data); + + /** + * Deletes a {@link TargetingCriterion} related to an {@link AdvertisingAccount} found by its campaignId. + * + * @param accountId identifies the account of which targeting criteria we wish to delete. + * @param id identifies the targeting criteria that we desire to delete. + * @throws ApiException if there is an error while communicating with Twitter. + * @throws MissingAuthorizationException if TwitterTemplate was not created with OAuth credentials. + */ + void deleteTargetingCriterion(String accountId, String id); + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriterion.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriterion.java new file mode 100644 index 00000000..648a8f7b --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriterion.java @@ -0,0 +1,119 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import java.time.LocalDateTime; + +import org.springframework.social.twitter.api.TwitterObject; + +/** + * Represents a Targeting Criteria to drive a {@link Campaign}. + * + * Source: https://dev.twitter.com/ads/campaigns/keyword-targeting-timelines + * Keyword targeting is already fundamental to our Promoted Tweets in Search product, + * and now we are now expanding the power of keyword targeting to timelines, giving + * campaigns better reach. Keyword targeting in timeline enables platforms to target + * Twitter users based on keywords in their recent Tweets. + * + * @author Hudson Mendes + */ +public class TargetingCriterion extends TwitterObject { + private static final long serialVersionUID = 1L; + private final String id; + private final String accountId; + private final String lineItemId; + private final String name; + private final String targetingType; + private final String targetingValue; + private final Boolean tailoredAudienceExpansion; + private final TailoredAudienceType tailoredAudienceType; + private final Boolean deleted; + private final LocalDateTime createdAt; + private final LocalDateTime updatedAt; + + public TargetingCriterion( + String id, + String accountId, + String lineItemId, + String name, + String targetingType, + String targetingValue, + Boolean tailoredAudienceExpansion, + TailoredAudienceType tailoredAudienceType, + Boolean deleted, + LocalDateTime createdAt, + LocalDateTime updatedAt) { + + this.id = id; + this.accountId = accountId; + this.lineItemId = lineItemId; + this.name = name; + + this.targetingType = targetingType; + this.targetingValue = targetingValue; + + this.tailoredAudienceExpansion = tailoredAudienceExpansion; + this.tailoredAudienceType = tailoredAudienceType; + + this.deleted = deleted; + this.createdAt = createdAt; + this.updatedAt = updatedAt; + } + + public String getId() { + return id; + } + + public String getAccountId() { + return accountId; + } + + public String getLineItemId() { + return lineItemId; + } + + public String getName() { + return name; + } + + public String getTargetingType() { + return targetingType; + } + + public String getTargetingValue() { + return targetingValue; + } + + public Boolean isTailoredAudienceExpansion() { + return tailoredAudienceExpansion; + } + + public TailoredAudienceType getTailoredAudienceType() { + return tailoredAudienceType; + } + + public Boolean isDeleted() { + return deleted; + } + + public LocalDateTime getCreatedAt() { + return createdAt; + } + + public LocalDateTime getUpdatedAt() { + return updatedAt; + } +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriterionAgeBucket.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriterionAgeBucket.java new file mode 100644 index 00000000..cc01c485 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriterionAgeBucket.java @@ -0,0 +1,30 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +/** + * Represent the possible age buckets for a {@link TargetingCriterion} + * + * @author Hudson Mendes + */ +public enum TargetingCriterionAgeBucket { + AGE_18_TO_24, + AGE_25_TO_34, + AGE_35_TO_44, + AGE_45_TO_54, + AGE_55_TO_64, + AGE_OVER_65 +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriterionForm.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriterionForm.java new file mode 100644 index 00000000..9adf9d10 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriterionForm.java @@ -0,0 +1,77 @@ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.twitter.api.TwitterForm; + +/** + * Describes the contract for the builder of {@link TargetingCriterion}'s + * data that will be posted / patched to the endpoint. + * + * @author Hudson Mendes + */ +public interface TargetingCriterionForm extends TwitterForm { + + /** + * The {@link LineItem} to which {@link TargetingCriterion} is related to. + * + * @param lineItemId is the id of the {@link LineItem} + * @return the fluent builder + */ + public abstract TargetingCriterionForm withLineItem(String lineItemId); + + /** + * The name of the {@link TargetingCriterion} + * + * @param name of the {@link TargetingCriterion}; + * @return the fluent builder + */ + public abstract TargetingCriterionForm withName(String name); + + /** + * The targeting definition of the {@link TargetingCriterion}. + * + * @param targetingType is the type of targeting chosen. + * @param targetingValue is the value of the targeting chose. + * @return the fluent builder + */ + public abstract TargetingCriterionForm targeting(String targetingType, String targetingValue); + + /** + * The targeting definition of the {@link TargetingCriterion}. + * + * @param targetingType is the type of targeting chosen; maybe any of the set out in {@link TargetingCriterionType}. + * @param targetingValue is the value of the targeting chose. + * @return the fluent builder + */ + public abstract TargetingCriterionForm targeting(TargetingCriterionType targetingType, String targetingValue); + + /** + * Deletes the {@link TargetingCriterion} + * + * @return the fluent builder + */ + public abstract TargetingCriterionForm active(); + + /** + * Reactivate the {@link TargetingCriterion}. + * + * @return the fluent builder. + */ + public abstract TargetingCriterionForm deleted(); + + /** + * A boolean value for expansion. Only available for Tailored Audience CRM. + * + * @param targetAudienceExpansion if expansion should be run on tailored audiences + * @return the fluent builder + */ + public abstract TargetingCriterionForm withTargetedAudienceExpansion(final Boolean targetAudienceExpansion); + + /** + * A value for the tailored audience type. + * + * @param tailoredAudienceType Example Values: WEB, CRM, MOBILE, EXCLUDED_WEB,EXCLUDED_CRM, EXCLUDED_MOBILE + * @return the fluent builder + */ + public abstract TargetingCriterionForm withTargetedAudienceType(final TailoredAudienceType tailoredAudienceType); + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriterionGender.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriterionGender.java new file mode 100644 index 00000000..d91a0a90 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriterionGender.java @@ -0,0 +1,17 @@ +package org.springframework.social.twitter.api.advertising; + +public enum TargetingCriterionGender { + BOTH(null), + MALE(1), + FEMALE(2); + + private final Integer value; + + TargetingCriterionGender(Integer number) { + this.value = number; + } + + public Integer value() { + return value; + } +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriterionQuery.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriterionQuery.java new file mode 100644 index 00000000..58e94b53 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriterionQuery.java @@ -0,0 +1,35 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +import org.springframework.social.twitter.api.TwitterQueryForSortableEntity; + +/** + * Defines the data that will be used to query a list of {@link TargetingCriterion}. + * + * @author Hudson Mendes + * + */ +public interface TargetingCriterionQuery extends TwitterQueryForSortableEntity { + + /** + * Filter the results by a particular {@link LineItem}. + * + * @param lineItemId defines the id of the line item for which we are filtering. + * @return itself, allowing you to keep going with the setup of your filter. + */ + public TargetingCriterionQuery withLineItem(String lineItemId); +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriterionSorting.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriterionSorting.java new file mode 100644 index 00000000..635b5b91 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriterionSorting.java @@ -0,0 +1,27 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +/** + * This {@link TargetingCriterionSorting} was created to keep compatibility with + * the {@link TargetingCriterionQuery} interface. This has no option and should + * not be used. + * + * @author Hudson Mendes + * + */ +public enum TargetingCriterionSorting { +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriterionType.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriterionType.java new file mode 100644 index 00000000..16fca75c --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/TargetingCriterionType.java @@ -0,0 +1,66 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.advertising; + +/** + * Define a non-restrictive list of possible TargetTypes, + * that allow you to create targeting criterias. + * + * When developping for {@link TailoredAudience}, consider + * the type 'TAILORED_AUDIENCE' and explore {@link TailoredAudienceOperations} for its operations. + * + * @author Hudson Mendes + * + */ +public enum TargetingCriterionType { + AGE, + FOLLOWERS_OF_USER, + SIMILAR_TO_FOLLOWERS_OF_USER, + INTEREST, + LOCATION, + LANGUAGE, + PLATFORM, + PLATFORM_VERSION, + DEVICE, + WIFI_ONLY, + GENDER, + TV_CHANNEL, + TV_GENRE, + TV_SHOW, + TV_SHOW_AIRING_RESTRICTED, + + NETWORK_OPERATOR, + NETWORK_ACTIVATION_DURATION_LT, + NETWORK_ACTIVATION_DURATION_GTE, + + BROAD_KEYWORD, + UNORDERED_KEYWORD, + PHRASE_KEYWORD, + EXACT_KEYWORD, + NEGATIVE_PHRASE_KEYWORD, + NEGATIVE_UNORDERED_KEYWORD, + NEGATIVE_EXACT_KEYWORD, + + TAILORED_AUDIENCE, + + BEHAVIOR, + NEGATIVE_BEHAVIOR, + BEHAVIOR_EXPANDED, + + APP_STORE_CATEGORY, + APP_STORE_CATEGORY_LOOKALIKE, + EXCLUDE_APP_LIST +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/package-info.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/package-info.java new file mode 100644 index 00000000..3bc7b16f --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/advertising/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author Hudson Mendes + * + */ +package org.springframework.social.twitter.api.advertising; \ No newline at end of file diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/AbstractTrendsList.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/AbstractTrendsList.java index 55bb8f25..0ecef8a5 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/AbstractTrendsList.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/AbstractTrendsList.java @@ -34,7 +34,7 @@ * Abstract model class representing a list of trends. * @author Craig Walls */ -class AbstractTrendsList { +public class AbstractTrendsList { private final List list; public AbstractTrendsList(Map> trends, DateFormat dateFormat) { diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/AbstractTwitterOperations.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/AbstractTwitterOperations.java index 6989a2e7..e05937f0 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/AbstractTwitterOperations.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/AbstractTwitterOperations.java @@ -1,12 +1,12 @@ /* * Copyright 2014 the original author or authors. - * + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * + * + * http://www.apache.org/licenses/LICENSE-2.0 + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -18,55 +18,66 @@ import java.net.URI; import org.springframework.social.MissingAuthorizationException; -import org.springframework.social.support.URIBuilder; -import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; -class AbstractTwitterOperations { - - private final boolean isUserAuthorized; +public abstract class AbstractTwitterOperations { - private boolean isAppAuthorized; + private final boolean isUserAuthorized; - public AbstractTwitterOperations(boolean isUserAuthorized, boolean isAppAuthorized) { - this.isUserAuthorized = isUserAuthorized; - this.isAppAuthorized = isAppAuthorized; - } - - protected void requireUserAuthorization() { - if (!isUserAuthorized) { - throw new MissingAuthorizationException("twitter"); - } - } + private boolean isAppAuthorized; - protected void requireAppAuthorization() { - if (!isAppAuthorized) { - throw new MissingAuthorizationException("twitter"); - } - } - - protected void requireEitherUserOrAppAuthorization() { - if (!isUserAuthorized && !isAppAuthorized) { - throw new MissingAuthorizationException("twitter"); - } - } - - protected URI buildUri(String path) { - return buildUri(path, EMPTY_PARAMETERS); - } - - protected URI buildUri(String path, String parameterName, String parameterValue) { - MultiValueMap parameters = new LinkedMultiValueMap(); - parameters.set(parameterName, parameterValue); - return buildUri(path, parameters); - } - - protected URI buildUri(String path, MultiValueMap parameters) { - return URIBuilder.fromUri(API_URL_BASE + path).queryParams(parameters).build(); - } - - private static final String API_URL_BASE = "https://api.twitter.com/1.1/"; + public AbstractTwitterOperations(boolean isUserAuthorized, boolean isAppAuthorized) { + this.isUserAuthorized = isUserAuthorized; + this.isAppAuthorized = isAppAuthorized; + } - private static final LinkedMultiValueMap EMPTY_PARAMETERS = new LinkedMultiValueMap(); + protected void requireUserAuthorization() { + if (!isUserAuthorized) { + throw new MissingAuthorizationException("twitter"); + } + } + protected void requireAppAuthorization() { + if (!isAppAuthorized) { + throw new MissingAuthorizationException("twitter"); + } + } + + protected void requireEitherUserOrAppAuthorization() { + if (!isUserAuthorized && !isAppAuthorized) { + throw new MissingAuthorizationException("twitter"); + } + } + + /* + * @deprecated use the {@link TwitterApiUriBuilder} instead. with the builder, you may build URIs for the AdCampaign API as well. + */ + @Deprecated + protected URI buildUri(String path) { + return new TwitterApiBuilderForUri() + .withResource(path) + .build(); + } + + /* + * @deprecated use the {@link TwitterApiUriBuilder} instead. with the builder, you may build URIs for the AdCampaign API as well. + */ + @Deprecated + protected URI buildUri(String path, String parameterName, String parameterValue) { + return new TwitterApiBuilderForUri() + .withResource(path) + .withArgument(parameterName, parameterValue) + .build(); + } + + /* + * @deprecated use the {@link TwitterApiUriBuilder} instead. with the builder, you may build URIs for the AdCampaign API as well. + */ + @Deprecated + protected URI buildUri(String path, MultiValueMap parameters) { + return new TwitterApiBuilderForUri() + .withResource(path) + .withArgument(parameters) + .build(); + } } diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/AccountSettingsMixin.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/AccountSettingsMixin.java index d29854e1..119cdc4f 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/AccountSettingsMixin.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/AccountSettingsMixin.java @@ -1,3 +1,18 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.springframework.social.twitter.api.impl; import java.util.List; @@ -10,7 +25,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; @JsonIgnoreProperties(ignoreUnknown = true) -abstract class AccountSettingsMixin extends TwitterObjectMixin { +public abstract class AccountSettingsMixin extends TwitterObjectMixin { @JsonProperty("always_use_https") private boolean alwaysUseHttps; diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/ArrayUtils.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/ArrayUtils.java index 5269a6af..deb763d8 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/ArrayUtils.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/ArrayUtils.java @@ -15,7 +15,7 @@ */ package org.springframework.social.twitter.api.impl; -class ArrayUtils { +public class ArrayUtils { private ArrayUtils() { } diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/BlockTemplate.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/BlockTemplate.java index 22dcf4ef..4c28b9c4 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/BlockTemplate.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/BlockTemplate.java @@ -16,6 +16,8 @@ package org.springframework.social.twitter.api.impl; +import java.net.URI; + import org.springframework.social.twitter.api.BlockOperations; import org.springframework.social.twitter.api.CursoredList; import org.springframework.social.twitter.api.TwitterProfile; @@ -27,7 +29,7 @@ * Implementation of {@link BlockOperations}, providing a binding to Twitter's block REST resources. * @author Craig Walls */ -class BlockTemplate extends AbstractTwitterOperations implements BlockOperations { +public class BlockTemplate extends AbstractTwitterOperations implements BlockOperations { private final RestTemplate restTemplate; @@ -38,30 +40,34 @@ public BlockTemplate(RestTemplate restTemplate, boolean isAuthorizedForUser, boo public TwitterProfile block(long userId) { requireUserAuthorization(); - MultiValueMap request = new LinkedMultiValueMap(); - request.set("user_id", String.valueOf(userId)); - return restTemplate.postForObject(buildUri("blocks/create.json"), request, TwitterProfile.class); + return restTemplate.postForObject( + new TwitterApiBuilderForUri().withResource(TwitterApiUriResourceForStandard.BLOCKS_CREATE).build(), + new RestRequestBodyBuilder().withField("user_id", String.valueOf(userId)).build(), + TwitterProfile.class); } public TwitterProfile block(String screenName) { requireUserAuthorization(); - MultiValueMap request = new LinkedMultiValueMap(); - request.set("screen_name", screenName); - return restTemplate.postForObject(buildUri("blocks/create.json"), request, TwitterProfile.class); + return restTemplate.postForObject( + new TwitterApiBuilderForUri().withResource(TwitterApiUriResourceForStandard.BLOCKS_CREATE).build(), + new RestRequestBodyBuilder().withField("screen_name", screenName).build(), + TwitterProfile.class); } public TwitterProfile unblock(long userId) { requireUserAuthorization(); - MultiValueMap request = new LinkedMultiValueMap(); - request.set("user_id", String.valueOf(userId)); - return restTemplate.postForObject(buildUri("blocks/destroy.json"), request, TwitterProfile.class); + return restTemplate.postForObject( + new TwitterApiBuilderForUri().withResource(TwitterApiUriResourceForStandard.BLOCKS_DESTROY).build(), + new RestRequestBodyBuilder().withField("user_id", String.valueOf(userId)).build(), + TwitterProfile.class); } public TwitterProfile unblock(String screenName) { requireUserAuthorization(); MultiValueMap request = new LinkedMultiValueMap(); request.set("screen_name", screenName); - return restTemplate.postForObject(buildUri("blocks/destroy.json"), request, TwitterProfile.class); + URI resourceUri = new TwitterApiBuilderForUri().withResource(TwitterApiUriResourceForStandard.BLOCKS_DESTROY).build(); + return restTemplate.postForObject(resourceUri, request, TwitterProfile.class); } public CursoredList getBlockedUsers() { @@ -70,9 +76,13 @@ public CursoredList getBlockedUsers() { public CursoredList getBlockedUsersInCursor(long cursor) { requireUserAuthorization(); - LinkedMultiValueMap parameters = new LinkedMultiValueMap(); - parameters.set("cursor", String.valueOf(cursor)); - return restTemplate.getForObject(buildUri("blocks/list.json", parameters), CursoredTwitterProfileUsersList.class).getList(); + return restTemplate.getForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.BLOCKS) + .withArgument("cursor", String.valueOf(cursor)) + .build(), + CursoredTwitterProfileUsersList.class + ).getList(); } public CursoredList getBlockedUserIds() { @@ -81,9 +91,13 @@ public CursoredList getBlockedUserIds() { public CursoredList getBlockedUserIdsInCursor(long cursor) { requireUserAuthorization(); - LinkedMultiValueMap parameters = new LinkedMultiValueMap(); - parameters.set("cursor", String.valueOf(cursor)); - return restTemplate.getForObject(buildUri("blocks/ids.json", parameters), CursoredLongList.class).getList(); + return restTemplate.getForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.BLOCKS_IDS) + .withArgument("cursor", String.valueOf(cursor)) + .build(), + CursoredLongList.class + ).getList(); } } diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/ClientAuthorizedTwitterTemplate.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/ClientAuthorizedTwitterTemplate.java index 36d40d6f..cf7e029e 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/ClientAuthorizedTwitterTemplate.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/ClientAuthorizedTwitterTemplate.java @@ -23,7 +23,7 @@ * the API binding needs to use OAuth 1.0a for user requests and OAuth 2 for client requests. * @author Craig Walls */ -class ClientAuthorizedTwitterTemplate extends AbstractOAuth2ApiBinding { +public class ClientAuthorizedTwitterTemplate extends AbstractOAuth2ApiBinding { public ClientAuthorizedTwitterTemplate(String clientToken) { super(clientToken); diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/CursoredLongList.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/CursoredLongList.java index 88457829..5fe8caf4 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/CursoredLongList.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/CursoredLongList.java @@ -27,7 +27,7 @@ @JsonIgnoreProperties(ignoreUnknown=true) @JsonIgnoreType -class CursoredLongList { +public class CursoredLongList { private final CursoredList list; diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/CursoredTwitterProfileList.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/CursoredTwitterProfileUsersList.java similarity index 65% rename from spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/CursoredTwitterProfileList.java rename to spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/CursoredTwitterProfileUsersList.java index edc1a07d..12735651 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/CursoredTwitterProfileList.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/CursoredTwitterProfileUsersList.java @@ -1,12 +1,12 @@ /* * Copyright 2011 the original author or authors. - * + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * + * + * http://www.apache.org/licenses/LICENSE-2.0 + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -27,22 +27,23 @@ /** * Holder for list of TwitterProfile objects pulled from a JSON object's "users" property. + * * @author Jeremy Appel */ @JsonIgnoreProperties(ignoreUnknown = true) -class CursoredTwitterProfileUsersList { - private final CursoredList list; +public class CursoredTwitterProfileUsersList { + private final CursoredList list; - @JsonCreator - public CursoredTwitterProfileUsersList( - @JsonProperty("users") List list, - @JsonProperty("previous_cursor") long previousCursor, - @JsonProperty("next_cursor") long nextCursor) { - this.list = new CursoredList(list, previousCursor, nextCursor); - } + @JsonCreator + public CursoredTwitterProfileUsersList( + @JsonProperty("users") List list, + @JsonProperty("previous_cursor") long previousCursor, + @JsonProperty("next_cursor") long nextCursor) { + this.list = new CursoredList(list, previousCursor, nextCursor); + } - @JsonIgnore - public CursoredList getList() { - return list; - } + @JsonIgnore + public CursoredList getList() { + return list; + } } diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/DataListHolder.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/DataListHolder.java new file mode 100644 index 00000000..46e0f40e --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/DataListHolder.java @@ -0,0 +1,75 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Most of the Twitter Ads API responses for SINGLE + * within a "data" attribute within the root result object: + * https://dev.twitter.com/ads/reference/get/accounts/%3Aaccount_id/targeting_criteria/%3Aid + * + * This forces us to create a holder class that can receive that "data" JsonProperty + * in its contructor, allowing our Mixin class to launch and do the actual object conversion. + * + * Our {@link DataSingleHolder} is the abstract/generic object that kills all + * the repetition necessary to create on holder for each of those. + * + * @author Hudson Mendes + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class DataListHolder implements Serializable { + private static final long serialVersionUID = 1L; + private final List list; + private final String dataType; + private final String nextCursor; + private final Long totalCount; + + @JsonCreator + public DataListHolder( + @JsonProperty("data") List data, + @JsonProperty("data_type") String dataType, + @JsonProperty("next_cursor") String nextCursor, + @JsonProperty("total_count") Long totalCount) { + + this.list = new ArrayList(data); + this.dataType = dataType; + this.nextCursor = nextCursor; + this.totalCount = totalCount; + } + + public List getList() { + return this.list; + } + + public String getDataType() { + return this.dataType; + } + + public String getNextCursor() { + return this.nextCursor; + } + + public Long getTotalCount() { + return totalCount; + } +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/DataSingleHolder.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/DataSingleHolder.java new file mode 100644 index 00000000..e294f4a3 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/DataSingleHolder.java @@ -0,0 +1,47 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + + +/** + * Most of the Twitter Ads API responses for SINGLE + * within a "data" attribute within the root result object: + * https://dev.twitter.com/ads/reference/get/accounts/%3Aaccount_id/targeting_criteria/%3Aid + * + * This forces us to create a holder class that can receive that "data" JsonProperty + * in its contructor, allowing our Mixin class to launch and do the actual object conversion. + * + * Our {@link DataSingleHolder} is the abstract/generic object that kills all + * the repetition necessary to create on holder for each of those. + * @author Hudson Mendes + */ +@JsonIgnoreProperties(ignoreUnknown=true) +public class DataSingleHolder { + private final TEntity data; + + @JsonCreator + DataSingleHolder(@JsonProperty("data") TEntity data) { + this.data = data; + } + + public TEntity getData() { + return this.data; + } +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/DataStatsHolder.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/DataStatsHolder.java new file mode 100644 index 00000000..159c59fa --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/DataStatsHolder.java @@ -0,0 +1,55 @@ +package org.springframework.social.twitter.api.impl; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.springframework.social.twitter.api.advertising.StatisticsSnapshot; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class DataStatsHolder { + + private final List list; + + @JsonCreator + public DataStatsHolder(@JsonProperty("data") JsonNode data) + throws JsonParseException, JsonMappingException, ClassNotFoundException, IOException { + + this.list = makeListFrom(data); + } + + private List makeListFrom(JsonNode node) + throws JsonParseException, JsonMappingException, IOException, ClassNotFoundException { + + List items = new ArrayList<>(); + if (node.isArray()) + for (JsonNode child : node) + populateWithItem(items, child); + else + populateWithItem(items, node); + + return items; + } + + private void populateWithItem( + List list, + JsonNode node) throws JsonParseException, JsonMappingException, IOException, ClassNotFoundException { + list.add(new ObjectMapper() + .registerModule(new TwitterModule()) + .readValue( + node.toString(), + StatisticsSnapshot.class)); + } + + public List getList() { + return list; + } +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/DirectMessageList.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/DirectMessageList.java index 19efcbbf..3d34232e 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/DirectMessageList.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/DirectMessageList.java @@ -25,5 +25,5 @@ * @author Craig Walls */ @SuppressWarnings("serial") -class DirectMessageList extends ArrayList { +public class DirectMessageList extends ArrayList { } diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/DirectMessageMixin.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/DirectMessageMixin.java index acb6e563..c6fca3a0 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/DirectMessageMixin.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/DirectMessageMixin.java @@ -29,7 +29,7 @@ * @author Craig Walls */ @JsonIgnoreProperties(ignoreUnknown = true) -abstract class DirectMessageMixin extends TwitterObjectMixin { +public abstract class DirectMessageMixin extends TwitterObjectMixin { @JsonCreator DirectMessageMixin( @JsonProperty("id") long id, diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/DirectMessageTemplate.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/DirectMessageTemplate.java index d451cef9..81df5eb6 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/DirectMessageTemplate.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/DirectMessageTemplate.java @@ -19,15 +19,13 @@ import org.springframework.social.twitter.api.DirectMessage; import org.springframework.social.twitter.api.DirectMessageOperations; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; import org.springframework.web.client.RestTemplate; /** * Implementation of {@link DirectMessageOperations}, providing a binding to Twitter's direct message-oriented REST resources. * @author Craig Walls */ -class DirectMessageTemplate extends AbstractTwitterOperations implements DirectMessageOperations { +public class DirectMessageTemplate extends AbstractTwitterOperations implements DirectMessageOperations { private final RestTemplate restTemplate; @@ -46,8 +44,12 @@ public List getDirectMessagesReceived(int page, int pageSize) { public List getDirectMessagesReceived(int page, int pageSize, long sinceId, long maxId) { requireUserAuthorization(); - MultiValueMap parameters = PagingUtils.buildPagingParametersWithCount(page, pageSize, sinceId, maxId); - return restTemplate.getForObject(buildUri("direct_messages.json", parameters), DirectMessageList.class); + return restTemplate.getForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.DIRECTMESSAGES) + .withArgument(PagingUtils.buildPagingParametersWithCount(page, pageSize, sinceId, maxId)) + .build(), + DirectMessageList.class); } public List getDirectMessagesSent() { @@ -60,36 +62,52 @@ public List getDirectMessagesSent(int page, int pageSize) { public List getDirectMessagesSent(int page, int pageSize, long sinceId, long maxId) { requireUserAuthorization(); - MultiValueMap parameters = PagingUtils.buildPagingParametersWithCount(page, pageSize, sinceId, maxId); - return restTemplate.getForObject(buildUri("direct_messages/sent.json", parameters), DirectMessageList.class); + return restTemplate.getForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.DIRECTMESSAGES_SENT) + .withArgument(PagingUtils.buildPagingParametersWithCount(page, pageSize, sinceId, maxId)) + .build(), + DirectMessageList.class); } public DirectMessage getDirectMessage(long id) { requireUserAuthorization(); - return restTemplate.getForObject(buildUri("direct_messages/show.json", "id", String.valueOf(id)), DirectMessage.class); + return restTemplate.getForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.DIRECTMESSAGES_SHOW) + .withArgument("id", String.valueOf(id)) + .build(), + DirectMessage.class); } public DirectMessage sendDirectMessage(String toScreenName, String text) { requireUserAuthorization(); - MultiValueMap data = new LinkedMultiValueMap(); - data.add("screen_name", String.valueOf(toScreenName)); - data.add("text", text); - return restTemplate.postForObject(buildUri("direct_messages/new.json"), data, DirectMessage.class); + return restTemplate.postForObject( + new TwitterApiBuilderForUri().withResource(TwitterApiUriResourceForStandard.DIRECTMESSAGES_NEW).build(), + new RestRequestBodyBuilder() + .withField("screen_name", String.valueOf(toScreenName)) + .withField("text", text) + .build(), + DirectMessage.class); } public DirectMessage sendDirectMessage(long toUserId, String text) { requireUserAuthorization(); - MultiValueMap data = new LinkedMultiValueMap(); - data.add("user_id", String.valueOf(toUserId)); - data.add("text", text); - return restTemplate.postForObject(buildUri("direct_messages/new.json"), data, DirectMessage.class); + return restTemplate.postForObject( + new TwitterApiBuilderForUri().withResource(TwitterApiUriResourceForStandard.DIRECTMESSAGES_NEW).build(), + new RestRequestBodyBuilder() + .withField("user_id", String.valueOf(toUserId)) + .withField("text", text) + .build(), + DirectMessage.class); } public void deleteDirectMessage(long messageId) { requireUserAuthorization(); - MultiValueMap data = new LinkedMultiValueMap(); - data.add("id", String.valueOf(messageId)); - restTemplate.postForObject(buildUri("direct_messages/destroy.json"), data, DirectMessage.class); + restTemplate.postForObject( + new TwitterApiBuilderForUri().withResource(TwitterApiUriResourceForStandard.DIRECTMESSAGES_DESTROY).build(), + new RestRequestBodyBuilder().withField("id", String.valueOf(messageId)).build(), + DirectMessage.class); } } diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/EntitiesMixin.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/EntitiesMixin.java index 4a4fc875..355ed4b9 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/EntitiesMixin.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/EntitiesMixin.java @@ -1,12 +1,12 @@ /* * Copyright 2014 the original author or authors. - * + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * + * + * http://www.apache.org/licenses/LICENSE-2.0 + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -27,13 +27,13 @@ import com.fasterxml.jackson.annotation.JsonProperty; @JsonIgnoreProperties(ignoreUnknown = true) -abstract class EntitiesMixin extends TwitterObjectMixin { +public abstract class EntitiesMixin extends TwitterObjectMixin { + + @JsonCreator + public EntitiesMixin( + @JsonProperty("urls") List urls, + @JsonProperty("hashtags") List tags, + @JsonProperty("user_mentions") List mentions, + @JsonProperty("media") List media) {} - @JsonCreator - public EntitiesMixin( - @JsonProperty("urls") List urls, - @JsonProperty("hashtags") List tags, - @JsonProperty("user_mentions") List mentions, - @JsonProperty("media") List media) {} - } diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/FriendTemplate.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/FriendTemplate.java index aa1a712a..0c79603a 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/FriendTemplate.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/FriendTemplate.java @@ -28,7 +28,7 @@ * Implementation of {@link FriendTemplate}, providing a binding to Twitter's friends and followers-oriented REST resources. * @author Craig Walls */ -class FriendTemplate extends AbstractTwitterOperations implements FriendOperations { +public class FriendTemplate extends AbstractTwitterOperations implements FriendOperations { private final RestTemplate restTemplate; @@ -43,9 +43,13 @@ public CursoredList getFriends() { public CursoredList getFriendsInCursor(long cursor) { requireUserAuthorization(); - LinkedMultiValueMap parameters = new LinkedMultiValueMap(); - parameters.set("cursor", String.valueOf(cursor)); - return restTemplate.getForObject(buildUri("friends/list.json", parameters), CursoredTwitterProfileUsersList.class).getList(); + return restTemplate.getForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.FRIENDS) + .withArgument("cursor", String.valueOf(cursor)) + .build(), + CursoredTwitterProfileUsersList.class + ).getList(); } public CursoredList getFriends(long userId) { @@ -54,10 +58,14 @@ public CursoredList getFriends(long userId) { public CursoredList getFriendsInCursor(long userId, long cursor) { requireEitherUserOrAppAuthorization(); - LinkedMultiValueMap parameters = new LinkedMultiValueMap(); - parameters.set("cursor", String.valueOf(cursor)); - parameters.set("user_id", String.valueOf(userId)); - return restTemplate.getForObject(buildUri("friends/list.json", parameters), CursoredTwitterProfileUsersList.class).getList(); + return restTemplate.getForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.FRIENDS) + .withArgument("cursor", String.valueOf(cursor)) + .withArgument("user_id", String.valueOf(userId)) + .build(), + CursoredTwitterProfileUsersList.class + ).getList(); } public CursoredList getFriends(String screenName) { @@ -66,10 +74,14 @@ public CursoredList getFriends(String screenName) { public CursoredList getFriendsInCursor(String screenName, long cursor) { requireEitherUserOrAppAuthorization(); - LinkedMultiValueMap parameters = new LinkedMultiValueMap(); - parameters.set("cursor", String.valueOf(cursor)); - parameters.set("screen_name", String.valueOf(screenName)); - return restTemplate.getForObject(buildUri("friends/list.json", parameters), CursoredTwitterProfileUsersList.class).getList(); + return restTemplate.getForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.FRIENDS) + .withArgument("cursor", String.valueOf(cursor)) + .withArgument("screen_name", String.valueOf(screenName)) + .build(), + CursoredTwitterProfileUsersList.class + ).getList(); } public CursoredList getFriendIds() { @@ -78,7 +90,13 @@ public CursoredList getFriendIds() { public CursoredList getFriendIdsInCursor(long cursor) { requireUserAuthorization(); - return restTemplate.getForObject(buildUri("friends/ids.json", "cursor", String.valueOf(cursor)), CursoredLongList.class).getList(); + return restTemplate.getForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.FRIENDS_IDS) + .withArgument("cursor", String.valueOf(cursor)) + .build(), + CursoredLongList.class + ).getList(); } public CursoredList getFriendIds(long userId) { @@ -87,10 +105,14 @@ public CursoredList getFriendIds(long userId) { public CursoredList getFriendIdsInCursor(long userId, long cursor) { requireEitherUserOrAppAuthorization(); - LinkedMultiValueMap parameters = new LinkedMultiValueMap(); - parameters.set("cursor", String.valueOf(cursor)); - parameters.set("user_id", String.valueOf(userId)); - return restTemplate.getForObject(buildUri("friends/ids.json", parameters), CursoredLongList.class).getList(); + return restTemplate.getForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.FRIENDS_IDS) + .withArgument("cursor", String.valueOf(cursor)) + .withArgument("user_id", String.valueOf(userId)) + .build(), + CursoredLongList.class + ).getList(); } public CursoredList getFriendIds(String screenName) { @@ -99,10 +121,14 @@ public CursoredList getFriendIds(String screenName) { public CursoredList getFriendIdsInCursor(String screenName, long cursor) { requireEitherUserOrAppAuthorization(); - LinkedMultiValueMap parameters = new LinkedMultiValueMap(); - parameters.set("cursor", String.valueOf(cursor)); - parameters.set("screen_name", screenName); - return restTemplate.getForObject(buildUri("friends/ids.json", parameters), CursoredLongList.class).getList(); + return restTemplate.getForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.FRIENDS_IDS) + .withArgument("cursor", String.valueOf(cursor)) + .withArgument("screen_name", screenName) + .build(), + CursoredLongList.class + ).getList(); } public CursoredList getFollowers() { @@ -111,9 +137,13 @@ public CursoredList getFollowers() { public CursoredList getFollowersInCursor(long cursor) { requireUserAuthorization(); - LinkedMultiValueMap parameters = new LinkedMultiValueMap(); - parameters.set("cursor", String.valueOf(cursor)); - return restTemplate.getForObject(buildUri("followers/list.json", parameters), CursoredTwitterProfileUsersList.class).getList(); + return restTemplate.getForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.FOLLOWERS) + .withArgument("cursor", String.valueOf(cursor)) + .build(), + CursoredTwitterProfileUsersList.class + ).getList(); } public CursoredList getFollowers(long userId) { @@ -122,10 +152,14 @@ public CursoredList getFollowers(long userId) { public CursoredList getFollowersInCursor(long userId, long cursor) { requireEitherUserOrAppAuthorization(); - LinkedMultiValueMap parameters = new LinkedMultiValueMap(); - parameters.set("cursor", String.valueOf(cursor)); - parameters.set("user_id", String.valueOf(userId)); - return restTemplate.getForObject(buildUri("followers/list.json", parameters), CursoredTwitterProfileUsersList.class).getList(); + return restTemplate.getForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.FOLLOWERS) + .withArgument("cursor", String.valueOf(cursor)) + .withArgument("user_id", String.valueOf(userId)) + .build(), + CursoredTwitterProfileUsersList.class + ).getList(); } public CursoredList getFollowers(String screenName) { @@ -134,10 +168,14 @@ public CursoredList getFollowers(String screenName) { public CursoredList getFollowersInCursor(String screenName, long cursor) { requireEitherUserOrAppAuthorization(); - LinkedMultiValueMap parameters = new LinkedMultiValueMap(); - parameters.set("cursor", String.valueOf(cursor)); - parameters.set("screen_name", String.valueOf(screenName)); - return restTemplate.getForObject(buildUri("followers/list.json", parameters), CursoredTwitterProfileUsersList.class).getList(); + return restTemplate.getForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.FOLLOWERS) + .withArgument("cursor", String.valueOf(cursor)) + .withArgument("screen_name", String.valueOf(screenName)) + .build(), + CursoredTwitterProfileUsersList.class + ).getList(); } public CursoredList getFollowerIds() { @@ -146,7 +184,13 @@ public CursoredList getFollowerIds() { public CursoredList getFollowerIdsInCursor(long cursor) { requireUserAuthorization(); - return restTemplate.getForObject(buildUri("followers/ids.json", "cursor", String.valueOf(cursor)), CursoredLongList.class).getList(); + return restTemplate.getForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.FOLLOWERS_IDS) + .withArgument("cursor", String.valueOf(cursor)) + .build(), + CursoredLongList.class + ).getList(); } public CursoredList getFollowerIds(long userId) { @@ -155,10 +199,14 @@ public CursoredList getFollowerIds(long userId) { public CursoredList getFollowerIdsInCursor(long userId, long cursor) { requireEitherUserOrAppAuthorization(); - LinkedMultiValueMap parameters = new LinkedMultiValueMap(); - parameters.set("cursor", String.valueOf(cursor)); - parameters.set("user_id", String.valueOf(userId)); - return restTemplate.getForObject(buildUri("followers/ids.json", parameters), CursoredLongList.class).getList(); + return restTemplate.getForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.FOLLOWERS_IDS) + .withArgument("cursor", String.valueOf(cursor)) + .withArgument("user_id", String.valueOf(userId)) + .build(), + CursoredLongList.class + ).getList(); } public CursoredList getFollowerIds(String screenName) { @@ -167,62 +215,110 @@ public CursoredList getFollowerIds(String screenName) { public CursoredList getFollowerIdsInCursor(String screenName, long cursor) { requireEitherUserOrAppAuthorization(); - LinkedMultiValueMap parameters = new LinkedMultiValueMap(); - parameters.set("cursor", String.valueOf(cursor)); - parameters.set("screen_name", screenName); - return restTemplate.getForObject(buildUri("followers/ids.json", parameters), CursoredLongList.class).getList(); + return restTemplate.getForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.FOLLOWERS_IDS) + .withArgument("cursor", String.valueOf(cursor)) + .withArgument("screen_name", screenName) + .build(), + CursoredLongList.class + ).getList(); } public String follow(long userId) { requireUserAuthorization(); - return (String) restTemplate.postForObject(buildUri("friendships/create.json", "user_id", String.valueOf(userId)), EMPTY_DATA, Map.class).get("screen_name"); + return (String) restTemplate.postForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.FRIENDSHIPS_CREATE) + .withArgument("user_id", String.valueOf(userId)) + .build(), + EMPTY_DATA, + Map.class + ).get("screen_name"); } public String follow(String screenName) { requireUserAuthorization(); - return (String) restTemplate.postForObject(buildUri("friendships/create.json", "screen_name", screenName), EMPTY_DATA, Map.class).get("screen_name"); + return (String) restTemplate.postForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.FRIENDSHIPS_CREATE) + .withArgument("screen_name", screenName) + .build(), + EMPTY_DATA, + Map.class + ).get("screen_name"); } public String unfollow(long userId) { requireUserAuthorization(); - return (String) restTemplate.postForObject(buildUri("friendships/destroy.json", "user_id", String.valueOf(userId)), EMPTY_DATA, Map.class).get("screen_name"); + return (String) restTemplate.postForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.FRIENDSHIPS_DESTROY) + .withArgument("user_id", String.valueOf(userId)) + .build(), + EMPTY_DATA, + Map.class + ).get("screen_name"); } public String unfollow(String screenName) { requireUserAuthorization(); - return (String) restTemplate.postForObject(buildUri("friendships/destroy.json", "screen_name", screenName), EMPTY_DATA, Map.class).get("screen_name"); + return (String) restTemplate.postForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.FRIENDSHIPS_DESTROY) + .withArgument("screen_name", screenName) + .build(), + EMPTY_DATA, + Map.class + ).get("screen_name"); } public TwitterProfile enableNotifications(long userId) { requireUserAuthorization(); - LinkedMultiValueMap params = new LinkedMultiValueMap(); - params.set("user_id", String.valueOf(userId)); - params.set("device", "true"); - return restTemplate.postForObject(buildUri("friendships/update.json", params), EMPTY_DATA, TwitterProfile.class); + return restTemplate.postForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.FRIENDSHIPS_UPDATE) + .withArgument("user_id", String.valueOf(userId)) + .withArgument("device", "true") + .build(), + EMPTY_DATA, + TwitterProfile.class); } public TwitterProfile enableNotifications(String screenName) { requireUserAuthorization(); - LinkedMultiValueMap params = new LinkedMultiValueMap(); - params.set("screen_name", screenName); - params.set("device", "true"); - return restTemplate.postForObject(buildUri("friendships/update.json", params), EMPTY_DATA, TwitterProfile.class); + return restTemplate.postForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.FRIENDSHIPS_UPDATE) + .withArgument("screen_name", screenName) + .withArgument("device", "true") + .build(), + EMPTY_DATA, + TwitterProfile.class); } public TwitterProfile disableNotifications(long userId) { requireUserAuthorization(); - LinkedMultiValueMap params = new LinkedMultiValueMap(); - params.set("user_id", String.valueOf(userId)); - params.set("device", "false"); - return restTemplate.postForObject(buildUri("friendships/update.json", params), EMPTY_DATA, TwitterProfile.class); + return restTemplate.postForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.FRIENDSHIPS_UPDATE) + .withArgument("user_id", String.valueOf(userId)) + .withArgument("device", "false") + .build(), + EMPTY_DATA, + TwitterProfile.class); } public TwitterProfile disableNotifications(String screenName) { requireUserAuthorization(); - LinkedMultiValueMap params = new LinkedMultiValueMap(); - params.set("screen_name", screenName); - params.set("device", "false"); - return restTemplate.postForObject(buildUri("friendships/update.json", params), EMPTY_DATA, TwitterProfile.class); + return restTemplate.postForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.FRIENDSHIPS_UPDATE) + .withArgument("screen_name", screenName) + .withArgument("device", "false") + .build(), + EMPTY_DATA, + TwitterProfile.class); } public CursoredList getIncomingFriendships() { @@ -231,7 +327,13 @@ public CursoredList getIncomingFriendships() { public CursoredList getIncomingFriendships(long cursor) { requireUserAuthorization(); - return restTemplate.getForObject(buildUri("friendships/incoming.json", "cursor", String.valueOf(cursor)), CursoredLongList.class).getList(); + return restTemplate.getForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.FRIENDSHIPS_INCOMING) + .withArgument("cursor", String.valueOf(cursor)) + .build(), + CursoredLongList.class + ).getList(); } public CursoredList getOutgoingFriendships() { @@ -240,7 +342,13 @@ public CursoredList getOutgoingFriendships() { public CursoredList getOutgoingFriendships(long cursor) { requireUserAuthorization(); - return restTemplate.getForObject(buildUri("friendships/outgoing.json", "cursor", String.valueOf(cursor)), CursoredLongList.class).getList(); + return restTemplate.getForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.FRIENDSHIPS_OUTGOING) + .withArgument("cursor", String.valueOf(cursor)) + .build(), + CursoredLongList.class + ).getList(); } private static final MultiValueMap EMPTY_DATA = new LinkedMultiValueMap(); diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/GeoTemplate.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/GeoTemplate.java index 415b0e2c..9ad70b53 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/GeoTemplate.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/GeoTemplate.java @@ -1,12 +1,12 @@ /* * Copyright 2014 the original author or authors. - * + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * + * + * http://www.apache.org/licenses/LICENSE-2.0 + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -28,87 +28,127 @@ public class GeoTemplate extends AbstractTwitterOperations implements GeoOperations { - private final RestTemplate restTemplate; - - public GeoTemplate(RestTemplate restTemplate, boolean isAuthorizedForUser, boolean isAuthorizedForApp) { - super(isAuthorizedForUser, isAuthorizedForApp); - this.restTemplate = restTemplate; - } - - public Place getPlace(String placeId) { - requireUserAuthorization(); - return restTemplate.getForObject(buildUri("geo/id/" + placeId + ".json"), Place.class); - } - - public List reverseGeoCode(double latitude, double longitude) { - return reverseGeoCode(latitude, longitude, null, null); - } - - public List reverseGeoCode(double latitude, double longitude, PlaceType granularity, String accuracy) { - requireUserAuthorization(); - MultiValueMap parameters = buildGeoParameters(latitude, longitude, granularity, accuracy, null); - return restTemplate.getForObject(buildUri("geo/reverse_geocode.json", parameters), PlacesList.class).getList(); - } - - public List search(double latitude, double longitude) { - return search(latitude, longitude, null, null, null); - } - - public List search(double latitude, double longitude, PlaceType granularity, String accuracy, String query) { - requireUserAuthorization(); - MultiValueMap parameters = buildGeoParameters(latitude, longitude, granularity, accuracy, query); - return restTemplate.getForObject(buildUri("geo/search.json", parameters), PlacesList.class).getList(); - } - - public SimilarPlaces findSimilarPlaces(double latitude, double longitude, String name) { - return findSimilarPlaces(latitude, longitude, name, null, null); - } - - public SimilarPlaces findSimilarPlaces(double latitude, double longitude, String name, String streetAddress, String containedWithin) { - requireUserAuthorization(); - MultiValueMap parameters = buildPlaceParameters(latitude, longitude, name, streetAddress, containedWithin); - SimilarPlacesResponse response = restTemplate.getForObject(buildUri("geo/similar_places.json", parameters), SimilarPlacesResponse.class); - PlacePrototype placePrototype = new PlacePrototype(response.getToken(), latitude, longitude, name, streetAddress, containedWithin); - return new SimilarPlaces(response.getPlaces(), placePrototype); - } - - public Place createPlace(PlacePrototype placePrototype) { - requireUserAuthorization(); - MultiValueMap request = buildPlaceParameters(placePrototype.getLatitude(), placePrototype.getLongitude(), placePrototype.getName(), placePrototype.getStreetAddress(), placePrototype.getContainedWithin()); - request.set("token", placePrototype.getCreateToken()); - return restTemplate.postForObject("https://api.twitter.com/1.1/geo/place.json", request, Place.class); - } - - // private helpers - - private MultiValueMap buildGeoParameters(double latitude, double longitude, PlaceType granularity, String accuracy, String query) { - MultiValueMap parameters = new LinkedMultiValueMap(); - parameters.set("lat", String.valueOf(latitude)); - parameters.set("long", String.valueOf(longitude)); - if(granularity != null) { - parameters.set("granularity", granularity.equals(PlaceType.POINT_OF_INTEREST) ? "poi" : granularity.toString().toLowerCase()); - } - if(accuracy != null) { - parameters.set("accuracy", accuracy); - } - if(query != null ) { - parameters.set("query", query); - } - return parameters; - } - - private MultiValueMap buildPlaceParameters(double latitude, double longitude, String name, String streetAddress, String containedWithin) { - MultiValueMap parameters = new LinkedMultiValueMap(); - parameters.set("lat", String.valueOf(latitude)); - parameters.set("long", String.valueOf(longitude)); - parameters.set("name", name); - if(streetAddress != null) { - parameters.set("attribute:street_address", streetAddress); - } - if(containedWithin != null) { - parameters.set("contained_within", containedWithin); - } - return parameters; - } + private final RestTemplate restTemplate; + + public GeoTemplate(RestTemplate restTemplate, boolean isAuthorizedForUser, boolean isAuthorizedForApp) { + super(isAuthorizedForUser, isAuthorizedForApp); + this.restTemplate = restTemplate; + } + + @Override + public Place getPlace(String placeId) { + requireUserAuthorization(); + return restTemplate.getForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.GEO_ID) + .withArgument("place_id", placeId) + .build(), + Place.class); + } + + @Override + public List reverseGeoCode(double latitude, double longitude) { + return reverseGeoCode(latitude, longitude, null, null); + } + + @Override + public List reverseGeoCode(double latitude, double longitude, PlaceType granularity, String accuracy) { + requireUserAuthorization(); + return restTemplate.getForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.GEO_REVERSE_GEOCODE) + .withArgument(buildGeoParameters(latitude, longitude, granularity, accuracy, null)) + .build(), + PlacesList.class + ).getList(); + } + + @Override + public List search(double latitude, double longitude) { + return search(latitude, longitude, null, null, null); + } + + @Override + public List search(double latitude, double longitude, PlaceType granularity, String accuracy, String query) { + requireUserAuthorization(); + return restTemplate.getForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.GEO_SEARCH) + .withArgument(buildGeoParameters(latitude, longitude, granularity, accuracy, query)) + .build(), + PlacesList.class + ).getList(); + } + + @Override + public SimilarPlaces findSimilarPlaces(double latitude, double longitude, String name) { + return findSimilarPlaces(latitude, longitude, name, null, null); + } + + @Override + public SimilarPlaces findSimilarPlaces(double latitude, double longitude, String name, String streetAddress, String containedWithin) { + requireUserAuthorization(); + + SimilarPlacesResponse response = restTemplate.getForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.GEO_SIMILAR_PLACES) + .withArgument(buildPlaceParameters(latitude, longitude, name, streetAddress, containedWithin)) + .build(), + SimilarPlacesResponse.class); + + return new SimilarPlaces( + response.getPlaces(), + new PlacePrototype(response.getToken(), latitude, longitude, name, streetAddress, containedWithin)); + } + + @Override + public Place createPlace(PlacePrototype placePrototype) { + requireUserAuthorization(); + + MultiValueMap bodyData = + buildPlaceParameters(placePrototype.getLatitude(), placePrototype.getLongitude(), placePrototype.getName(), + placePrototype.getStreetAddress(), placePrototype.getContainedWithin()); + bodyData.set("token", placePrototype.getCreateToken()); + + return restTemplate.postForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.GEO_PLACE) + .build(), + bodyData, + Place.class); + } + + // private helpers + + private MultiValueMap buildGeoParameters(double latitude, double longitude, PlaceType granularity, String accuracy, String query) { + MultiValueMap parameters = new LinkedMultiValueMap(); + parameters.set("lat", String.valueOf(latitude)); + parameters.set("long", String.valueOf(longitude)); + if (granularity != null) { + parameters.set("granularity", granularity.equals(PlaceType.POINT_OF_INTEREST) ? "poi" : granularity.toString().toLowerCase()); + } + if (accuracy != null) { + parameters.set("accuracy", accuracy); + } + if (query != null) { + parameters.set("query", query); + } + return parameters; + } + + private MultiValueMap buildPlaceParameters(double latitude, double longitude, String name, String streetAddress, + String containedWithin) { + MultiValueMap parameters = new LinkedMultiValueMap(); + parameters.set("lat", String.valueOf(latitude)); + parameters.set("long", String.valueOf(longitude)); + parameters.set("name", name); + if (streetAddress != null) { + parameters.set("attribute:street_address", streetAddress); + } + if (containedWithin != null) { + parameters.set("contained_within", containedWithin); + } + return parameters; + } } diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/HashTagEntityMixin.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/HashTagEntityMixin.java index 9bf8e035..3e74f190 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/HashTagEntityMixin.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/HashTagEntityMixin.java @@ -20,7 +20,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; @JsonIgnoreProperties(ignoreUnknown=true) -abstract class HashTagEntityMixin extends TwitterObjectMixin { +public abstract class HashTagEntityMixin extends TwitterObjectMixin { @JsonCreator public HashTagEntityMixin( diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/InvalidInputDataException.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/InvalidInputDataException.java new file mode 100644 index 00000000..ae4ea0e6 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/InvalidInputDataException.java @@ -0,0 +1,22 @@ +package org.springframework.social.twitter.api.impl; + +import java.util.List; + +import org.springframework.social.ApiException; + +public class InvalidInputDataException extends ApiException { + + private static final long serialVersionUID = 1L; + + public InvalidInputDataException(String providerId, List validationErrors) { + super(providerId, formatValidationErrors(validationErrors)); + } + + private static String formatValidationErrors(List validationErrors) { + StringBuilder builder = new StringBuilder(); + builder.append("Some validation errors occurred:\n"); + for (String message : validationErrors) + builder.append(" - " + message + "\n"); + return builder.toString(); + } +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/ListTemplate.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/ListTemplate.java index c21f531a..88683214 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/ListTemplate.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/ListTemplate.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -31,313 +31,322 @@ /** * Implementation of {@link ListOperations}, providing a binding to Twitter's list-oriented REST resources. + * * @author Craig Walls */ +@SuppressWarnings("deprecation") class ListTemplate extends AbstractTwitterOperations implements ListOperations { - - private final RestTemplate restTemplate; - - public ListTemplate(RestTemplate restTemplate, boolean isAuthorizedForUser, boolean isAuthorizedForApp) { - super(isAuthorizedForUser, isAuthorizedForApp); - this.restTemplate = restTemplate; - } - - public List getLists() { - requireUserAuthorization(); - return restTemplate.getForObject(buildUri("lists/list.json"), UserSubscriptionList.class); - } - - public List getLists(long userId) { - requireEitherUserOrAppAuthorization(); - return restTemplate.getForObject(buildUri("lists/list.json", "user_id", String.valueOf(userId)), UserSubscriptionList.class); - } - - public List getLists(String screenName) { - requireEitherUserOrAppAuthorization(); - return restTemplate.getForObject(buildUri("lists/list.json", "screen_name", String.valueOf(screenName)), UserSubscriptionList.class); - } - - public UserList getList(long listId) { - requireUserAuthorization(); - return restTemplate.getForObject(buildUri("lists/show.json", "list_id", String.valueOf(listId)), UserList.class); - } - - public UserList getList(String screenName, String listSlug) { - requireEitherUserOrAppAuthorization(); - LinkedMultiValueMap parameters = new LinkedMultiValueMap(); - parameters.set("owner_screen_name", screenName); - parameters.set("slug", listSlug); - return restTemplate.getForObject(buildUri("lists/show.json", parameters), UserList.class); - } - - public List getListStatuses(long listId) { - return getListStatuses(listId, 20, 0, 0); - } - - public List getListStatuses(long listId, int pageSize) { - return getListStatuses(listId, pageSize, 0, 0); - } - - public List getListStatuses(long listId, int pageSize, long sinceId, long maxId) { - requireEitherUserOrAppAuthorization(); - MultiValueMap parameters = PagingUtils.buildPagingParametersWithCount(pageSize, sinceId, maxId); - parameters.set("list_id", String.valueOf(listId)); - parameters.set("include_entities", "true"); - return restTemplate.getForObject(buildUri("lists/statuses.json", parameters), TweetList.class); - } - - public List getListStatuses(String screenName, String listSlug) { - return getListStatuses(screenName, listSlug, 20, 0, 0); - } - - public List getListStatuses(String screenName, String listSlug, int pageSize) { - return getListStatuses(screenName, listSlug, pageSize, 0, 0); - } - - public List getListStatuses(String screenName, String listSlug, int pageSize, long sinceId, long maxId) { - requireEitherUserOrAppAuthorization(); - MultiValueMap parameters = PagingUtils.buildPagingParametersWithCount(pageSize, sinceId, maxId); - parameters.set("owner_screen_name", screenName); - parameters.set("slug", listSlug); - parameters.set("include_entities", "true"); - return restTemplate.getForObject(buildUri("lists/statuses.json", parameters), TweetList.class); - } - - public UserList createList(String name, String description, boolean isPublic) { - requireUserAuthorization(); - MultiValueMap request = buildListDataMap(name, description, isPublic); - return restTemplate.postForObject(buildUri("lists/create.json"), request, UserList.class); - } - - public UserList updateList(long listId, String name, String description, boolean isPublic) { - requireUserAuthorization(); - MultiValueMap request = buildListDataMap(name, description, isPublic); - request.set("list_id", String.valueOf(listId)); - return restTemplate.postForObject(buildUri("lists/update.json"), request, UserList.class); - } - - public void deleteList(long listId) { - requireUserAuthorization(); - MultiValueMap request = new LinkedMultiValueMap(); - request.set("list_id", String.valueOf(listId)); - restTemplate.postForObject(buildUri("lists/destroy.json"), request, String.class); - } - - public CursoredList getListMembers(long listId) { - requireEitherUserOrAppAuthorization(); - return restTemplate.getForObject(buildUri("lists/members.json", "list_id", String.valueOf(listId)), TwitterProfileUsersList.class).getList(); - } - - public CursoredList getListMembersInCursor(long listId, long cursor) { - requireEitherUserOrAppAuthorization(); - MultiValueMap request = new LinkedMultiValueMap(); - request.set("list_id", String.valueOf(listId)); - request.set("cursor", String.valueOf(cursor)); - return restTemplate.getForObject(buildUri("lists/members.json", request), TwitterProfileUsersList.class).getList(); - } - - public CursoredList getListMembers(String screenName, String listSlug) { - requireEitherUserOrAppAuthorization(); - LinkedMultiValueMap parameters = new LinkedMultiValueMap(); - parameters.set("owner_screen_name", screenName); - parameters.set("slug", listSlug); - return restTemplate.getForObject(buildUri("lists/members.json", parameters), TwitterProfileUsersList.class).getList(); - } - - public CursoredList getListMembersInCursor(String screenName, String listSlug, long cursor) { - requireEitherUserOrAppAuthorization(); - LinkedMultiValueMap parameters = new LinkedMultiValueMap(); - parameters.set("owner_screen_name", screenName); - parameters.set("slug", listSlug); - parameters.set("cursor", String.valueOf(cursor)); - return restTemplate.getForObject(buildUri("lists/members.json", parameters), TwitterProfileUsersList.class).getList(); - } - - public UserList addToList(long listId, long... newMemberIds) { - requireUserAuthorization(); - MultiValueMap request = new LinkedMultiValueMap(); - request.set("user_id", ArrayUtils.join(newMemberIds)); - request.set("list_id", String.valueOf(listId)); - return restTemplate.postForObject(buildUri("lists/members/create_all.json"), request, UserList.class); - } - - public UserList addToList(long listId, String... newMemberScreenNames) { - requireUserAuthorization(); - MultiValueMap request = new LinkedMultiValueMap(); - request.set("screen_name", ArrayUtils.join(newMemberScreenNames)); - request.set("list_id", String.valueOf(listId)); - return restTemplate.postForObject(buildUri("lists/members/create_all.json"), request, UserList.class); - } - - public void removeFromList(long listId, long memberId) { - requireUserAuthorization(); - MultiValueMap request = new LinkedMultiValueMap(); - request.set("user_id", String.valueOf(memberId)); - request.set("list_id", String.valueOf(listId)); - restTemplate.postForObject(buildUri("lists/members/destroy.json"), request, String.class); - } - - public void removeFromList(long listId, String memberScreenName) { - requireUserAuthorization(); - MultiValueMap request = new LinkedMultiValueMap(); - request.set("screen_name", String.valueOf(memberScreenName)); - request.set("list_id", String.valueOf(listId)); - restTemplate.postForObject(buildUri("lists/members/destroy.json"), request, String.class); - } - - public List getListSubscribers(long listId) { - requireEitherUserOrAppAuthorization(); - return restTemplate.getForObject(buildUri("lists/subscribers.json", "list_id", String.valueOf(listId)), TwitterProfileUsersList.class).getList(); - } - - public List getListSubscribers(String screenName, String listSlug) { - requireEitherUserOrAppAuthorization(); - LinkedMultiValueMap parameters = new LinkedMultiValueMap(); - parameters.set("owner_screen_name", screenName); - parameters.set("slug", listSlug); - return restTemplate.getForObject(buildUri("lists/subscribers.json", parameters), TwitterProfileUsersList.class).getList(); - } - - public UserList subscribe(long listId) { - requireUserAuthorization(); - MultiValueMap request = new LinkedMultiValueMap(); - request.set("list_id", String.valueOf(listId)); - return restTemplate.postForObject(buildUri("lists/subscribers/create.json"), request, UserList.class); - } - - public UserList subscribe(String ownerScreenName, String listSlug) { - requireUserAuthorization(); - MultiValueMap request = new LinkedMultiValueMap(); - request.set("owner_screen_name", ownerScreenName); - request.set("slug", listSlug); - return restTemplate.postForObject(buildUri("lists/subscribers/create.json"), request, UserList.class); - } - - public UserList unsubscribe(long listId) { - requireUserAuthorization(); - MultiValueMap request = new LinkedMultiValueMap(); - request.set("list_id", String.valueOf(listId)); - return restTemplate.postForObject(buildUri("lists/subscribers/destroy.json"), request, UserList.class); - } - - public UserList unsubscribe(String ownerScreenName, String listSlug) { - requireUserAuthorization(); - MultiValueMap request = new LinkedMultiValueMap(); - request.set("owner_screen_name", ownerScreenName); - request.set("slug", listSlug); - return restTemplate.postForObject(buildUri("lists/subscribers/destroy.json"), request, UserList.class); - } - - public CursoredList getMemberships(long userId) { - requireEitherUserOrAppAuthorization(); - return restTemplate.getForObject(buildUri("lists/memberships.json", "user_id", String.valueOf(userId)), UserListList.class).getList(); - } - - public CursoredList getMemberships(String screenName) { - requireEitherUserOrAppAuthorization(); - return restTemplate.getForObject(buildUri("lists/memberships.json", "screen_name", screenName), UserListList.class).getList(); - } - - public CursoredList getMembershipsInCursor(long userId, long cursor) { - requireEitherUserOrAppAuthorization(); - MultiValueMap request = new LinkedMultiValueMap(); - request.set("user_id", String.valueOf(userId)); - request.set("cursor", String.valueOf(cursor)); - return restTemplate.getForObject(buildUri("lists/memberships.json", request), UserListList.class).getList(); - } - - public CursoredList getMembershipsInCursor(String screenName, long cursor) { - requireEitherUserOrAppAuthorization(); - MultiValueMap request = new LinkedMultiValueMap(); - request.set("screen_name", screenName); - request.set("cursor", String.valueOf(cursor)); - return restTemplate.getForObject(buildUri("lists/memberships.json", request), UserListList.class).getList(); - } - - public CursoredList getSubscriptions(long userId) { - requireEitherUserOrAppAuthorization(); - return restTemplate.getForObject(buildUri("lists/subscriptions.json", "user_id", String.valueOf(userId)), UserListList.class).getList(); - } - - public CursoredList getSubscriptions(String screenName) { - requireEitherUserOrAppAuthorization(); - return restTemplate.getForObject(buildUri("lists/subscriptions.json", "screen_name", screenName), UserListList.class).getList(); - } - - public CursoredList getSubscriptionsInCursor(long userId, long cursor) { - requireEitherUserOrAppAuthorization(); - MultiValueMap request = new LinkedMultiValueMap(); - request.set("user_id", String.valueOf(userId)); - request.set("cursor", String.valueOf(cursor)); - return restTemplate.getForObject(buildUri("lists/subscriptions.json", request), UserListList.class).getList(); - } - - public CursoredList getSubscriptionsInCursor(String screenName, long cursor) { - requireEitherUserOrAppAuthorization(); - MultiValueMap request = new LinkedMultiValueMap(); - request.set("screen_name", screenName); - request.set("cursor", String.valueOf(cursor)); - return restTemplate.getForObject(buildUri("lists/subscriptions.json", request), UserListList.class).getList(); - } - - public boolean isMember(long listId, long memberId) { - requireEitherUserOrAppAuthorization(); - LinkedMultiValueMap parameters = new LinkedMultiValueMap(); - parameters.set("list_id", String.valueOf(listId)); - parameters.set("user_id", String.valueOf(memberId)); - return checkListConnection(buildUri("lists/members/show.json", parameters)); - } - - public boolean isMember(String screenName, String listSlug, String memberScreenName) { - requireEitherUserOrAppAuthorization(); - LinkedMultiValueMap parameters = new LinkedMultiValueMap(); - parameters.set("owner_screen_name", screenName); - parameters.set("slug", listSlug); - parameters.set("screen_name", memberScreenName); - return checkListConnection(buildUri("lists/members/show.json", parameters)); - } - - public boolean isSubscriber(long listId, long subscriberId) { - requireEitherUserOrAppAuthorization(); - LinkedMultiValueMap parameters = new LinkedMultiValueMap(); - parameters.set("list_id", String.valueOf(listId)); - parameters.set("user_id", String.valueOf(subscriberId)); - return checkListConnection(buildUri("lists/subscribers/show.json", parameters)); - } - - public boolean isSubscriber(String screenName, String listSlug, String subscriberScreenName) { - requireEitherUserOrAppAuthorization(); - LinkedMultiValueMap parameters = new LinkedMultiValueMap(); - parameters.set("owner_screen_name", screenName); - parameters.set("slug", listSlug); - parameters.set("screen_name", subscriberScreenName); - return checkListConnection(buildUri("lists/subscribers/show.json", parameters)); - } - - // private helpers - - private boolean checkListConnection(URI uri) { - try { - restTemplate.getForObject(uri, String.class); - return true; - } catch (ResourceNotFoundException e) { - return false; - } - } - - private MultiValueMap buildListDataMap(String name, - String description, boolean isPublic) { - MultiValueMap request = new LinkedMultiValueMap(); - request.set("name", name); - request.set("description", description); - request.set("mode", isPublic ? "public" : "private"); - return request; - } - - @SuppressWarnings("serial") - private static class TweetList extends ArrayList {} - - @SuppressWarnings("serial") - private static class UserSubscriptionList extends ArrayList {} - -} + + private final RestTemplate restTemplate; + + public ListTemplate(RestTemplate restTemplate, boolean isAuthorizedForUser, boolean isAuthorizedForApp) { + super(isAuthorizedForUser, isAuthorizedForApp); + this.restTemplate = restTemplate; + } + + public List getLists() { + requireUserAuthorization(); + return restTemplate.getForObject(buildUri("lists/list.json"), UserSubscriptionList.class); + } + + public List getLists(long userId) { + requireEitherUserOrAppAuthorization(); + return restTemplate.getForObject(buildUri("lists/list.json", "user_id", String.valueOf(userId)), UserSubscriptionList.class); + } + + public List getLists(String screenName) { + requireEitherUserOrAppAuthorization(); + return restTemplate.getForObject(buildUri("lists/list.json", "screen_name", String.valueOf(screenName)), UserSubscriptionList.class); + } + + public UserList getList(long listId) { + requireUserAuthorization(); + return restTemplate.getForObject(buildUri("lists/show.json", "list_id", String.valueOf(listId)), UserList.class); + } + + public UserList getList(String screenName, String listSlug) { + requireEitherUserOrAppAuthorization(); + LinkedMultiValueMap parameters = new LinkedMultiValueMap(); + parameters.set("owner_screen_name", screenName); + parameters.set("slug", listSlug); + return restTemplate.getForObject(buildUri("lists/show.json", parameters), UserList.class); + } + + public List getListStatuses(long listId) { + return getListStatuses(listId, 20, 0, 0); + } + + public List getListStatuses(long listId, int pageSize) { + return getListStatuses(listId, pageSize, 0, 0); + } + + public List getListStatuses(long listId, int pageSize, long sinceId, long maxId) { + requireEitherUserOrAppAuthorization(); + MultiValueMap parameters = PagingUtils.buildPagingParametersWithCount(pageSize, sinceId, maxId); + parameters.set("list_id", String.valueOf(listId)); + parameters.set("include_entities", "true"); + return restTemplate.getForObject(buildUri("lists/statuses.json", parameters), TweetList.class); + } + + public List getListStatuses(String screenName, String listSlug) { + return getListStatuses(screenName, listSlug, 20, 0, 0); + } + + public List getListStatuses(String screenName, String listSlug, int pageSize) { + return getListStatuses(screenName, listSlug, pageSize, 0, 0); + } + + public List getListStatuses(String screenName, String listSlug, int pageSize, long sinceId, long maxId) { + requireEitherUserOrAppAuthorization(); + MultiValueMap parameters = PagingUtils.buildPagingParametersWithCount(pageSize, sinceId, maxId); + parameters.set("owner_screen_name", screenName); + parameters.set("slug", listSlug); + parameters.set("include_entities", "true"); + return restTemplate.getForObject(buildUri("lists/statuses.json", parameters), TweetList.class); + } + + public UserList createList(String name, String description, boolean isPublic) { + requireUserAuthorization(); + MultiValueMap request = buildListDataMap(name, description, isPublic); + return restTemplate.postForObject(buildUri("lists/create.json"), request, UserList.class); + } + + public UserList updateList(long listId, String name, String description, boolean isPublic) { + requireUserAuthorization(); + MultiValueMap request = buildListDataMap(name, description, isPublic); + request.set("list_id", String.valueOf(listId)); + return restTemplate.postForObject(buildUri("lists/update.json"), request, UserList.class); + } + + public void deleteList(long listId) { + requireUserAuthorization(); + MultiValueMap request = new LinkedMultiValueMap(); + request.set("list_id", String.valueOf(listId)); + restTemplate.postForObject(buildUri("lists/destroy.json"), request, String.class); + } + + public CursoredList getListMembers(long listId) { + requireEitherUserOrAppAuthorization(); + return restTemplate.getForObject(buildUri("lists/members.json", "list_id", String.valueOf(listId)), TwitterProfileUsersList.class).getList(); + } + + public CursoredList getListMembersInCursor(long listId, long cursor) { + requireEitherUserOrAppAuthorization(); + MultiValueMap request = new LinkedMultiValueMap(); + request.set("list_id", String.valueOf(listId)); + request.set("cursor", String.valueOf(cursor)); + return restTemplate.getForObject(buildUri("lists/members.json", request), TwitterProfileUsersList.class).getList(); + } + + public CursoredList getListMembers(String screenName, String listSlug) { + requireEitherUserOrAppAuthorization(); + LinkedMultiValueMap parameters = new LinkedMultiValueMap(); + parameters.set("owner_screen_name", screenName); + parameters.set("slug", listSlug); + return restTemplate.getForObject(buildUri("lists/members.json", parameters), TwitterProfileUsersList.class).getList(); + } + + public CursoredList getListMembersInCursor(String screenName, String listSlug, long cursor) { + requireEitherUserOrAppAuthorization(); + LinkedMultiValueMap parameters = new LinkedMultiValueMap(); + parameters.set("owner_screen_name", screenName); + parameters.set("slug", listSlug); + parameters.set("cursor", String.valueOf(cursor)); + return restTemplate.getForObject(buildUri("lists/members.json", parameters), TwitterProfileUsersList.class).getList(); + } + + public UserList addToList(long listId, long... newMemberIds) { + requireUserAuthorization(); + MultiValueMap request = new LinkedMultiValueMap(); + request.set("user_id", ArrayUtils.join(newMemberIds)); + request.set("list_id", String.valueOf(listId)); + return restTemplate.postForObject(buildUri("lists/members/create_all.json"), request, UserList.class); + } + + public UserList addToList(long listId, String... newMemberScreenNames) { + requireUserAuthorization(); + MultiValueMap request = new LinkedMultiValueMap(); + request.set("screen_name", ArrayUtils.join(newMemberScreenNames)); + request.set("list_id", String.valueOf(listId)); + return restTemplate.postForObject(buildUri("lists/members/create_all.json"), request, UserList.class); + } + + public void removeFromList(long listId, long memberId) { + requireUserAuthorization(); + MultiValueMap request = new LinkedMultiValueMap(); + request.set("user_id", String.valueOf(memberId)); + request.set("list_id", String.valueOf(listId)); + restTemplate.postForObject(buildUri("lists/members/destroy.json"), request, String.class); + } + + public void removeFromList(long listId, String memberScreenName) { + requireUserAuthorization(); + MultiValueMap request = new LinkedMultiValueMap(); + request.set("screen_name", String.valueOf(memberScreenName)); + request.set("list_id", String.valueOf(listId)); + restTemplate.postForObject(buildUri("lists/members/destroy.json"), request, String.class); + } + + public List getListSubscribers(long listId) { + requireEitherUserOrAppAuthorization(); + return restTemplate + .getForObject(buildUri("lists/subscribers.json", "list_id", String.valueOf(listId)), TwitterProfileUsersList.class) + .getList(); + } + + public List getListSubscribers(String screenName, String listSlug) { + requireEitherUserOrAppAuthorization(); + LinkedMultiValueMap parameters = new LinkedMultiValueMap(); + parameters.set("owner_screen_name", screenName); + parameters.set("slug", listSlug); + return restTemplate.getForObject(buildUri("lists/subscribers.json", parameters), TwitterProfileUsersList.class).getList(); + } + + public UserList subscribe(long listId) { + requireUserAuthorization(); + MultiValueMap request = new LinkedMultiValueMap(); + request.set("list_id", String.valueOf(listId)); + return restTemplate.postForObject(buildUri("lists/subscribers/create.json"), request, UserList.class); + } + + public UserList subscribe(String ownerScreenName, String listSlug) { + requireUserAuthorization(); + MultiValueMap request = new LinkedMultiValueMap(); + request.set("owner_screen_name", ownerScreenName); + request.set("slug", listSlug); + return restTemplate.postForObject(buildUri("lists/subscribers/create.json"), request, UserList.class); + } + + public UserList unsubscribe(long listId) { + requireUserAuthorization(); + MultiValueMap request = new LinkedMultiValueMap(); + request.set("list_id", String.valueOf(listId)); + return restTemplate.postForObject(buildUri("lists/subscribers/destroy.json"), request, UserList.class); + } + + public UserList unsubscribe(String ownerScreenName, String listSlug) { + requireUserAuthorization(); + MultiValueMap request = new LinkedMultiValueMap(); + request.set("owner_screen_name", ownerScreenName); + request.set("slug", listSlug); + return restTemplate.postForObject(buildUri("lists/subscribers/destroy.json"), request, UserList.class); + } + + public CursoredList getMemberships(long userId) { + requireEitherUserOrAppAuthorization(); + return restTemplate.getForObject(buildUri("lists/memberships.json", "user_id", String.valueOf(userId)), UserListList.class).getList(); + } + + public CursoredList getMemberships(String screenName) { + requireEitherUserOrAppAuthorization(); + return restTemplate.getForObject(buildUri("lists/memberships.json", "screen_name", screenName), UserListList.class).getList(); + } + + public CursoredList getMembershipsInCursor(long userId, long cursor) { + requireEitherUserOrAppAuthorization(); + MultiValueMap request = new LinkedMultiValueMap(); + request.set("user_id", String.valueOf(userId)); + request.set("cursor", String.valueOf(cursor)); + return restTemplate.getForObject(buildUri("lists/memberships.json", request), UserListList.class).getList(); + } + + public CursoredList getMembershipsInCursor(String screenName, long cursor) { + requireEitherUserOrAppAuthorization(); + MultiValueMap request = new LinkedMultiValueMap(); + request.set("screen_name", screenName); + request.set("cursor", String.valueOf(cursor)); + return restTemplate.getForObject(buildUri("lists/memberships.json", request), UserListList.class).getList(); + } + + public CursoredList getSubscriptions(long userId) { + requireEitherUserOrAppAuthorization(); + return restTemplate.getForObject(buildUri("lists/subscriptions.json", "user_id", String.valueOf(userId)), UserListList.class).getList(); + } + + public CursoredList getSubscriptions(String screenName) { + requireEitherUserOrAppAuthorization(); + return restTemplate.getForObject(buildUri("lists/subscriptions.json", "screen_name", screenName), UserListList.class).getList(); + } + + public CursoredList getSubscriptionsInCursor(long userId, long cursor) { + requireEitherUserOrAppAuthorization(); + MultiValueMap request = new LinkedMultiValueMap(); + request.set("user_id", String.valueOf(userId)); + request.set("cursor", String.valueOf(cursor)); + return restTemplate.getForObject(buildUri("lists/subscriptions.json", request), UserListList.class).getList(); + } + + public CursoredList getSubscriptionsInCursor(String screenName, long cursor) { + requireEitherUserOrAppAuthorization(); + MultiValueMap request = new LinkedMultiValueMap(); + request.set("screen_name", screenName); + request.set("cursor", String.valueOf(cursor)); + return restTemplate.getForObject(buildUri("lists/subscriptions.json", request), UserListList.class).getList(); + } + + public boolean isMember(long listId, long memberId) { + requireEitherUserOrAppAuthorization(); + LinkedMultiValueMap parameters = new LinkedMultiValueMap(); + parameters.set("list_id", String.valueOf(listId)); + parameters.set("user_id", String.valueOf(memberId)); + return checkListConnection(buildUri("lists/members/show.json", parameters)); + } + + public boolean isMember(String screenName, String listSlug, String memberScreenName) { + requireEitherUserOrAppAuthorization(); + LinkedMultiValueMap parameters = new LinkedMultiValueMap(); + parameters.set("owner_screen_name", screenName); + parameters.set("slug", listSlug); + parameters.set("screen_name", memberScreenName); + return checkListConnection(buildUri("lists/members/show.json", parameters)); + } + + public boolean isSubscriber(long listId, long subscriberId) { + requireEitherUserOrAppAuthorization(); + LinkedMultiValueMap parameters = new LinkedMultiValueMap(); + parameters.set("list_id", String.valueOf(listId)); + parameters.set("user_id", String.valueOf(subscriberId)); + return checkListConnection(buildUri("lists/subscribers/show.json", parameters)); + } + + public boolean isSubscriber(String screenName, String listSlug, String subscriberScreenName) { + requireEitherUserOrAppAuthorization(); + LinkedMultiValueMap parameters = new LinkedMultiValueMap(); + parameters.set("owner_screen_name", screenName); + parameters.set("slug", listSlug); + parameters.set("screen_name", subscriberScreenName); + return checkListConnection(buildUri("lists/subscribers/show.json", parameters)); + } + + // private helpers + + private boolean checkListConnection(URI uri) { + try { + restTemplate.getForObject(uri, String.class); + return true; + } + catch (ResourceNotFoundException e) { + return false; + } + } + + private MultiValueMap buildListDataMap( + String name, + String description, + boolean isPublic) { + MultiValueMap request = new LinkedMultiValueMap(); + request.set("name", name); + request.set("description", description); + request.set("mode", isPublic ? "public" : "private"); + return request; + } + + @SuppressWarnings("serial") + private static class TweetList extends ArrayList { + } + + @SuppressWarnings("serial") + private static class UserSubscriptionList extends ArrayList { + } + +} \ No newline at end of file diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/LocalDateTimeDeserializer.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/LocalDateTimeDeserializer.java new file mode 100644 index 00000000..0f87a338 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/LocalDateTimeDeserializer.java @@ -0,0 +1,50 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl; + +import java.io.IOException; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; + +/** + * Deserializer to get ISO dates with a Z in the end and transform it to a LocalDateTime. + * @author Hudson Mendes + */ +public class LocalDateTimeDeserializer extends JsonDeserializer { + private static final ZoneId utc = ZoneId.of("UTC"); + + @Override + public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt) + throws IOException, JsonProcessingException { + + /** + * Very ugly fix to get the damn date in ISO format working + * I'm still trying to figure out a better solution. + */ + return parse(p.getText()); + } + + public static LocalDateTime parse(String dateTimeAsString) { + Instant instant = Instant.parse(dateTimeAsString); + return LocalDateTime.ofInstant(instant, utc); + } +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/LocalTrendsDeserializer.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/LocalTrendsDeserializer.java index 62904cc9..a384c44c 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/LocalTrendsDeserializer.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/LocalTrendsDeserializer.java @@ -36,7 +36,7 @@ * Deserializer to read local trends data into a LocalTrendsHolder object. * @author Craig Walls */ -class LocalTrendsDeserializer extends JsonDeserializer { +public class LocalTrendsDeserializer extends JsonDeserializer { @Override public LocalTrendsHolder deserialize(JsonParser jp, DeserializationContext ctxt) diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/LocalTrendsHolder.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/LocalTrendsHolder.java index f3916d7b..3a83023a 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/LocalTrendsHolder.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/LocalTrendsHolder.java @@ -27,7 +27,7 @@ */ @JsonIgnoreProperties(ignoreUnknown=true) @JsonDeserialize(using = LocalTrendsDeserializer.class) -class LocalTrendsHolder { +public class LocalTrendsHolder { private final Trends trends; diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/MediaEntityMixin.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/MediaEntityMixin.java index e6acc7b3..79c14846 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/MediaEntityMixin.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/MediaEntityMixin.java @@ -1,12 +1,12 @@ /* * Copyright 2014 the original author or authors. - * + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * + * + * http://www.apache.org/licenses/LICENSE-2.0 + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -15,22 +15,25 @@ */ package org.springframework.social.twitter.api.impl; +import org.springframework.social.twitter.api.VideoInfoMediaEntity; + import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; @JsonIgnoreProperties(ignoreUnknown = true) -abstract class MediaEntityMixin extends TwitterObjectMixin { +public abstract class MediaEntityMixin extends TwitterObjectMixin { + + @JsonCreator + public MediaEntityMixin( + @JsonProperty("id") long id, + @JsonProperty("media_url") String mediaHttp, + @JsonProperty("media_url_https") String mediaHttps, + @JsonProperty("url") String url, + @JsonProperty("display_url") String display, + @JsonProperty("expanded_url") String expanded, + @JsonProperty("type") String type, + @JsonProperty("indices") int[] indices, + @JsonProperty("video_info") VideoInfoMediaEntity videoInfo) {} - @JsonCreator - public MediaEntityMixin( - @JsonProperty("id") long id, - @JsonProperty("media_url")String mediaHttp, - @JsonProperty("media_url_https")String mediaHttps, - @JsonProperty("url")String url, - @JsonProperty("display_url")String display, - @JsonProperty("expanded_url")String expanded, - @JsonProperty("type")String type, - @JsonProperty("indices")int[] indices) {} - } diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/MentionEntityMixin.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/MentionEntityMixin.java index b995c156..003f073a 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/MentionEntityMixin.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/MentionEntityMixin.java @@ -20,7 +20,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; @JsonIgnoreProperties(ignoreUnknown = true) -abstract class MentionEntityMixin extends TwitterObjectMixin { +public abstract class MentionEntityMixin extends TwitterObjectMixin { @JsonCreator public MentionEntityMixin( diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/OEmbedTweetMixin.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/OEmbedTweetMixin.java index 29bca716..a189bd5f 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/OEmbedTweetMixin.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/OEmbedTweetMixin.java @@ -19,7 +19,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; @JsonIgnoreProperties(ignoreUnknown = true) -abstract class OEmbedTweetMixin extends TwitterObjectMixin { +public abstract class OEmbedTweetMixin extends TwitterObjectMixin { @JsonProperty("type") private String type; diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/PagingUtils.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/PagingUtils.java index dc733d39..db17774d 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/PagingUtils.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/PagingUtils.java @@ -1,12 +1,12 @@ /* * Copyright 2014 the original author or authors. - * + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * + * + * http://www.apache.org/licenses/LICENSE-2.0 + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -20,33 +20,34 @@ /** * Utility methods for creating paging parameters for Twitter requests supporting paging. + * * @author Craig Walls */ -class PagingUtils { - - public static MultiValueMap buildPagingParametersWithCount(int page, int pageSize, long sinceId, long maxId) { - MultiValueMap parameters = new LinkedMultiValueMap(); - parameters.set("page", String.valueOf(page)); - parameters.set("count", String.valueOf(pageSize)); - if (sinceId > 0) { - parameters.set("since_id", String.valueOf(sinceId)); - } - if (maxId > 0) { - parameters.set("max_id", String.valueOf(maxId)); - } - return parameters; - } +public class PagingUtils { - public static MultiValueMap buildPagingParametersWithCount(int pageSize, long sinceId, long maxId) { - MultiValueMap parameters = new LinkedMultiValueMap(); - parameters.set("count", String.valueOf(pageSize)); - if (sinceId > 0) { - parameters.set("since_id", String.valueOf(sinceId)); - } - if (maxId > 0) { - parameters.set("max_id", String.valueOf(maxId)); - } - return parameters; - } + public static MultiValueMap buildPagingParametersWithCount(int page, int pageSize, long sinceId, long maxId) { + MultiValueMap parameters = new LinkedMultiValueMap(); + parameters.set("page", String.valueOf(page)); + parameters.set("count", String.valueOf(pageSize)); + if (sinceId > 0) { + parameters.set("since_id", String.valueOf(sinceId)); + } + if (maxId > 0) { + parameters.set("max_id", String.valueOf(maxId)); + } + return parameters; + } + + public static MultiValueMap buildPagingParametersWithCount(int pageSize, long sinceId, long maxId) { + MultiValueMap parameters = new LinkedMultiValueMap(); + parameters.set("count", String.valueOf(pageSize)); + if (sinceId > 0) { + parameters.set("since_id", String.valueOf(sinceId)); + } + if (maxId > 0) { + parameters.set("max_id", String.valueOf(maxId)); + } + return parameters; + } } diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/PlaceMixin.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/PlaceMixin.java index 5ca0ce42..17940103 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/PlaceMixin.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/PlaceMixin.java @@ -21,10 +21,10 @@ import java.util.Map; import org.springframework.social.twitter.api.Place; +import org.springframework.social.twitter.api.PlaceType; import org.springframework.social.twitter.api.Place.GeoPoint; import org.springframework.social.twitter.api.Place.Geometry; import org.springframework.social.twitter.api.Place.GeometryType; -import org.springframework.social.twitter.api.PlaceType; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @@ -38,7 +38,7 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize; @JsonIgnoreProperties(ignoreUnknown = true) -abstract class PlaceMixin extends TwitterObjectMixin { +public abstract class PlaceMixin extends TwitterObjectMixin { @JsonCreator public PlaceMixin( diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/PlaceTypeDeserializer.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/PlaceTypeDeserializer.java index e973b784..544bcdba 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/PlaceTypeDeserializer.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/PlaceTypeDeserializer.java @@ -24,7 +24,7 @@ import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; -class PlaceTypeDeserializer extends JsonDeserializer { +public class PlaceTypeDeserializer extends JsonDeserializer { @Override public PlaceType deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/PlacesList.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/PlacesList.java index 82490045..279a0d39 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/PlacesList.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/PlacesList.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -33,28 +33,28 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize; @JsonIgnoreProperties(ignoreUnknown = true) -class PlacesList { - - private final List list; - - @JsonCreator - public PlacesList(@JsonProperty("result") @JsonDeserialize(using=PlacesDeserializer.class) List list) { - this.list = list; - } - - public List getList() { - return list; - } - - private static class PlacesDeserializer extends JsonDeserializer> { - @SuppressWarnings("unchecked") - @Override - public List deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { - ObjectMapper mapper = new ObjectMapper(); - mapper.registerModule(new TwitterModule()); - jp.setCodec(mapper); - JsonNode treeNode = (JsonNode) jp.readValueAs(JsonNode.class).get("places"); - return (List) mapper.reader(new TypeReference>() {}).readValue(treeNode); - } - } +public class PlacesList { + + private final List list; + + @JsonCreator + public PlacesList(@JsonProperty("result") @JsonDeserialize(using = PlacesDeserializer.class) List list) { + this.list = list; + } + + public List getList() { + return list; + } + + private static class PlacesDeserializer extends JsonDeserializer> { + @SuppressWarnings({"unchecked", "deprecation"}) + @Override + public List deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { + ObjectMapper mapper = new ObjectMapper(); + mapper.registerModule(new TwitterModule()); + jp.setCodec(mapper); + JsonNode treeNode = (JsonNode) jp.readValueAs(JsonNode.class).get("places"); + return (List) mapper.reader(new TypeReference>() {}).readValue(treeNode); + } + } } diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/RestRequestBodyBuilder.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/RestRequestBodyBuilder.java new file mode 100644 index 00000000..2d5ff619 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/RestRequestBodyBuilder.java @@ -0,0 +1,22 @@ +package org.springframework.social.twitter.api.impl; + +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +public class RestRequestBodyBuilder { + private final MultiValueMap map = new LinkedMultiValueMap(); + + public RestRequestBodyBuilder withField(String name, Object value) { + this.map.set(name, value); + return this; + } + + public RestRequestBodyBuilder withFields(MultiValueMap fields) { + this.map.putAll(fields); + return this; + } + + public MultiValueMap build() { + return this.map; + } +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/SavedSearchList.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/SavedSearchList.java index ab8c2539..dc45693c 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/SavedSearchList.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/SavedSearchList.java @@ -26,5 +26,5 @@ * @author Craig Walls */ @SuppressWarnings("serial") -class SavedSearchList extends ArrayList { +public class SavedSearchList extends ArrayList { } diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/SavedSearchMixin.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/SavedSearchMixin.java index d588aa60..10af370b 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/SavedSearchMixin.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/SavedSearchMixin.java @@ -27,7 +27,7 @@ * @author Craig Walls */ @JsonIgnoreProperties(ignoreUnknown=true) -abstract class SavedSearchMixin extends TwitterObjectMixin { +public abstract class SavedSearchMixin extends TwitterObjectMixin { @JsonCreator SavedSearchMixin( @JsonProperty("id") long id, diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/SearchMetadata.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/SearchMetadata.java similarity index 89% rename from spring-social-twitter/src/main/java/org/springframework/social/twitter/api/SearchMetadata.java rename to spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/SearchMetadata.java index 3ad5a625..3b0ba179 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/SearchMetadata.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/SearchMetadata.java @@ -1,4 +1,4 @@ -package org.springframework.social.twitter.api; +package org.springframework.social.twitter.api.impl; /** * Represents the cursor metadata associated with a search query via the Twitter Search API. diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/SearchMetadataDeserializer.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/SearchMetadataDeserializer.java index b5212f14..e2cd42a2 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/SearchMetadataDeserializer.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/SearchMetadataDeserializer.java @@ -2,8 +2,6 @@ import java.io.IOException; -import org.springframework.social.twitter.api.SearchMetadata; - import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.DeserializationContext; @@ -14,7 +12,7 @@ * Deserializer to read search metadata into a SearchMetaData object * @author Jeremy Appel */ -class SearchMetadataDeserializer extends JsonDeserializer{ +public class SearchMetadataDeserializer extends JsonDeserializer{ @Override public SearchMetadata deserialize(JsonParser jp, DeserializationContext ctxt) diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/SearchParametersUtil.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/SearchParametersUtil.java index 6073551c..e4f027ab 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/SearchParametersUtil.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/SearchParametersUtil.java @@ -1,12 +1,12 @@ /* * Copyright 2014 the original author or authors. - * + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * + * + * http://www.apache.org/licenses/LICENSE-2.0 + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -21,39 +21,40 @@ import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; -class SearchParametersUtil { +public class SearchParametersUtil { - public static MultiValueMap buildQueryParametersFromSearchParameters(SearchParameters searchParameters) { - MultiValueMap parameters = new LinkedMultiValueMap(); - parameters.set("q", searchParameters.getQuery()); - if (searchParameters.getGeoCode() != null) { - parameters.set("geocode", searchParameters.getGeoCode().toString()); - } - if (searchParameters.getLang() != null) { - parameters.set("lang", searchParameters.getLang()); - } - if (searchParameters.getLocale() != null) { - parameters.set("locale", searchParameters.getLocale()); - } - if (searchParameters.getResultType() != null) { - parameters.set("result_type", searchParameters.getResultType().toString()); - } - parameters.set("count", searchParameters.getCount() != null ? String.valueOf(searchParameters.getCount()) : String.valueOf(DEFAULT_RESULTS_PER_PAGE)); - if (searchParameters.getUntil() != null) { - parameters.set("until", new SimpleDateFormat("yyyy-MM-dd").format(searchParameters.getUntil())); - } - if (searchParameters.getSinceId() != null) { - parameters.set("since_id", String.valueOf(searchParameters.getSinceId())); - } - if (searchParameters.getMaxId() != null) { - parameters.set("max_id", String.valueOf(searchParameters.getMaxId())); - } - if (!searchParameters.isIncludeEntities()) { - parameters.set("include_entities", "false"); - } - return parameters; - } + public static MultiValueMap buildQueryParametersFromSearchParameters(SearchParameters searchParameters) { + MultiValueMap parameters = new LinkedMultiValueMap(); + parameters.set("q", searchParameters.getQuery()); + if (searchParameters.getGeoCode() != null) { + parameters.set("geocode", searchParameters.getGeoCode().toString()); + } + if (searchParameters.getLang() != null) { + parameters.set("lang", searchParameters.getLang()); + } + if (searchParameters.getLocale() != null) { + parameters.set("locale", searchParameters.getLocale()); + } + if (searchParameters.getResultType() != null) { + parameters.set("result_type", searchParameters.getResultType().toString()); + } + parameters.set("count", + searchParameters.getCount() != null ? String.valueOf(searchParameters.getCount()) : String.valueOf(DEFAULT_RESULTS_PER_PAGE)); + if (searchParameters.getUntil() != null) { + parameters.set("until", new SimpleDateFormat("yyyy-MM-dd").format(searchParameters.getUntil())); + } + if (searchParameters.getSinceId() != null) { + parameters.set("since_id", String.valueOf(searchParameters.getSinceId())); + } + if (searchParameters.getMaxId() != null) { + parameters.set("max_id", String.valueOf(searchParameters.getMaxId())); + } + if (!searchParameters.isIncludeEntities()) { + parameters.set("include_entities", "false"); + } + return parameters; + } + + public static final int DEFAULT_RESULTS_PER_PAGE = 50; - public static final int DEFAULT_RESULTS_PER_PAGE = 50; - } diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/SearchResultsMixin.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/SearchResultsMixin.java index 9dc04944..fea81623 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/SearchResultsMixin.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/SearchResultsMixin.java @@ -17,7 +17,6 @@ import java.util.List; -import org.springframework.social.twitter.api.SearchMetadata; import org.springframework.social.twitter.api.Tweet; import com.fasterxml.jackson.annotation.JsonCreator; @@ -30,7 +29,7 @@ * @author Craig Walls */ @JsonIgnoreProperties(ignoreUnknown = true) -abstract class SearchResultsMixin extends TwitterObjectMixin { +public abstract class SearchResultsMixin extends TwitterObjectMixin { @JsonCreator SearchResultsMixin( diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/SearchTemplate.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/SearchTemplate.java index 30374834..41bd6190 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/SearchTemplate.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/SearchTemplate.java @@ -1,12 +1,12 @@ /* * Copyright 2014 the original author or authors. - * + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * + * + * http://www.apache.org/licenses/LICENSE-2.0 + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -15,7 +15,7 @@ */ package org.springframework.social.twitter.api.impl; -import static org.springframework.social.twitter.api.impl.SearchParametersUtil.*; +import static org.springframework.social.twitter.api.impl.SearchParametersUtil.buildQueryParametersFromSearchParameters; import java.util.List; @@ -31,78 +31,120 @@ /** * Implementation of {@link SearchOperations}, providing a binding to Twitter's search and trend-oriented REST resources. + * * @author Craig Walls */ -class SearchTemplate extends AbstractTwitterOperations implements SearchOperations { - - private final RestTemplate restTemplate; - - public SearchTemplate(RestTemplate restTemplate, boolean isAuthorizedForUser, boolean isAuthorizedForApp) { - super(isAuthorizedForUser, isAuthorizedForApp); - this.restTemplate = restTemplate; - } - - public SearchResults search(String query) { - return this.search(new SearchParameters(query)); - } - - public SearchResults search(String query, int resultsPerPage) { - SearchParameters p = new SearchParameters(query).count(resultsPerPage); - return this.search(p); - } - - public SearchResults search(String query, int resultsPerPage, long sinceId, long maxId) { - SearchParameters p = new SearchParameters(query).count(resultsPerPage).sinceId(sinceId); - if (maxId > 0) { - p.maxId(maxId); - } - return this.search(p); - } - - public SearchResults search(SearchParameters searchParameters) { - requireEitherUserOrAppAuthorization(); - Assert.notNull(searchParameters); - MultiValueMap parameters = buildQueryParametersFromSearchParameters(searchParameters); - return restTemplate.getForObject(buildUri("search/tweets.json", parameters),SearchResults.class); - } - - public List getSavedSearches() { - requireUserAuthorization(); - return restTemplate.getForObject(buildUri("saved_searches/list.json"), SavedSearchList.class); - } - - public SavedSearch getSavedSearch(long searchId) { - requireUserAuthorization(); - return restTemplate.getForObject(buildUri("saved_searches/show/" + searchId + ".json"), SavedSearch.class); - } - - public SavedSearch createSavedSearch(String query) { - requireUserAuthorization(); - MultiValueMap data = new LinkedMultiValueMap(); - data.set("query", query); - return restTemplate.postForObject(buildUri("saved_searches/create.json"), data, SavedSearch.class); - } - - public void deleteSavedSearch(long searchId) { - requireUserAuthorization(); - MultiValueMap data = new LinkedMultiValueMap(); - restTemplate.postForObject(buildUri("saved_searches/destroy/" + searchId + ".json"), data, SavedSearch.class); - } - - // Trends - - public Trends getLocalTrends(long whereOnEarthId) { - return getLocalTrends(whereOnEarthId, false); - } - - public Trends getLocalTrends(long whereOnEarthId, boolean excludeHashtags) { - requireEitherUserOrAppAuthorization(); - LinkedMultiValueMap parameters = new LinkedMultiValueMap(); - parameters.set("id",String.valueOf(whereOnEarthId)); - if(excludeHashtags) { - parameters.set("exclude", "hashtags"); - } - return restTemplate.getForObject(buildUri("trends/place.json", parameters), LocalTrendsHolder.class).getTrends(); - } +public class SearchTemplate extends AbstractTwitterOperations implements SearchOperations { + private static final MultiValueMap EMPTY_DATA = new LinkedMultiValueMap(); + private final RestTemplate restTemplate; + + public SearchTemplate(RestTemplate restTemplate, boolean isAuthorizedForUser, boolean isAuthorizedForApp) { + super(isAuthorizedForUser, isAuthorizedForApp); + this.restTemplate = restTemplate; + } + + @Override + public SearchResults search(String query) { + return this.search(new SearchParameters(query)); + } + + @Override + public SearchResults search(String query, int resultsPerPage) { + SearchParameters p = new SearchParameters(query).count(resultsPerPage); + return this.search(p); + } + + @Override + public SearchResults search(String query, int resultsPerPage, long sinceId, long maxId) { + SearchParameters p = new SearchParameters(query).count(resultsPerPage).sinceId(sinceId); + if (maxId > 0) { + p.maxId(maxId); + } + return this.search(p); + } + + @Override + public SearchResults search(SearchParameters searchParameters) { + requireEitherUserOrAppAuthorization(); + Assert.notNull(searchParameters); + return restTemplate.getForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.SEARCH_TWEETS) + .withArgument(buildQueryParametersFromSearchParameters(searchParameters)) + .build(), + SearchResults.class); + } + + @Override + public List getSavedSearches() { + requireUserAuthorization(); + return restTemplate.getForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.SAVED_SEARCHES_LIST) + .build(), + SavedSearchList.class); + } + + @Override + public SavedSearch getSavedSearch(long searchId) { + requireUserAuthorization(); + return restTemplate.getForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.SAVED_SEARCHES_SHOW) + .withArgument("search_id", searchId) + .build(), + SavedSearch.class); + } + + @Override + public SavedSearch createSavedSearch(String query) { + requireUserAuthorization(); + return restTemplate.postForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.SAVED_SEARCHES_CREATE) + .build(), + new RestRequestBodyBuilder() + .withField("query", query) + .build(), + SavedSearch.class); + } + + @Override + public void deleteSavedSearch(long searchId) { + requireUserAuthorization(); + restTemplate.postForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.SAVED_SEARCHES_DESTROY) + .withArgument("search_id", searchId) + .build(), + EMPTY_DATA, + SavedSearch.class); + } + + // Trends + + @Override + public Trends getLocalTrends(long whereOnEarthId) { + return getLocalTrends(whereOnEarthId, false); + } + + @Override + public Trends getLocalTrends(long whereOnEarthId, boolean excludeHashtags) { + requireEitherUserOrAppAuthorization(); + + LinkedMultiValueMap parameters = new LinkedMultiValueMap(); + parameters.set("id", String.valueOf(whereOnEarthId)); + if (excludeHashtags) { + parameters.set("exclude", "hashtags"); + } + + return restTemplate.getForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.TRENDS_PLACE) + .withArgument(parameters) + .build(), + LocalTrendsHolder.class + ).getTrends(); + } } diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/SettingsImpl.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/SettingsImpl.java new file mode 100644 index 00000000..b3bb63db --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/SettingsImpl.java @@ -0,0 +1,33 @@ +package org.springframework.social.twitter.api.impl; + +import org.springframework.social.twitter.api.Settings; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; + +public class SettingsImpl implements Settings { + + @Override + @JsonProperty("host_for_standard_api") + public String hostForStandardApi() { + return TwitterApiHosts.getStandardApi(); + } + + @Override + @JsonProperty("host_for_ads_api") + public String hostForAdsApi() { + return TwitterApiHosts.getAdsApi(); + } + + @Override + public String toString() { + try { + return new ObjectMapper().writeValueAsString(this); + } + catch (JsonProcessingException e) { + e.printStackTrace(); + return e.toString(); + } + } +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/SimilarPlacesDeserializer.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/SimilarPlacesDeserializer.java index 7eafc79c..f9a708ee 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/SimilarPlacesDeserializer.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/SimilarPlacesDeserializer.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -28,18 +28,19 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -class SimilarPlacesDeserializer extends JsonDeserializer { - @Override - public SimilarPlacesResponse deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { - ObjectMapper mapper = new ObjectMapper(); - mapper.registerModule(new TwitterModule()); - jp.setCodec(mapper); - JsonNode node = jp.readValueAs(JsonNode.class); - JsonNode resultNode = node.get("result"); - String token = resultNode.get("token").textValue(); - JsonNode placesNode = resultNode.get("places"); - @SuppressWarnings("unchecked") - List places = (List) mapper.reader(new TypeReference>() {}).readValue(placesNode); - return new SimilarPlacesResponse(places, token); - } +public class SimilarPlacesDeserializer extends JsonDeserializer { + @SuppressWarnings("deprecation") + @Override + public SimilarPlacesResponse deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { + ObjectMapper mapper = new ObjectMapper(); + mapper.registerModule(new TwitterModule()); + jp.setCodec(mapper); + JsonNode node = jp.readValueAs(JsonNode.class); + JsonNode resultNode = node.get("result"); + String token = resultNode.get("token").textValue(); + JsonNode placesNode = resultNode.get("places"); + @SuppressWarnings("unchecked") + List places = (List) mapper.reader(new TypeReference>() {}).readValue(placesNode); + return new SimilarPlacesResponse(places, token); + } } diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/SimilarPlacesMixin.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/SimilarPlacesMixin.java index 49a672e8..db0450db 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/SimilarPlacesMixin.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/SimilarPlacesMixin.java @@ -20,6 +20,6 @@ @JsonIgnoreProperties(ignoreUnknown = true) @JsonDeserialize(using = SimilarPlacesDeserializer.class) -abstract class SimilarPlacesMixin extends TwitterObjectMixin { +public abstract class SimilarPlacesMixin extends TwitterObjectMixin { } diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/SimilarPlacesResponse.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/SimilarPlacesResponse.java index 22bf2930..2230c152 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/SimilarPlacesResponse.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/SimilarPlacesResponse.java @@ -1,12 +1,12 @@ /* * Copyright 2014 the original author or authors. - * + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * + * + * http://www.apache.org/licenses/LICENSE-2.0 + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -20,31 +20,36 @@ import org.springframework.social.twitter.api.Place; /** - * Represents the results of a similar places search. Includes places that match the search criteria and a token that may be used to create a new place. + * Represents the results of a similar places search. Includes places that match the search criteria and a token that may be used to create a new + * place. + * * @author Craig Walls */ -class SimilarPlacesResponse { - - private final String token; - private final List places; - - public SimilarPlacesResponse(List places, String token) { - this.places = places; - this.token = token; - } - - /** - * The list of places found in a similar places search. - * @return - */ - public List getPlaces() { - return places; - } +public class SimilarPlacesResponse { - /** - * A token that may be used to create a new place. - */ - public String getToken() { - return token; - } + private final String token; + private final List places; + + public SimilarPlacesResponse(List places, String token) { + this.places = places; + this.token = token; + } + + /** + * The list of places found in a similar places search. + * + * @return the list of {@link Place} + */ + public List getPlaces() { + return places; + } + + /** + * A token that may be used to create a new place. + * + * @return the token. + */ + public String getToken() { + return token; + } } diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/StreamCreationException.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/StreamCreationException.java index 62af85b0..833165d3 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/StreamCreationException.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/StreamCreationException.java @@ -18,7 +18,7 @@ import org.springframework.http.HttpStatus; @SuppressWarnings("serial") -class StreamCreationException extends Exception { +public class StreamCreationException extends Exception { private HttpStatus httpStatus; diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/StreamDeleteEventMixin.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/StreamDeleteEventMixin.java index a6267b1d..aeb49281 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/StreamDeleteEventMixin.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/StreamDeleteEventMixin.java @@ -30,7 +30,7 @@ @JsonIgnoreProperties(ignoreUnknown = true) @JsonDeserialize(using = DeleteTweetEventDeserializer.class) -abstract class StreamDeleteEventMixin extends TwitterObjectMixin { +public abstract class StreamDeleteEventMixin extends TwitterObjectMixin { static final class DeleteTweetEventDeserializer extends JsonDeserializer { @Override diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/StreamDispatcher.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/StreamDispatcher.java index 6770ea41..c40f2efd 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/StreamDispatcher.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/StreamDispatcher.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -20,7 +20,6 @@ import java.util.Queue; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicBoolean; import org.springframework.social.twitter.api.StreamDeleteEvent; @@ -30,99 +29,105 @@ import com.fasterxml.jackson.databind.ObjectMapper; -class StreamDispatcher implements Runnable { - - private final List listeners; - - private ObjectMapper objectMapper; - - private AtomicBoolean active; - - private final Queue queue; - - private final ExecutorService pool; - - public StreamDispatcher(Queue queue, List listeners) { - this.queue = queue; - this.listeners = listeners; - pool = Executors.newCachedThreadPool(); - objectMapper = new ObjectMapper(); - objectMapper.addMixInAnnotations(Tweet.class, TweetMixin.class); - objectMapper.addMixInAnnotations(StreamDeleteEvent.class, StreamDeleteEventMixin.class); - objectMapper.addMixInAnnotations(StreamWarningEvent.class, StreamWarningEventMixin.class); - active = new AtomicBoolean(true); - } - - public void run() { - while(active.get()) { - String line = queue.poll(); - if(line == null || line.length() == 0) return; - - // TODO: handle scrub_geo, status_withheld, user_withheld, disconnect, friends, events, - - try { - if (line.contains("in_reply_to_status_id_str")) { // TODO: This is kinda hacky - handleTweet(line); - } else if (line.startsWith("{\"limit")) { - handleLimit(line); - } else if (line.startsWith("{\"delete")) { - handleDelete(line); - } else if (line.startsWith("{\"warning")) { - handleWarning(line); - } - } catch (IOException e) { - // TODO: Should only happen if Jackson doesn't know how to map the line - } - } - } - - public void stop() { - active.set(false); - pool.shutdown(); - } - - private void handleDelete(String line) throws IOException { - final StreamDeleteEvent deleteEvent = objectMapper.readValue(line, StreamDeleteEvent.class); - for (final StreamListener listener : listeners) { - Future result = pool.submit((new Runnable() { - public void run() { - listener.onDelete(deleteEvent); - } - })); - } - } - - private void handleLimit(String line) throws IOException { - final TrackLimitEvent limitEvent = objectMapper.readValue(line, TrackLimitEvent.class); - for (final StreamListener listener : listeners) { - Future result = pool.submit((new Runnable() { - public void run() { - listener.onLimit(limitEvent.getNumberOfLimitedTweets()); - } - })); - } - } - - private void handleTweet(String line) throws IOException { - final Tweet tweet = objectMapper.readValue(line, Tweet.class); - for (final StreamListener listener : listeners) { - Future result = pool.submit((new Runnable() { - public void run() { - listener.onTweet(tweet); - } - })); - } - } - - private void handleWarning(String line) throws IOException { - final StreamWarningEvent warningEvent = objectMapper.readValue(line, StreamWarningEvent.class); - for (final StreamListener listener : listeners) { - Future result = pool.submit((new Runnable() { - public void run() { - listener.onWarning(warningEvent); - } - })); - } - } - +public class StreamDispatcher implements Runnable { + + private final List listeners; + + private ObjectMapper objectMapper; + + private AtomicBoolean active; + + private final Queue queue; + + private final ExecutorService pool; + + @SuppressWarnings("deprecation") + public StreamDispatcher(Queue queue, List listeners) { + this.queue = queue; + this.listeners = listeners; + pool = Executors.newCachedThreadPool(); + objectMapper = new ObjectMapper(); + objectMapper.addMixInAnnotations(Tweet.class, TweetMixin.class); + objectMapper.addMixInAnnotations(StreamDeleteEvent.class, StreamDeleteEventMixin.class); + objectMapper.addMixInAnnotations(StreamWarningEvent.class, StreamWarningEventMixin.class); + active = new AtomicBoolean(true); + } + + public void run() { + while (active.get()) { + String line = queue.poll(); + if (line == null || line.length() == 0) + return; + + // TODO: handle scrub_geo, status_withheld, user_withheld, disconnect, friends, events, + + try { + if (line.contains("in_reply_to_status_id_str")) { // TODO: This is kinda hacky + handleTweet(line); + } + else if (line.startsWith("{\"limit")) { + handleLimit(line); + } + else if (line.startsWith("{\"delete")) { + handleDelete(line); + } + else if (line.startsWith("{\"warning")) { + handleWarning(line); + } + } + catch (IOException e) { + // TODO: Should only happen if Jackson doesn't know how to map the line + } + } + } + + public void stop() { + active.set(false); + pool.shutdown(); + } + + private void handleDelete(String line) throws IOException { + final StreamDeleteEvent deleteEvent = objectMapper.readValue(line, StreamDeleteEvent.class); + for (final StreamListener listener : listeners) { + pool.submit((new Runnable() { + public void run() { + listener.onDelete(deleteEvent); + } + })); + } + } + + private void handleLimit(String line) throws IOException { + final TrackLimitEvent limitEvent = objectMapper.readValue(line, TrackLimitEvent.class); + for (final StreamListener listener : listeners) { + pool.submit((new Runnable() { + public void run() { + listener.onLimit(limitEvent.getNumberOfLimitedTweets()); + } + })); + } + } + + private void handleTweet(String line) throws IOException { + final Tweet tweet = objectMapper.readValue(line, Tweet.class); + for (final StreamListener listener : listeners) { + pool.submit((new Runnable() { + public void run() { + listener.onTweet(tweet); + } + })); + } + } + + private void handleWarning(String line) throws IOException { + final StreamWarningEvent warningEvent = objectMapper.readValue(line, StreamWarningEvent.class); + for (final StreamListener listener : listeners) { + pool.submit((new Runnable() { + public void run() { + listener.onWarning(warningEvent); + } + })); + } + } + } diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/StreamReader.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/StreamReader.java index bc583754..b6e028d5 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/StreamReader.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/StreamReader.java @@ -15,7 +15,7 @@ */ package org.springframework.social.twitter.api.impl; -interface StreamReader { +public interface StreamReader { void next(); diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/StreamReaderImpl.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/StreamReaderImpl.java index bb830e0c..0c1088d4 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/StreamReaderImpl.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/StreamReaderImpl.java @@ -30,7 +30,7 @@ import org.springframework.social.twitter.api.StreamListener; import org.springframework.social.twitter.api.StreamingException; -class StreamReaderImpl implements StreamReader { +public class StreamReaderImpl implements StreamReader { private AtomicBoolean open; diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/StreamWarningEventMixin.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/StreamWarningEventMixin.java index 816ed167..40236ee7 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/StreamWarningEventMixin.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/StreamWarningEventMixin.java @@ -30,7 +30,7 @@ @JsonIgnoreProperties(ignoreUnknown = true) @JsonDeserialize(using=StreamWarningEventDeserializer.class) -abstract class StreamWarningEventMixin extends TwitterObjectMixin { +public abstract class StreamWarningEventMixin extends TwitterObjectMixin { static final class StreamWarningEventDeserializer extends JsonDeserializer { @Override diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/StreamingTemplate.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/StreamingTemplate.java index 00f3f9de..72af8b9e 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/StreamingTemplate.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/StreamingTemplate.java @@ -42,7 +42,7 @@ /** * @author Craig Walls */ -class StreamingTemplate extends AbstractTwitterOperations implements StreamingOperations { +public class StreamingTemplate extends AbstractTwitterOperations implements StreamingOperations { private final RestTemplate restTemplate; diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/SuggestionCategoryList.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/SuggestionCategoryList.java index d2f5c30d..8b23b371 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/SuggestionCategoryList.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/SuggestionCategoryList.java @@ -26,5 +26,5 @@ * @author Craig Walls */ @SuppressWarnings("serial") -class SuggestionCategoryList extends ArrayList { +public class SuggestionCategoryList extends ArrayList { } diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/SuggestionCategoryMixin.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/SuggestionCategoryMixin.java index fab86135..d8d70b77 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/SuggestionCategoryMixin.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/SuggestionCategoryMixin.java @@ -22,7 +22,7 @@ * Mixin class for adding Jackson annotations to SuggestionCategory. * @author Craig Walls */ -abstract class SuggestionCategoryMixin extends TwitterObjectMixin { +public abstract class SuggestionCategoryMixin extends TwitterObjectMixin { @JsonCreator SuggestionCategoryMixin( @JsonProperty("name") String name, diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/ThreadedStreamConsumer.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/ThreadedStreamConsumer.java index c7fed525..25db90c8 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/ThreadedStreamConsumer.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/ThreadedStreamConsumer.java @@ -20,7 +20,7 @@ import org.springframework.social.twitter.api.Stream; import org.springframework.social.twitter.api.StreamingException; -abstract class ThreadedStreamConsumer extends Thread implements Stream { +public abstract class ThreadedStreamConsumer extends Thread implements Stream { private AtomicBoolean open; @@ -91,9 +91,9 @@ protected void sleepBeforeRetry(long timeToSleep) { } catch (InterruptedException e1) {} } - static final long HTTP_ERROR_SLEEP_MAX = 320000; + public static final long HTTP_ERROR_SLEEP_MAX = 320000; - static final long NETWORK_ERROR_SLEEP_MAX = 16000; + public static final long NETWORK_ERROR_SLEEP_MAX = 16000; private static final long MIN_WAIT = 250; diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TimelineDateDeserializer.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TimelineDateDeserializer.java index 1731a609..377f39c5 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TimelineDateDeserializer.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TimelineDateDeserializer.java @@ -30,7 +30,7 @@ * Deserializer to read date values from Twitter timeline entries. * @author Craig Walls */ -class TimelineDateDeserializer extends JsonDeserializer { +public class TimelineDateDeserializer extends JsonDeserializer { @Override public Date deserialize(JsonParser jp, DeserializationContext ctxt) diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TimelineTemplate.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TimelineTemplate.java index 92036935..d25aa2d9 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TimelineTemplate.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TimelineTemplate.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -34,257 +34,390 @@ /** * Implementation of {@link TimelineOperations}, providing a binding to Twitter's tweet and timeline-oriented REST resources. + * * @author Craig Walls */ +@SuppressWarnings("deprecation") class TimelineTemplate extends AbstractTwitterOperations implements TimelineOperations { - - private final RestTemplate restTemplate; - - public TimelineTemplate(RestTemplate restTemplate, boolean isAuthorizedForUser, boolean isAuthorizedForApp) { - super(isAuthorizedForUser, isAuthorizedForApp); - this.restTemplate = restTemplate; - } - - public List getHomeTimeline() { - return getHomeTimeline(20, 0, 0); - } - - public List getHomeTimeline(int pageSize) { - return getHomeTimeline(pageSize, 0, 0); - } - - public List getHomeTimeline(int pageSize, long sinceId, long maxId) { - requireUserAuthorization(); - MultiValueMap parameters = PagingUtils.buildPagingParametersWithCount(pageSize, sinceId, maxId); - parameters.set("include_entities", "true"); - return restTemplate.getForObject(buildUri("statuses/home_timeline.json", parameters), TweetList.class); - } - - public List getUserTimeline() { - return getUserTimeline(20, 0, 0); - } - - public List getUserTimeline(int pageSize) { - return getUserTimeline(pageSize, 0, 0); - } - - public List getUserTimeline(int pageSize, long sinceId, long maxId) { - requireUserAuthorization(); - MultiValueMap parameters = PagingUtils.buildPagingParametersWithCount(pageSize, sinceId, maxId); - parameters.set("include_entities", "true"); - return restTemplate.getForObject(buildUri("statuses/user_timeline.json", parameters), TweetList.class); - } - - public List getUserTimeline(String screenName) { - return getUserTimeline(screenName, 20, 0, 0); - } - - public List getUserTimeline(String screenName, int pageSize) { - return getUserTimeline(screenName, pageSize, 0, 0); - } - - public List getUserTimeline(String screenName, int pageSize, long sinceId, long maxId) { - requireEitherUserOrAppAuthorization(); - MultiValueMap parameters = PagingUtils.buildPagingParametersWithCount(pageSize, sinceId, maxId); - parameters.set("screen_name", screenName); - parameters.set("include_entities", "true"); - return restTemplate.getForObject(buildUri("statuses/user_timeline.json", parameters), TweetList.class); - } - - public List getUserTimeline(long userId) { - return getUserTimeline(userId, 20, 0, 0); - } - - public List getUserTimeline(long userId, int pageSize) { - return getUserTimeline(userId, pageSize, 0, 0); - } - - public List getUserTimeline(long userId, int pageSize, long sinceId, long maxId) { - requireEitherUserOrAppAuthorization(); - MultiValueMap parameters = PagingUtils.buildPagingParametersWithCount(pageSize, sinceId, maxId); - parameters.set("user_id", String.valueOf(userId)); - parameters.set("include_entities", "true"); - return restTemplate.getForObject(buildUri("statuses/user_timeline.json", parameters), TweetList.class); - } - - public List getMentions() { - return getMentions(20, 0, 0); - } - - public List getMentions(int pageSize) { - return getMentions(pageSize, 0, 0); - } - - public List getMentions(int pageSize, long sinceId, long maxId) { - requireUserAuthorization(); - MultiValueMap parameters = PagingUtils.buildPagingParametersWithCount(pageSize, sinceId, maxId); - parameters.set("include_entities", "true"); - return restTemplate.getForObject(buildUri("statuses/mentions_timeline.json", parameters), TweetList.class); - } - - public List getRetweetsOfMe() { - return getRetweetsOfMe(1, 20, 0, 0); - } - - public List getRetweetsOfMe(int page, int pageSize) { - return getRetweetsOfMe(page, pageSize, 0, 0); - } - - public List getRetweetsOfMe(int page, int pageSize, long sinceId, long maxId) { - requireUserAuthorization(); - MultiValueMap parameters = PagingUtils.buildPagingParametersWithCount(page, pageSize, sinceId, maxId); - parameters.set("include_entities", "true"); - return restTemplate.getForObject(buildUri("statuses/retweets_of_me.json", parameters), TweetList.class); - } - - public Tweet getStatus(long tweetId) { - requireEitherUserOrAppAuthorization(); - MultiValueMap parameters = new LinkedMultiValueMap(); - parameters.set("include_entities", "true"); - return restTemplate.getForObject(buildUri("statuses/show/" + tweetId + ".json", parameters), Tweet.class); - } - - public OEmbedTweet getStatusOEmbed(String tweetId) { - return getStatusOEmbed(tweetId, new OEmbedOptions()); - } - - public OEmbedTweet getStatusOEmbed(String tweetId, OEmbedOptions options) { - requireEitherUserOrAppAuthorization(); - MultiValueMap parameters = options.toRequestParameters(); - parameters.set("id", String.valueOf(tweetId)); - return restTemplate.getForObject(buildUri("statuses/oembed.json", parameters), OEmbedTweet.class); - } - - - public Tweet updateStatus(String message) { - return updateStatus(new TweetData(message)); - } - - public Tweet updateStatus(String message, Resource media) { - return updateStatus(new TweetData(message).withMedia(media)); - } - - public Tweet updateStatus(String message, StatusDetails details) { - requireUserAuthorization(); - MultiValueMap tweetParams = new LinkedMultiValueMap(); - tweetParams.add("status", message); - tweetParams.putAll(details.toParameterMap()); - return restTemplate.postForObject(buildUri("statuses/update.json"), tweetParams, Tweet.class); - } - - public Tweet updateStatus(String message, Resource media, StatusDetails details) { - requireUserAuthorization(); - MultiValueMap tweetParams = new LinkedMultiValueMap(); - tweetParams.add("status", message); - tweetParams.putAll(details.toParameterMap()); - if (media != null) { - MultiValueMap uploadParams = new LinkedMultiValueMap(); - uploadParams.set("media", media); - MediaUploadResponse response = restTemplate.postForObject("https://upload.twitter.com/1.1/media/upload.json", - uploadParams, MediaUploadResponse.class); - tweetParams.set("media_ids", response.getMediaId()); - } - return restTemplate.postForObject(buildUri("statuses/update.json"), tweetParams, Tweet.class); - } - - public Tweet updateStatus(TweetData tweetData) { - requireUserAuthorization(); - MultiValueMap postParameters = tweetData.toTweetParameters(); - if (tweetData.hasMedia()) { - MediaUploadResponse response = restTemplate.postForObject("https://upload.twitter.com/1.1/media/upload.json", - tweetData.toUploadMediaParameters(), MediaUploadResponse.class); - postParameters.set("media_ids", response.getMediaId()); - } - return restTemplate.postForObject(buildUri("statuses/update.json"), postParameters, Tweet.class); - } - - public void deleteStatus(long tweetId) { - requireUserAuthorization(); - MultiValueMap data = new LinkedMultiValueMap(); - restTemplate.postForObject(buildUri("statuses/destroy/" + tweetId + ".json"), data, String.class); - } - - public Tweet retweet(long tweetId) { - requireUserAuthorization(); - MultiValueMap data = new LinkedMultiValueMap(); - return restTemplate.postForObject(buildUri("statuses/retweet/" + tweetId + ".json"), data, Tweet.class); - } - - public List getRetweets(long tweetId) { - return getRetweets(tweetId, 100); - } - - public List getRetweets(long tweetId, int count) { - requireEitherUserOrAppAuthorization(); - MultiValueMap parameters = new LinkedMultiValueMap(); - parameters.set("count", String.valueOf(count)); - parameters.set("include_entities", "true"); - return restTemplate.getForObject(buildUri("statuses/retweets/" + tweetId + ".json", parameters), TweetList.class); - } - - public List getFavorites() { - return getFavorites(20); - } - - public List getFavorites(int pageSize) { - requireEitherUserOrAppAuthorization(); - // Note: The documentation for /favorites.json doesn't list the count parameter, but it works anyway. - MultiValueMap parameters = PagingUtils.buildPagingParametersWithCount(pageSize, 0, 0); - parameters.set("include_entities", "true"); - return restTemplate.getForObject(buildUri("favorites/list.json", parameters), TweetList.class); - } - - public List getFavorites(long userId) { - return getFavorites(userId, 20); - } - - public List getFavorites(long userId, int pageSize) { - requireEitherUserOrAppAuthorization(); - MultiValueMap parameters = PagingUtils.buildPagingParametersWithCount(pageSize, 0, 0); - parameters.set("user_id", String.valueOf(userId)); - parameters.set("include_entities", "true"); - return restTemplate.getForObject(buildUri("favorites/list.json", parameters), TweetList.class); - } - - public List getFavorites(String screenName) { - return getFavorites(screenName, 20); - } - - public List getFavorites(String screenName, int pageSize) { - requireEitherUserOrAppAuthorization(); - MultiValueMap parameters = PagingUtils.buildPagingParametersWithCount(pageSize, 0, 0); - parameters.set("screen_name", screenName); - parameters.set("include_entities", "true"); - return restTemplate.getForObject(buildUri("favorites/list.json", parameters), TweetList.class); - } - - public void addToFavorites(long tweetId) { - requireUserAuthorization(); - MultiValueMap data = new LinkedMultiValueMap(); - data.set("id", String.valueOf(tweetId)); - restTemplate.postForObject(buildUri("favorites/create.json"), data, String.class); - } - - public void removeFromFavorites(long tweetId) { - requireUserAuthorization(); - MultiValueMap data = new LinkedMultiValueMap(); - data.set("id", String.valueOf(tweetId)); - restTemplate.postForObject(buildUri("favorites/destroy.json"), data, String.class); - } - - @SuppressWarnings("serial") - private static class TweetList extends ArrayList {} - - @JsonIgnoreProperties(ignoreUnknown=true) - private static class MediaUploadResponse { - - @JsonProperty("media_id") - private String mediaId; - - public String getMediaId() { - return mediaId; - } - - } - -} + private static final MultiValueMap EMPTY_DATA = new LinkedMultiValueMap(); + + private final RestTemplate restTemplate; + + public TimelineTemplate(final RestTemplate restTemplate, final boolean isAuthorizedForUser, final boolean isAuthorizedForApp) { + super(isAuthorizedForUser, isAuthorizedForApp); + this.restTemplate = restTemplate; + } + + @Override + public List getHomeTimeline() { + return getHomeTimeline(20, 0, 0); + } + + @Override + public List getHomeTimeline(final int pageSize) { + return getHomeTimeline(pageSize, 0, 0); + } + + @Override + public List getHomeTimeline(final int pageSize, final long sinceId, final long maxId) { + requireUserAuthorization(); + final MultiValueMap parameters = PagingUtils.buildPagingParametersWithCount(pageSize, sinceId, maxId); + parameters.set("include_entities", "true"); + return restTemplate.getForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.STATUSES_HOME_TIMELINE) + .withArgument(parameters) + .build(), + TweetList.class); + } + + @Override + public List getUserTimeline() { + return getUserTimeline(20, 0, 0); + } + + @Override + public List getUserTimeline(final int pageSize) { + return getUserTimeline(pageSize, 0, 0); + } + + @Override + public List getUserTimeline(final int pageSize, final long sinceId, final long maxId) { + requireUserAuthorization(); + final MultiValueMap parameters = PagingUtils.buildPagingParametersWithCount(pageSize, sinceId, maxId); + parameters.set("include_entities", "true"); + return restTemplate.getForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.STATUSES_USER_TIMELINE) + .withArgument(parameters) + .build(), + TweetList.class); + } + + @Override + public List getUserTimeline(final String screenName) { + return getUserTimeline(screenName, 20, 0, 0); + } + + @Override + public List getUserTimeline(final String screenName, final int pageSize) { + return getUserTimeline(screenName, pageSize, 0, 0); + } + + @Override + public List getUserTimeline(final String screenName, final int pageSize, final long sinceId, final long maxId) { + requireEitherUserOrAppAuthorization(); + final MultiValueMap parameters = PagingUtils.buildPagingParametersWithCount(pageSize, sinceId, maxId); + parameters.set("screen_name", screenName); + parameters.set("include_entities", "true"); + return restTemplate.getForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.STATUSES_USER_TIMELINE) + .withArgument(parameters) + .build(), + TweetList.class); + } + + @Override + public List getUserTimeline(final long userId) { + return getUserTimeline(userId, 20, 0, 0); + } + + @Override + public List getUserTimeline(final long userId, final int pageSize) { + return getUserTimeline(userId, pageSize, 0, 0); + } + + @Override + public List getUserTimeline(final long userId, final int pageSize, final long sinceId, final long maxId) { + requireEitherUserOrAppAuthorization(); + final MultiValueMap parameters = PagingUtils.buildPagingParametersWithCount(pageSize, sinceId, maxId); + parameters.set("user_id", String.valueOf(userId)); + parameters.set("include_entities", "true"); + return restTemplate.getForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.STATUSES_USER_TIMELINE) + .withArgument(parameters) + .build(), + TweetList.class); + } + + @Override + public List getMentions() { + return getMentions(20, 0, 0); + } + + @Override + public List getMentions(final int pageSize) { + return getMentions(pageSize, 0, 0); + } + + @Override + public List getMentions(final int pageSize, final long sinceId, final long maxId) { + requireUserAuthorization(); + final MultiValueMap parameters = PagingUtils.buildPagingParametersWithCount(pageSize, sinceId, maxId); + parameters.set("include_entities", "true"); + return restTemplate.getForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.STATUSES_MENTIONS_TIMELINE) + .withArgument(parameters) + .build(), + TweetList.class); + } + + @Override + public List getRetweetsOfMe() { + return getRetweetsOfMe(1, 20, 0, 0); + } + + @Override + public List getRetweetsOfMe(final int page, final int pageSize) { + return getRetweetsOfMe(page, pageSize, 0, 0); + } + + @Override + public List getRetweetsOfMe(final int page, final int pageSize, final long sinceId, final long maxId) { + requireUserAuthorization(); + final MultiValueMap parameters = PagingUtils.buildPagingParametersWithCount(page, pageSize, sinceId, maxId); + parameters.set("include_entities", "true"); + return restTemplate.getForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.STATUSES_RETWEETS_OF_ME) + .withArgument(parameters) + .build(), + TweetList.class); + } + + @Override + public Tweet getStatus(final long tweetId) { + requireEitherUserOrAppAuthorization(); + final MultiValueMap parameters = new LinkedMultiValueMap(); + parameters.set("include_entities", "true"); + return restTemplate.getForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.STATUSES_SHOW) + .withArgument("tweet_id", tweetId) + .withArgument(parameters) + .build(), + Tweet.class); + } + + @Override + public OEmbedTweet getStatusOEmbed(final String tweetId) { + return getStatusOEmbed(tweetId, new OEmbedOptions()); + } + + @Override + public OEmbedTweet getStatusOEmbed(final String tweetId, final OEmbedOptions options) { + requireEitherUserOrAppAuthorization(); + final MultiValueMap parameters = options.toRequestParameters(); + parameters.set("id", String.valueOf(tweetId)); + return restTemplate.getForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.STATUSES_OEMBEDED) + .withArgument(parameters) + .build(), + OEmbedTweet.class); + } + + @Override + public Tweet updateStatus(final String message) { + return updateStatus(new TweetData(message)); + } + + @Override + public Tweet updateStatus(final String message, final Resource media) { + return updateStatus(new TweetData(message).withMedia(media)); + } + + @Override + public Tweet updateStatus(final String message, final StatusDetails details) { + requireUserAuthorization(); + final MultiValueMap tweetParams = new LinkedMultiValueMap(); + tweetParams.add("status", message); + tweetParams.putAll(details.toParameterMap()); + return restTemplate.postForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.STATUSES_UPDATE) + .build(), + new RestRequestBodyBuilder() + .withField("status", message) + .withFields(details.toParameterMap()) + .build(), + Tweet.class); + } + + @Override + public Tweet updateStatus(final String message, final Resource media, final StatusDetails details) { + requireUserAuthorization(); + MultiValueMap tweetParams = new LinkedMultiValueMap(); + tweetParams.add("status", message); + tweetParams.putAll(details.toParameterMap()); + if (media != null) { + MultiValueMap uploadParams = new LinkedMultiValueMap(); + uploadParams.set("media", media); + MediaUploadResponse response = restTemplate.postForObject( + "https://upload.twitter.com/1.1/media/upload.json", + uploadParams, + MediaUploadResponse.class); + tweetParams.set("media_ids", response.getMediaId()); + } + return restTemplate.postForObject(buildUri("statuses/update.json"), tweetParams, Tweet.class); + } + + @Override + public Tweet updateStatus(final TweetData tweetData) { + requireUserAuthorization(); + MultiValueMap postParameters = tweetData.toTweetParameters(); + if (tweetData.hasMedia()) { + MediaUploadResponse response = restTemplate.postForObject( + "https://upload.twitter.com/1.1/media/upload.json", + tweetData.toUploadMediaParameters(), + MediaUploadResponse.class); + postParameters.set("media_ids", response.getMediaId()); + } + return restTemplate.postForObject(buildUri("statuses/update.json"), postParameters, Tweet.class); + } + + @Override + public void deleteStatus(final long tweetId) { + requireUserAuthorization(); + restTemplate.postForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.STATUSES_DESTROY) + .withArgument("tweet_id", tweetId) + .build(), + EMPTY_DATA, + String.class); + } + + @Override + public Tweet retweet(final long tweetId) { + requireUserAuthorization(); + return restTemplate.postForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.STATUSES_RETWEET) + .withArgument("tweet_id", tweetId) + .build(), + EMPTY_DATA, + Tweet.class); + } + + @Override + public List getRetweets(final long tweetId) { + return getRetweets(tweetId, 100); + } + + @Override + public List getRetweets(final long tweetId, final int count) { + requireEitherUserOrAppAuthorization(); + return restTemplate.getForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.STATUSES_RETWEETS) + .withArgument("tweet_id", tweetId) + .withArgument("count", String.valueOf(count)) + .withArgument("include_entities", "true") + .build(), + TweetList.class); + } + + @Override + public List getFavorites() { + return getFavorites(20); + } + + @Override + public List getFavorites(final int pageSize) { + requireEitherUserOrAppAuthorization(); + // Note: The documentation for /favorites.json doesn't list the count parameter, but it works anyway. + final MultiValueMap parameters = PagingUtils.buildPagingParametersWithCount(pageSize, 0, 0); + parameters.set("include_entities", "true"); + return restTemplate.getForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.FAVORITES_LIST) + .withArgument(parameters) + .build(), + TweetList.class); + } + + @Override + public List getFavorites(final long userId) { + return getFavorites(userId, 20); + } + + @Override + public List getFavorites(final long userId, final int pageSize) { + requireEitherUserOrAppAuthorization(); + final MultiValueMap parameters = PagingUtils.buildPagingParametersWithCount(pageSize, 0, 0); + parameters.set("user_id", String.valueOf(userId)); + parameters.set("include_entities", "true"); + return restTemplate.getForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.FAVORITES_LIST) + .withArgument(parameters) + .build(), + TweetList.class); + } + + @Override + public List getFavorites(final String screenName) { + return getFavorites(screenName, 20); + } + + @Override + public List getFavorites(final String screenName, final int pageSize) { + requireEitherUserOrAppAuthorization(); + final MultiValueMap parameters = PagingUtils.buildPagingParametersWithCount(pageSize, 0, 0); + parameters.set("screen_name", screenName); + parameters.set("include_entities", "true"); + return restTemplate.getForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.FAVORITES_LIST) + .withArgument(parameters) + .build(), + TweetList.class); + } + + @Override + public void addToFavorites(final long tweetId) { + requireUserAuthorization(); + restTemplate.postForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.FAVORITES_CREATE) + .build(), + new RestRequestBodyBuilder() + .withField("id", String.valueOf(tweetId)) + .build(), + String.class); + } + + @Override + public void removeFromFavorites(final long tweetId) { + requireUserAuthorization(); + restTemplate.postForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.FAVORITES_DESTROY) + .build(), + new RestRequestBodyBuilder() + .withField("id", String.valueOf(tweetId)) + .build(), + String.class); + } + + private static class TweetList extends ArrayList { + private static final long serialVersionUID = 1L; + } + + @JsonIgnoreProperties(ignoreUnknown = true) + private static class MediaUploadResponse { + + @JsonProperty("media_id") + private String mediaId; + + public String getMediaId() { + return mediaId; + } + + } + +} \ No newline at end of file diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TrackLimitEvent.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TrackLimitEvent.java index f1a349aa..4bb9fa22 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TrackLimitEvent.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TrackLimitEvent.java @@ -1,12 +1,12 @@ /* * Copyright 2014 the original author or authors. - * + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * + * + * http://www.apache.org/licenses/LICENSE-2.0 + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -30,31 +30,34 @@ /** * A stream event indicating that Twitter is track-limiting the stream. * This is a sign that a stream's query may not be specific enough, because it matches more tweets than are allowed through the stream. + * * @author Craig Walls */ @JsonIgnoreProperties(ignoreUnknown = true) @JsonDeserialize(using = StreamingLimitationEventDeserializer.class) -class TrackLimitEvent { - - private final int numberOfLimitedTweets; - - private TrackLimitEvent(int numberOfLimitedTweets) { - this.numberOfLimitedTweets = numberOfLimitedTweets; - } - - /** - * The number of tweets since the start of the streaming connection that matched the query, but were rate limited. - */ - public int getNumberOfLimitedTweets() { - return numberOfLimitedTweets; - } - - static final class StreamingLimitationEventDeserializer extends JsonDeserializer { - @Override - public TrackLimitEvent deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { - JsonNode trackNode = jp.readValueAs(JsonNode.class).get("limit").get("track"); - return new TrackLimitEvent(trackNode.asInt()); - } - } - +public class TrackLimitEvent { + + private final int numberOfLimitedTweets; + + private TrackLimitEvent(int numberOfLimitedTweets) { + this.numberOfLimitedTweets = numberOfLimitedTweets; + } + + /** + * The number of tweets since the start of the streaming connection that matched the query, but were rate limited. + * + * @return the number that indicate the limit of tweets. + */ + public int getNumberOfLimitedTweets() { + return numberOfLimitedTweets; + } + + static final class StreamingLimitationEventDeserializer extends JsonDeserializer { + @Override + public TrackLimitEvent deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { + JsonNode trackNode = jp.readValueAs(JsonNode.class).get("limit").get("track"); + return new TrackLimitEvent(trackNode.asInt()); + } + } + } diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TrendMixin.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TrendMixin.java index 9458757e..03c0162a 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TrendMixin.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TrendMixin.java @@ -24,7 +24,7 @@ * @author Craig Walls */ @JsonIgnoreProperties(ignoreUnknown=true) -abstract class TrendMixin extends TwitterObjectMixin { +public abstract class TrendMixin extends TwitterObjectMixin { @JsonCreator TrendMixin(@JsonProperty("name") String name, @JsonProperty("query") String query) {} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TrendsMixin.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TrendsMixin.java index d20d74bf..aabe3395 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TrendsMixin.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TrendsMixin.java @@ -30,7 +30,7 @@ * @author Craig Walls */ @JsonIgnoreProperties(ignoreUnknown=true) -abstract class TrendsMixin extends TwitterObjectMixin { +public abstract class TrendsMixin extends TwitterObjectMixin { @JsonCreator TrendsMixin( @JsonProperty("created_at") @JsonDeserialize(using=TimelineDateDeserializer.class) Date time, diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TweetDeserializer.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TweetDeserializer.java index 0653e1ae..63e28c3f 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TweetDeserializer.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TweetDeserializer.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -40,120 +40,181 @@ /** * Custom Jackson deserializer for tweets. Tweets can't be simply mapped like other Twitter model objects because the JSON structure * varies between the search API and the timeline API. This deserializer determine which structure is in play and creates a tweet from it. + * * @author Craig Walls */ class TweetDeserializer extends JsonDeserializer { + private static final String TIMELINE_DATE_FORMAT = "EEE MMM dd HH:mm:ss ZZZZZ yyyy"; - @Override - public Tweet deserialize(final JsonParser jp, final DeserializationContext ctx) throws IOException { - final JsonNode node = jp.readValueAs(JsonNode.class); - if (null == node || node.isMissingNode() || node.isNull()) { - return null; - } - final Tweet tweet = this.deserialize(node); - jp.skipChildren(); - return tweet; - } - - - public Tweet deserialize(JsonNode node) throws IOException, JsonProcessingException { - final long id = node.path("id").asLong(); - final String idStr = node.path("id_str").asText(); - final String text = node.path("text").asText(); - if (id <= 0 || text == null || text.isEmpty()) { - return null; - } - JsonNode fromUserNode = node.get("user"); - String dateFormat = TIMELINE_DATE_FORMAT; - String fromScreenName = fromUserNode.get("screen_name").asText(); - long fromId = fromUserNode.get("id").asLong(); - String fromImageUrl = fromUserNode.get("profile_image_url").asText(); - Date createdAt = toDate(node.get("created_at").asText(), new SimpleDateFormat(dateFormat, Locale.ENGLISH)); - String source = node.get("source").asText(); - JsonNode toUserIdNode = node.get("in_reply_to_user_id"); - Long toUserId = toUserIdNode != null ? toUserIdNode.asLong() : null; - JsonNode languageCodeNode = node.get("lang"); - String languageCode = languageCodeNode != null && !languageCodeNode.isNull() ? languageCodeNode.asText() : null; - Tweet tweet = new Tweet(id, idStr, text, createdAt, fromScreenName, fromImageUrl, toUserId, fromId, languageCode, source); - JsonNode inReplyToStatusIdNode = node.get("in_reply_to_status_id"); - Long inReplyToStatusId = inReplyToStatusIdNode != null && !inReplyToStatusIdNode.isNull() ? inReplyToStatusIdNode.asLong() : null; - tweet.setInReplyToStatusId(inReplyToStatusId); - JsonNode inReplyToUserIdNode = node.get("in_reply_to_user_id"); - Long inReplyUsersId = inReplyToUserIdNode != null && !inReplyToUserIdNode.isNull() ? inReplyToUserIdNode.asLong() : null; - tweet.setInReplyToUserId(inReplyUsersId); - tweet.setInReplyToScreenName(node.path("in_reply_to_screen_name").asText()); - JsonNode retweetCountNode = node.get("retweet_count"); - Integer retweetCount = retweetCountNode != null && !retweetCountNode.isNull() ? retweetCountNode.asInt() : null; - tweet.setRetweetCount(retweetCount); - JsonNode retweetedNode = node.get("retweeted"); - JsonNode retweetedStatusNode = node.get("retweeted_status"); - boolean retweeted = retweetedNode != null && !retweetedNode.isNull() ? retweetedNode.asBoolean() : false; - tweet.setRetweeted(retweeted); - Tweet retweetedStatus = retweetedStatusNode != null ? this.deserialize(retweetedStatusNode) : null; - tweet.setRetweetedStatus(retweetedStatus); - JsonNode favoritedNode = node.get("favorited"); - boolean favorited = favoritedNode != null && !favoritedNode.isNull() ? favoritedNode.asBoolean() : false; - tweet.setFavorited(favorited); - JsonNode favoriteCountNode = node.get("favorite_count"); - Integer favoriteCount = favoriteCountNode != null && !favoriteCountNode.isNull() ? favoriteCountNode.asInt() : null; - tweet.setFavoriteCount(favoriteCount); - Entities entities = toEntities(node.get("entities"), text); - tweet.setEntities(entities); - TwitterProfile user = toProfile(fromUserNode); - tweet.setUser(user); - return tweet; - } - - private ObjectMapper createMapper() { - final ObjectMapper mapper = new ObjectMapper(); - mapper.registerModule(new TwitterModule()); - return mapper; - } - - private Date toDate(String dateString, DateFormat dateFormat) { - if (dateString == null) { - return null; - } - - try { - return dateFormat.parse(dateString); - } catch (ParseException e) { - return null; - } - } - - // passing in text to fetch ticker symbol pseudo-entities - private Entities toEntities(final JsonNode node, String text) throws IOException { - if (null == node || node.isNull() || node.isMissingNode()) { - return null; - } - final ObjectMapper mapper = this.createMapper(); - Entities entities = mapper.reader(Entities.class).readValue(node); - extractTickerSymbolEntitiesFromText(text, entities); - return entities; - } - - private void extractTickerSymbolEntitiesFromText(String text, Entities entities) { - Pattern pattern = Pattern.compile("\\$[A-Za-z]+"); - Matcher matcher = pattern.matcher(text); - while (matcher.find()) { - MatchResult matchResult = matcher.toMatchResult(); - String tickerSymbol = matchResult.group().substring(1); - String url = "https://twitter.com/search?q=%24" + tickerSymbol + "&src=ctag"; - entities.getTickerSymbols().add(new TickerSymbolEntity(tickerSymbol, url, new int[] {matchResult.start(), matchResult.end()})); - } - } - - - private TwitterProfile toProfile(final JsonNode node) throws IOException { - if (null == node || node.isNull() || node.isMissingNode()) { - return null; - } - final ObjectMapper mapper = this.createMapper(); - return mapper.reader(TwitterProfile.class).readValue(node); - } - - - private static final String TIMELINE_DATE_FORMAT = "EEE MMM dd HH:mm:ss ZZZZZ yyyy"; - -} + @Override + public Tweet deserialize(final JsonParser jp, final DeserializationContext ctx) throws IOException { + final JsonNode node = jp.readValueAs(JsonNode.class); + if (null == node || node.isMissingNode() || node.isNull()) + return null; + final Tweet tweet = this.deserialize(node); + jp.skipChildren(); + return tweet; + } + + public Tweet deserialize(JsonNode node) throws IOException, JsonProcessingException { + final long id = node.path("id").asLong(); + final String text = node.path("text").asText(); + if (id <= 0 || text == null || text.isEmpty()) + return null; + + final Tweet tweet = readTweetFromJson(node, id, text); + readReplyParameters(node, tweet); + readRetweetParameters(node, tweet); + readFavoriteParameters(node, tweet); + readTruncatedParameters(node, tweet); + readSensitivityParameters(node, tweet); + return tweet; + } + + @SuppressWarnings("deprecation") + private Tweet readTweetFromJson(JsonNode node, Long id, String text) throws IOException { + final JsonNode fromUserNode = node.get("user"); + final String dateFormat = TIMELINE_DATE_FORMAT; + + String fromScreenName = null; + final JsonNode fromScreenNameNode = fromUserNode.get("screen_name"); + if (fromScreenNameNode != null) + fromScreenName = fromScreenNameNode.asText(); + + Long fromId = null; + final JsonNode fromIdNode = fromUserNode.get("id"); + if (fromIdNode != null) + fromId = fromIdNode.asLong(); + + String fromImageUrl = null; + final JsonNode fromImageUrlNode = fromUserNode.get("profile_image_url"); + if (fromImageUrlNode != null) + fromImageUrl = fromImageUrlNode.asText(); + + final Date createdAt = toDate(node.get("created_at").asText(), new SimpleDateFormat(dateFormat, Locale.ENGLISH)); + final String source = node.get("source").asText(); + + Long toUserId = null; + final JsonNode toUserIdNode = node.get("in_reply_to_user_id"); + if (toUserIdNode != null) + toUserId = toUserIdNode.asLong(); + + JsonNode languageCodeNode = node.get("lang"); + String languageCode = languageCodeNode != null && !languageCodeNode.isNull() ? languageCodeNode.asText() : null; + + final Tweet tweet = new Tweet(id, text, createdAt, fromScreenName, fromImageUrl, toUserId, fromId, languageCode, source); + readUserAndEntities(node, fromUserNode, text, tweet); + return tweet; + } + + private void readUserAndEntities(JsonNode node, JsonNode fromUserNode, String text, Tweet tweet) throws IOException { + final Entities entities = toEntities(node.get("entities"), text); + tweet.setEntities(entities); + + final Entities extendedEntities = toEntities(node.get("extended_entities"), text); + tweet.setExtendedEntities(extendedEntities); + + final TwitterProfile user = toProfile(fromUserNode); + tweet.setUser(user); + } + + private void readFavoriteParameters(JsonNode node, Tweet tweet) { + final JsonNode favoritedNode = node.get("favorited"); + final boolean favorited = favoritedNode != null && !favoritedNode.isNull() ? favoritedNode.asBoolean() : false; + tweet.setFavorited(favorited); + + final JsonNode favoriteCountNode = node.get("favorite_count"); + final Integer favoriteCount = favoriteCountNode != null && !favoriteCountNode.isNull() ? favoriteCountNode.asInt() : null; + tweet.setFavoriteCount(favoriteCount); + } + + private void readTruncatedParameters(JsonNode node, Tweet tweet) { + final JsonNode truncatedNode = node.get("truncated"); + if (truncatedNode != null) + tweet.setTruncated(truncatedNode.asBoolean()); + } + + private void readSensitivityParameters(JsonNode node, Tweet tweet) { + final JsonNode possiblySensitiveNode = node.get("possibly_sensitive"); + if (possiblySensitiveNode != null) + tweet.setPossiblySensitive(possiblySensitiveNode.asBoolean()); + } + + private void readRetweetParameters(JsonNode node, Tweet tweet) throws JsonProcessingException, IOException { + final JsonNode retweetCountNode = node.get("retweet_count"); + final Integer retweetCount = retweetCountNode != null && !retweetCountNode.isNull() ? retweetCountNode.asInt() : null; + tweet.setRetweetCount(retweetCount); + + final JsonNode retweetedNode = node.get("retweeted"); + final boolean retweeted = retweetedNode != null && !retweetedNode.isNull() ? retweetedNode.asBoolean() : false; + tweet.setRetweeted(retweeted); + + final JsonNode retweetedStatusNode = node.get("retweeted_status"); + final Tweet retweetedStatus = retweetedStatusNode != null ? this.deserialize(retweetedStatusNode) : null; + tweet.setRetweetedStatus(retweetedStatus); + } + + private void readReplyParameters(JsonNode node, Tweet tweet) { + final JsonNode inReplyToStatusIdNode = node.get("in_reply_to_status_id"); + final Long inReplyToStatusId = inReplyToStatusIdNode != null && !inReplyToStatusIdNode.isNull() ? inReplyToStatusIdNode.asLong() : null; + tweet.setInReplyToStatusId(inReplyToStatusId); + + final JsonNode inReplyToUserIdNode = node.get("in_reply_to_user_id"); + final Long inReplyUsersId = inReplyToUserIdNode != null && !inReplyToUserIdNode.isNull() ? inReplyToUserIdNode.asLong() : null; + tweet.setInReplyToUserId(inReplyUsersId); + + final JsonNode inReplyToScreenNameNode = node.get("in_reply_to_screen_name"); + final String inReplyToScreenName = + inReplyToScreenNameNode != null && !inReplyToScreenNameNode.isNull() ? inReplyToScreenNameNode.asText() : null; + tweet.setInReplyToScreenName(inReplyToScreenName); + } + + private ObjectMapper createMapper() { + final ObjectMapper mapper = new ObjectMapper(); + mapper.registerModule(new TwitterModule()); + return mapper; + } + + private Date toDate(String dateString, DateFormat dateFormat) { + if (dateString == null) + return null; + + try { + return dateFormat.parse(dateString); + } + catch (final ParseException e) { + return null; + } + } + + // passing in text to fetch ticker symbol pseudo-entities + @SuppressWarnings("deprecation") + private Entities toEntities(final JsonNode node, String text) throws IOException { + if (null == node || node.isNull() || node.isMissingNode()) + return null; + final ObjectMapper mapper = createMapper(); + final Entities entities = mapper.reader(Entities.class).readValue(node); + extractTickerSymbolEntitiesFromText(text, entities); + return entities; + } + + private void extractTickerSymbolEntitiesFromText(String text, Entities entities) { + final Pattern pattern = Pattern.compile("\\$[A-Za-z]+"); + final Matcher matcher = pattern.matcher(text); + while (matcher.find()) { + final MatchResult matchResult = matcher.toMatchResult(); + final String tickerSymbol = matchResult.group().substring(1); + final String url = "https://twitter.com/search?q=%24" + tickerSymbol + "&src=ctag"; + entities.getTickerSymbols().add(new TickerSymbolEntity(tickerSymbol, url, new int[] {matchResult.start(), matchResult.end()})); + } + } + + @SuppressWarnings("deprecation") + private TwitterProfile toProfile(final JsonNode node) throws IOException { + if (null == node || node.isNull() || node.isMissingNode()) + return null; + final ObjectMapper mapper = createMapper(); + return mapper.reader(TwitterProfile.class).readValue(node); + } + +} \ No newline at end of file diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TweetMixin.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TweetMixin.java index 33f5c62b..88b685e6 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TweetMixin.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TweetMixin.java @@ -25,5 +25,5 @@ */ @JsonIgnoreProperties(ignoreUnknown = true) @JsonDeserialize(using = TweetDeserializer.class) -abstract class TweetMixin extends TwitterObjectMixin { +public abstract class TweetMixin extends TwitterObjectMixin { } diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterApiBuilderForHttpEntity.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterApiBuilderForHttpEntity.java new file mode 100644 index 00000000..2ab0e6cc --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterApiBuilderForHttpEntity.java @@ -0,0 +1,54 @@ +package org.springframework.social.twitter.api.impl; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.util.StringUtils; + +public class TwitterApiBuilderForHttpEntity { + private final TData data; + private boolean multipart = false; + Map> headers = new HashMap>(); + + public TwitterApiBuilderForHttpEntity(TData data) { + this.data = data; + } + + public TwitterApiBuilderForHttpEntity addHeader(String key, Collection values) { + this.headers.put(key, values); + return this; + } + + public TwitterApiBuilderForHttpEntity multipart(boolean multipart) { + this.multipart = multipart; + return this; + } + + public HttpEntity build() { + return new HttpEntity<>( + this.data, + this.makeHeaders()); + } + + private HttpHeaders makeHeaders() { + HttpHeaders httpHeaders = new HttpHeaders(); + for(Entry> header: headers.entrySet()) { + httpHeaders.add(header.getKey(), StringUtils.collectionToDelimitedString(header.getValue(), ";")); + } + + if(null == httpHeaders.getContentType()) { + if(this.multipart) { + httpHeaders.setContentType(MediaType.MULTIPART_FORM_DATA); + } else { + httpHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED); + } + } + + return httpHeaders; + } +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterApiBuilderForUri.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterApiBuilderForUri.java new file mode 100644 index 00000000..e9e7771a --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterApiBuilderForUri.java @@ -0,0 +1,171 @@ +/* + * Copyright 2014 the original author or authors. Licensed under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law + * or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +package org.springframework.social.twitter.api.impl; + +import java.net.URI; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.springframework.social.support.URIBuilder; +import org.springframework.util.Assert; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +/** + * Builds API URIs and provide them to operations implementing {@link AbstractTwitterOperations} for both the Standard API and for the + * Twitter AdCampaign API. + * + * @author Hudson Mendes + */ +public class TwitterApiBuilderForUri { + + private final MultiValueMap parameters = new LinkedMultiValueMap(); + private String resource; + private String baseLocation = treatBaseUrl(TwitterApiHosts.getStandardApi()); + + public TwitterApiBuilderForUri forStandardApi() { + this.baseLocation = treatBaseUrl(TwitterApiHosts.getStandardApi()); + return this; + } + + public TwitterApiBuilderForUri forAdCampaignsApi() { + this.baseLocation = treatBaseUrl(TwitterApiHosts.getAdsApi()); + return this; + } + + public TwitterApiBuilderForUri forTonApi() { + this.baseLocation = treatBaseUrl(TwitterApiHosts.getTonApi()); + return this; + } + + public TwitterApiBuilderForUri forUploadApi() { + this.baseLocation = treatBaseUrl(TwitterApiHosts.getUploadApi()); + return this; + } + + public TwitterApiBuilderForUri withResource(String resource) { + this.resource = resource; + return this; + } + + public TwitterApiBuilderForUri withResource(TwitterApiUriResourceForAdvertising resource) { + this.resource = resource.getPath(); + return this.forAdCampaignsApi(); + } + + public TwitterApiBuilderForUri withResource(TwitterApiUriResourceForStandard resource) { + this.resource = resource.getPath(); + return this.forStandardApi(); + } + + public TwitterApiBuilderForUri withResource(TwitterApiUriResourceForTon resource) { + this.resource = resource.getPath(); + return this.forTonApi(); + } + + public TwitterApiBuilderForUri withResource(TwitterApiUriResourceForUpload resource) { + this.resource = resource.getPath(); + return this.forUploadApi(); + } + + public TwitterApiBuilderForUri withArgument(String argument, Object value) { + if(null!=value) { + this.parameters.add(argument, value.toString()); + } + return this; + } + + public TwitterApiBuilderForUri withArgument(MultiValueMap arguments) { + this.parameters.putAll(arguments); + return this; + } + + public URI build() { + this.assertRequirements(); + URI output = URIBuilder + .fromUri(makeFullyQualifiedResourcePath()) + .queryParams(makeCompatbileQueryParameters()) + .build(); + + return output; + } + + private void assertRequirements() { + Assert.notNull(this.resource, "You have to provide a 'resource' in order to build the Uri."); + } + + private String makeFullyQualifiedResourcePath() { + String qualifiedPath = qualifyPath(); + return replaceImplicitArguments(qualifiedPath); + } + + private MultiValueMap makeCompatbileQueryParameters() { + MultiValueMap output = new LinkedMultiValueMap(); + for (Iterator i = this.parameters.keySet().iterator(); i.hasNext();) { + String key = i.next(); + this.parameters.get(key).forEach(value -> { + output.add(key, value); + }); + } + return output; + } + + private String replaceImplicitArguments(String path) { + + String finalPath = path; + List toRemove = new ArrayList(); + + for (Iterator i = this.parameters.keySet().iterator(); i.hasNext();) { + String key = i.next(); + String argName = (":" + key).toLowerCase(); + + if (path.toLowerCase().contains(argName)) { + List values = this.parameters.get(key); + for (int j = 0; j < values.size(); j++) { + Object value = values.get(j); + finalPath = finalPath.replace(argName, value.toString()); + } + toRemove.add(key); + } + } + + toRemove.forEach(key -> this.parameters.remove(key)); + return finalPath; + } + + private String qualifyPath() { + String qualified = trimUriPart(this.baseLocation) + "/" + trimUriPart(this.resource); + return qualified; + } + + private String trimUriPart(String part) { + return part.replaceAll("[/]+$", ""); + } + + private String treatBaseUrl(String apiHost) { + if (apiHost == null) + throw new IllegalArgumentException("The 'apiHost' is null and cannot be treated"); + + apiHost = apiHost.trim(); + if (apiHost.isEmpty()) + throw new IllegalArgumentException("The 'apiHost' is null and cannot be treated"); + if (!apiHost.startsWith("https://") && !apiHost.startsWith("http://")) + throw new IllegalArgumentException("The 'apiHost' must start with 'https://' or 'http://'"); + + if (!apiHost.endsWith("/")) { + apiHost += "/"; + } + + return apiHost; + } + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterApiHosts.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterApiHosts.java new file mode 100644 index 00000000..7ddfbff3 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterApiHosts.java @@ -0,0 +1,59 @@ +package org.springframework.social.twitter.api.impl; + +import org.springframework.util.StringUtils; + +/** + * Decouples host definition so that test diversions become possible. + * + * @author Hudson Mendes + * + */ +public abstract class TwitterApiHosts { + + private static final String DEFAULT_STANDARD_API_URL_BASE = "https://api.twitter.com/1.1/"; + private static final String DEFAULT_TON_API_URL_BASE = "https://ton.twitter.com/1.1/"; + private static final String DEFAULT_ADS_API_URL_BASE = "https://ads-api.twitter.com/0/"; + private static final String DEFAULT_UPLOAD_API_URL_BASE = "https://upload.twitter.com/1.1/"; + + private static String hostForAdsApi = DEFAULT_ADS_API_URL_BASE; + private static String hostForStandardApi = DEFAULT_STANDARD_API_URL_BASE; + private static String hostForTonApi = DEFAULT_TON_API_URL_BASE; + private static String hostForUploadApi = DEFAULT_UPLOAD_API_URL_BASE; + + public static String getAdsApi() { + return hostForAdsApi; + } + + static void setAdsApiHost(String host) { + if (StringUtils.hasText(host)) + hostForAdsApi = host; + } + + public static String getStandardApi() { + return hostForStandardApi; + } + + static void setStandardApiHost(String host) { + if (StringUtils.hasText(host)) + hostForStandardApi = host; + } + + public static String getTonApi() { + return hostForTonApi; + } + + static void setTonApiHost(String host) { + if (StringUtils.hasText(host)) + hostForTonApi = host; + } + + public static String getUploadApi() { + return hostForUploadApi; + } + + static void setUploadApiHost(String host) { + if (StringUtils.hasText(host)) + hostForUploadApi = host; + } + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterApiUriResourceForAdvertising.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterApiUriResourceForAdvertising.java new file mode 100644 index 00000000..dba18022 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterApiUriResourceForAdvertising.java @@ -0,0 +1,96 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl; + +/** + * + * @author Hudson Mendes + * + */ +public enum TwitterApiUriResourceForAdvertising { + ACCOUNTS("accounts"), + ACCOUNT("accounts/:account_id"), + ACCOUNT_FEATURES("accounts/:account_id/features"), + ACCOUNT_PERMISSIONS("accounts/:account_id/authenticated_user_access"), + + CAMPAIGNS("accounts/:account_id/campaigns"), + CAMPAIGN("accounts/:account_id/campaigns/:campaign_id"), + + PROMOTABLE_USERS("accounts/:account_id/promotable_users"), + SPONSORED_TWEETS("accounts/:account_id/scoped_timeline"), + SPONSORED_TWEETS_CREATE("accounts/:account_id/tweet"), + + PROMOTED_TWEET_REFERENCES("accounts/:account_id/promoted_tweets"), + PROMOTED_TWEET_REFERENCE("accounts/:account_id/promoted_tweets/:promoted_tweet_id"), + + PROMOTED_USER_REFERENCES("accounts/:account_id/promoted_accounts"), + PROMOTED_USER_REFERENCE("accounts/:account_id/promoted_accounts/:promoted_account_id"), + + FUNDING_INSTRUMENTS("accounts/:account_id/funding_instruments"), + FUNDING_INSTRUMENT("accounts/:account_id/funding_instruments/:funding_instrument_id"), + + LINE_ITEMS("accounts/:account_id/line_items"), + LINE_ITEM("accounts/:account_id/line_items/:line_item_id"), + + LINE_ITEM_PLACEMENTS("line_items/placements"), + + TARGETING_CRITERIAS("accounts/:account_id/targeting_criteria"), + TARGETING_CRITERIA("accounts/:account_id/targeting_criteria/:targeting_criteria_id"), + + TARGETINGS_DISCOVERY_APP_STORE_CATEGORIES("targeting_criteria/app_store_categories"), + TARGETINGS_DISCOVERY_BEHAVIOR_TAXONOMIES("targeting_criteria/behavior_taxonomies"), + TARGETINGS_DISCOVERY_BEHAVIORS("targeting_criteria/behaviors"), + TARGETINGS_DISCOVERY_DEVICES("targeting_criteria/devices"), + TARGETINGS_DISCOVERY_EVENTS("targeting_criteria/events"), + TARGETINGS_DISCOVERY_INTERESTS("targeting_criteria/interests"), + TARGETINGS_DISCOVERY_LANGUAGES("targeting_criteria/languages"), + TARGETINGS_DISCOVERY_LOCATIONS("targeting_criteria/locations"), + TARGETINGS_DISCOVERY_NETWORK_OPERATORS("targeting_criteria/network_operators"), + TARGETINGS_DISCOVERY_PLATFORM_VERSIONS("targeting_criteria/platform_versions"), + TARGETINGS_DISCOVERY_PLATFORMS("targeting_criteria/platforms"), + TARGETINGS_DISCOVERY_TV_CHANNELS("targeting_criteria/tv_channels"), + TARGETINGS_DISCOVERY_TV_GENRES("targeting_criteria/tv_genres"), + TARGETINGS_DISCOVERY_TV_MARKETS("targeting_criteria/tv_markets"), + TARGETINGS_DISCOVERY_TV_SHOWS("targeting_criteria/tv_shows"), + + TAILORED_AUDIENCES("accounts/:account_id/tailored_audiences"), + TAILORED_AUDIENCE("accounts/:account_id/tailored_audiences/:tailored_audience_id"), + TAILORED_AUDIENCE_CHANGES("accounts/:account_id/tailored_audience_changes"), + TAILORED_AUDIENCE_CHANGE("accounts/:account_id/tailored_audience_changes/:tailored_audience_change_id"), + GLOBAL_OPT_OUT("accounts/:account_id/tailored_audiences/global_opt_out"), + + STATS_ACCOUNT("stats/accounts/:account_id"), + STATS_CAMPAIGNS("stats/accounts/:account_id/campaigns"), + STATS_CAMPAIGN("stats/accounts/:account_id/campaigns/:campaign_id"), + STATS_FUNDING_INSTRUMENTS("stats/accounts/:account_id/funding_instruments"), + STATS_FUNDING_INSTRUMENT("stats/accounts/:account_id/funding_instruments/:funding_instrument_id"), + STATS_LINE_ITEMS("stats/accounts/:account_id/line_items"), + STATS_LINE_ITEM("stats/accounts/:account_id/line_items/:line_item_id"), + STATS_PROMOTED_ACCOUNTS("stats/accounts/:account_id/promoted_accounts"), + STATS_PROMOTED_ACCOUNT("stats/accounts/:account_id/promoted_accounts/:promoted_account_id"), + STATS_PROMOTED_TWEETS("stats/accounts/:account_id/promoted_tweets"), + STATS_PROMOTED_TWEET("stats/accounts/:account_id/promoted_tweets/:promoted_tweet_id"); + + private final String name; + + TwitterApiUriResourceForAdvertising(String path) { + name = path; + } + + public String getPath() { + return name; + } +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterApiUriResourceForStandard.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterApiUriResourceForStandard.java new file mode 100644 index 00000000..ba222ed5 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterApiUriResourceForStandard.java @@ -0,0 +1,118 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl; + +/** + * + * @author Hudson Mendes + * + */ +public enum TwitterApiUriResourceForStandard { + APPLICATION_RATE_LIMIT_STATUS("application/rate_limit_status.json"), + + ACCOUNT_VERIFY_CREDENTIALS("account/verify_credentials.json"), + ACCOUNT_SETTINGS("account/settings.json"), + + BLOCKS("blocks/list.json"), + BLOCKS_IDS("blocks/ids.json"), + BLOCKS_CREATE("blocks/create.json"), + BLOCKS_DESTROY("blocks/destroy.json"), + + DIRECTMESSAGES("direct_messages.json"), + DIRECTMESSAGES_SENT("direct_messages/sent.json"), + DIRECTMESSAGES_SHOW("direct_messages/show.json"), + DIRECTMESSAGES_NEW("direct_messages/new.json"), + DIRECTMESSAGES_DESTROY("direct_messages/destroy.json"), + + FRIENDS("friends/list.json"), + FRIENDS_IDS("friends/ids.json"), + + FOLLOWERS("followers/list.json"), + FOLLOWERS_IDS("followers/ids.json"), + + FRIENDSHIPS_CREATE("friendships/create.json"), + FRIENDSHIPS_DESTROY("friendships/destroy.json"), + FRIENDSHIPS_UPDATE("friendships/update.json"), + FRIENDSHIPS_INCOMING("friendships/incoming.json"), + FRIENDSHIPS_OUTGOING("friendships/outgoing.json"), + + LISTS("lists/list.json"), + LISTS_SHOW("lists/show.json"), + LISTS_CREATE("lists/create.json"), + LISTS_UPDATE("lists/update.json"), + LISTS_DESTROY("lists/destroy.json"), + LISTS_STATUSES("lists/statuses.json"), + + LISTS_SUBSCRIBERS("lists/subscribers.json"), + LISTS_SUBSCRIBERS_SHOW("lists/subscribers/show.json"), + LISTS_SUBSCRIBERS_CREATE("lists/subscribers/create.json"), + LISTS_SUBSCRIBERS_DESTROY("lists/subscribers/destroy.json"), + + LISTS_MEMBERS("lists/members.json"), + LISTS_MEMBERS_SHOW("lists/members/show.json"), + LISTS_MEMBERS_CREATE_ALL("lists/members/create_all.json"), + LISTS_MEMBERS_DESTROY("lists/members/destroy.json"), + + LISTS_MEMBERSHIPS("lists/memberships.json"), + LISTS_SUBSCRIPTIONS("lists/subscriptions.json"), + + GEO_ID("geo/id/:place_id.json"), + GEO_PLACE("geo/place.json"), + GEO_SEARCH("geo/search.json"), + GEO_SIMILAR_PLACES("geo/similar_places.json"), + GEO_REVERSE_GEOCODE("geo/reverse_geocode.json"), + + SAVED_SEARCHES_LIST("saved_searches/list.json"), + SAVED_SEARCHES_SHOW("saved_searches/show/:search_id.json"), + SAVED_SEARCHES_CREATE("saved_searches/create.json"), + SAVED_SEARCHES_DESTROY("saved_searches/destroy/:search_id.json"), + + SEARCH_TWEETS("search/tweets.json"), + + TRENDS_PLACE("trends/place.json"), + + STATUSES_HOME_TIMELINE("statuses/home_timeline.json"), + STATUSES_USER_TIMELINE("statuses/user_timeline.json"), + STATUSES_MENTIONS_TIMELINE("statuses/mentions_timeline.json"), + STATUSES_RETWEETS_OF_ME("statuses/retweets_of_me.json"), + STATUSES_SHOW("statuses/show/:tweet_id.json"), + STATUSES_UPDATE("statuses/update.json"), + STATUSES_UPDATE_WITH_MEDIA("statuses/update_with_media.json"), + STATUSES_DESTROY("statuses/destroy/:tweet_id.json"), + STATUSES_RETWEET("statuses/retweet/:tweet_id.json"), + STATUSES_RETWEETS("statuses/retweets/:tweet_id.json"), + STATUSES_OEMBEDED("statuses/oembed.json"), + + FAVORITES_LIST("favorites/list.json"), + FAVORITES_CREATE("favorites/create.json"), + FAVORITES_DESTROY("favorites/destroy.json"), + + USERS_SHOW("users/show.json"), + USERS_LOOKUP("users/lookup.json"), + USERS_SEARCH("users/search.json"), + USERS_SUGGESTIONS("users/suggestions.json"), + USERS_SUGGESTIONS_WITH_SLUG("users/suggestions/:slug.json"); + + private final String path; + + TwitterApiUriResourceForStandard(String path) { + this.path = path; + } + + public String getPath() { + return path; + } +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterApiUriResourceForTon.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterApiUriResourceForTon.java new file mode 100644 index 00000000..d922b53e --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterApiUriResourceForTon.java @@ -0,0 +1,35 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl; + +/** + * + * @author Chris Latko + * + */ +public enum TwitterApiUriResourceForTon { + TWITTER_OBJECT_NEST("ton/bucket/:bucket_name"); + + private final String path; + + TwitterApiUriResourceForTon(String path) { + this.path = path; + } + + public String getPath() { + return path; + } +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterApiUriResourceForUpload.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterApiUriResourceForUpload.java new file mode 100644 index 00000000..67c36441 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterApiUriResourceForUpload.java @@ -0,0 +1,35 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl; + +/** + * + * @author Chris Latko + * + */ +public enum TwitterApiUriResourceForUpload { + UPLOAD("media/upload.json"); + + private final String path; + + TwitterApiUriResourceForUpload(String path) { + this.path = path; + } + + public String getPath() { + return path; + } +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterErrorHandler.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterErrorHandler.java index bbd2e721..9d3fce4b 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterErrorHandler.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterErrorHandler.java @@ -1,12 +1,12 @@ /* * Copyright 2014 the original author or authors. - * + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * + * + * http://www.apache.org/licenses/LICENSE-2.0 + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -16,6 +16,7 @@ package org.springframework.social.twitter.api.impl; import java.io.IOException; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; @@ -47,110 +48,132 @@ /** * Subclass of {@link DefaultResponseErrorHandler} that handles errors from Twitter's * REST API, interpreting them into appropriate exceptions. + * * @author Craig Walls */ -class TwitterErrorHandler extends DefaultResponseErrorHandler { - - @Override - public void handleError(ClientHttpResponse response) throws IOException { - HttpStatus statusCode = response.getStatusCode(); - if (statusCode.series() == Series.SERVER_ERROR) { - handleServerErrors(statusCode); - } else if (statusCode.series() == Series.CLIENT_ERROR) { - handleClientErrors(response); - } - - // if not otherwise handled, do default handling and wrap with UncategorizedApiException - try { - super.handleError(response); - } catch(Exception e) { - throw new UncategorizedApiException("twitter", "Error consuming Twitter REST API", e); - } - } - - private void handleClientErrors(ClientHttpResponse response) throws IOException { - HttpStatus statusCode = response.getStatusCode(); - Map errorMap = extractErrorDetailsFromResponse(response); - - String errorText = ""; - if (errorMap.containsKey("error")) { - errorText = (String) errorMap.get("error"); - } else if(errorMap.containsKey("errors")) { - Object errors = errorMap.get("errors"); - if (errors instanceof List) { - @SuppressWarnings("unchecked") - List> errorsList = (List>) errors; - errorText = errorsList.get(0).get("message"); - } else if (errors instanceof String ) { - errorText = (String) errors; - } - } - - System.out.println("ERROR: " + statusCode + " :: " + errorText); - - - if (statusCode == HttpStatus.BAD_REQUEST) { - if (errorText.contains("Rate limit exceeded.")) { - throw new RateLimitExceededException("twitter"); - } - } else if (statusCode == HttpStatus.UNAUTHORIZED) { - if (errorText == null) { - throw new NotAuthorizedException("twitter", response.getStatusText()); - } else if (errorText.equals("Could not authenticate you.")) { - throw new MissingAuthorizationException("twitter"); - } else if (errorText.equals("Could not authenticate with OAuth.")) { // revoked token - throw new RevokedAuthorizationException("twitter"); - } else if (errorText.equals("Invalid / expired Token")) { // Note that Twitter doesn't actually expire tokens - throw new InvalidAuthorizationException("twitter", errorText); - } else { - throw new NotAuthorizedException("twitter", errorText); - } - } else if (statusCode == HttpStatus.FORBIDDEN) { - if (errorText.equals(DUPLICATE_STATUS_TEXT) || errorText.contains("You already said that")) { - throw new DuplicateStatusException("twitter", errorText); - } else if (errorText.equals(STATUS_TOO_LONG_TEXT) || errorText.contains(MESSAGE_TOO_LONG_TEXT)) { - throw new MessageTooLongException(errorText); - } else if (errorText.equals(INVALID_MESSAGE_RECIPIENT_TEXT)) { - throw new InvalidMessageRecipientException(errorText); - } else if (errorText.equals(DAILY_RATE_LIMIT_TEXT)) { - throw new RateLimitExceededException("twitter"); - } else { - throw new OperationNotPermittedException("twitter", errorText); - } - } else if (statusCode == HttpStatus.NOT_FOUND) { - throw new ResourceNotFoundException("twitter", errorText); - } else if (statusCode == HttpStatus.valueOf(ENHANCE_YOUR_CALM) || statusCode == HttpStatus.valueOf(TOO_MANY_REQUESTS)) { - throw new RateLimitExceededException("twitter"); - } - - } - - private void handleServerErrors(HttpStatus statusCode) throws IOException { - if (statusCode == HttpStatus.INTERNAL_SERVER_ERROR) { - throw new InternalServerErrorException("twitter", "Something is broken at Twitter. Please see http://dev.twitter.com/pages/support to report the issue."); - } else if (statusCode == HttpStatus.BAD_GATEWAY) { - throw new ServerDownException("twitter", "Twitter is down or is being upgraded."); - } else if (statusCode == HttpStatus.SERVICE_UNAVAILABLE) { - throw new ServerOverloadedException("twitter", "Twitter is overloaded with requests. Try again later."); - } - } - - private Map extractErrorDetailsFromResponse(ClientHttpResponse response) throws IOException { - ObjectMapper mapper = new ObjectMapper(new JsonFactory()); - try { - return mapper.>readValue(response.getBody(), new TypeReference>() {}); - } catch (JsonParseException e) { - return Collections.emptyMap(); - } - } - - private static final String INVALID_MESSAGE_RECIPIENT_TEXT = "You cannot send messages to users who are not following you."; - private static final String STATUS_TOO_LONG_TEXT = "Status is over 140 characters."; - private static final String MESSAGE_TOO_LONG_TEXT = "The text of your direct message is over 140 characters"; - private static final String DUPLICATE_STATUS_TEXT = "Status is a duplicate."; - private static final String DAILY_RATE_LIMIT_TEXT = "User is over daily status update limit."; - - - private static final int ENHANCE_YOUR_CALM = 420; - private static final int TOO_MANY_REQUESTS = 429; -} +public class TwitterErrorHandler extends DefaultResponseErrorHandler { + + @Override + public void handleError(ClientHttpResponse response) throws IOException { + final HttpStatus statusCode = response.getStatusCode(); + if (statusCode.series() == Series.SERVER_ERROR) + handleServerErrors(statusCode); + else if (statusCode.series() == Series.CLIENT_ERROR) + handleClientErrors(response); + + // if not otherwise handled, do default handling and wrap with UncategorizedApiException + try { + super.handleError(response); + } + catch (final Exception e) { + throw new UncategorizedApiException("twitter", "Error consuming Twitter REST API", e); + } + } + + private void handleClientErrors(ClientHttpResponse response) throws IOException { + final HttpStatus statusCode = response.getStatusCode(); + final Map errorMap = extractErrorDetailsFromResponse(response); + + final List validationErrors = new ArrayList<>(); + String errorText = ""; + if (errorMap.containsKey("error")) + errorText = (String) errorMap.get("error"); + else if (errorMap.containsKey("errors")) { + + final Object errors = errorMap.get("errors"); + if (errors instanceof List) { + + @SuppressWarnings("unchecked") + final List> errorsList = (List>) errors; + + for (final Map error : errorsList) { + final String errorMessage = error.get("message"); + + if (statusCode == HttpStatus.BAD_REQUEST) + validationErrors.add(errorMessage); + else { + if (errorText.length() != 0) + errorText += "; "; + + errorText += error.get("message"); + } + } + } + else if (errors instanceof String) + errorText = (String) errors; + } + + if (statusCode == HttpStatus.BAD_REQUEST) { + if (errorText.contains("Rate limit exceeded.")) + throw new TwitterRateLimitExceededException(response.getHeaders()); + + if (validationErrors.size() != 0) + throw new InvalidInputDataException("twitter", validationErrors); + + if (!errorText.isEmpty()) { + validationErrors.add(errorText); + throw new InvalidInputDataException("twitter", validationErrors); + } + + } + else if (statusCode == HttpStatus.UNAUTHORIZED) { + if (errorText == null) + throw new NotAuthorizedException("twitter", response.getStatusText()); + else if (errorText.equals("Could not authenticate you.")) + throw new MissingAuthorizationException("twitter"); + else if (errorText.equals("Could not authenticate with OAuth.")) + throw new RevokedAuthorizationException("twitter"); + else if (errorText.equals("Invalid / expired Token")) + throw new InvalidAuthorizationException("twitter", errorText); + else + throw new NotAuthorizedException("twitter", errorText); + } + else if (statusCode == HttpStatus.FORBIDDEN) { + if (errorText.equals(DUPLICATE_STATUS_TEXT) || errorText.contains("You already said that")) + throw new DuplicateStatusException("twitter", errorText); + else if (errorText.equals(STATUS_TOO_LONG_TEXT) || errorText.contains(MESSAGE_TOO_LONG_TEXT)) + throw new MessageTooLongException(errorText); + else if (errorText.equals(INVALID_MESSAGE_RECIPIENT_TEXT)) + throw new InvalidMessageRecipientException(errorText); + else if (errorText.equals(DAILY_RATE_LIMIT_TEXT)) + throw new RateLimitExceededException("twitter"); + else + throw new OperationNotPermittedException("twitter", errorText); + } + else if (statusCode == HttpStatus.NOT_FOUND) + throw new ResourceNotFoundException("twitter", errorText); + else if (statusCode == HttpStatus.valueOf(ENHANCE_YOUR_CALM) || statusCode == HttpStatus.valueOf(TOO_MANY_REQUESTS)) + throw new TwitterRateLimitExceededException(response.getHeaders()); + + } + + private void handleServerErrors(HttpStatus statusCode) throws IOException { + if (statusCode == HttpStatus.INTERNAL_SERVER_ERROR) + throw new InternalServerErrorException( + "twitter", + "Something is broken at Twitter. Please see http://dev.twitter.com/pages/support to report the issue."); + else if (statusCode == HttpStatus.BAD_GATEWAY) + throw new ServerDownException("twitter", "Twitter is down or is being upgraded."); + else if (statusCode == HttpStatus.SERVICE_UNAVAILABLE) + throw new ServerOverloadedException("twitter", "Twitter is overloaded with requests. Try again later."); + } + + private Map extractErrorDetailsFromResponse(ClientHttpResponse response) throws IOException { + final ObjectMapper mapper = new ObjectMapper(new JsonFactory()); + try { + return mapper.>readValue(response.getBody(), new TypeReference>() {}); + } + catch (final JsonParseException e) { + return Collections.emptyMap(); + } + } + + private static final String INVALID_MESSAGE_RECIPIENT_TEXT = "You cannot send messages to users who are not following you."; + private static final String STATUS_TOO_LONG_TEXT = "Status is over 140 characters."; + private static final String MESSAGE_TOO_LONG_TEXT = "The text of your direct message is over 140 characters"; + private static final String DUPLICATE_STATUS_TEXT = "Status is a duplicate."; + private static final String DAILY_RATE_LIMIT_TEXT = "User is over daily status update limit."; + + private static final int ENHANCE_YOUR_CALM = 420; + private static final int TOO_MANY_REQUESTS = 429; +} \ No newline at end of file diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterEscapingFormHttpMessageConverter.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterEscapingFormHttpMessageConverter.java index cc02912d..01f54f2e 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterEscapingFormHttpMessageConverter.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterEscapingFormHttpMessageConverter.java @@ -36,7 +36,7 @@ * Custom FormHttpMessageConverter that meets Twitter's non-RFC1738 escaping of asterisks ('*'). * @author Craig Walls */ -class TwitterEscapingFormHttpMessageConverter extends FormHttpMessageConverter { +public class TwitterEscapingFormHttpMessageConverter extends FormHttpMessageConverter { TwitterEscapingFormHttpMessageConverter() { setCharset(Charset.forName("UTF-8")); diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterModule.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterModule.java index b5805445..2d45f15f 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterModule.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterModule.java @@ -1,12 +1,12 @@ /* * Copyright 2014 the original author or authors. - * + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * + * + * http://www.apache.org/licenses/LICENSE-2.0 + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -32,6 +32,72 @@ import org.springframework.social.twitter.api.TwitterProfile; import org.springframework.social.twitter.api.UrlEntity; import org.springframework.social.twitter.api.UserList; +import org.springframework.social.twitter.api.VideoInfoMediaEntity; +import org.springframework.social.twitter.api.VideoInfoVariantMediaEntity; +import org.springframework.social.twitter.api.advertising.AdvertisingAccount; +import org.springframework.social.twitter.api.advertising.AdvertisingAccountPermissions; +import org.springframework.social.twitter.api.advertising.Campaign; +import org.springframework.social.twitter.api.advertising.FundingInstrument; +import org.springframework.social.twitter.api.advertising.GlobalOptOut; +import org.springframework.social.twitter.api.advertising.LineItem; +import org.springframework.social.twitter.api.advertising.LineItemPlacements; +import org.springframework.social.twitter.api.advertising.PromotableUser; +import org.springframework.social.twitter.api.advertising.PromotedTweetReference; +import org.springframework.social.twitter.api.advertising.PromotedUserReference; +import org.springframework.social.twitter.api.advertising.StatisticsSnapshot; +import org.springframework.social.twitter.api.advertising.TailoredAudience; +import org.springframework.social.twitter.api.advertising.TailoredAudienceChange; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForAppStoreCategories; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForBehaviorTaxonomies; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForBehaviors; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForDevices; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForEvents; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForInterests; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForLanguages; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForLocations; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForNetworkOperators; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForPlatformVersions; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForPlatforms; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForTvChannel; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForTvGenre; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForTvMarket; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForTvShow; +import org.springframework.social.twitter.api.advertising.TargetingCriterion; +import org.springframework.social.twitter.api.impl.advertising.AdvertisingAccountMixin; +import org.springframework.social.twitter.api.impl.advertising.AdvertisingAccountPermissionsMixin; +import org.springframework.social.twitter.api.impl.advertising.CampaignMixin; +import org.springframework.social.twitter.api.impl.advertising.FundingInstrumentMixin; +import org.springframework.social.twitter.api.impl.advertising.GlobalOptOutMixin; +import org.springframework.social.twitter.api.impl.advertising.LineItemMixin; +import org.springframework.social.twitter.api.impl.advertising.LineItemPlacementsMixin; +import org.springframework.social.twitter.api.impl.advertising.PromotableUserMixin; +import org.springframework.social.twitter.api.impl.advertising.PromotedTweetReferenceMixin; +import org.springframework.social.twitter.api.impl.advertising.PromotedUserReferenceMixin; +import org.springframework.social.twitter.api.impl.advertising.StatisticsSnapshotMixin; +import org.springframework.social.twitter.api.impl.advertising.TailoredAudienceChangeMixin; +import org.springframework.social.twitter.api.impl.advertising.TailoredAudienceMixin; +import org.springframework.social.twitter.api.impl.advertising.TargetingCriteriaDiscoveryForAppStoreCategoriesMixin; +import org.springframework.social.twitter.api.impl.advertising.TargetingCriteriaDiscoveryForBehaviorTaxonomiesMixin; +import org.springframework.social.twitter.api.impl.advertising.TargetingCriteriaDiscoveryForBehaviorsMixin; +import org.springframework.social.twitter.api.impl.advertising.TargetingCriteriaDiscoveryForDevicesMixin; +import org.springframework.social.twitter.api.impl.advertising.TargetingCriteriaDiscoveryForEventsMixin; +import org.springframework.social.twitter.api.impl.advertising.TargetingCriteriaDiscoveryForInterestsMixin; +import org.springframework.social.twitter.api.impl.advertising.TargetingCriteriaDiscoveryForLanguagesMixin; +import org.springframework.social.twitter.api.impl.advertising.TargetingCriteriaDiscoveryForLocationsMixin; +import org.springframework.social.twitter.api.impl.advertising.TargetingCriteriaDiscoveryForNetworkOperatorsMixin; +import org.springframework.social.twitter.api.impl.advertising.TargetingCriteriaDiscoveryForPlatformVersionsMixin; +import org.springframework.social.twitter.api.impl.advertising.TargetingCriteriaDiscoveryForPlatformsMixin; +import org.springframework.social.twitter.api.impl.advertising.TargetingCriteriaDiscoveryForTvChannelMixin; +import org.springframework.social.twitter.api.impl.advertising.TargetingCriteriaDiscoveryForTvGenreMixin; +import org.springframework.social.twitter.api.impl.advertising.TargetingCriteriaDiscoveryForTvMarketMixin; +import org.springframework.social.twitter.api.impl.advertising.TargetingCriteriaDiscoveryForTvShowMixin; +import org.springframework.social.twitter.api.impl.advertising.TargetingCriterionMixin; +import org.springframework.social.twitter.api.impl.upload.ImageEntityMixin; +import org.springframework.social.twitter.api.impl.upload.UploadedEntityMixin; +import org.springframework.social.twitter.api.impl.upload.VideoEntityMixin; +import org.springframework.social.twitter.api.upload.ImageEntity; +import org.springframework.social.twitter.api.upload.UploadedEntity; +import org.springframework.social.twitter.api.upload.VideoEntity; import com.fasterxml.jackson.databind.module.SimpleModule; @@ -39,35 +105,74 @@ * Jackson module for registering mixin annotations against Twitter model classes. */ @SuppressWarnings("serial") -class TwitterModule extends SimpleModule { +public class TwitterModule extends SimpleModule { - public TwitterModule() { - super("TwitterModule"); - } - - @Override - public void setupModule(SetupContext context) { - context.setMixInAnnotations(TwitterProfile.class, TwitterProfileMixin.class); - context.setMixInAnnotations(SavedSearch.class, SavedSearchMixin.class); - context.setMixInAnnotations(Trend.class, TrendMixin.class); - context.setMixInAnnotations(Trends.class, TrendsMixin.class); - context.setMixInAnnotations(SuggestionCategory.class, SuggestionCategoryMixin.class); - context.setMixInAnnotations(DirectMessage.class, DirectMessageMixin.class); - context.setMixInAnnotations(UserList.class, UserListMixin.class); - context.setMixInAnnotations(Tweet.class, TweetMixin.class); - context.setMixInAnnotations(SearchResults.class, SearchResultsMixin.class); - context.setMixInAnnotations(Place.class, PlaceMixin.class); - context.setMixInAnnotations(SimilarPlacesResponse.class, SimilarPlacesMixin.class); - context.setMixInAnnotations(Entities.class, EntitiesMixin.class); - context.setMixInAnnotations(HashTagEntity.class, HashTagEntityMixin.class); - context.setMixInAnnotations(MediaEntity.class, MediaEntityMixin.class); - context.setMixInAnnotations(MentionEntity.class, MentionEntityMixin.class); - context.setMixInAnnotations(UrlEntity.class, UrlEntityMixin.class); - context.setMixInAnnotations(AccountSettings.class, AccountSettingsMixin.class); - context.setMixInAnnotations(AccountSettings.TimeZone.class, AccountSettingsMixin.TimeZoneMixin.class); - context.setMixInAnnotations(AccountSettings.SleepTime.class, AccountSettingsMixin.SleepTimeMixin.class); - context.setMixInAnnotations(AccountSettings.TrendLocation.class, AccountSettingsMixin.TrendLocationMixin.class); - context.setMixInAnnotations(OEmbedTweet.class, OEmbedTweetMixin.class); - } + public TwitterModule() { + super("TwitterModule"); + } + + @Override + public void setupModule(SetupContext context) { + context.setMixInAnnotations(TwitterProfile.class, TwitterProfileMixin.class); + context.setMixInAnnotations(SavedSearch.class, SavedSearchMixin.class); + context.setMixInAnnotations(Trend.class, TrendMixin.class); + context.setMixInAnnotations(Trends.class, TrendsMixin.class); + context.setMixInAnnotations(SuggestionCategory.class, SuggestionCategoryMixin.class); + context.setMixInAnnotations(DirectMessage.class, DirectMessageMixin.class); + context.setMixInAnnotations(UserList.class, UserListMixin.class); + context.setMixInAnnotations(Tweet.class, TweetMixin.class); + context.setMixInAnnotations(SearchResults.class, SearchResultsMixin.class); + context.setMixInAnnotations(Place.class, PlaceMixin.class); + context.setMixInAnnotations(SimilarPlacesResponse.class, SimilarPlacesMixin.class); + context.setMixInAnnotations(Entities.class, EntitiesMixin.class); + context.setMixInAnnotations(HashTagEntity.class, HashTagEntityMixin.class); + context.setMixInAnnotations(MediaEntity.class, MediaEntityMixin.class); + context.setMixInAnnotations(VideoInfoMediaEntity.class, VideoInfoEntityMediaMixin.class); + context.setMixInAnnotations(VideoInfoVariantMediaEntity.class, VideoInfoVariantMediaEntityMixin.class); + context.setMixInAnnotations(MentionEntity.class, MentionEntityMixin.class); + context.setMixInAnnotations(UrlEntity.class, UrlEntityMixin.class); + + context.setMixInAnnotations(PromotableUser.class, PromotableUserMixin.class); + context.setMixInAnnotations(PromotedTweetReference.class, PromotedTweetReferenceMixin.class); + context.setMixInAnnotations(PromotedUserReference.class, PromotedUserReferenceMixin.class); + context.setMixInAnnotations(AdvertisingAccount.class, AdvertisingAccountMixin.class); + context.setMixInAnnotations(AdvertisingAccountPermissions.class, AdvertisingAccountPermissionsMixin.class); + context.setMixInAnnotations(FundingInstrument.class, FundingInstrumentMixin.class); + context.setMixInAnnotations(LineItem.class, LineItemMixin.class); + context.setMixInAnnotations(LineItemPlacements.class, LineItemPlacementsMixin.class); + context.setMixInAnnotations(Campaign.class, CampaignMixin.class); + context.setMixInAnnotations(TargetingCriterion.class, TargetingCriterionMixin.class); + context.setMixInAnnotations(StatisticsSnapshot.class, StatisticsSnapshotMixin.class); + context.setMixInAnnotations(TailoredAudience.class, TailoredAudienceMixin.class); + context.setMixInAnnotations(GlobalOptOut.class, GlobalOptOutMixin.class); + context.setMixInAnnotations(TailoredAudience.class, TailoredAudienceMixin.class); + context.setMixInAnnotations(TailoredAudienceChange.class, TailoredAudienceChangeMixin.class); + context.setMixInAnnotations(TargetingCriteriaDiscoveryForAppStoreCategories.class, TargetingCriteriaDiscoveryForAppStoreCategoriesMixin.class); + context.setMixInAnnotations(TargetingCriteriaDiscoveryForBehaviorTaxonomies.class, TargetingCriteriaDiscoveryForBehaviorTaxonomiesMixin.class); + context.setMixInAnnotations(TargetingCriteriaDiscoveryForBehaviors.class, TargetingCriteriaDiscoveryForBehaviorsMixin.class); + context.setMixInAnnotations(TargetingCriteriaDiscoveryForDevices.class, TargetingCriteriaDiscoveryForDevicesMixin.class); + context.setMixInAnnotations(TargetingCriteriaDiscoveryForEvents.class, TargetingCriteriaDiscoveryForEventsMixin.class); + context.setMixInAnnotations(TargetingCriteriaDiscoveryForInterests.class, TargetingCriteriaDiscoveryForInterestsMixin.class); + context.setMixInAnnotations(TargetingCriteriaDiscoveryForLanguages.class, TargetingCriteriaDiscoveryForLanguagesMixin.class); + context.setMixInAnnotations(TargetingCriteriaDiscoveryForLocations.class, TargetingCriteriaDiscoveryForLocationsMixin.class); + context.setMixInAnnotations(TargetingCriteriaDiscoveryForNetworkOperators.class, TargetingCriteriaDiscoveryForNetworkOperatorsMixin.class); + context.setMixInAnnotations(TargetingCriteriaDiscoveryForPlatformVersions.class, TargetingCriteriaDiscoveryForPlatformVersionsMixin.class); + context.setMixInAnnotations(TargetingCriteriaDiscoveryForPlatforms.class, TargetingCriteriaDiscoveryForPlatformsMixin.class); + context.setMixInAnnotations(TargetingCriteriaDiscoveryForTvChannel.class, TargetingCriteriaDiscoveryForTvChannelMixin.class); + context.setMixInAnnotations(TargetingCriteriaDiscoveryForTvGenre.class, TargetingCriteriaDiscoveryForTvGenreMixin.class); + context.setMixInAnnotations(TargetingCriteriaDiscoveryForTvMarket.class, TargetingCriteriaDiscoveryForTvMarketMixin.class); + context.setMixInAnnotations(TargetingCriteriaDiscoveryForTvShow.class, TargetingCriteriaDiscoveryForTvShowMixin.class); + + context.setMixInAnnotations(AccountSettings.class, AccountSettingsMixin.class); + context.setMixInAnnotations(AccountSettings.TimeZone.class, AccountSettingsMixin.TimeZoneMixin.class); + context.setMixInAnnotations(AccountSettings.SleepTime.class, AccountSettingsMixin.SleepTimeMixin.class); + context.setMixInAnnotations(AccountSettings.TrendLocation.class, AccountSettingsMixin.TrendLocationMixin.class); + + context.setMixInAnnotations(UploadedEntity.class, UploadedEntityMixin.class); + context.setMixInAnnotations(ImageEntity.class, ImageEntityMixin.class); + context.setMixInAnnotations(VideoEntity.class, VideoEntityMixin.class); + + context.setMixInAnnotations(OEmbedTweet.class, OEmbedTweetMixin.class); + } } diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterObjectMixin.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterObjectMixin.java index 7e66c5ec..ff1231b7 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterObjectMixin.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterObjectMixin.java @@ -8,7 +8,7 @@ * @author Craig Walls */ @JsonIgnoreProperties(ignoreUnknown = true) -abstract class TwitterObjectMixin { +public abstract class TwitterObjectMixin { @JsonAnySetter abstract void add(String key, Object value); diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterProfileList.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterProfileList.java index d03e955e..3aaf1bcb 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterProfileList.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterProfileList.java @@ -24,5 +24,5 @@ * @author Craig Walls */ @SuppressWarnings("serial") -class TwitterProfileList extends ArrayList { +public class TwitterProfileList extends ArrayList { } diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterProfileMixin.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterProfileMixin.java index 7cdc76fd..9e9eb868 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterProfileMixin.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterProfileMixin.java @@ -27,7 +27,7 @@ * @author Craig Walls */ @JsonIgnoreProperties(ignoreUnknown=true) -abstract class TwitterProfileMixin extends TwitterObjectMixin { +public abstract class TwitterProfileMixin extends TwitterObjectMixin { @JsonCreator TwitterProfileMixin( @JsonProperty("id") long id, @@ -116,4 +116,4 @@ abstract class TwitterProfileMixin extends TwitterObjectMixin { @JsonProperty("profile_banner_url") private String profileBannerUrl; -} +} \ No newline at end of file diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterProfileUsersList.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterProfileUsersList.java index a4af931a..d3633096 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterProfileUsersList.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterProfileUsersList.java @@ -29,7 +29,7 @@ * @author Craig Walls */ @JsonIgnoreProperties(ignoreUnknown = true) -class TwitterProfileUsersList { +public class TwitterProfileUsersList { private final CursoredList list; diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterRateLimitExceededException.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterRateLimitExceededException.java new file mode 100644 index 00000000..b65a869a --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterRateLimitExceededException.java @@ -0,0 +1,75 @@ +package org.springframework.social.twitter.api.impl; + +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneOffset; + +import org.springframework.http.HttpHeaders; +import org.springframework.social.RateLimitExceededException; + +public class TwitterRateLimitExceededException extends RateLimitExceededException { + private static final String X_RATE_LIMIT_RESET = "x-rate-limit-reset"; + private static final String X_RATE_LIMIT_REMAINING = "x-rate-limit-remaining"; + private static final String X_RATE_LIMIT_LIMIT = "x-rate-limit-limit"; + private static final long serialVersionUID = 1L; + private final Long rateLimitTotal; + private final Long rateLimitRemaining; + private final Long rateLimitResetTimeStamp; + + public TwitterRateLimitExceededException( + final Long rateLimitTotal, + final Long rateLimitRemaining, + final Long rateLimitResetTimeStamp) { + super("twitter"); + + this.rateLimitTotal = rateLimitTotal; + this.rateLimitRemaining = rateLimitRemaining; + this.rateLimitResetTimeStamp = rateLimitResetTimeStamp; + } + + public TwitterRateLimitExceededException(final HttpHeaders headers) { + this( + readRateLimitTotal(headers), + readRateLimitRemaining(headers), + readRateLimitResetTimeStamp(headers)); + } + + public Long getRateLimitTotal() { + return rateLimitTotal; + } + + public Long getRateLimitRemaining() { + return rateLimitRemaining; + } + + public Long getRateLimitResetTimeStamp() { + return rateLimitResetTimeStamp; + } + + public LocalDateTime getRateLimitReset() { + return fromUnixTimeStamp(rateLimitResetTimeStamp); + } + + private static Long readRateLimitTotal(final HttpHeaders headers) { + return returnHeaderAsLongIfAvailable(headers, X_RATE_LIMIT_LIMIT); + } + + private static Long readRateLimitRemaining(final HttpHeaders headers) { + return returnHeaderAsLongIfAvailable(headers, X_RATE_LIMIT_REMAINING); + } + + private static Long readRateLimitResetTimeStamp(final HttpHeaders headers) { + return returnHeaderAsLongIfAvailable(headers, X_RATE_LIMIT_RESET); + } + + private static Long returnHeaderAsLongIfAvailable(final HttpHeaders headers, final String headerName) { + return headers.containsKey(headerName) + ? Long.valueOf(headers.getFirst(headerName)) + : null; + } + + private static LocalDateTime fromUnixTimeStamp(final Long rateLimitResetTimeStamp) { + final Instant i = Instant.ofEpochMilli(rateLimitResetTimeStamp * 1000L); + return LocalDateTime.ofInstant(i, ZoneOffset.UTC); + } +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterTemplate.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterTemplate.java index 9c7be2f4..266c88ce 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterTemplate.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterTemplate.java @@ -1,12 +1,12 @@ /* * Copyright 2014 the original author or authors. - * + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * + * + * http://www.apache.org/licenses/LICENSE-2.0 + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -15,6 +15,10 @@ */ package org.springframework.social.twitter.api.impl; +import java.util.Arrays; + +import org.springframework.http.MediaType; +import org.springframework.http.converter.ByteArrayHttpMessageConverter; import org.springframework.http.converter.FormHttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.social.oauth1.AbstractOAuth1ApiBinding; @@ -26,10 +30,31 @@ import org.springframework.social.twitter.api.GeoOperations; import org.springframework.social.twitter.api.ListOperations; import org.springframework.social.twitter.api.SearchOperations; +import org.springframework.social.twitter.api.Settings; import org.springframework.social.twitter.api.StreamingOperations; import org.springframework.social.twitter.api.TimelineOperations; import org.springframework.social.twitter.api.Twitter; import org.springframework.social.twitter.api.UserOperations; +import org.springframework.social.twitter.api.advertising.AdvertisingOperations; +import org.springframework.social.twitter.api.advertising.CampaignOperations; +import org.springframework.social.twitter.api.advertising.LineItemOperations; +import org.springframework.social.twitter.api.advertising.PromotionOperations; +import org.springframework.social.twitter.api.advertising.StatisticsOperations; +import org.springframework.social.twitter.api.advertising.TailoredAudienceOperations; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryOperations; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaOperations; +import org.springframework.social.twitter.api.impl.advertising.AdvertisingTemplate; +import org.springframework.social.twitter.api.impl.advertising.CampaignTemplate; +import org.springframework.social.twitter.api.impl.advertising.LineItemTemplate; +import org.springframework.social.twitter.api.impl.advertising.PromotionTemplate; +import org.springframework.social.twitter.api.impl.advertising.StatisticsTemplate; +import org.springframework.social.twitter.api.impl.advertising.TailoredAudienceTemplate; +import org.springframework.social.twitter.api.impl.advertising.TargetingCriteriaDiscoveryTemplate; +import org.springframework.social.twitter.api.impl.advertising.TargetingCriteriaTemplate; +import org.springframework.social.twitter.api.impl.ton.TonTemplate; +import org.springframework.social.twitter.api.impl.upload.UploadTemplate; +import org.springframework.social.twitter.api.ton.TonOperations; +import org.springframework.social.twitter.api.upload.UploadOperations; import org.springframework.util.Assert; import org.springframework.web.client.RestOperations; import org.springframework.web.client.RestTemplate; @@ -39,168 +64,311 @@ /** * This is the central class for interacting with Twitter. *

- * Most (not all) Twitter operations require OAuth authentication. To perform - * such operations, {@link TwitterTemplate} must be constructed with the minimal - * amount of information required to sign requests to Twitter's API with an - * OAuth Authorization header. + * Most (not all) Twitter operations require OAuth authentication. To perform such operations, {@link TwitterTemplate} must be constructed with the + * minimal amount of information required to sign requests to Twitter's API with an OAuth Authorization header. *

+ * * @author Craig Walls */ public class TwitterTemplate extends AbstractOAuth1ApiBinding implements Twitter { - - private TimelineOperations timelineOperations; - - private UserOperations userOperations; - - private FriendOperations friendOperations; - - private ListOperations listOperations; - - private SearchOperations searchOperations; - - private DirectMessageOperations directMessageOperations; - - private BlockOperations blockOperations; - - private GeoOperations geoOperations; - - private StreamingOperations streamOperations; - - private RestTemplate clientRestTemplate = null; - - /** - * Create a new instance of TwitterTemplate. - * @param consumerKey the application's API key - * @param consumerSecret the application's API secret - * @param accessToken an access token acquired through OAuth authentication with Twitter - * @param accessTokenSecret an access token secret acquired through OAuth authentication with Twitter - */ - public TwitterTemplate(String consumerKey, String consumerSecret, String accessToken, String accessTokenSecret) { - super(consumerKey, consumerSecret, accessToken, accessTokenSecret); - initSubApis(); - } - - /** - * Create a new instance of TwitterTemplate. - * This instance of TwitterTemplate is limited to only performing operations requiring client authorization. - * For instance, you can use it to search Twitter, but you cannot use it to post a status update. - * The access token you use here must be obtained via OAuth 2 Client Credentials Grant. See {@link OAuth2Operations#authenticateClient()}. - * @param clientToken an access token obtained through OAuth 2 client credentials grant with Twitter. - */ - public TwitterTemplate(String clientToken) { - super(); - Assert.notNull(clientToken, "Constructor argument 'clientToken' cannot be null."); - this.clientRestTemplate = createClientRestTemplate(clientToken); - initSubApis(); - } - - /** - * Create a new instance of TwitterTemplate. - * This instance of TwitterTemplate is limited to only performing operations requiring client authorization. - * For instance, you can use it to search Twitter, but you cannot use it to post a status update. - * The client credentials given here are used to obtain a client access token via OAuth 2 Client Credentials Grant. See {@link OAuth2Operations#authenticateClient()}. - * @param consumerKey the application's API key - * @param consumerSecret the application's API secret - */ - public TwitterTemplate(String consumerKey, String consumerSecret) { - this(exchangeCredentialsForClientToken(consumerKey, consumerSecret)); - } - - public TimelineOperations timelineOperations() { - return timelineOperations; - } - - public FriendOperations friendOperations() { - return friendOperations; - } - - public ListOperations listOperations() { - return listOperations; - } - - public SearchOperations searchOperations() { - return searchOperations; - } - - public DirectMessageOperations directMessageOperations() { - return directMessageOperations; - } - - public UserOperations userOperations() { - return userOperations; - } - - public BlockOperations blockOperations() { - return blockOperations; - } - - public GeoOperations geoOperations() { - return geoOperations; - } - - public StreamingOperations streamingOperations() { - return streamOperations; - } - - public RestOperations restOperations() { - return getRestTemplate(); - } - - // Override getRestTemplate() to return an app-authorized RestTemplate if a client token is available. - @Override - public RestTemplate getRestTemplate() { - if (clientRestTemplate != null) { - return clientRestTemplate; - } - return super.getRestTemplate(); - } - - // AbstractOAuth1ApiBinding hooks - - @Override - protected MappingJackson2HttpMessageConverter getJsonMessageConverter() { - MappingJackson2HttpMessageConverter converter = super.getJsonMessageConverter(); - converter.setObjectMapper(new ObjectMapper().registerModule(new TwitterModule())); - return converter; - } - - @Override - protected FormHttpMessageConverter getFormMessageConverter() { - return new TwitterEscapingFormHttpMessageConverter(); - } - - @Override - protected void configureRestTemplate(RestTemplate restTemplate) { - restTemplate.setErrorHandler(new TwitterErrorHandler()); - } - - // private helper - private static String exchangeCredentialsForClientToken(String consumerKey, String consumerSecret) { - OAuth2Template oauth2 = new OAuth2Template(consumerKey, consumerSecret, "", "https://api.twitter.com/oauth2/token"); - return oauth2.authenticateClient().getAccessToken(); - } - - private RestTemplate createClientRestTemplate(String clientToken) { - RestTemplate restTemplate = new ClientAuthorizedTwitterTemplate(clientToken).getRestTemplate(); - restTemplate.setMessageConverters(getMessageConverters()); - configureRestTemplate(restTemplate); - return restTemplate; - } - - private void initSubApis() { - this.userOperations = new UserTemplate(getRestTemplate(), isAuthorized(), isAuthorizedForApp()); - this.directMessageOperations = new DirectMessageTemplate(getRestTemplate(), isAuthorized(), isAuthorizedForApp()); - this.friendOperations = new FriendTemplate(getRestTemplate(), isAuthorized(), isAuthorizedForApp()); - this.listOperations = new ListTemplate(getRestTemplate(), isAuthorized(), isAuthorizedForApp()); - this.timelineOperations = new TimelineTemplate(getRestTemplate(), isAuthorized(), isAuthorizedForApp()); - this.searchOperations = new SearchTemplate(getRestTemplate(), isAuthorized(), isAuthorizedForApp()); - this.blockOperations = new BlockTemplate(getRestTemplate(), isAuthorized(),isAuthorizedForApp()); - this.geoOperations = new GeoTemplate(getRestTemplate(), isAuthorized(), isAuthorizedForApp()); - this.streamOperations = new StreamingTemplate(getRestTemplate(), isAuthorized(), isAuthorizedForApp()); - } - - private boolean isAuthorizedForApp() { - return clientRestTemplate != null; - } - -} + + private TimelineOperations timelineOperations; + + private UserOperations userOperations; + + private FriendOperations friendOperations; + + private ListOperations listOperations; + + private SearchOperations searchOperations; + + private DirectMessageOperations directMessageOperations; + + private BlockOperations blockOperations; + + private GeoOperations geoOperations; + + private StreamingOperations streamOperations; + + private AdvertisingOperations advertisingOperations; + + private PromotionOperations promotionOperations; + + private StatisticsOperations statisticsOperations; + + private CampaignOperations campaignOperations; + + private LineItemOperations lineItemOperations; + + private TargetingCriteriaOperations targetingCriteriaOperations; + + private TargetingCriteriaDiscoveryOperations targetingCriteriaDiscoveryOperations; + + private TailoredAudienceOperations tailoredAudienceOperations; + + private TonOperations tonOperations; + + private UploadOperations uploadOperations; + + private RestTemplate clientRestTemplate = null; + + private Settings settings = null; + + /** + * Create a new instance of TwitterTemplate. + * + * @param consumerKey the application's API key + * @param consumerSecret the application's API secret + * @param accessToken an access token acquired through OAuth authentication with Twitter + * @param accessTokenSecret an access token secret acquired through OAuth authentication with Twitter + * @param hostForStandardApi defines the host for which standard api calls will be pointed + * @param hostForAdsApi defines the host for which ads api calls will be pointed. + */ + public TwitterTemplate( + String consumerKey, + String consumerSecret, + String accessToken, + String accessTokenSecret, + String hostForStandardApi, + String hostForAdsApi) { + super(consumerKey, consumerSecret, accessToken, accessTokenSecret); + initSubApis(); + initHosts(hostForStandardApi, hostForAdsApi); + } + + /** + * Create a new instance of TwitterTemplate. + * + * @param consumerKey the application's API key + * @param consumerSecret the application's API secret + * @param accessToken an access token acquired through OAuth authentication with Twitter + * @param accessTokenSecret an access token secret acquired through OAuth authentication with Twitter + */ + public TwitterTemplate(String consumerKey, String consumerSecret, String accessToken, String accessTokenSecret) { + super(consumerKey, consumerSecret, accessToken, accessTokenSecret); + initSubApis(); + initHosts(null, null); + } + + /** + * Create a new instance of TwitterTemplate. + * This instance of TwitterTemplate is limited to only performing operations requiring client authorization. + * For instance, you can use it to search Twitter, but you cannot use it to post a status update. + * The access token you use here must be obtained via OAuth 2 Client Credentials Grant. See {@link OAuth2Operations#authenticateClient()}. + * + * @param clientToken an access token obtained through OAuth 2 client credentials grant with Twitter. + */ + public TwitterTemplate(String clientToken) { + super(); + Assert.notNull(clientToken, "Constructor argument 'clientToken' cannot be null."); + this.clientRestTemplate = createClientRestTemplate(clientToken); + initSubApis(); + initHosts(null, null); + } + + /** + * Create a new instance of TwitterTemplate. + * This instance of TwitterTemplate is limited to only performing operations requiring client authorization. + * For instance, you can use it to search Twitter, but you cannot use it to post a status update. + * The client credentials given here are used to obtain a client access token via OAuth 2 Client Credentials Grant. See + * {@link OAuth2Operations#authenticateClient()}. + * + * @param consumerKey the application's API key + * @param consumerSecret the application's API secret + */ + public TwitterTemplate(String consumerKey, String consumerSecret) { + this(exchangeCredentialsForClientToken(consumerKey, consumerSecret)); + } + + @Override + /** + * Add additional media types for TON upload + */ + protected ByteArrayHttpMessageConverter getByteArrayMessageConverter() { + ByteArrayHttpMessageConverter converter = new ByteArrayHttpMessageConverter(); + converter.setSupportedMediaTypes(Arrays.asList(MediaType.TEXT_PLAIN, MediaType.IMAGE_JPEG, MediaType.IMAGE_GIF, MediaType.IMAGE_PNG)); + return converter; + } + + @Override + public TimelineOperations timelineOperations() { + return timelineOperations; + } + + @Override + public FriendOperations friendOperations() { + return friendOperations; + } + + @Override + public ListOperations listOperations() { + return listOperations; + } + + @Override + public SearchOperations searchOperations() { + return searchOperations; + } + + @Override + public DirectMessageOperations directMessageOperations() { + return directMessageOperations; + } + + @Override + public UserOperations userOperations() { + return userOperations; + } + + @Override + public BlockOperations blockOperations() { + return blockOperations; + } + + @Override + public GeoOperations geoOperations() { + return geoOperations; + } + + @Override + public StreamingOperations streamingOperations() { + return streamOperations; + } + + @Override + public AdvertisingOperations advertisingOperations() { + return advertisingOperations; + } + + @Override + public PromotionOperations promotionOperations() { + return promotionOperations; + } + + @Override + public StatisticsOperations statisticsOperations() { + return statisticsOperations; + } + + @Override + public CampaignOperations campaignOperations() { + return campaignOperations; + } + + @Override + public LineItemOperations lineItemOperations() { + return lineItemOperations; + } + + @Override + public TargetingCriteriaOperations targetingCriteriaOperations() { + return targetingCriteriaOperations; + } + + @Override + public TailoredAudienceOperations tailoredAudienceOperations() { + return tailoredAudienceOperations; + } + + @Override + public TargetingCriteriaDiscoveryOperations targetingCriteriaDiscoveryOperations() { + return targetingCriteriaDiscoveryOperations; + } + + @Override + public TonOperations tonOperations() { + return tonOperations; + } + + @Override + public UploadOperations uploadOperations() { + return uploadOperations; + } + + @Override + public Settings settings() { + return settings; + } + + @Override + public RestOperations restOperations() { + return getRestTemplate(); + } + + // Override getRestTemplate() to return an app-authorized RestTemplate if a client token is available. + @Override + public RestTemplate getRestTemplate() { + if (clientRestTemplate != null) { + return clientRestTemplate; + } + return super.getRestTemplate(); + } + + // AbstractOAuth1ApiBinding hooks + + @Override + protected MappingJackson2HttpMessageConverter getJsonMessageConverter() { + MappingJackson2HttpMessageConverter converter = super.getJsonMessageConverter(); + converter.setObjectMapper(new ObjectMapper().registerModule(new TwitterModule())); + return converter; + } + + @Override + protected FormHttpMessageConverter getFormMessageConverter() { + return new TwitterEscapingFormHttpMessageConverter(); + } + + @Override + protected void configureRestTemplate(RestTemplate restTemplate) { + restTemplate.setErrorHandler(new TwitterErrorHandler()); + } + + // private helper + private static String exchangeCredentialsForClientToken(String consumerKey, String consumerSecret) { + OAuth2Template oauth2 = new OAuth2Template(consumerKey, consumerSecret, "", "https://api.twitter.com/oauth2/token"); + return oauth2.authenticateClient().getAccessToken(); + } + + private RestTemplate createClientRestTemplate(String clientToken) { + RestTemplate restTemplate = new ClientAuthorizedTwitterTemplate(clientToken).getRestTemplate(); + restTemplate.setMessageConverters(getMessageConverters()); + configureRestTemplate(restTemplate); + return restTemplate; + } + + private void initSubApis() { + this.userOperations = new UserTemplate(getRestTemplate(), isAuthorized(), isAuthorizedForApp()); + this.directMessageOperations = new DirectMessageTemplate(getRestTemplate(), isAuthorized(), isAuthorizedForApp()); + this.friendOperations = new FriendTemplate(getRestTemplate(), isAuthorized(), isAuthorizedForApp()); + this.listOperations = new ListTemplate(getRestTemplate(), isAuthorized(), isAuthorizedForApp()); + this.timelineOperations = new TimelineTemplate(getRestTemplate(), isAuthorized(), isAuthorizedForApp()); + this.searchOperations = new SearchTemplate(getRestTemplate(), isAuthorized(), isAuthorizedForApp()); + this.blockOperations = new BlockTemplate(getRestTemplate(), isAuthorized(), isAuthorizedForApp()); + this.geoOperations = new GeoTemplate(getRestTemplate(), isAuthorized(), isAuthorizedForApp()); + this.streamOperations = new StreamingTemplate(getRestTemplate(), isAuthorized(), isAuthorizedForApp()); + + this.advertisingOperations = new AdvertisingTemplate(getRestTemplate(), isAuthorized(), isAuthorized()); + this.promotionOperations = new PromotionTemplate(getRestTemplate(), isAuthorized(), isAuthorized()); + this.statisticsOperations = new StatisticsTemplate(getRestTemplate(), isAuthorized(), isAuthorized()); + this.campaignOperations = new CampaignTemplate(getRestTemplate(), isAuthorized(), isAuthorized()); + this.lineItemOperations = new LineItemTemplate(getRestTemplate(), isAuthorized(), isAuthorized()); + this.targetingCriteriaOperations = new TargetingCriteriaTemplate(getRestTemplate(), isAuthorized(), isAuthorized()); + this.targetingCriteriaDiscoveryOperations = new TargetingCriteriaDiscoveryTemplate(getRestTemplate(), isAuthorized(), isAuthorized()); + this.tailoredAudienceOperations = new TailoredAudienceTemplate(getRestTemplate(), isAuthorized(), isAuthorized()); + this.tonOperations = new TonTemplate(getRestTemplate(), isAuthorized(), isAuthorized()); + + this.uploadOperations = new UploadTemplate(getRestTemplate(), isAuthorized(), isAuthorized()); + + this.settings = new SettingsImpl(); + } + + private void initHosts(String standardApiHost, String adsApiHost) { + TwitterApiHosts.setStandardApiHost(standardApiHost); + TwitterApiHosts.setAdsApiHost(adsApiHost); + } + + private boolean isAuthorizedForApp() { + return clientRestTemplate != null; + } + +} \ No newline at end of file diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterTimeStamp.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterTimeStamp.java new file mode 100644 index 00000000..02e3b59a --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/TwitterTimeStamp.java @@ -0,0 +1,54 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl; + +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneOffset; + +/** + * Represents a time stamp in twitter standard. + * It's basically a ISO LocalDateTime without the fraction and with the Z. + * + * @author Hudson Mendes + * + */ +public class TwitterTimeStamp { + private final Instant translated; + + public TwitterTimeStamp(LocalDateTime original) { + translated = translate(original); + } + + private Instant translate(LocalDateTime original) { + return LocalDateTime.of( + original.getYear(), + original.getMonth(), + original.getDayOfMonth(), + original.getHour(), + original.getMinute(), + original.getSecond()).toInstant(ZoneOffset.UTC); + } + + @Override + public String toString() { + return translated.toString(); + } + + public Instant toInstant() { + return translated; + } +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/UrlEntityMixin.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/UrlEntityMixin.java index 50b0ac48..406e6441 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/UrlEntityMixin.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/UrlEntityMixin.java @@ -17,7 +17,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; -abstract class UrlEntityMixin extends TwitterObjectMixin { +public abstract class UrlEntityMixin extends TwitterObjectMixin { public UrlEntityMixin( @JsonProperty("display_url") String display, diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/UserListList.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/UserListList.java index 60dea34a..7343da45 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/UserListList.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/UserListList.java @@ -30,7 +30,7 @@ * @author Craig Walls */ @JsonIgnoreProperties(ignoreUnknown = true) -class UserListList { +public class UserListList { private final CursoredList list; @JsonCreator diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/UserListMixin.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/UserListMixin.java index 4e2edae8..85ffb3f3 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/UserListMixin.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/UserListMixin.java @@ -31,7 +31,7 @@ * @author Craig Walls */ @JsonIgnoreProperties(ignoreUnknown=true) -abstract class UserListMixin extends TwitterObjectMixin { +public abstract class UserListMixin extends TwitterObjectMixin { @JsonCreator UserListMixin( diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/UserTemplate.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/UserTemplate.java index fd3c6fca..78de507c 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/UserTemplate.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/UserTemplate.java @@ -1,12 +1,12 @@ /* * Copyright 2014 the original author or authors. - * + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * + * + * http://www.apache.org/licenses/LICENSE-2.0 + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -29,89 +29,159 @@ /** * Implementation of the {@link UserOperations} interface providing binding to Twitters' user-oriented REST resources. + * * @author Craig Walls */ -class UserTemplate extends AbstractTwitterOperations implements UserOperations { - - private final RestTemplate restTemplate; - - public UserTemplate(RestTemplate restTemplate, boolean isAuthorizedForUser, boolean isAuthorizedForApp) { - super(isAuthorizedForUser, isAuthorizedForApp); - this.restTemplate = restTemplate; - } - - public long getProfileId() { - requireUserAuthorization(); - return getUserProfile().getId(); - } - - public String getScreenName() { - requireUserAuthorization(); - return getUserProfile().getScreenName(); - } - - public TwitterProfile getUserProfile() { - requireUserAuthorization(); - return restTemplate.getForObject(buildUri("account/verify_credentials.json"), TwitterProfile.class); - } - - public TwitterProfile getUserProfile(String screenName) { - requireEitherUserOrAppAuthorization(); - return restTemplate.getForObject(buildUri("users/show.json", "screen_name", screenName), TwitterProfile.class); - } - - public TwitterProfile getUserProfile(long userId) { - requireEitherUserOrAppAuthorization(); - return restTemplate.getForObject(buildUri("users/show.json", "user_id", String.valueOf(userId)), TwitterProfile.class); - } - - public List getUsers(long... userIds) { - requireEitherUserOrAppAuthorization(); - String joinedIds = ArrayUtils.join(userIds); - return restTemplate.getForObject(buildUri("users/lookup.json", "user_id", joinedIds), TwitterProfileList.class); - } - - public List getUsers(String... screenNames) { - requireEitherUserOrAppAuthorization(); - String joinedScreenNames = ArrayUtils.join(screenNames); - return restTemplate.getForObject(buildUri("users/lookup.json", "screen_name", joinedScreenNames), TwitterProfileList.class); - } - - public List searchForUsers(String query) { - return searchForUsers(query, 1, 20); - } - - public List searchForUsers(String query, int page, int pageSize) { - requireUserAuthorization(); - MultiValueMap parameters = PagingUtils.buildPagingParametersWithCount(page, pageSize, 0, 0); - parameters.set("q", query); - return restTemplate.getForObject(buildUri("users/search.json", parameters), TwitterProfileList.class); - } - - public List getSuggestionCategories() { - requireEitherUserOrAppAuthorization(); - return restTemplate.getForObject(buildUri("users/suggestions.json"), SuggestionCategoryList.class); - } - - public List getSuggestions(String slug) { - requireEitherUserOrAppAuthorization(); - return restTemplate.getForObject(buildUri("users/suggestions/" + slug + ".json"), TwitterProfileUsersList.class).getList(); - } - - public Map> getRateLimitStatus(ResourceFamily... resources) { - requireEitherUserOrAppAuthorization(); - String joinedResources = ArrayUtils.join(resources); - return restTemplate.getForObject(buildUri("application/rate_limit_status.json", "resources", joinedResources), RateLimitStatusHolder.class).getRateLimits(); - } - - public AccountSettings getAccountSettings() { - requireUserAuthorization(); - return restTemplate.getForObject(buildUri("account/settings.json"), AccountSettings.class); - } - - public AccountSettings updateAccountSettings(AccountSettingsData accountSettingsData) { - requireUserAuthorization(); - return restTemplate.postForObject(buildUri("account/settings.json"), accountSettingsData.toRequestParameters(), AccountSettings.class); - } +public class UserTemplate extends AbstractTwitterOperations implements UserOperations { + + private final RestTemplate restTemplate; + + public UserTemplate(RestTemplate restTemplate, boolean isAuthorizedForUser, boolean isAuthorizedForApp) { + super(isAuthorizedForUser, isAuthorizedForApp); + this.restTemplate = restTemplate; + } + + @Override + public long getProfileId() { + requireUserAuthorization(); + return getUserProfile().getId(); + } + + @Override + public String getScreenName() { + requireUserAuthorization(); + return getUserProfile().getScreenName(); + } + + @Override + public TwitterProfile getUserProfile() { + requireUserAuthorization(); + return restTemplate.getForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.ACCOUNT_VERIFY_CREDENTIALS) + .build(), + TwitterProfile.class); + } + + @Override + public TwitterProfile getUserProfile(String screenName) { + requireEitherUserOrAppAuthorization(); + return restTemplate.getForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.USERS_SHOW) + .withArgument("screen_name", screenName) + .build(), + TwitterProfile.class); + } + + @Override + public TwitterProfile getUserProfile(long userId) { + requireEitherUserOrAppAuthorization(); + return restTemplate.getForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.USERS_SHOW) + .withArgument("user_id", String.valueOf(userId)) + .build(), + TwitterProfile.class); + } + + @Override + public List getUsers(long... userIds) { + requireEitherUserOrAppAuthorization(); + String joinedIds = ArrayUtils.join(userIds); + return restTemplate.getForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.USERS_LOOKUP) + .withArgument("user_id", joinedIds) + .build(), + TwitterProfileList.class); + } + + @Override + public List getUsers(String... screenNames) { + requireEitherUserOrAppAuthorization(); + String joinedScreenNames = ArrayUtils.join(screenNames); + return restTemplate.getForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.USERS_LOOKUP) + .withArgument("screen_name", joinedScreenNames) + .build(), + TwitterProfileList.class); + } + + @Override + public List searchForUsers(String query) { + return searchForUsers(query, 1, 20); + } + + @Override + public List searchForUsers(String query, int page, int pageSize) { + requireUserAuthorization(); + + MultiValueMap parameters = PagingUtils.buildPagingParametersWithCount(page, pageSize, 0, 0); + parameters.set("q", query); + + return restTemplate.getForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.USERS_SEARCH) + .withArgument(parameters) + .build(), + TwitterProfileList.class); + } + + @Override + public List getSuggestionCategories() { + requireEitherUserOrAppAuthorization(); + return restTemplate.getForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.USERS_SUGGESTIONS) + .build(), + SuggestionCategoryList.class); + } + + @Override + public List getSuggestions(String slug) { + requireEitherUserOrAppAuthorization(); + return restTemplate.getForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.USERS_SUGGESTIONS_WITH_SLUG) + .withArgument("slug", slug) + .build(), + TwitterProfileUsersList.class + ).getList(); + } + + @Override + public Map> getRateLimitStatus(ResourceFamily... resources) { + requireEitherUserOrAppAuthorization(); + return restTemplate.getForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.APPLICATION_RATE_LIMIT_STATUS) + .withArgument("resources", ArrayUtils.join(resources)) + .build(), + RateLimitStatusHolder.class + ).getRateLimits(); + } + + @Override + public AccountSettings getAccountSettings() { + requireUserAuthorization(); + return restTemplate.getForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.ACCOUNT_SETTINGS) + .build(), + AccountSettings.class); + } + + @Override + public AccountSettings updateAccountSettings(AccountSettingsData accountSettingsData) { + requireUserAuthorization(); + return restTemplate.postForObject( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForStandard.ACCOUNT_SETTINGS) + .build(), + accountSettingsData.toRequestParameters(), + AccountSettings.class); + } } diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/VideoInfoEntityMediaMixin.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/VideoInfoEntityMediaMixin.java new file mode 100644 index 00000000..5017d392 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/VideoInfoEntityMediaMixin.java @@ -0,0 +1,40 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl; + +import java.util.List; + +import org.springframework.social.twitter.api.MediaEntity; +import org.springframework.social.twitter.api.Tweet; +import org.springframework.social.twitter.api.VideoInfoVariantMediaEntity; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Represents the Video Info part of the {@link MediaEntity} in the {@link Tweet}. + * + * @author Hudson Mendes + * + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public abstract class VideoInfoEntityMediaMixin extends TwitterObjectMixin { + @JsonCreator + public VideoInfoEntityMediaMixin( + @JsonProperty("aspect_ratio") List aspectRatio, + @JsonProperty("variants") List variants) {} +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/VideoInfoVariantMediaEntityMixin.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/VideoInfoVariantMediaEntityMixin.java new file mode 100644 index 00000000..789ea121 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/VideoInfoVariantMediaEntityMixin.java @@ -0,0 +1,39 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl; + +import org.springframework.social.twitter.api.MediaEntity; +import org.springframework.social.twitter.api.Tweet; +import org.springframework.social.twitter.api.VideoInfoMediaEntity; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Represents the possible variation of {@link VideoInfoMediaEntity} for the {@link MediaEntity} in the {@link Tweet}. + * + * @author Hudson Mendes + * + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public abstract class VideoInfoVariantMediaEntityMixin extends TwitterObjectMixin { + @JsonCreator + public VideoInfoVariantMediaEntityMixin( + @JsonProperty("bitrate") Long bitrate, + @JsonProperty("content_type") String contentType, + @JsonProperty("url") String url) {} +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/AbstractTwitterFormBuilder.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/AbstractTwitterFormBuilder.java new file mode 100644 index 00000000..492895ef --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/AbstractTwitterFormBuilder.java @@ -0,0 +1,31 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import org.springframework.social.twitter.api.TwitterForm; +import org.springframework.util.MultiValueMap; + +/** + * Builder base for all other builders which have the intent of + * POSTing or PUTting data through an api endpoint, transforming + * them in to a body Map of values. + * + * @author Hudson Mendes + */ +public abstract class AbstractTwitterFormBuilder extends AbstractTwitterParametersBuilder implements TwitterForm { + @Override + public abstract MultiValueMap toRequestBody(); +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/AbstractTwitterParametersBuilder.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/AbstractTwitterParametersBuilder.java new file mode 100644 index 00000000..1a2cb2a7 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/AbstractTwitterParametersBuilder.java @@ -0,0 +1,79 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import java.math.BigDecimal; +import java.util.ArrayList; + +import org.springframework.util.MultiValueMap; + +/** + * Provides basic functionality for parameter building related components + * (for both QueryBuilders and FormBuilders) that shall be especialised + * to produce contract-specific builders. + * + * @author Hudson Mendes + */ +public abstract class AbstractTwitterParametersBuilder { + private static final BigDecimal MICRO_MULTIPLIER = new BigDecimal(1000000); + + protected static void appendParameter( + MultiValueMap params, + String name, + TValue value) { + + appendParameter(params, name, value, false); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + protected static void appendParameter( + MultiValueMap params, + String name, + TValue value, + Boolean showIfNull) { + + if (value == null) + if (!showIfNull) + return; + else { + params.set(name, (String) null); + return; + } + if (value instanceof String && ((String) value).isEmpty()) + return; + if (value instanceof ArrayList && ((ArrayList) value).size() == 0) + return; + if (value instanceof ArrayList) { + final ArrayList valueAsList = (ArrayList) value; + final String[] valueArray = (String[]) valueAsList.stream() + .filter(i -> i != null) + .map(i -> i.toString()) + .toArray(size -> new String[size]); + + params.add(name, String.join(",", valueArray)); + } + else + params.set(name, value.toString()); + + } + + protected static Long translateBigDecimalIntoMicro(BigDecimal value) { + if (value == null) + return null; + + return value.multiply(MICRO_MULTIPLIER).longValue(); + } +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/AbstractTwitterQueryForDataBuilder.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/AbstractTwitterQueryForDataBuilder.java new file mode 100644 index 00000000..f50e162c --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/AbstractTwitterQueryForDataBuilder.java @@ -0,0 +1,54 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import org.springframework.social.twitter.api.TwitterQueryForData; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +/** + * Basic representation of the QueryString parameters builders + * that shall be used for querying basic data in the APIs. + * Important: unfortunately, the basic API is a lot less standardized than the ADs Api + * and therefore we cannot use this base builder for _everything_. However, + * it's reasonable the Twitter moves towards standardization and then, this + * builder will become a richer asset to the Api. + * + * @author Hudson Mendes + */ +public abstract class AbstractTwitterQueryForDataBuilder> + extends AbstractTwitterParametersBuilder + implements TwitterQueryForData { + + protected Boolean includeDeleted; + + @Override + @SuppressWarnings("unchecked") + public TBuilderInterface includeDeleted(Boolean include) { + this.includeDeleted = include; + return (TBuilderInterface) this; + } + + @Override + public MultiValueMap toQueryParameters() { + MultiValueMap map = new LinkedMultiValueMap(); + makeParameters(map); + appendParameter(map, "with_deleted", this.includeDeleted); + return map; + } + + protected abstract void makeParameters(MultiValueMap map); +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/AbstractTwitterQueryForEntityBuilder.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/AbstractTwitterQueryForEntityBuilder.java new file mode 100644 index 00000000..17258655 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/AbstractTwitterQueryForEntityBuilder.java @@ -0,0 +1,83 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import java.net.URLEncoder; + +import org.springframework.social.twitter.api.TwitterQueryForData; +import org.springframework.social.twitter.api.TwitterQueryForEntity; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.util.StringUtils; + +/** + * Basic representation of the QueryString parameters builders + * that shall be used for querying any data in the APIs. + * Important: unfortunately, the basic API is a lot less standardized than the ADs Api + * and therefore we cannot use this base builder for _everything_. However, + * it's reasonable the Twitter moves towards standardization and then, this + * builder will become a richer asset to the Api. + * + * @author Hudson Mendes + */ +public abstract class AbstractTwitterQueryForEntityBuilder> + extends AbstractTwitterQueryForDataBuilder + implements TwitterQueryForEntity { + private String query; + private String cursor; + private Integer pageSize; + + @Override + @SuppressWarnings("unchecked") + public TBuilderInterface pagedBy(String cursor, Integer pageSize) { + this.cursor = cursor; + this.pageSize = pageSize; + return (TBuilderInterface) this; + } + + @Override + @SuppressWarnings("unchecked") + public TBuilderInterface withQuery(String query) { + this.query = query; + return (TBuilderInterface) this; + } + + @Override + public MultiValueMap toQueryParameters() { + MultiValueMap map = new LinkedMultiValueMap(); + makeParameters(map); + + MultiValueMap parentMap = super.toQueryParameters(); + for (String parentKey : parentMap.keySet()) + if (parentMap.get(parentKey).size() != 0) + appendParameter(map, parentKey, parentMap.get(parentKey).get(0)); + + try { + if (this.query != null) + appendParameter(map, "q", URLEncoder.encode(this.query, "UTF-8")); + } catch(Exception e) { + appendParameter(map, "q", this.query); + } + + if (!StringUtils.isEmpty(this.cursor)) + appendParameter(map, "cursor", this.cursor); + + if (this.pageSize != null) + appendParameter(map, "count", this.pageSize); + + return map; + } +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/AbstractTwitterQueryForSortableEntityBuilder.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/AbstractTwitterQueryForSortableEntityBuilder.java new file mode 100644 index 00000000..9b278694 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/AbstractTwitterQueryForSortableEntityBuilder.java @@ -0,0 +1,84 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import org.springframework.social.twitter.api.TwitterQueryForEntity; +import org.springframework.social.twitter.api.TwitterQueryForSortableEntity; +import org.springframework.social.twitter.api.advertising.SortDirection; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +/** + * Basic representation of the QueryString parameters builders + * that shall be used for querying any data in the APIs. + * Important: unfortunately, the basic API is a lot less standardized than the ADs Api + * and therefore we cannot use this base builder for _everything_. However, + * it's reasonable the Twitter moves towards standardization and then, this + * builder will become a richer asset to the Api. + * + * @author Hudson Mendes + * + * @param the sort enumberation that varies for each entity being requested. + */ +public abstract class AbstractTwitterQueryForSortableEntityBuilder, TSort> + extends AbstractTwitterQueryForEntityBuilder + implements TwitterQueryForSortableEntity { + + private TSort sort; + private SortDirection direction; + + @Override + @SuppressWarnings("unchecked") + public TBuilderInterface sortBy(TSort sort) { + this.sort = sort; + return (TBuilderInterface) this; + } + + @Override + @SuppressWarnings("unchecked") + public TBuilderInterface sortBy(TSort sort, SortDirection direction) { + this.sort = sort; + this.direction = direction; + return (TBuilderInterface) this; + } + + @Override + public MultiValueMap toQueryParameters() { + final MultiValueMap map = new LinkedMultiValueMap(); + makeParameters(map); + + final MultiValueMap parentMap = super.toQueryParameters(); + for (final String parentKey : parentMap.keySet()) + if (parentMap.get(parentKey).size() != 0) + appendParameter(map, parentKey, parentMap.get(parentKey).get(0)); + + final String sort = this.makeSort(); + if (sort != null) + appendParameter(map, "sort_by", sort); + + return map; + } + + private String makeSort() { + if (this.sort == null && this.direction == null) + return null; + + if (this.direction != null) + return this.sort + "-" + this.direction; + + return this.sort.toString() + "-" + SortDirection.asc; + } +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/AbstractTwitterQueryForStatsBuilder.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/AbstractTwitterQueryForStatsBuilder.java new file mode 100644 index 00000000..1b3171ef --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/AbstractTwitterQueryForStatsBuilder.java @@ -0,0 +1,107 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +import org.springframework.social.twitter.api.advertising.StatisticsGranularity; +import org.springframework.social.twitter.api.advertising.StatisticsMetric; +import org.springframework.social.twitter.api.advertising.StatisticsSegmentationType; +import org.springframework.social.twitter.api.impl.TwitterTimeStamp; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +/** + * Basic representation of the QueryString parameters builders + * that shall be used for querying any data in the APIs. + * Important: unfortunately, the basic API is a lot less standardized than the ADs Api + * and therefore we cannot use this base builder for _everything_. However, + * it's reasonable the Twitter moves towards standardization and then, this + * builder will become a richer asset to the Api. + * + * @author Hudson Mendes + */ +public abstract class AbstractTwitterQueryForStatsBuilder + extends AbstractTwitterParametersBuilder { + + private LocalDateTime startTime; + private LocalDateTime endTime; + private StatisticsSegmentationType segmentation; + private StatisticsGranularity granularity; + private List metrics; + + public MultiValueMap toQueryParameters() { + final MultiValueMap map = new LinkedMultiValueMap(); + + makeParameters(map); + + appendParameter(map, "segmentation_type", this.segmentation); + + appendParameter(map, "granularity", this.granularity); + + appendParameter(map, "metrics", this.metrics); + + if (this.startTime != null) + appendParameter(map, "start_time", new TwitterTimeStamp(this.startTime).toString()); + + if (this.endTime != null) + appendParameter(map, "end_time", new TwitterTimeStamp(this.endTime).toString()); + + return map; + } + + public TBuilderInterface activeUntil(LocalDateTime endTime) { + return activeBetween(null, endTime); + } + + public TBuilderInterface activeFrom(LocalDateTime startTime) { + return activeBetween(startTime, null); + } + + @SuppressWarnings("unchecked") + public TBuilderInterface activeBetween(LocalDateTime startTime, LocalDateTime endTime) { + if (startTime != null) + this.startTime = startTime; + if (endTime != null) + this.endTime = endTime; + return (TBuilderInterface) this; + } + + @SuppressWarnings("unchecked") + public TBuilderInterface withGranularity(StatisticsGranularity granularity) { + this.granularity = granularity; + return (TBuilderInterface) this; + } + + @SuppressWarnings("unchecked") + public TBuilderInterface withSegmentationType(StatisticsSegmentationType segmentation) { + this.segmentation = segmentation; + return (TBuilderInterface) this; + } + + @SuppressWarnings("unchecked") + public TBuilderInterface withStatisticalMetric(StatisticsMetric... metrics) { + this.metrics = new ArrayList(); + if (metrics != null) + for (final StatisticsMetric metric : metrics) + this.metrics.add(metric); + return (TBuilderInterface) this; + } + + protected abstract void makeParameters(MultiValueMap map); +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/AdvertisingAccountFeatureQueryBuilder.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/AdvertisingAccountFeatureQueryBuilder.java new file mode 100644 index 00000000..643f95aa --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/AdvertisingAccountFeatureQueryBuilder.java @@ -0,0 +1,52 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.social.twitter.api.advertising.AdvertisingAccountFeatureQuery; +import org.springframework.social.twitter.api.advertising.FeatureKey; +import org.springframework.util.MultiValueMap; + +/** + * Facilitates the creation of the query that will be + * used to filter results from the feature endpoint. + * + * @author Hudson Mendes + */ +public class AdvertisingAccountFeatureQueryBuilder + extends AbstractTwitterQueryForEntityBuilder + implements AdvertisingAccountFeatureQuery { + + private List featureKeys = new ArrayList(); + + @Override + public AdvertisingAccountFeatureQuery withFeatureKey(FeatureKey... featureKeys) { + if(null!=featureKeys) { + for(final FeatureKey featureKey: featureKeys) { + this.featureKeys.add(featureKey); + } + } + return this; + } + + @Override + protected void makeParameters(MultiValueMap map) { + appendParameter(map, "feature_keys", featureKeys); + } + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/AdvertisingAccountMixin.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/AdvertisingAccountMixin.java new file mode 100644 index 00000000..47cbdd91 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/AdvertisingAccountMixin.java @@ -0,0 +1,51 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import java.time.LocalDateTime; +import java.util.TimeZone; + +import org.springframework.social.twitter.api.advertising.AdvertisingAccount; +import org.springframework.social.twitter.api.advertising.ApprovalStatus; +import org.springframework.social.twitter.api.impl.LocalDateTimeDeserializer; +import org.springframework.social.twitter.api.impl.TwitterObjectMixin; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; + +/** + * Mixin class for adding Jackson annotations to {@link AdvertisingAccount}. + * @author Hudson Mendes + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public abstract class AdvertisingAccountMixin extends TwitterObjectMixin { + + @JsonCreator + AdvertisingAccountMixin( + @JsonProperty("id") String id, + @JsonProperty("name") String name, + @JsonProperty("salt") String salt, + @JsonProperty("timezone") TimeZone timeZone, + @JsonProperty("timezone_switch_at") @JsonDeserialize(using=LocalDateTimeDeserializer.class) @JsonFormat(pattern="yyyy-MM-dd'T'HH:mm:ssZ") LocalDateTime timeZoneSwitchAt, + @JsonProperty("created_at") @JsonDeserialize(using=LocalDateTimeDeserializer.class) @JsonFormat(pattern="yyyy-MM-dd'T'HH:mm:ssZ") LocalDateTime createdAt, + @JsonProperty("updated_at") @JsonDeserialize(using=LocalDateTimeDeserializer.class) @JsonFormat(pattern="yyyy-MM-dd'T'HH:mm:ssZ") LocalDateTime updatedAt, + @JsonProperty("approval_status") ApprovalStatus approvalStatus, + @JsonProperty("deleted") Boolean deleted) {} + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/AdvertisingAccountPermissionsMixin.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/AdvertisingAccountPermissionsMixin.java new file mode 100644 index 00000000..9736ad05 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/AdvertisingAccountPermissionsMixin.java @@ -0,0 +1,40 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import java.util.List; + +import org.springframework.social.twitter.api.advertising.AdvertisingPermission; +import org.springframework.social.twitter.api.advertising.AdvertisingAccountPermissions; +import org.springframework.social.twitter.api.impl.TwitterObjectMixin; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Mixin class for adding Jackson annotations to {@link AdvertisingAccountPermissions}. + * @author Hudson Mendes + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public abstract class AdvertisingAccountPermissionsMixin extends TwitterObjectMixin { + + @JsonCreator + AdvertisingAccountPermissionsMixin( + @JsonProperty("user_id") Long userId, + @JsonProperty("permissions") List permissions) {} + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/AdvertisingAccountQueryBuilder.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/AdvertisingAccountQueryBuilder.java new file mode 100644 index 00000000..6d36a5aa --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/AdvertisingAccountQueryBuilder.java @@ -0,0 +1,37 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import org.springframework.social.twitter.api.advertising.AdvertisingAccount; +import org.springframework.social.twitter.api.advertising.AdvertisingAccountQuery; +import org.springframework.social.twitter.api.advertising.AdvertisingAccountSorting; +import org.springframework.util.MultiValueMap; + +/** + * Facilitates the creation of the query that will be + * used to filter results from the {@link AdvertisingAccount} endpoint. + * + * @author Hudson Mendes + */ +public class AdvertisingAccountQueryBuilder + extends AbstractTwitterQueryForSortableEntityBuilder + implements AdvertisingAccountQuery { + + @Override + protected void makeParameters(MultiValueMap map) { + // no parameters to add here + } +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/AdvertisingTemplate.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/AdvertisingTemplate.java new file mode 100644 index 00000000..b9ad7896 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/AdvertisingTemplate.java @@ -0,0 +1,133 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpMethod; +import org.springframework.social.twitter.api.advertising.AdvertisingAccount; +import org.springframework.social.twitter.api.advertising.AdvertisingAccountFeatureQuery; +import org.springframework.social.twitter.api.advertising.AdvertisingAccountPermissions; +import org.springframework.social.twitter.api.advertising.AdvertisingAccountQuery; +import org.springframework.social.twitter.api.advertising.AdvertisingOperations; +import org.springframework.social.twitter.api.advertising.FundingInstrument; +import org.springframework.social.twitter.api.advertising.FundingInstrumentQuery; +import org.springframework.social.twitter.api.impl.AbstractTwitterOperations; +import org.springframework.social.twitter.api.impl.DataListHolder; +import org.springframework.social.twitter.api.impl.DataSingleHolder; +import org.springframework.social.twitter.api.impl.TwitterApiBuilderForUri; +import org.springframework.social.twitter.api.impl.TwitterApiUriResourceForAdvertising; +import org.springframework.web.client.RestTemplate; + +/** + * Implementation of {@link AdvertisingOperations}, providing a binding to Twitter's direct message-oriented REST resources. + * + * @author Hudson Mendes + */ +public class AdvertisingTemplate extends AbstractTwitterOperations implements AdvertisingOperations { + private final RestTemplate restTemplate; + + public AdvertisingTemplate(RestTemplate restTemplate, boolean isAuthorizedForUser, boolean isAuthorizedForApp) { + super(isAuthorizedForUser, isAuthorizedForApp); + this.restTemplate = restTemplate; + } + + @Override + public DataListHolder getAccounts(AdvertisingAccountQuery query) { + requireUserAuthorization(); + return restTemplate.exchange( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.ACCOUNTS) + .withArgument(query.toQueryParameters()) + .build(), + HttpMethod.GET, + null, + new ParameterizedTypeReference>() {} + ).getBody(); + } + + @Override + public AdvertisingAccount getAccount(String id) { + requireUserAuthorization(); + return restTemplate.exchange( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.ACCOUNT) + .withArgument("account_id", id) + .build(), + HttpMethod.GET, + null, + new ParameterizedTypeReference>() {} + ).getBody().getData(); + } + + @Override + public DataListHolder getAccountFeatures(String accountId, AdvertisingAccountFeatureQuery query) { + requireUserAuthorization(); + return restTemplate.exchange( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.ACCOUNT_FEATURES) + .withArgument("account_id", accountId) + .withArgument(query.toQueryParameters()) + .build(), + HttpMethod.GET, + null, + new ParameterizedTypeReference>() {} + ).getBody(); + } + + @Override + public AdvertisingAccountPermissions getAccountPermissions(String accountId) { + requireUserAuthorization(); + return restTemplate.exchange( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.ACCOUNT_PERMISSIONS) + .withArgument("account_id", accountId) + .build(), + HttpMethod.GET, + null, + new ParameterizedTypeReference>() {} + ).getBody().getData(); + } + + @Override + public DataListHolder getFundingInstruments(String accountId, FundingInstrumentQuery query) { + requireUserAuthorization(); + return restTemplate.exchange( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.FUNDING_INSTRUMENTS) + .withArgument("account_id", accountId) + .withArgument(query.toQueryParameters()) + .build(), + HttpMethod.GET, + null, + new ParameterizedTypeReference>() {} + ).getBody(); + } + + @Override + public FundingInstrument getFundingInstrument(String accountId, String fundingInstrumentId) { + requireUserAuthorization(); + return restTemplate.exchange( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.FUNDING_INSTRUMENT) + .withArgument("account_id", accountId) + .withArgument("funding_instrument_id", fundingInstrumentId) + .build(), + HttpMethod.GET, + null, + new ParameterizedTypeReference>() {} + ).getBody().getData(); + } +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/BigDecimalMicroAmountDeserializer.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/BigDecimalMicroAmountDeserializer.java new file mode 100644 index 00000000..1c3f93f7 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/BigDecimalMicroAmountDeserializer.java @@ -0,0 +1,49 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import java.io.IOException; +import java.math.BigDecimal; +import java.math.MathContext; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; + +/** + * Deserializer to get a BigDecimal (money or similar) value from a "micro" value. + * "Micro" values, in parts of the twitter Ads api is defined by a value multiplied + * by 1.000.000. This is to preserve the precision of the number (and also to make + * sure that IEEE typed floating points will not break the number). But within java + * we can safely work with BigDecimal type instead, for better representation and + * manipulation of the number. + * @author Hudson Mendes + */ +public class BigDecimalMicroAmountDeserializer extends JsonDeserializer { + + @Override + public BigDecimal deserialize(JsonParser p, DeserializationContext ctxt) + throws IOException, JsonProcessingException { + + return parse(p.getText()); + } + + public static BigDecimal parse(String rawValue) { + Long microAmount = new Long(rawValue); + return new BigDecimal(microAmount / 1000000.00).round(MathContext.DECIMAL32); + } +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/CampaignFormBuilder.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/CampaignFormBuilder.java new file mode 100644 index 00000000..b977417d --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/CampaignFormBuilder.java @@ -0,0 +1,161 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.time.temporal.ChronoUnit; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.springframework.social.twitter.api.advertising.Campaign; +import org.springframework.social.twitter.api.advertising.CampaignForm; +import org.springframework.social.twitter.api.advertising.ReasonNotServable; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +/** + * Facilitate the creation of the request body for post and put + * requests made to the management of {@link Campaign} data. + * + * @author Hudson Mendes + */ +public class CampaignFormBuilder extends AbstractTwitterFormBuilder implements CampaignForm { + private String name; + private String currency; + private String fundingInstrumentId; + private BigDecimal totalBudget; + private BigDecimal dailyBudget; + private LocalDateTime startTime; + private LocalDateTime endTime; + private final List reasonsNotServable; + private Boolean standardDelivery = true; + private Boolean paused = false; + private Boolean deleted = false; + + public CampaignFormBuilder() { + this.reasonsNotServable = new ArrayList(); + } + + @Override + public CampaignForm withName(String name) { + this.name = name; + return this; + } + + @Override + public CampaignForm withCurrency(String currency) { + this.currency = currency; + return this; + } + + @Override + public CampaignForm withFundingInstrument(String fundingInstrumentId) { + this.fundingInstrumentId = fundingInstrumentId; + return this; + } + + @Override + public CampaignForm withBudget(String totalBudget, String dailyBudget) { + if(null!=totalBudget) + this.totalBudget = new BigDecimal(totalBudget); + if(null!=dailyBudget) + this.dailyBudget = new BigDecimal(dailyBudget); + return this; + } + + @Override + public CampaignForm activeUntil(LocalDateTime endTime) { + return activeBetween(null, endTime); + } + + @Override + public CampaignForm activeFrom(LocalDateTime startTime) { + return activeBetween(startTime, null); + } + + @Override + public CampaignForm activeBetween(LocalDateTime startTime, LocalDateTime endTime) { + this.startTime = startTime; + this.endTime = endTime; + return this; + } + + @Override + public CampaignForm thatCantBeServedDueTo(ReasonNotServable... reasons) { + if (reasons != null) + Arrays.stream(reasons).forEach(reason -> { + this.reasonsNotServable.add(reason); + }); + return this; + } + + @Override + public CampaignForm withStandardDelivery(Boolean standardDelivery) { + this.standardDelivery = standardDelivery; + return this; + } + + @Override + public CampaignForm paused() { + this.paused = true; + return this; + } + + @Override + public CampaignForm unpaused() { + this.paused = false; + return this; + } + + @Override + public CampaignForm deleted() { + this.deleted = true; + return this; + } + + @Override + public CampaignForm active() { + this.deleted = false; + return this; + } + + @Override + public MultiValueMap toRequestBody() { + MultiValueMap params = new LinkedMultiValueMap(); + + appendParameter(params, "name", this.name); + appendParameter(params, "currency", this.currency); + appendParameter(params, "funding_instrument_id", this.fundingInstrumentId); + + appendParameter(params, "total_budget_amount_local_micro", translateBigDecimalIntoMicro(this.totalBudget)); + appendParameter(params, "daily_budget_amount_local_micro", translateBigDecimalIntoMicro(this.dailyBudget)); + + if (this.startTime != null) + appendParameter(params, "start_time", this.startTime.toInstant(ZoneOffset.UTC).truncatedTo(ChronoUnit.SECONDS)); + if (this.endTime != null) + appendParameter(params, "end_time", this.endTime.toInstant(ZoneOffset.UTC).truncatedTo(ChronoUnit.SECONDS)); + + appendParameter(params, "reasons_not_servable", this.reasonsNotServable); + appendParameter(params, "standard_delivery", this.standardDelivery); + appendParameter(params, "paused", this.paused); + appendParameter(params, "deleted", this.deleted); + + return params; + } +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/CampaignMixin.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/CampaignMixin.java new file mode 100644 index 00000000..b1e37a49 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/CampaignMixin.java @@ -0,0 +1,56 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +import org.springframework.social.twitter.api.advertising.Campaign; +import org.springframework.social.twitter.api.advertising.ReasonNotServable; +import org.springframework.social.twitter.api.impl.LocalDateTimeDeserializer; +import org.springframework.social.twitter.api.impl.TwitterObjectMixin; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; + +/** + * Mixin class for adding Jackson annotations to {@link Campaign}. + * @author Hudson Mendes + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public abstract class CampaignMixin extends TwitterObjectMixin { + + @JsonCreator + CampaignMixin( + @JsonProperty("id") String id, + @JsonProperty("name") String name, + @JsonProperty("account_id") String accountId, + @JsonProperty("currency") String currency, + @JsonProperty("funding_instrument_id") String fundingInstrumentId, + @JsonProperty("total_budget_amount_local_micro") @JsonDeserialize(using=BigDecimalMicroAmountDeserializer.class) BigDecimal totalBudget, + @JsonProperty("daily_budget_amount_local_micro") @JsonDeserialize(using=BigDecimalMicroAmountDeserializer.class) BigDecimal dailyBudget, + @JsonProperty("start_time") @JsonDeserialize(using=LocalDateTimeDeserializer.class) LocalDateTime startTime, + @JsonProperty("end_time") @JsonDeserialize(using=LocalDateTimeDeserializer.class) LocalDateTime endTime, + @JsonProperty("created_at") @JsonDeserialize(using=LocalDateTimeDeserializer.class) LocalDateTime createdAt, + @JsonProperty("updated_at") @JsonDeserialize(using=LocalDateTimeDeserializer.class) LocalDateTime updatedAt, + @JsonProperty("reasons_not_servable") List reasonsNotServable, + @JsonProperty("standard_delivery") Boolean standardDelivery, + @JsonProperty("paused") Boolean paused, + @JsonProperty("deleted") Boolean deleted) {} +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/CampaignQueryBuilder.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/CampaignQueryBuilder.java new file mode 100644 index 00000000..003db8df --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/CampaignQueryBuilder.java @@ -0,0 +1,76 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.social.twitter.api.advertising.Campaign; +import org.springframework.social.twitter.api.advertising.CampaignQuery; +import org.springframework.social.twitter.api.advertising.CampaignSorting; +import org.springframework.util.MultiValueMap; + +/** + * Facilitates the creation of the query that will be + * used to filter results from the {@link Campaign} endpoint. + * + * @author Hudson Mendes + */ +public class CampaignQueryBuilder + extends AbstractTwitterQueryForSortableEntityBuilder + implements CampaignQuery { + + private List fundingInstrumentIds; + private List campaignIds; + private Integer count; + private Integer cursor; + + @Override + public CampaignQuery withCampaigns(String... campaignIds) { + this.campaignIds = new ArrayList(); + for (int i = 0; i < campaignIds.length; i++) + this.campaignIds.add(campaignIds[i]); + return this; + } + + @Override + public CampaignQuery withFundingInstruments(String... fundingInstrumentIds) { + this.fundingInstrumentIds = new ArrayList(); + for (int i = 0; i < fundingInstrumentIds.length; i++) + this.fundingInstrumentIds.add(fundingInstrumentIds[i]); + return this; + } + + @Override + public CampaignQuery withCount(Integer count) { + this.count = count; + return this; + } + + @Override + public CampaignQuery withCursor(Integer cursor) { + this.cursor = cursor; + return this; + } + + @Override + protected void makeParameters(MultiValueMap map) { + appendParameter(map, "campaign_ids", this.campaignIds); + appendParameter(map, "funding_instrument_ids", this.fundingInstrumentIds); + appendParameter(map, "count", this.count); + appendParameter(map, "cursor", this.cursor); + } +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/CampaignTemplate.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/CampaignTemplate.java new file mode 100644 index 00000000..691ad596 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/CampaignTemplate.java @@ -0,0 +1,113 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpMethod; +import org.springframework.social.twitter.api.advertising.AdvertisingOperations; +import org.springframework.social.twitter.api.advertising.Campaign; +import org.springframework.social.twitter.api.advertising.CampaignForm; +import org.springframework.social.twitter.api.advertising.CampaignOperations; +import org.springframework.social.twitter.api.advertising.CampaignQuery; +import org.springframework.social.twitter.api.impl.AbstractTwitterOperations; +import org.springframework.social.twitter.api.impl.DataListHolder; +import org.springframework.social.twitter.api.impl.DataSingleHolder; +import org.springframework.social.twitter.api.impl.TwitterApiBuilderForHttpEntity; +import org.springframework.social.twitter.api.impl.TwitterApiBuilderForUri; +import org.springframework.social.twitter.api.impl.TwitterApiUriResourceForAdvertising; +import org.springframework.web.client.RestTemplate; + +/** + * Implementation of {@link AdvertisingOperations}, providing a binding to Twitter's direct message-oriented REST resources. + * + * @author Hudson Mendes + */ +public class CampaignTemplate extends AbstractTwitterOperations implements CampaignOperations { + private final RestTemplate restTemplate; + + public CampaignTemplate(RestTemplate restTemplate, boolean isAuthorizedForUser, boolean isAuthorizedForApp) { + super(isAuthorizedForUser, isAuthorizedForApp); + this.restTemplate = restTemplate; + } + + @Override + public Campaign getCampaign(String accountId, String id) { + requireUserAuthorization(); + return restTemplate.exchange( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.CAMPAIGN) + .withArgument("account_id", accountId) + .withArgument("campaign_id", id) + .withArgument("with_deleted", true) + .build(), + HttpMethod.GET, + null, + new ParameterizedTypeReference>() {} + ).getBody().getData(); + } + + @Override + public DataListHolder getCampaigns(String accountId, CampaignQuery query) { + requireUserAuthorization(); + return restTemplate.exchange( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.CAMPAIGNS) + .withArgument("account_id", accountId) + .withArgument(query.toQueryParameters()) + .build(), + HttpMethod.GET, + null, + new ParameterizedTypeReference>() {} + ).getBody(); + } + + @Override + public Campaign createCampaign(String accountId, CampaignForm data) { + requireUserAuthorization(); + return restTemplate.exchange( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.CAMPAIGNS) + .withArgument("account_id", accountId) + .build(), + HttpMethod.POST, + new TwitterApiBuilderForHttpEntity<>(data.toRequestBody()).build(), + new ParameterizedTypeReference>() {} + ).getBody().getData(); + } + + @Override + public void updateCampaign(String accountId, String id, CampaignForm data) { + requireUserAuthorization(); + restTemplate.put( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.CAMPAIGN) + .withArgument("account_id", accountId) + .withArgument("campaign_id", id) + .build(), + data.toRequestBody()); + } + + @Override + public void deleteCampaign(String accountId, String id) { + requireUserAuthorization(); + restTemplate.delete(new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.CAMPAIGN) + .withArgument("account_id", accountId) + .withArgument("campaign_id", id) + .build()); + } + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/FundingInstrumentMixin.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/FundingInstrumentMixin.java new file mode 100644 index 00000000..fa2fcd5c --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/FundingInstrumentMixin.java @@ -0,0 +1,54 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +import org.springframework.social.twitter.api.advertising.FundingInstrument; +import org.springframework.social.twitter.api.advertising.FundingInstrumentType; +import org.springframework.social.twitter.api.impl.LocalDateTimeDeserializer; +import org.springframework.social.twitter.api.impl.TwitterObjectMixin; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; + +/** + * Mixin class for adding Jackson annotations to {@link FundingInstrument}. + * @author Hudson Mendes + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public abstract class FundingInstrumentMixin extends TwitterObjectMixin { + + @JsonCreator + FundingInstrumentMixin( + @JsonProperty("id") String id, + @JsonProperty("instrument_type") FundingInstrumentType type, + @JsonProperty("account_id") String accountId, + @JsonProperty("currency") String currency, + @JsonProperty("description") String description, + @JsonProperty("cancelled") Boolean cancelled, + @JsonProperty("deleted") Boolean deleted, + @JsonProperty("credit_limit_local_micro") @JsonDeserialize(using=BigDecimalMicroAmountDeserializer.class) BigDecimal creditLimit, + @JsonProperty("credit_remaining_local_micro") @JsonDeserialize(using=BigDecimalMicroAmountDeserializer.class) BigDecimal creditRemaining, + @JsonProperty("funded_amount_local_micro") @JsonDeserialize(using=BigDecimalMicroAmountDeserializer.class) BigDecimal fundedAmount, + @JsonProperty("start_time") @JsonDeserialize(using=LocalDateTimeDeserializer.class) LocalDateTime startTime, + @JsonProperty("end_time") @JsonDeserialize(using=LocalDateTimeDeserializer.class) LocalDateTime endTime, + @JsonProperty("created_at") @JsonDeserialize(using=LocalDateTimeDeserializer.class) LocalDateTime createdAt, + @JsonProperty("updated_at") @JsonDeserialize(using=LocalDateTimeDeserializer.class) LocalDateTime updatedAt) {} +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/FundingInstrumentQueryBuilder.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/FundingInstrumentQueryBuilder.java new file mode 100644 index 00000000..3bd560d0 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/FundingInstrumentQueryBuilder.java @@ -0,0 +1,51 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.social.twitter.api.advertising.FundingInstrument; +import org.springframework.social.twitter.api.advertising.FundingInstrumentQuery; +import org.springframework.social.twitter.api.advertising.FundingInstrumentSorting; +import org.springframework.util.MultiValueMap; + +/** + * Facilitates the creation of the query that will be + * used to filter results from the {@link FundingInstrument} endpoint. + * + * @author Hudson Mendes + */ +public class FundingInstrumentQueryBuilder + extends AbstractTwitterQueryForSortableEntityBuilder + implements FundingInstrumentQuery { + + private List fundingInstrumentIds; + + @Override + public FundingInstrumentQuery withFundingInstruments(String... fundingInstrumentIds) { + this.fundingInstrumentIds = new ArrayList(); + for (int i = 0; i < fundingInstrumentIds.length; i++) + this.fundingInstrumentIds.add(fundingInstrumentIds[i]); + return this; + } + + @Override + protected void makeParameters(MultiValueMap map) { + appendParameter(map, "funding_instrument_ids", this.fundingInstrumentIds); + } + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/GlobalOptOutFormBuilder.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/GlobalOptOutFormBuilder.java new file mode 100644 index 00000000..818f560b --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/GlobalOptOutFormBuilder.java @@ -0,0 +1,43 @@ +package org.springframework.social.twitter.api.impl.advertising; + +import org.springframework.social.twitter.api.advertising.GlobalOptOutForm; +import org.springframework.social.twitter.api.advertising.TailoredAudienceListType; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +public class GlobalOptOutFormBuilder extends AbstractTwitterFormBuilder implements GlobalOptOutForm { + private String tonFilePath; + private TailoredAudienceListType listType; + + @Override + public MultiValueMap toRequestBody() { + MultiValueMap params = new LinkedMultiValueMap(); + appendParameter(params, "input_file_path", this.tonFilePath); + appendParameter(params, "list_type", this.listType); + return params; + } + + /* + * (non-Javadoc) + * + * @see org.springframework.social.twitter.api.impl.advertising.GlobalOptOutForm#withInputFilePath(java.lang.String) + */ + @Override + public GlobalOptOutFormBuilder withInputFilePath(String tonFilePath) { + this.tonFilePath = tonFilePath; + return this; + } + + /* + * (non-Javadoc) + * + * @see org.springframework.social.twitter.api.impl.advertising.GlobalOptOutForm#withListType(org.springframework.social.twitter.api.advertising. + * TailoredAudienceListType) + */ + @Override + public GlobalOptOutForm withListType(TailoredAudienceListType listType) { + this.listType = listType; + return this; + } + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/GlobalOptOutMixin.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/GlobalOptOutMixin.java new file mode 100644 index 00000000..bec50387 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/GlobalOptOutMixin.java @@ -0,0 +1,39 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import org.springframework.social.twitter.api.advertising.GlobalOptOut; +import org.springframework.social.twitter.api.advertising.TailoredAudienceListType; +import org.springframework.social.twitter.api.impl.TwitterObjectMixin; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Mixin class for adding Jackson annotations to {@link GlobalOptOut}. + * + * @author Hudson Mendes + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public abstract class GlobalOptOutMixin extends TwitterObjectMixin { + + @JsonCreator + GlobalOptOutMixin( + @JsonProperty("input_file_path") String inputFilePath, + @JsonProperty("list_type") TailoredAudienceListType listType) {} + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/LineItemFormBuilder.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/LineItemFormBuilder.java new file mode 100644 index 00000000..b13c7856 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/LineItemFormBuilder.java @@ -0,0 +1,182 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; + +import org.springframework.social.twitter.api.advertising.AdvertisingObjective; +import org.springframework.social.twitter.api.advertising.AdvertisingPlacement; +import org.springframework.social.twitter.api.advertising.AdvertisingProductType; +import org.springframework.social.twitter.api.advertising.AdvertisingSentiment; +import org.springframework.social.twitter.api.advertising.BidUnit; +import org.springframework.social.twitter.api.advertising.LineItem; +import org.springframework.social.twitter.api.advertising.LineItemForm; +import org.springframework.social.twitter.api.advertising.LineItemOptimization; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +/** + * Facilitate the creation of the request body for post and put + * requests made to the management of {@link LineItem} data. + * + * @author Hudson Mendes + */ +public class LineItemFormBuilder extends AbstractTwitterFormBuilder implements LineItemForm { + private String campaignId; + private String name; + private AdvertisingObjective objective; + private AdvertisingSentiment includeSentiment; + private LineItemOptimization optimization; + private BidUnit bidUnit; + private AdvertisingProductType productType; + private final List placements = new ArrayList<>(); + private BigDecimal totalBudgetAmount; + private BigDecimal bidAmount; + private Boolean paused; + private Boolean deleted; + private Boolean automaticallySelectBid; + + @Override + public MultiValueMap toRequestBody() { + final MultiValueMap params = new LinkedMultiValueMap(); + + appendParameter(params, "campaign_id", campaignId); + appendParameter(params, "name", name); + + appendParameter(params, "objective", objective); + appendParameter(params, "include_sentiment", includeSentiment); + appendParameter(params, "optimization", optimization); + appendParameter(params, "bid_unit", bidUnit); + + appendParameter(params, "product_type", productType); + appendParameter(params, "placements", placements); + + appendParameter(params, "automatically_select_bid", automaticallySelectBid); + appendParameter(params, "paused", paused); + appendParameter(params, "deleted", deleted); + + appendParameter(params, "total_budget_amount_local_micro", translateBigDecimalIntoMicro(totalBudgetAmount)); + appendParameter(params, "bid_amount_local_micro", translateBigDecimalIntoMicro(bidAmount), true); + + return params; + } + + @Override + public LineItemForm forCampaign(String campaignId) { + this.campaignId = campaignId; + return this; + } + + @Override + public LineItemForm named(String name) { + this.name = name; + return this; + } + + @Override + public LineItemForm productType(AdvertisingProductType productType) { + this.productType = productType; + return this; + } + + @Override + public LineItemForm placedOn(AdvertisingPlacement... placements) { + if (placements != null) + for (final AdvertisingPlacement placement : placements) + this.placements.add(placement); + return this; + } + + @Override + public LineItemForm objective(AdvertisingObjective objective) { + this.objective = objective; + return this; + } + + @Override + public LineItemForm includingSentiment(AdvertisingSentiment sentiment) { + includeSentiment = sentiment; + return this; + } + + @Override + public LineItemForm optimizedFor(LineItemOptimization optimization) { + this.optimization = optimization; + return this; + } + + @Override + public LineItemForm bidUnit(BidUnit bidUnit) { + this.bidUnit = bidUnit; + return this; + } + + @Override + public LineItemForm totalBudget(String totalBudgetAmount) { + if (totalBudgetAmount != null) + this.totalBudgetAmount = new BigDecimal(totalBudgetAmount); + else + this.totalBudgetAmount = null; + return this; + } + + @Override + public LineItemForm bidAmount(String bidAmount) { + if (bidAmount != null) { + this.bidAmount = new BigDecimal(bidAmount); + automaticallySelectBid = false; + } + else + this.bidAmount = null; + return this; + } + + @Override + public LineItemForm automaticallySelectBid(Boolean auto) { + if (auto != null) { + automaticallySelectBid = auto; + if (auto) + bidAmount = null; + } + return this; + } + + @Override + public LineItemForm paused() { + paused = true; + return this; + } + + @Override + public LineItemForm unpaused() { + paused = false; + return this; + } + + @Override + public LineItemFormBuilder deleted() { + deleted = true; + return this; + } + + @Override + public LineItemFormBuilder active() { + deleted = false; + return this; + } +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/LineItemMixin.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/LineItemMixin.java new file mode 100644 index 00000000..4a4a49c9 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/LineItemMixin.java @@ -0,0 +1,65 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +import org.springframework.social.twitter.api.advertising.AdvertisingObjective; +import org.springframework.social.twitter.api.advertising.AdvertisingPlacement; +import org.springframework.social.twitter.api.advertising.AdvertisingProductType; +import org.springframework.social.twitter.api.advertising.AdvertisingSentiment; +import org.springframework.social.twitter.api.advertising.BidUnit; +import org.springframework.social.twitter.api.advertising.LineItem; +import org.springframework.social.twitter.api.advertising.LineItemOptimization; +import org.springframework.social.twitter.api.impl.LocalDateTimeDeserializer; +import org.springframework.social.twitter.api.impl.TwitterObjectMixin; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; + +/** + * Mixin class for adding Jackson annotations to {@link LineItem}. + * + * @author Hudson Mendes + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public abstract class LineItemMixin extends TwitterObjectMixin { + + @JsonCreator + LineItemMixin( + @JsonProperty("id") String id, + @JsonProperty("account_id") String accountId, + @JsonProperty("campaign_id") String campaignId, + @JsonProperty("name") String name, + @JsonProperty("bid_unit") BidUnit bidUnit, + @JsonProperty("optimization") LineItemOptimization optimization, + @JsonProperty("objective") AdvertisingObjective objective, + @JsonProperty("include_sentiment") AdvertisingSentiment includeSentiment, + @JsonProperty("product_type") AdvertisingProductType productType, + @JsonProperty("placements") AdvertisingPlacement[] placements, + @JsonProperty("currency") String currency, + @JsonProperty("total_budget_amount_local_micro") @JsonDeserialize(using = BigDecimalMicroAmountDeserializer.class) BigDecimal totalBudgetAmount, + @JsonProperty("bid_amount_local_micro") @JsonDeserialize(using = BigDecimalMicroAmountDeserializer.class) BigDecimal bidAmount, + @JsonProperty("automatically_select_bid") Boolean automaticallySelectBid, + @JsonProperty("paused") Boolean paused, + @JsonProperty("deleted") Boolean deleted, + @JsonProperty("created_at") @JsonDeserialize(using = LocalDateTimeDeserializer.class) LocalDateTime createdAt, + @JsonProperty("updated_at") @JsonDeserialize(using = LocalDateTimeDeserializer.class) LocalDateTime updatedAt) {} + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/LineItemPlacementsMixin.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/LineItemPlacementsMixin.java new file mode 100644 index 00000000..104280d4 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/LineItemPlacementsMixin.java @@ -0,0 +1,41 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import java.util.List; + +import org.springframework.social.twitter.api.advertising.AdvertisingPlacement; +import org.springframework.social.twitter.api.advertising.AdvertisingProductType; +import org.springframework.social.twitter.api.advertising.LineItemPlacements; +import org.springframework.social.twitter.api.impl.TwitterObjectMixin; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Mixin class for adding Jackson annotations to {@link LineItemPlacements}. + * @author Hudson Mendes + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public abstract class LineItemPlacementsMixin extends TwitterObjectMixin { + + @JsonCreator + LineItemPlacementsMixin( + @JsonProperty("placements") List placements, + @JsonProperty("product_type") AdvertisingProductType productType) {} + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/LineItemPlacementsQueryBuilder.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/LineItemPlacementsQueryBuilder.java new file mode 100644 index 00000000..705d2470 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/LineItemPlacementsQueryBuilder.java @@ -0,0 +1,52 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.social.twitter.api.advertising.AdvertisingProductType; +import org.springframework.social.twitter.api.advertising.LineItemPlacementsQuery; +import org.springframework.util.MultiValueMap; + +/** + * Facilitates the creation of the query that will be + * used to filter results from the feature endpoint. + * + * @author Hudson Mendes + */ +public class LineItemPlacementsQueryBuilder + extends AbstractTwitterQueryForEntityBuilder + implements LineItemPlacementsQuery { + + private List productTypes = new ArrayList(); + + @Override + public LineItemPlacementsQuery withProductTypes(List productTypes) { + if(null!=productTypes) { + for(final AdvertisingProductType productType: productTypes) { + this.productTypes.add(productType); + } + } + return this; + } + + @Override + protected void makeParameters(MultiValueMap map) { + appendParameter(map, "product_type", productTypes); + } + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/LineItemQueryBuilder.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/LineItemQueryBuilder.java new file mode 100644 index 00000000..d80db13d --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/LineItemQueryBuilder.java @@ -0,0 +1,112 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import java.time.LocalDateTime; +import java.time.temporal.ChronoUnit; +import java.util.ArrayList; +import java.util.List; + +import org.springframework.social.twitter.api.advertising.LineItem; +import org.springframework.social.twitter.api.advertising.LineItemQuery; +import org.springframework.social.twitter.api.advertising.LineItemSorting; +import org.springframework.util.MultiValueMap; + +/** + * Facilitates the creation of the query that will be + * used to filter results from the {@link LineItem} endpoint. + * + * @author Hudson Mendes + */ +public class LineItemQueryBuilder + extends AbstractTwitterQueryForSortableEntityBuilder + implements LineItemQuery { + + private List fundingInstrumentIds; + private List campaignIds; + private List lineItemIds; + private Integer count; + private Integer cursor; + private LocalDateTime startTime; + private LocalDateTime endTime; + + @Override + public LineItemQuery withCampaigns(String... campaignIds) { + this.campaignIds = new ArrayList(); + for (int i = 0; i < campaignIds.length; i++) + this.campaignIds.add(campaignIds[i]); + return this; + } + + @Override + public LineItemQuery withFundingInstruments(String... fundingInstrumentIds) { + this.fundingInstrumentIds = new ArrayList(); + for (int i = 0; i < fundingInstrumentIds.length; i++) + this.fundingInstrumentIds.add(fundingInstrumentIds[i]); + return this; + } + + @Override + public LineItemQuery withLineItems(String... lineItemIds) { + this.lineItemIds = new ArrayList(); + for (int i = 0; i < lineItemIds.length; i++) + this.lineItemIds.add(lineItemIds[i]); + return this; + } + + + @Override + public LineItemQuery withCount(Integer count) { + this.count = count; + return this; + } + + @Override + public LineItemQuery withCursor(Integer cursor) { + this.cursor = cursor; + return this; + } + + @Override + public LineItemQuery activeFrom(LocalDateTime time) { + this.activeBeetween(time, null); + return this; + } + + @Override + public LineItemQuery activeBeetween(LocalDateTime from, LocalDateTime until) { + this.activeBeetween(from, until); + return null; + } + + @Override + protected void makeParameters(MultiValueMap map) { + appendParameter(map, "campaign_ids", this.campaignIds); + appendParameter(map, "funding_instrument_ids", this.fundingInstrumentIds); + appendParameter(map, "line_item_ids", this.lineItemIds); + appendParameter(map, "count", this.count); + appendParameter(map, "cursor", this.cursor); + appendParameter(map, "with_deleted", true); + + if (this.startTime != null) + appendParameter(map, "start_time", this.startTime.truncatedTo(ChronoUnit.SECONDS).toString()); + + + if (this.endTime != null) + appendParameter(map, "end_time", this.endTime.truncatedTo(ChronoUnit.SECONDS).toString()); + } + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/LineItemTemplate.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/LineItemTemplate.java new file mode 100644 index 00000000..ebfb67d3 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/LineItemTemplate.java @@ -0,0 +1,122 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpMethod; +import org.springframework.social.twitter.api.advertising.LineItem; +import org.springframework.social.twitter.api.advertising.LineItemForm; +import org.springframework.social.twitter.api.advertising.LineItemOperations; +import org.springframework.social.twitter.api.advertising.LineItemPlacements; +import org.springframework.social.twitter.api.advertising.LineItemPlacementsQuery; +import org.springframework.social.twitter.api.advertising.LineItemQuery; +import org.springframework.social.twitter.api.impl.AbstractTwitterOperations; +import org.springframework.social.twitter.api.impl.DataListHolder; +import org.springframework.social.twitter.api.impl.DataSingleHolder; +import org.springframework.social.twitter.api.impl.TwitterApiBuilderForHttpEntity; +import org.springframework.social.twitter.api.impl.TwitterApiBuilderForUri; +import org.springframework.social.twitter.api.impl.TwitterApiUriResourceForAdvertising; +import org.springframework.web.client.RestTemplate; + +public class LineItemTemplate extends AbstractTwitterOperations implements LineItemOperations { + private final RestTemplate restTemplate; + + public LineItemTemplate(RestTemplate restTemplate, boolean isAuthorizedForUser, boolean isAuthorizedForApp) { + super(isAuthorizedForUser, isAuthorizedForApp); + this.restTemplate = restTemplate; + } + + @Override + public LineItem getLineItem(String accountId, String id) { + requireUserAuthorization(); + return restTemplate.exchange( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.LINE_ITEM) + .withArgument("account_id", accountId) + .withArgument("line_item_id", id) + .withArgument("with_deleted", true) + .build(), + HttpMethod.GET, + null, + new ParameterizedTypeReference>() {} + ).getBody().getData(); + } + + @Override + public DataListHolder getLineItems(String accountId, LineItemQuery query) { + requireUserAuthorization(); + return restTemplate.exchange( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.LINE_ITEMS) + .withArgument("account_id", accountId) + .withArgument(query.toQueryParameters()) + .build(), + HttpMethod.GET, + null, + new ParameterizedTypeReference>() {} + ).getBody(); + } + + @Override + public LineItem createLineItem(String accountId, LineItemForm data) { + requireUserAuthorization(); + return restTemplate.exchange( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.LINE_ITEMS) + .withArgument("account_id", accountId) + .build(), + HttpMethod.POST, + new TwitterApiBuilderForHttpEntity<>(data.toRequestBody()).build(), + new ParameterizedTypeReference>() {} + ).getBody().getData(); + } + + @Override + public void updateLineItem(String accountId, String id, LineItemForm data) { + requireUserAuthorization(); + restTemplate.put( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.LINE_ITEM) + .withArgument("account_id", accountId) + .withArgument("line_item_id", id) + .build(), + data.toRequestBody()); + } + + @Override + public void deleteLineItem(String accountId, String id) { + requireUserAuthorization(); + restTemplate.delete(new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.LINE_ITEM) + .withArgument("account_id", accountId) + .withArgument("line_item_id", id) + .build()); + } + + @Override + public DataListHolder getLineItemPlacements(LineItemPlacementsQuery query) { + return restTemplate.exchange( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.LINE_ITEM_PLACEMENTS) + .withArgument(query.toQueryParameters()) + .build(), + HttpMethod.GET, + null, + new ParameterizedTypeReference>() {} + ).getBody(); + } + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/PromotableUserMixin.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/PromotableUserMixin.java new file mode 100644 index 00000000..79687c16 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/PromotableUserMixin.java @@ -0,0 +1,43 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import java.time.LocalDateTime; + +import org.springframework.social.twitter.api.impl.LocalDateTimeDeserializer; +import org.springframework.social.twitter.api.impl.TwitterObjectMixin; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; + +/** + * @author Hudson Mendes + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public abstract class PromotableUserMixin extends TwitterObjectMixin { + + @JsonCreator + public PromotableUserMixin( + @JsonProperty("user_id") Long userId, + @JsonProperty("id") String id, + @JsonProperty("account_id") String accountId, + @JsonProperty("promotable_user_type") String promotableUserType, + @JsonProperty("created_at") @JsonDeserialize(using = LocalDateTimeDeserializer.class) LocalDateTime createdAt, + @JsonProperty("updated_at") @JsonDeserialize(using = LocalDateTimeDeserializer.class) LocalDateTime updatedAt, + @JsonProperty("deleted") Boolean deleted) {} +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/PromotableUserQueryBuilder.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/PromotableUserQueryBuilder.java new file mode 100644 index 00000000..13bfbcf4 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/PromotableUserQueryBuilder.java @@ -0,0 +1,31 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import org.springframework.social.twitter.api.advertising.PromotableUser; +import org.springframework.social.twitter.api.advertising.PromotableUserQuery; +import org.springframework.util.MultiValueMap; + +/** + * Query builder for {@link PromotableUser} queries. + * + * @author Hudson Mendes + */ +public class PromotableUserQueryBuilder extends AbstractTwitterQueryForEntityBuilder implements PromotableUserQuery { + + @Override + protected void makeParameters(MultiValueMap map) {} +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/PromotedTweetReferenceFormBuilder.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/PromotedTweetReferenceFormBuilder.java new file mode 100644 index 00000000..ceaae308 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/PromotedTweetReferenceFormBuilder.java @@ -0,0 +1,58 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.social.twitter.api.advertising.PromotedTweetReference; +import org.springframework.social.twitter.api.advertising.PromotedTweetReferenceForm; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +/** + * Builder for {@link PromotedTweetReference} input form. + * + * @author Hudson Mendes + */ +public class PromotedTweetReferenceFormBuilder extends AbstractTwitterFormBuilder implements PromotedTweetReferenceForm { + + private final List tweetIds = new ArrayList<>(); + private String lineItemId; + + @Override + public MultiValueMap toRequestBody() { + MultiValueMap params = new LinkedMultiValueMap(); + appendParameter(params, "line_item_id", lineItemId); + appendParameter(params, "tweet_ids", this.tweetIds); + return params; + } + + @Override + public PromotedTweetReferenceForm onLineItem(String lineItemId) { + this.lineItemId = lineItemId; + return this; + } + + @Override + public PromotedTweetReferenceForm forTweets(Long... tweetIds) { + if (tweetIds != null) + for (Long tweetId : tweetIds) + this.tweetIds.add(tweetId); + return this; + } + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/PromotedTweetReferenceMixin.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/PromotedTweetReferenceMixin.java new file mode 100644 index 00000000..3147fe4c --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/PromotedTweetReferenceMixin.java @@ -0,0 +1,44 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import java.time.LocalDateTime; + +import org.springframework.social.twitter.api.advertising.ApprovalStatus; +import org.springframework.social.twitter.api.impl.LocalDateTimeDeserializer; +import org.springframework.social.twitter.api.impl.TwitterObjectMixin; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; + +/** + * @author Hudson Mendes + */ +public abstract class PromotedTweetReferenceMixin extends TwitterObjectMixin { + + @JsonCreator + PromotedTweetReferenceMixin( + @JsonProperty("id") String id, + @JsonProperty("line_item_id") String lineItemId, + @JsonProperty("tweet_id") Long tweetId, + @JsonProperty("paused") Boolean paused, + @JsonProperty("deleted") Boolean deleted, + @JsonProperty("created_at") @JsonDeserialize(using = LocalDateTimeDeserializer.class) LocalDateTime createdAt, + @JsonProperty("updated_at") @JsonDeserialize(using = LocalDateTimeDeserializer.class) LocalDateTime updatedAt, + @JsonProperty("approval_status") ApprovalStatus approvalStatus) {} + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/PromotedTweetReferenceQueryBuilder.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/PromotedTweetReferenceQueryBuilder.java new file mode 100644 index 00000000..2f214ec6 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/PromotedTweetReferenceQueryBuilder.java @@ -0,0 +1,33 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import org.springframework.social.twitter.api.advertising.PromotedTweetReference; +import org.springframework.social.twitter.api.advertising.PromotedTweetReferenceQuery; +import org.springframework.util.MultiValueMap; + +/** + * Query builder for {@link PromotedTweetReference} queries. + * + * @author Hudson Mendes + */ +public class PromotedTweetReferenceQueryBuilder + extends AbstractTwitterQueryForEntityBuilder + implements PromotedTweetReferenceQuery { + + @Override + protected void makeParameters(MultiValueMap map) {} +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/PromotedUserReferenceFormBuilder.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/PromotedUserReferenceFormBuilder.java new file mode 100644 index 00000000..2f165ab5 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/PromotedUserReferenceFormBuilder.java @@ -0,0 +1,53 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import org.springframework.social.twitter.api.advertising.PromotedUserReference; +import org.springframework.social.twitter.api.advertising.PromotedUserReferenceForm; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +/** + * Builder for {@link PromotedUserReference} input form. + * + * @author Hudson Mendes + */ +public class PromotedUserReferenceFormBuilder extends AbstractTwitterFormBuilder implements PromotedUserReferenceForm { + + private String userId; + private String lineItemId; + + @Override + public MultiValueMap toRequestBody() { + MultiValueMap params = new LinkedMultiValueMap(); + appendParameter(params, "line_item_id", lineItemId); + appendParameter(params, "user_id", this.userId); + return params; + } + + @Override + public PromotedUserReferenceForm onLineItem(String lineItemId) { + this.lineItemId = lineItemId; + return this; + } + + @Override + public PromotedUserReferenceForm forUser(String userId) { + this.userId = userId; + return this; + } + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/PromotedUserReferenceMixin.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/PromotedUserReferenceMixin.java new file mode 100644 index 00000000..67ffd859 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/PromotedUserReferenceMixin.java @@ -0,0 +1,44 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import java.time.LocalDateTime; + +import org.springframework.social.twitter.api.advertising.ApprovalStatus; +import org.springframework.social.twitter.api.impl.LocalDateTimeDeserializer; +import org.springframework.social.twitter.api.impl.TwitterObjectMixin; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; + +/** + * @author Hudson Mendes + */ +public abstract class PromotedUserReferenceMixin extends TwitterObjectMixin { + + @JsonCreator + PromotedUserReferenceMixin( + @JsonProperty("id") String id, + @JsonProperty("line_item_id") String lineItemId, + @JsonProperty("user_id") String userId, + @JsonProperty("paused") Boolean paused, + @JsonProperty("deleted") Boolean deleted, + @JsonProperty("created_at") @JsonDeserialize(using = LocalDateTimeDeserializer.class) LocalDateTime createdAt, + @JsonProperty("updated_at") @JsonDeserialize(using = LocalDateTimeDeserializer.class) LocalDateTime updatedAt, + @JsonProperty("approval_status") ApprovalStatus approvalStatus) {} + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/PromotedUserReferenceQueryBuilder.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/PromotedUserReferenceQueryBuilder.java new file mode 100644 index 00000000..094381a0 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/PromotedUserReferenceQueryBuilder.java @@ -0,0 +1,64 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import org.springframework.social.twitter.api.advertising.PromotedUserReference; +import org.springframework.social.twitter.api.advertising.PromotedUserReferenceQuery; +import org.springframework.social.twitter.api.advertising.PromotedUserReferenceSorting; +import org.springframework.social.twitter.api.advertising.SortDirection; +import org.springframework.util.MultiValueMap; + +/** + * Query builder for {@link PromotedUserReference} queries. + * + * @author Hudson Mendes + */ +public class PromotedUserReferenceQueryBuilder +extends AbstractTwitterQueryForEntityBuilder +implements PromotedUserReferenceQuery { + + private PromotedUserReferenceSorting sort; + private SortDirection direction; + + @Override + protected void makeParameters(MultiValueMap map) { + final String sort = makeSort(); + if (sort != null) + appendParameter(map, "sort", sort); + } + + @Override + public PromotedUserReferenceQuery sortBy(PromotedUserReferenceSorting sort) { + this.sort = sort; + return this; + } + + @Override + public PromotedUserReferenceQuery sortBy(PromotedUserReferenceSorting sort, SortDirection direction) { + this.sort = sort; + this.direction = direction; + return null; + } + + private String makeSort() { + if (sort != null & direction == null) + return sort.name(); + else if (sort != null & direction != null) + return sort + "-" + direction; + + return null; + } +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/PromotionTemplate.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/PromotionTemplate.java new file mode 100644 index 00000000..118fa057 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/PromotionTemplate.java @@ -0,0 +1,202 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpMethod; +import org.springframework.social.twitter.api.Tweet; +import org.springframework.social.twitter.api.advertising.PromotableUser; +import org.springframework.social.twitter.api.advertising.PromotableUserQuery; +import org.springframework.social.twitter.api.advertising.PromotedTweetReference; +import org.springframework.social.twitter.api.advertising.PromotedTweetReferenceForm; +import org.springframework.social.twitter.api.advertising.PromotedTweetReferenceQuery; +import org.springframework.social.twitter.api.advertising.PromotedUserReference; +import org.springframework.social.twitter.api.advertising.PromotedUserReferenceForm; +import org.springframework.social.twitter.api.advertising.PromotedUserReferenceQuery; +import org.springframework.social.twitter.api.advertising.PromotionOperations; +import org.springframework.social.twitter.api.advertising.SponsoredTweetForm; +import org.springframework.social.twitter.api.advertising.SponsoredTweetQuery; +import org.springframework.social.twitter.api.impl.AbstractTwitterOperations; +import org.springframework.social.twitter.api.impl.DataListHolder; +import org.springframework.social.twitter.api.impl.DataSingleHolder; +import org.springframework.social.twitter.api.impl.TwitterApiBuilderForHttpEntity; +import org.springframework.social.twitter.api.impl.TwitterApiBuilderForUri; +import org.springframework.social.twitter.api.impl.TwitterApiUriResourceForAdvertising; +import org.springframework.util.StringUtils; +import org.springframework.web.client.RestTemplate; + +/** + * @author Hudson Mendes + */ +public class PromotionTemplate extends AbstractTwitterOperations implements PromotionOperations { + private final RestTemplate restTemplate; + + public PromotionTemplate(RestTemplate restTemplate, boolean isUserAuthorized, boolean isAppAuthorized) { + super(isUserAuthorized, isAppAuthorized); + this.restTemplate = restTemplate; + } + + @Override + public DataListHolder getPromotableUsers( + String accountId, + PromotableUserQuery query) { + + requireUserAuthorization(); + return restTemplate.exchange( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.PROMOTABLE_USERS) + .withArgument("account_id", accountId) + .withArgument(query.toQueryParameters()) + .build(), + HttpMethod.GET, + null, + new ParameterizedTypeReference>() {}).getBody(); + } + + @Override + public DataListHolder getSponsoredTweets( + String accountId, + SponsoredTweetQuery query) { + + requireUserAuthorization(); + return restTemplate.exchange( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.SPONSORED_TWEETS) + .withArgument("account_id", accountId) + .withArgument("scoped_to", "none") + .withArgument(query.toQueryParameters()) + .build(), + HttpMethod.GET, + null, + new ParameterizedTypeReference>() {}).getBody(); + } + + @Override + public Tweet createSponsoredTweet( + String accountId, + SponsoredTweetForm input) { + + requireUserAuthorization(); + return restTemplate.exchange( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.SPONSORED_TWEETS_CREATE) + .withArgument("account_id", accountId) + .build(), + HttpMethod.POST, + new TwitterApiBuilderForHttpEntity<>(input.toRequestBody()).build(), + new ParameterizedTypeReference>() {}).getBody().getData(); + } + + @Override + public DataListHolder getPromotedTweetReferences( + String accountId, + String lineItemId, + PromotedTweetReferenceQuery query) { + + requireUserAuthorization(); + + TwitterApiBuilderForUri uriBuilder = new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.PROMOTED_TWEET_REFERENCES) + .withArgument("account_id", accountId) + .withArgument(query.toQueryParameters()); + + if (!StringUtils.isEmpty(lineItemId)) + uriBuilder = uriBuilder.withArgument("line_item_id", lineItemId); + + return restTemplate.exchange( + uriBuilder.build(), + HttpMethod.GET, + null, + new ParameterizedTypeReference>() {}).getBody(); + } + + @Override + public DataListHolder getPromotedTweetReferences( + String accountId, + PromotedTweetReferenceQuery query) { + + return getPromotedTweetReferences( + accountId, + null, + query); + } + + @Override + public DataListHolder createPromotedTweetReference( + String accountId, + PromotedTweetReferenceForm input) { + + requireUserAuthorization(); + return restTemplate.exchange( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.PROMOTED_TWEET_REFERENCES) + .withArgument("account_id", accountId) + .build(), + HttpMethod.POST, + new TwitterApiBuilderForHttpEntity<>(input.toRequestBody()).build(), + new ParameterizedTypeReference>() {}).getBody(); + } + + @Override + public void deletePromotedTweetReference(String accountId, String promotedTweetId) { + requireUserAuthorization(); + restTemplate.delete( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.PROMOTED_TWEET_REFERENCE) + .withArgument("account_id", accountId) + .withArgument("promoted_tweet_id", promotedTweetId) + .build()); + } + + @Override + public DataListHolder getPromotedUserReferences(String accountId, String lineItemId, PromotedUserReferenceQuery query) { + requireUserAuthorization(); + return restTemplate.exchange( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.PROMOTED_USER_REFERENCES) + .withArgument("account_id", accountId) + .withArgument("line_item_id", lineItemId) + .withArgument(query.toQueryParameters()) + .build(), + HttpMethod.GET, + null, + new ParameterizedTypeReference>() {}).getBody(); + } + + @Override + public PromotedUserReference createPromotedUserReferences(String accountId, PromotedUserReferenceForm input) { + requireUserAuthorization(); + return restTemplate.exchange( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.PROMOTED_USER_REFERENCES) + .withArgument("account_id", accountId) + .build(), + HttpMethod.POST, + new TwitterApiBuilderForHttpEntity<>(input.toRequestBody()).build(), + new ParameterizedTypeReference>() {}).getBody().getData(); + } + + @Override + public void deletePromotedUserReference(String accountId, String promotedUserId) { + requireUserAuthorization(); + restTemplate.delete( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.PROMOTED_USER_REFERENCE) + .withArgument("account_id", accountId) + .withArgument("promoted_account_id", promotedUserId) + .build()); + } +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/SponsoredTweetFormBuilder.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/SponsoredTweetFormBuilder.java new file mode 100644 index 00000000..d2f35e0c --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/SponsoredTweetFormBuilder.java @@ -0,0 +1,69 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.social.twitter.api.advertising.SponsoredTweetForm; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +/** + * @author Hudson Mendes + */ +public class SponsoredTweetFormBuilder extends AbstractTwitterFormBuilder implements SponsoredTweetForm { + + private String status; + private Long asUserId; + private Boolean trimUser; + private final List mediaIds = new ArrayList<>(); + + @Override + public MultiValueMap toRequestBody() { + MultiValueMap map = new LinkedMultiValueMap(); + appendParameter(map, "status", this.status); + appendParameter(map, "as_user_id", this.asUserId); + appendParameter(map, "trim_user", this.trimUser); + appendParameter(map, "media_ids", this.mediaIds); + return map; + } + + @Override + public SponsoredTweetForm withStatus(String text) { + this.status = text; + return this; + } + + @Override + public SponsoredTweetForm asUser(Long userId) { + this.asUserId = userId; + return this; + } + + @Override + public SponsoredTweetForm trimUser(Boolean trimUser) { + this.trimUser = trimUser; + return this; + } + + @Override + public SponsoredTweetForm withMediaIds(Long... mediaIds) { + for (Long mediaId : mediaIds) + this.mediaIds.add(mediaId); + return this; + } +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/SponsoredTweetQueryBuilder.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/SponsoredTweetQueryBuilder.java new file mode 100644 index 00000000..bf8d1d28 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/SponsoredTweetQueryBuilder.java @@ -0,0 +1,40 @@ +package org.springframework.social.twitter.api.impl.advertising; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.social.twitter.api.advertising.AdvertisingObjective; +import org.springframework.social.twitter.api.advertising.SponsoredTweetQuery; +import org.springframework.util.MultiValueMap; + +public class SponsoredTweetQueryBuilder extends AbstractTwitterQueryForEntityBuilder implements SponsoredTweetQuery { + private final List userIds = new ArrayList<>(); + private AdvertisingObjective objective; + private Boolean trimUser; + + @Override + public SponsoredTweetQuery ofUsers(Long... userIds) { + for (Long userId : userIds) + this.userIds.add(userId); + return this; + } + + @Override + public SponsoredTweetQuery withObjective(AdvertisingObjective objective) { + this.objective = objective; + return this; + } + + @Override + public SponsoredTweetQuery trimUser(Boolean trimUser) { + this.trimUser = trimUser; + return this; + } + + @Override + protected void makeParameters(MultiValueMap map) { + appendParameter(map, "user_ids", this.userIds); + appendParameter(map, "objective", this.objective); + appendParameter(map, "trim_user", this.trimUser); + } +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/StatisticsOfAccountQueryBuilder.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/StatisticsOfAccountQueryBuilder.java new file mode 100644 index 00000000..71bc7c43 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/StatisticsOfAccountQueryBuilder.java @@ -0,0 +1,36 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import org.springframework.social.twitter.api.advertising.StatisticsOfAccountQuery; +import org.springframework.social.twitter.api.advertising.StatisticsSnapshot; +import org.springframework.util.MultiValueMap; + +/** + * Facilitates the creation of the query that will be + * used to filter results from the {@link StatisticsSnapshot} endpoint. + * + * @author Hudson Mendes + */ +public class StatisticsOfAccountQueryBuilder extends AbstractTwitterQueryForStatsBuilder implements + StatisticsOfAccountQuery { + + @Override + protected void makeParameters(MultiValueMap map) { + // nothing to add here + } + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/StatisticsOfCampaignQueryBuilder.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/StatisticsOfCampaignQueryBuilder.java new file mode 100644 index 00000000..8c3f78c0 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/StatisticsOfCampaignQueryBuilder.java @@ -0,0 +1,52 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.social.twitter.api.advertising.StatisticsOfCampaignQuery; +import org.springframework.social.twitter.api.advertising.StatisticsSnapshot; +import org.springframework.util.MultiValueMap; + +/** + * Facilitates the creation of the query that will be + * used to filter results from the {@link StatisticsSnapshot} endpoint. + * + * @author Hudson Mendes + */ +public class StatisticsOfCampaignQueryBuilder extends AbstractTwitterQueryForStatsBuilder implements + StatisticsOfCampaignQuery { + private List campaignIds; + + /* + * (non-Javadoc) + * + * @see org.springframework.social.twitter.api.impl.advertising.TwitterQueryForStatsOfCampaign#withCampaigns(java.lang.String) + */ + @Override + public StatisticsOfCampaignQueryBuilder withCampaigns(String... campaignIds) { + this.campaignIds = new ArrayList(); + for (int i = 0; i < campaignIds.length; i++) + this.campaignIds.add(campaignIds[i]); + return this; + } + + @Override + protected void makeParameters(MultiValueMap map) { + appendParameter(map, "campaign_ids", this.campaignIds); + } +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/StatisticsOfFundingInstrumentQueryBuilder.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/StatisticsOfFundingInstrumentQueryBuilder.java new file mode 100644 index 00000000..481c7d06 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/StatisticsOfFundingInstrumentQueryBuilder.java @@ -0,0 +1,53 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.social.twitter.api.advertising.StatisticsOfFundingInstrumentQuery; +import org.springframework.social.twitter.api.advertising.StatisticsSnapshot; +import org.springframework.util.MultiValueMap; + +/** + * Facilitates the creation of the query that will be + * used to filter results from the {@link StatisticsSnapshot} endpoint. + * + * @author Hudson Mendes + */ +public class StatisticsOfFundingInstrumentQueryBuilder extends AbstractTwitterQueryForStatsBuilder implements + StatisticsOfFundingInstrumentQuery { + private List fundingInstrumentIds; + + /* + * (non-Javadoc) + * + * @see org.springframework.social.twitter.api.impl.advertising.TwitterQueryForStatsOfFundingInstrument#withFundingInstruments(java.lang.String) + */ + @Override + public StatisticsOfFundingInstrumentQueryBuilder withFundingInstruments(String... fundingInstrumentIds) { + this.fundingInstrumentIds = new ArrayList(); + for (int i = 0; i < fundingInstrumentIds.length; i++) + this.fundingInstrumentIds.add(fundingInstrumentIds[i]); + return this; + } + + @Override + protected void makeParameters(MultiValueMap map) { + appendParameter(map, "funding_instrument_ids", this.fundingInstrumentIds); + } + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/StatisticsOfLineItemQueryBuilder.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/StatisticsOfLineItemQueryBuilder.java new file mode 100644 index 00000000..36168d3c --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/StatisticsOfLineItemQueryBuilder.java @@ -0,0 +1,53 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.social.twitter.api.advertising.StatisticsOfLineItemQuery; +import org.springframework.social.twitter.api.advertising.StatisticsSnapshot; +import org.springframework.util.MultiValueMap; + +/** + * Facilitates the creation of the query that will be + * used to filter results from the {@link StatisticsSnapshot} endpoint. + * + * @author Hudson Mendes + */ +public class StatisticsOfLineItemQueryBuilder extends AbstractTwitterQueryForStatsBuilder implements + StatisticsOfLineItemQuery { + private List lineItemIds; + + /* + * (non-Javadoc) + * + * @see org.springframework.social.twitter.api.impl.advertising.TwitterQueryForStatsOfLineItem#withLineItems(java.lang.String) + */ + @Override + public StatisticsOfLineItemQueryBuilder withLineItems(String... lineItemIds) { + this.lineItemIds = new ArrayList(); + for (int i = 0; i < lineItemIds.length; i++) + this.lineItemIds.add(lineItemIds[i]); + return this; + } + + @Override + protected void makeParameters(MultiValueMap map) { + appendParameter(map, "line_item_ids", this.lineItemIds); + } + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/StatisticsOfPromotedAccountQueryBuilder.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/StatisticsOfPromotedAccountQueryBuilder.java new file mode 100644 index 00000000..36e1aafc --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/StatisticsOfPromotedAccountQueryBuilder.java @@ -0,0 +1,53 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.social.twitter.api.advertising.StatisticsOfPromotedAccountQuery; +import org.springframework.social.twitter.api.advertising.StatisticsSnapshot; +import org.springframework.util.MultiValueMap; + +/** + * Facilitates the creation of the query that will be + * used to filter results from the {@link StatisticsSnapshot} endpoint. + * + * @author Hudson Mendes + */ +public class StatisticsOfPromotedAccountQueryBuilder extends AbstractTwitterQueryForStatsBuilder implements + StatisticsOfPromotedAccountQuery { + private List promotedAccountIds; + + /* + * (non-Javadoc) + * + * @see org.springframework.social.twitter.api.impl.advertising.TwitterQueryForStatsOfPromotedAccount#withPromotedAccounts(java.lang.String) + */ + @Override + public StatisticsOfPromotedAccountQueryBuilder withPromotedAccounts(String... promotedAccountIds) { + this.promotedAccountIds = new ArrayList(); + for (int i = 0; i < promotedAccountIds.length; i++) + this.promotedAccountIds.add(promotedAccountIds[i]); + return this; + } + + @Override + protected void makeParameters(MultiValueMap map) { + appendParameter(map, "promoted_account_ids", this.promotedAccountIds); + } + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/StatisticsOfPromotedTweetQueryBuilder.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/StatisticsOfPromotedTweetQueryBuilder.java new file mode 100644 index 00000000..b4e6a093 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/StatisticsOfPromotedTweetQueryBuilder.java @@ -0,0 +1,47 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.social.twitter.api.advertising.StatisticsOfPromotedTweetQuery; +import org.springframework.social.twitter.api.advertising.StatisticsSnapshot; +import org.springframework.util.MultiValueMap; + +/** + * Facilitates the creation of the query that will be + * used to filter results from the {@link StatisticsSnapshot} endpoint. + * + * @author Hudson Mendes + */ +public class StatisticsOfPromotedTweetQueryBuilder extends AbstractTwitterQueryForStatsBuilder implements + StatisticsOfPromotedTweetQuery { + private final List promotedTweetIds = new ArrayList<>(); + + public StatisticsOfPromotedTweetQueryBuilder withPromotedTweets(String... promotedAccountIds) { + if (promotedAccountIds != null) + for (int i = 0; i < promotedAccountIds.length; i++) + this.promotedTweetIds.add(promotedAccountIds[i]); + return this; + } + + @Override + protected void makeParameters(MultiValueMap map) { + appendParameter(map, "promoted_tweet_ids", this.promotedTweetIds); + } + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/StatisticsSnapshotDeserializer.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/StatisticsSnapshotDeserializer.java new file mode 100644 index 00000000..583f13da --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/StatisticsSnapshotDeserializer.java @@ -0,0 +1,157 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import java.io.IOException; +import java.lang.reflect.Type; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Spliterator; + +import org.springframework.social.twitter.api.advertising.StatisticsGranularity; +import org.springframework.social.twitter.api.advertising.StatisticsMetric; +import org.springframework.social.twitter.api.advertising.StatisticsSegmentation; +import org.springframework.social.twitter.api.advertising.StatisticsSegmentationType; +import org.springframework.social.twitter.api.advertising.StatisticsSnapshot; +import org.springframework.social.twitter.api.advertising.StatisticsSnapshotMetric; +import org.springframework.social.twitter.api.impl.LocalDateTimeDeserializer; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.ObjectCodec; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.JsonNode; + +/** + * Deserializes the complex object {@link StatisticsSnapshot} Differently from the other REST objects in the domain, the {@link StatisticsSnapshot} + * has a very fluent interface and changes according to the parameters passed to the endpoint. + * + * This deserializer tackles this complexity by getting the flexible JSON parts and pushing them + * into a rigit model {@link StatisticsSnapshotMetric} + * + * @author hudson + * + */ +public class StatisticsSnapshotDeserializer extends JsonDeserializer { + @Override + public StatisticsSnapshot deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException { + ObjectCodec codec = p.getCodec(); + JsonNode root = codec.readTree(p); + JsonNode data = root.get("data"); + if (data == null) + data = root; + + if (data.size() == 0) + return null; + + return new StatisticsSnapshot( + extractId(data), + extractSegmentation(data), + extractGranularity(data), + extractMetrics(data), + extractStartTime(data), + extractEndTime(data)); + } + + private String extractId(JsonNode data) { + return data.get("id").asText(); + } + + private StatisticsSegmentation extractSegmentation(JsonNode data) { + JsonNode segmentationNode = data.get("segment"); + if (segmentationNode == null) + return null; + + return new StatisticsSegmentation( + StatisticsSegmentationType.valueOf(segmentationNode.get("segmentation_type").asText()), + segmentationNode.get("segmentation_value").asText(), + segmentationNode.get("name").asText()); + + } + + private StatisticsGranularity extractGranularity(JsonNode data) { + return StatisticsGranularity.valueOf(data.get("granularity").asText()); + } + + private Map extractMetrics(JsonNode data) { + Map map = new HashMap(); + StatisticsMetric[] values = StatisticsMetric.class.getEnumConstants(); + for (int i = 0; i < values.length; i++) { + StatisticsMetric metric = values[i]; + JsonNode metricNode = data.get(metric.toString()); + if (metricNode != null) { + List entries = new ArrayList(); + parseMetricEntries(metric, metricNode.spliterator(), entries); + map.put(metric, new StatisticsSnapshotMetric(metric, entries)); + } + } + + return map; + } + + private LocalDateTime extractStartTime(JsonNode data) { + return LocalDateTimeDeserializer.parse(data.get("start_time").asText()); + } + + private LocalDateTime extractEndTime(JsonNode data) { + return LocalDateTimeDeserializer.parse(data.get("end_time").asText()); + } + + private void parseMetricEntries(StatisticsMetric metric, Spliterator iterator, List entries) { + Type metricType = metric.getValueType(); + if (metricType == BigDecimal.class) + dumpEntriesAsDecimals(iterator, entries); + else if (metricType == Integer.class) + dumpEntriesAsNumbers(iterator, entries); + else if (metricType == Object.class) + dumpEntriesAsHashes(iterator, entries); + } + + private void dumpEntriesAsDecimals(Spliterator iterator, List entries) { + iterator.forEachRemaining(i -> { + String entryValue = i.asText(); + entries.add(BigDecimalMicroAmountDeserializer.parse(entryValue)); + }); + } + + private void dumpEntriesAsNumbers(Spliterator iterator, List entries) { + iterator.forEachRemaining(i -> { + String entryValue = i.asText(); + if (!entryValue.contains(".")) { + entries.add(new Long(entryValue)); + } + else { + entries.add(new Float(entryValue)); + } + }); + } + + private void dumpEntriesAsHashes(Spliterator iterator, List entries) { + iterator.forEachRemaining(i -> { + i.fields().forEachRemaining(j -> { + String key = j.getKey(); + String value = j.getValue().asText(); + entries.add(new AbstractMap.SimpleEntry(key, value)); + }); + }); + } +} \ No newline at end of file diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/StatisticsSnapshotMixin.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/StatisticsSnapshotMixin.java new file mode 100644 index 00000000..ecfacf43 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/StatisticsSnapshotMixin.java @@ -0,0 +1,33 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import org.springframework.social.twitter.api.advertising.StatisticsSnapshot; +import org.springframework.social.twitter.api.impl.TwitterObjectMixin; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; + +/** + * Mixin class for adding Jackson annotations to {@link StatisticsSnapshot}. + * Relies on {@link StatisticsSnapshotDeserializer} to do actual deserialization, + * as Tweet JSON structures are flexible according to parameters passed. + * @author Hudson Mendes + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonDeserialize(using = StatisticsSnapshotDeserializer.class) +public abstract class StatisticsSnapshotMixin extends TwitterObjectMixin { +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/StatisticsTemplate.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/StatisticsTemplate.java new file mode 100644 index 00000000..9e52700f --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/StatisticsTemplate.java @@ -0,0 +1,210 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import java.net.URI; +import java.util.List; + +import org.springframework.http.HttpMethod; +import org.springframework.social.twitter.api.advertising.StatisticsOfAccountQuery; +import org.springframework.social.twitter.api.advertising.StatisticsOfCampaignQuery; +import org.springframework.social.twitter.api.advertising.StatisticsOfFundingInstrumentQuery; +import org.springframework.social.twitter.api.advertising.StatisticsOfLineItemQuery; +import org.springframework.social.twitter.api.advertising.StatisticsOfPromotedAccountQuery; +import org.springframework.social.twitter.api.advertising.StatisticsOfPromotedTweetQuery; +import org.springframework.social.twitter.api.advertising.StatisticsOperations; +import org.springframework.social.twitter.api.advertising.StatisticsSnapshot; +import org.springframework.social.twitter.api.impl.AbstractTwitterOperations; +import org.springframework.social.twitter.api.impl.DataStatsHolder; +import org.springframework.social.twitter.api.impl.TwitterApiBuilderForUri; +import org.springframework.social.twitter.api.impl.TwitterApiUriResourceForAdvertising; +import org.springframework.web.client.RestTemplate; + +/** + * Implementation of {@link StatisticsOperations}, providing a binding to + * Twitter's direct message-oriented REST resources. + * + * @author Hudson Mendes + */ +public class StatisticsTemplate extends AbstractTwitterOperations implements StatisticsOperations { + private final RestTemplate restTemplate; + + public StatisticsTemplate(RestTemplate restTemplate, boolean isAuthorizedForUser, boolean isAuthorizedForApp) { + super(isAuthorizedForUser, isAuthorizedForApp); + this.restTemplate = restTemplate; + } + + @Override + public List byAccounts(String accountId, StatisticsOfAccountQuery query) { + requireUserAuthorization(); + URI uri = new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.STATS_ACCOUNT) + .withArgument("account_id", accountId) + .withArgument(query.toQueryParameters()) + .build(); + + return restTemplate.exchange( + uri, + HttpMethod.GET, + null, + DataStatsHolder.class).getBody().getList(); + } + + @Override + public List byCampaigns(String accountId, StatisticsOfCampaignQuery query) { + requireUserAuthorization(); + return restTemplate.exchange( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.STATS_CAMPAIGNS) + .withArgument("account_id", accountId) + .withArgument(query.toQueryParameters()) + .build(), + HttpMethod.GET, + null, + DataStatsHolder.class).getBody().getList(); + } + + @Override + public List byCampaign(String accountId, String campaignId, StatisticsOfCampaignQuery query) { + requireUserAuthorization(); + return restTemplate.exchange( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.STATS_CAMPAIGN) + .withArgument("account_id", accountId) + .withArgument("campaign_id", campaignId) + .withArgument(query.toQueryParameters()) + .build(), + HttpMethod.GET, + null, + DataStatsHolder.class).getBody().getList(); + } + + @Override + public List byFundingInstruments(String accountId, StatisticsOfFundingInstrumentQuery query) { + requireUserAuthorization(); + return restTemplate.exchange( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.STATS_FUNDING_INSTRUMENTS) + .withArgument("account_id", accountId) + .withArgument(query.toQueryParameters()) + .build(), + HttpMethod.GET, + null, + DataStatsHolder.class).getBody().getList(); + } + + @Override + public List byFundingInstrument(String accountId, String fundingInstrumentId, StatisticsOfFundingInstrumentQuery query) { + requireUserAuthorization(); + return restTemplate.exchange( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.STATS_FUNDING_INSTRUMENT) + .withArgument("account_id", accountId) + .withArgument("funding_instrument_id", fundingInstrumentId) + .withArgument(query.toQueryParameters()) + .build(), + HttpMethod.GET, + null, + DataStatsHolder.class).getBody().getList(); + } + + @Override + public List byLineItems(String accountId, StatisticsOfLineItemQuery query) { + requireUserAuthorization(); + return restTemplate.exchange( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.STATS_LINE_ITEMS) + .withArgument("account_id", accountId) + .withArgument(query.toQueryParameters()) + .build(), + HttpMethod.GET, + null, + DataStatsHolder.class).getBody().getList(); + } + + @Override + public List byLineItem(String accountId, String lineItemId, StatisticsOfLineItemQuery query) { + requireUserAuthorization(); + return restTemplate.exchange( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.STATS_LINE_ITEM) + .withArgument("account_id", accountId) + .withArgument("line_item_id", lineItemId) + .withArgument(query.toQueryParameters()) + .build(), + HttpMethod.GET, + null, + DataStatsHolder.class).getBody().getList(); + } + + @Override + public List byPromotedAccounts(String accountId, StatisticsOfPromotedAccountQuery query) { + requireUserAuthorization(); + return restTemplate.exchange( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.STATS_PROMOTED_ACCOUNTS) + .withArgument("account_id", accountId) + .withArgument(query.toQueryParameters()) + .build(), + HttpMethod.GET, + null, + DataStatsHolder.class).getBody().getList(); + } + + @Override + public List byPromotedAccount(String accountId, String promotedAccountId, StatisticsOfPromotedAccountQuery query) { + requireUserAuthorization(); + return restTemplate.exchange( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.STATS_PROMOTED_ACCOUNT) + .withArgument("account_id", accountId) + .withArgument("promoted_account_id", promotedAccountId) + .withArgument(query.toQueryParameters()) + .build(), + HttpMethod.GET, + null, + DataStatsHolder.class).getBody().getList(); + } + + @Override + public List byPromotedTweets(String accountId, StatisticsOfPromotedTweetQuery query) { + requireUserAuthorization(); + return restTemplate.exchange( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.STATS_PROMOTED_TWEETS) + .withArgument("account_id", accountId) + .withArgument(query.toQueryParameters()) + .build(), + HttpMethod.GET, + null, + DataStatsHolder.class).getBody().getList(); + } + + @Override + public List byPromotedTweet(String accountId, String promotedTweetId, StatisticsOfPromotedTweetQuery query) { + requireUserAuthorization(); + return restTemplate.exchange( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.STATS_PROMOTED_TWEET) + .withArgument("account_id", accountId) + .withArgument("promoted_tweet_id", promotedTweetId) + .withArgument(query.toQueryParameters()) + .build(), + HttpMethod.GET, + null, + DataStatsHolder.class).getBody().getList(); + } +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TailoredAudienceChangeFormBuilder.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TailoredAudienceChangeFormBuilder.java new file mode 100644 index 00000000..0e58051b --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TailoredAudienceChangeFormBuilder.java @@ -0,0 +1,43 @@ +package org.springframework.social.twitter.api.impl.advertising; + +import org.springframework.social.twitter.api.advertising.TailoredAudienceChangeForm; +import org.springframework.social.twitter.api.advertising.TailoredAudienceChangeOperation; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +public class TailoredAudienceChangeFormBuilder extends AbstractTwitterFormBuilder implements TailoredAudienceChangeForm { + + private String tailoredAudienceId; + private String inputFilePath; + private TailoredAudienceChangeOperation operation; + + @Override + public TailoredAudienceChangeForm withTailoredAudience(String tailoredAudienceId) { + this.tailoredAudienceId = tailoredAudienceId; + return this; + } + + @Override + public TailoredAudienceChangeForm withInputFilePath(String inputFilePath) { + this.inputFilePath = inputFilePath; + return this; + } + + @Override + public TailoredAudienceChangeForm withOperation(TailoredAudienceChangeOperation operation) { + this.operation = operation; + return this; + } + + @Override + public MultiValueMap toRequestBody() { + MultiValueMap params = new LinkedMultiValueMap(); + + appendParameter(params, "tailored_audience_id", this.tailoredAudienceId); + appendParameter(params, "input_file_path", this.inputFilePath); + appendParameter(params, "operation", this.operation); + + return params; + } + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TailoredAudienceChangeMixin.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TailoredAudienceChangeMixin.java new file mode 100644 index 00000000..a311a333 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TailoredAudienceChangeMixin.java @@ -0,0 +1,40 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import org.springframework.social.twitter.api.advertising.TailoredAudienceChangeOperation; +import org.springframework.social.twitter.api.advertising.TailoredAudienceChangeState; +import org.springframework.social.twitter.api.impl.TwitterObjectMixin; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * @author Hudson Mendes + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public abstract class TailoredAudienceChangeMixin extends TwitterObjectMixin { + + @JsonCreator + TailoredAudienceChangeMixin( + @JsonProperty("id") String id, + @JsonProperty("tailored_audience_id") String tailoredAudienceId, + @JsonProperty("input_file_path") String inputFilePath, + @JsonProperty("operation") TailoredAudienceChangeOperation operation, + @JsonProperty("state") TailoredAudienceChangeState state) {} + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TailoredAudienceFormBuilder.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TailoredAudienceFormBuilder.java new file mode 100644 index 00000000..50af6e91 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TailoredAudienceFormBuilder.java @@ -0,0 +1,57 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import org.springframework.social.twitter.api.advertising.TailoredAudience; +import org.springframework.social.twitter.api.advertising.TailoredAudienceForm; +import org.springframework.social.twitter.api.advertising.TailoredAudienceListType; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +/** + * Facilitate the creation of the request body for post and put + * requests made to the management of {@link TailoredAudience} data. + * + * @author Hudson Mendes + */ +public class TailoredAudienceFormBuilder extends AbstractTwitterFormBuilder implements TailoredAudienceForm { + + private String name; + private TailoredAudienceListType listType; + + @Override + public MultiValueMap toRequestBody() { + MultiValueMap params = new LinkedMultiValueMap(); + + appendParameter(params, "name", this.name); + appendParameter(params, "list_type", this.listType); + + return params; + } + + @Override + public TailoredAudienceFormBuilder named(String name) { + this.name = name; + return this; + } + + @Override + public TailoredAudienceFormBuilder ofListType(TailoredAudienceListType listType) { + this.listType = listType; + return this; + } + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TailoredAudienceMixin.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TailoredAudienceMixin.java new file mode 100644 index 00000000..b6667253 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TailoredAudienceMixin.java @@ -0,0 +1,54 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import java.time.LocalDateTime; + +import org.springframework.social.twitter.api.advertising.TailoredAudience; +import org.springframework.social.twitter.api.advertising.TailoredAudienceListType; +import org.springframework.social.twitter.api.advertising.TailoredAudienceType; +import org.springframework.social.twitter.api.impl.LocalDateTimeDeserializer; +import org.springframework.social.twitter.api.impl.TwitterObjectMixin; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; + +/** + * Mixin class for adding Jackson annotations to {@link TailoredAudience}. + * + * @author Hudson Mendes + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public abstract class TailoredAudienceMixin extends TwitterObjectMixin { + + @JsonCreator + TailoredAudienceMixin( + @JsonProperty("id") String id, + @JsonProperty("name") String name, + @JsonProperty("list_type") TailoredAudienceListType listType, + @JsonProperty("audience_type") TailoredAudienceType audienceType, + @JsonProperty("audience_size") Integer audienceSize, + @JsonProperty("partner_source") String partnerSource, + @JsonProperty("deleted") Boolean deleted, + @JsonProperty("targetable") Boolean targetable, + @JsonProperty("reasons_not_targetable") String[] reasonsNotTargetable, + @JsonProperty("targetable_types") String[] targetableTypes, + @JsonProperty("created_at") @JsonDeserialize(using = LocalDateTimeDeserializer.class) LocalDateTime createdAt, + @JsonProperty("updated_at") @JsonDeserialize(using = LocalDateTimeDeserializer.class) LocalDateTime updatedAt) {} + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TailoredAudienceQueryBuilder.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TailoredAudienceQueryBuilder.java new file mode 100644 index 00000000..26e60025 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TailoredAudienceQueryBuilder.java @@ -0,0 +1,45 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import org.springframework.social.twitter.api.advertising.TailoredAudience; +import org.springframework.social.twitter.api.advertising.TailoredAudienceQuery; +import org.springframework.util.MultiValueMap; + +/** + * Facilitates the creation of the query that will be + * used to filter results from the {@link TailoredAudience} endpoint. + * + * @author Hudson Mendes + */ +public class TailoredAudienceQueryBuilder extends AbstractTwitterQueryForDataBuilder implements TailoredAudienceQuery { + + private String cursor; + private Integer pageSize; + + @Override + public TailoredAudienceQuery pagedBy(String cursor, Integer pageSize) { + this.cursor = cursor; + this.pageSize = pageSize; + return this; + } + + @Override + protected void makeParameters(MultiValueMap map) { + appendParameter(map, "cursor", this.cursor); + appendParameter(map, "count", this.pageSize); + } +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TailoredAudienceTemplate.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TailoredAudienceTemplate.java new file mode 100644 index 00000000..76d7a86f --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TailoredAudienceTemplate.java @@ -0,0 +1,148 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpMethod; +import org.springframework.social.twitter.api.advertising.GlobalOptOut; +import org.springframework.social.twitter.api.advertising.GlobalOptOutForm; +import org.springframework.social.twitter.api.advertising.TailoredAudience; +import org.springframework.social.twitter.api.advertising.TailoredAudienceChange; +import org.springframework.social.twitter.api.advertising.TailoredAudienceChangeForm; +import org.springframework.social.twitter.api.advertising.TailoredAudienceForm; +import org.springframework.social.twitter.api.advertising.TailoredAudienceOperations; +import org.springframework.social.twitter.api.advertising.TailoredAudienceQuery; +import org.springframework.social.twitter.api.impl.AbstractTwitterOperations; +import org.springframework.social.twitter.api.impl.DataListHolder; +import org.springframework.social.twitter.api.impl.DataSingleHolder; +import org.springframework.social.twitter.api.impl.TwitterApiBuilderForHttpEntity; +import org.springframework.social.twitter.api.impl.TwitterApiBuilderForUri; +import org.springframework.social.twitter.api.impl.TwitterApiUriResourceForAdvertising; +import org.springframework.web.client.RestTemplate; + +/** + * Implementation of {@link TailoredAudience}, providing a binding to + * Twitter's direct message-oriented REST resources. + * + * @author Hudson Mendes + */ +public class TailoredAudienceTemplate extends AbstractTwitterOperations implements TailoredAudienceOperations { + private final RestTemplate restTemplate; + + public TailoredAudienceTemplate(RestTemplate restTemplate, boolean isUserAuthorized, boolean isAppAuthorized) { + super(isUserAuthorized, isAppAuthorized); + this.restTemplate = restTemplate; + } + + @Override + public TailoredAudience getTailoredAudience(String accountId, String id) { + requireUserAuthorization(); + return restTemplate.exchange( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.TAILORED_AUDIENCE) + .withArgument("account_id", accountId) + .withArgument("tailored_audience_id", id) + .withArgument("with_deleted", true) + .build(), + HttpMethod.GET, + null, + new ParameterizedTypeReference>() {} + ).getBody().getData(); + } + + @Override + public DataListHolder getTailoredAudiences(String accountId, TailoredAudienceQuery query) { + requireUserAuthorization(); + return restTemplate.exchange( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.TAILORED_AUDIENCES) + .withArgument("account_id", accountId) + .withArgument(query.toQueryParameters()) + .build(), + HttpMethod.GET, + null, + new ParameterizedTypeReference>() {} + ).getBody(); + } + + @Override + public TailoredAudience createTailoredAudience(String accountId, TailoredAudienceForm input) { + requireUserAuthorization(); + return restTemplate.exchange( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.TAILORED_AUDIENCES) + .withArgument("account_id", accountId) + .build(), + HttpMethod.POST, + new TwitterApiBuilderForHttpEntity<>(input.toRequestBody()).build(), + new ParameterizedTypeReference>() {} + ).getBody().getData(); + } + + @Override + public void deleteTailoredAudience(String accountId, String id) { + requireUserAuthorization(); + restTemplate.delete(new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.TAILORED_AUDIENCE) + .withArgument("account_id", accountId) + .withArgument("tailored_audience_id", id) + .build()); + } + + @Override + public TailoredAudienceChange createTailoredAudienceChange(String accountId, TailoredAudienceChangeForm input) { + requireUserAuthorization(); + return restTemplate.exchange( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.TAILORED_AUDIENCE_CHANGES) + .withArgument("account_id", accountId) + .build(), + HttpMethod.POST, + new TwitterApiBuilderForHttpEntity<>(input.toRequestBody()).build(), + new ParameterizedTypeReference>() {} + ).getBody().getData(); + } + + @Override + public TailoredAudienceChange getTailoredAudienceChange(String accountId, String id) { + requireUserAuthorization(); + return restTemplate.exchange( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.TAILORED_AUDIENCE_CHANGE) + .withArgument("account_id", accountId) + .withArgument("tailored_audience_change_id", id) + .build(), + HttpMethod.GET, + null, + new ParameterizedTypeReference>() {} + ).getBody().getData(); + } + + @Override + public GlobalOptOut createGlobalOptOut(String accountId, GlobalOptOutForm input) { + requireUserAuthorization(); + return restTemplate.exchange( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.GLOBAL_OPT_OUT) + .withArgument("account_id", accountId) + .build(), + HttpMethod.PUT, + new TwitterApiBuilderForHttpEntity<>(input.toRequestBody()).build(), + new ParameterizedTypeReference>() {} + ).getBody().getData(); + } + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForAppStoreCategoriesMixin.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForAppStoreCategoriesMixin.java new file mode 100644 index 00000000..4298fad0 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForAppStoreCategoriesMixin.java @@ -0,0 +1,34 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import org.springframework.social.twitter.api.impl.TwitterObjectMixin; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +@JsonIgnoreProperties(ignoreUnknown = true) +public abstract class TargetingCriteriaDiscoveryForAppStoreCategoriesMixin extends TwitterObjectMixin { + + @JsonCreator + TargetingCriteriaDiscoveryForAppStoreCategoriesMixin( + @JsonProperty("name") String name, + @JsonProperty("os_type") String osType, + @JsonProperty("targeting_type") String targetingType, + @JsonProperty("targeting_value") String targetingValue) {} + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForAppStoreCategoriesQueryBuilder.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForAppStoreCategoriesQueryBuilder.java new file mode 100644 index 00000000..c9a6ef00 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForAppStoreCategoriesQueryBuilder.java @@ -0,0 +1,24 @@ +package org.springframework.social.twitter.api.impl.advertising; + +import org.springframework.social.twitter.api.advertising.AppStore; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForAppStoreCategoriesQuery; +import org.springframework.util.MultiValueMap; + +public class TargetingCriteriaDiscoveryForAppStoreCategoriesQueryBuilder + extends AbstractTwitterQueryForEntityBuilder + implements TargetingCriteriaDiscoveryForAppStoreCategoriesQuery { + + private AppStore appStore; + + @Override + public TargetingCriteriaDiscoveryForAppStoreCategoriesQuery inAppStore(AppStore appStore) { + this.appStore = appStore; + return this; + } + + @Override + protected void makeParameters(MultiValueMap map) { + appendParameter(map, "store", this.appStore); + } + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForBehaviorTaxonomiesMixin.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForBehaviorTaxonomiesMixin.java new file mode 100644 index 00000000..688b610a --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForBehaviorTaxonomiesMixin.java @@ -0,0 +1,35 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import org.springframework.social.twitter.api.impl.TwitterObjectMixin; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +@JsonIgnoreProperties(ignoreUnknown = true) +public abstract class TargetingCriteriaDiscoveryForBehaviorTaxonomiesMixin extends TwitterObjectMixin { + + @JsonCreator + TargetingCriteriaDiscoveryForBehaviorTaxonomiesMixin( + @JsonProperty("created_at") String createdAt, + @JsonProperty("id") String id, + @JsonProperty("name") String name, + @JsonProperty("parent_id") String parentId, + @JsonProperty("updated_at") String updatedAt) {} + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForBehaviorTaxonomiesQueryBuilder.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForBehaviorTaxonomiesQueryBuilder.java new file mode 100644 index 00000000..2e86bb4a --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForBehaviorTaxonomiesQueryBuilder.java @@ -0,0 +1,43 @@ +package org.springframework.social.twitter.api.impl.advertising; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForBehaviorTaxonomiesQuery; +import org.springframework.util.MultiValueMap; + +public class TargetingCriteriaDiscoveryForBehaviorTaxonomiesQueryBuilder + extends AbstractTwitterQueryForEntityBuilder + implements TargetingCriteriaDiscoveryForBehaviorTaxonomiesQuery { + + private final List taxonomyIds = new ArrayList<>(); + private final List parentIds = new ArrayList<>(); + + + @Override + public TargetingCriteriaDiscoveryForBehaviorTaxonomiesQueryBuilder ofTaxonomyIds(String... taxonomyIds) { + if(taxonomyIds!=null) { + for(String taxonomyId: taxonomyIds) { + this.taxonomyIds.add(taxonomyId); + } + } + return this; + } + + @Override + public TargetingCriteriaDiscoveryForBehaviorTaxonomiesQueryBuilder ofParentTaxonomyIds(String... parentIds) { + if(parentIds!=null) { + for(String parentId: parentIds) { + this.parentIds.add(parentId); + } + } + return this; + } + + @Override + protected void makeParameters(MultiValueMap map) { + appendParameter(map, "behavior_taxonomy_ids", this.taxonomyIds); + appendParameter(map, "parent_behavior_taxonomy_ids", this.parentIds); + } + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForBehaviorsMixin.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForBehaviorsMixin.java new file mode 100644 index 00000000..471b73d0 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForBehaviorsMixin.java @@ -0,0 +1,38 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import java.util.List; + +import org.springframework.social.twitter.api.impl.TwitterObjectMixin; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +@JsonIgnoreProperties(ignoreUnknown = true) +public abstract class TargetingCriteriaDiscoveryForBehaviorsMixin extends TwitterObjectMixin { + + @JsonCreator + TargetingCriteriaDiscoveryForBehaviorsMixin( + @JsonProperty("audience_size") String audienceSize, + @JsonProperty("behavior_taxonomy_id") String behaviorTaxonomyId, + @JsonProperty("id") String id, + @JsonProperty("name") String name, + @JsonProperty("partner_source") String partnerSource, + @JsonProperty("targetable_types") List targetableTypes) {} + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForBehaviorsQueryBuilder.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForBehaviorsQueryBuilder.java new file mode 100644 index 00000000..d9bb6781 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForBehaviorsQueryBuilder.java @@ -0,0 +1,40 @@ +package org.springframework.social.twitter.api.impl.advertising; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.social.twitter.api.advertising.SortDirection; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForBehaviorsQuery; +import org.springframework.util.MultiValueMap; + +public class TargetingCriteriaDiscoveryForBehaviorsQueryBuilder +extends AbstractTwitterQueryForEntityBuilder +implements TargetingCriteriaDiscoveryForBehaviorsQuery { + + private final List behaviorIds = new ArrayList(); + private String condition; + + @Override + public TargetingCriteriaDiscoveryForBehaviorsQuery ofBehaviors(String... behaviorIds) { + if (behaviorIds != null) + for (final String behaviorId : behaviorIds) + this.behaviorIds.add(behaviorId); + return this; + } + + @Override + public TargetingCriteriaDiscoveryForBehaviorsQuery sortBy(String field, SortDirection direction) { + if (field != null && direction != null) + condition = field + "-" + direction.name(); + else if (field != null) + condition = field; + return this; + } + + @Override + protected void makeParameters(MultiValueMap map) { + appendParameter(map, "behavior_ids", behaviorIds); + appendParameter(map, "sort_by", condition); + } + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForDevicesMixin.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForDevicesMixin.java new file mode 100644 index 00000000..09230658 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForDevicesMixin.java @@ -0,0 +1,35 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import org.springframework.social.twitter.api.impl.TwitterObjectMixin; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +@JsonIgnoreProperties(ignoreUnknown = true) +public abstract class TargetingCriteriaDiscoveryForDevicesMixin extends TwitterObjectMixin { + + @JsonCreator + TargetingCriteriaDiscoveryForDevicesMixin( + @JsonProperty("targeting_value") String targetingValue, + @JsonProperty("targeting_type") String targetingType, + @JsonProperty("platform") String platform, + @JsonProperty("manufacturer") String manufacturer, + @JsonProperty("name") String name) {} + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForDevicesQueryBuilder.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForDevicesQueryBuilder.java new file mode 100644 index 00000000..3e2c20fd --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForDevicesQueryBuilder.java @@ -0,0 +1,13 @@ +package org.springframework.social.twitter.api.impl.advertising; + +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForDevicesQuery; +import org.springframework.util.MultiValueMap; + +public class TargetingCriteriaDiscoveryForDevicesQueryBuilder + extends AbstractTwitterQueryForEntityBuilder + implements TargetingCriteriaDiscoveryForDevicesQuery { + + @Override + protected void makeParameters(MultiValueMap map) {} + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForEventsMixin.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForEventsMixin.java new file mode 100644 index 00000000..5968e960 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForEventsMixin.java @@ -0,0 +1,49 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import java.util.List; +import java.util.Map; + +import org.springframework.social.twitter.api.advertising.EventType; +import org.springframework.social.twitter.api.impl.TwitterObjectMixin; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +@JsonIgnoreProperties(ignoreUnknown = true) +public abstract class TargetingCriteriaDiscoveryForEventsMixin extends TwitterObjectMixin { + + @JsonCreator + TargetingCriteriaDiscoveryForEventsMixin( + @JsonProperty("country_breakdown_percentage") Map countryBreakdownPercentage, + @JsonProperty("country_code") String countryCode, + @JsonProperty("device_breakdown_percentage") Map deviceBreakdownPercentage, + @JsonProperty("end_time") String endTime, + @JsonProperty("event_type") EventType eventType, + @JsonProperty("gender_breakdown_percentage") Map genderBreakdownPercentage, + @JsonProperty("id") String id, + @JsonProperty("is_global") boolean isGlobal, + @JsonProperty("name") String name, + @JsonProperty("reach") Map reach, + @JsonProperty("start_time") String startTime, + @JsonProperty("top_hashtags") List topHashTags, + @JsonProperty("top_tweets") List topTweets, + @JsonProperty("top_users") List topUsers) {} + + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForEventsQueryBuilder.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForEventsQueryBuilder.java new file mode 100644 index 00000000..6a374120 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForEventsQueryBuilder.java @@ -0,0 +1,65 @@ +package org.springframework.social.twitter.api.impl.advertising; + +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.util.List; + +import org.springframework.social.twitter.api.advertising.EventType; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForEventsQuery; +import org.springframework.util.MultiValueMap; + +public class TargetingCriteriaDiscoveryForEventsQueryBuilder + extends AbstractTwitterQueryForEntityBuilder + implements TargetingCriteriaDiscoveryForEventsQuery { + private List eventIds; + private List eventTypes; + private List countryCodes; + private LocalDateTime startTime; + private LocalDateTime endTime; + + + @Override + public TargetingCriteriaDiscoveryForEventsQuery withEventIds(List eventIds) { + this.eventIds = eventIds; + return this; + } + + @Override + public TargetingCriteriaDiscoveryForEventsQuery withEventTypes(List eventTypes) { + this.eventTypes = eventTypes; + return this; + } + + @Override + public TargetingCriteriaDiscoveryForEventsQuery withCountryCodes(List countryCodes) { + this.countryCodes = countryCodes; + return this; + } + + @Override + public TargetingCriteriaDiscoveryForEventsQuery withStartTime(LocalDateTime startTime) { + this.startTime = startTime; + return this; + } + + @Override + public TargetingCriteriaDiscoveryForEventsQuery withEndTime(LocalDateTime endTime) { + this.endTime = endTime; + return this; + } + + @Override + protected void makeParameters(MultiValueMap map) { + appendParameter(map, "ids", this.eventIds); + appendParameter(map, "event_types", this.eventTypes); + appendParameter(map, "country_codes", this.countryCodes); + if(null!=this.startTime) { + appendParameter(map, "start_time", this.startTime.toInstant(ZoneOffset.UTC)); + } + if(null!=this.endTime) { + appendParameter(map, "end_time", this.endTime.toInstant(ZoneOffset.UTC)); + } + } + + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForInterestsMixin.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForInterestsMixin.java new file mode 100644 index 00000000..e3272940 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForInterestsMixin.java @@ -0,0 +1,33 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import org.springframework.social.twitter.api.impl.TwitterObjectMixin; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +@JsonIgnoreProperties(ignoreUnknown = true) +public abstract class TargetingCriteriaDiscoveryForInterestsMixin extends TwitterObjectMixin { + + @JsonCreator + TargetingCriteriaDiscoveryForInterestsMixin( + @JsonProperty("name") String name, + @JsonProperty("targeting_type") String targetingType, + @JsonProperty("targeting_value") String targetingValue) {} + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForInterestsQueryBuilder.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForInterestsQueryBuilder.java new file mode 100644 index 00000000..bd9e2bc4 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForInterestsQueryBuilder.java @@ -0,0 +1,22 @@ +package org.springframework.social.twitter.api.impl.advertising; + +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForInterestsQuery; +import org.springframework.util.MultiValueMap; + +public class TargetingCriteriaDiscoveryForInterestsQueryBuilder + extends AbstractTwitterQueryForEntityBuilder + implements TargetingCriteriaDiscoveryForInterestsQuery { + private String language; + + @Override + public TargetingCriteriaDiscoveryForInterestsQuery withLanguage(String language) { + this.language = language; + return this; + } + + @Override + protected void makeParameters(MultiValueMap map) { + appendParameter(map, "lang", this.language); + } + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForLanguagesMixin.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForLanguagesMixin.java new file mode 100644 index 00000000..bc85033f --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForLanguagesMixin.java @@ -0,0 +1,33 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import org.springframework.social.twitter.api.impl.TwitterObjectMixin; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +@JsonIgnoreProperties(ignoreUnknown = true) +public abstract class TargetingCriteriaDiscoveryForLanguagesMixin extends TwitterObjectMixin { + + @JsonCreator + TargetingCriteriaDiscoveryForLanguagesMixin( + @JsonProperty("name") String name, + @JsonProperty("targeting_type") String targetingType, + @JsonProperty("targeting_value") String targetingValue) {} + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForLanguagesQueryBuilder.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForLanguagesQueryBuilder.java new file mode 100644 index 00000000..4e632c47 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForLanguagesQueryBuilder.java @@ -0,0 +1,13 @@ +package org.springframework.social.twitter.api.impl.advertising; + +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForLanguagesQuery; +import org.springframework.util.MultiValueMap; + +public class TargetingCriteriaDiscoveryForLanguagesQueryBuilder + extends AbstractTwitterQueryForEntityBuilder + implements TargetingCriteriaDiscoveryForLanguagesQuery { + + @Override + protected void makeParameters(MultiValueMap map) {} + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForLocationsMixin.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForLocationsMixin.java new file mode 100644 index 00000000..b5c601d3 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForLocationsMixin.java @@ -0,0 +1,34 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import org.springframework.social.twitter.api.impl.TwitterObjectMixin; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +@JsonIgnoreProperties(ignoreUnknown = true) +public abstract class TargetingCriteriaDiscoveryForLocationsMixin extends TwitterObjectMixin { + + @JsonCreator + TargetingCriteriaDiscoveryForLocationsMixin( + @JsonProperty("location_type") String locationType, + @JsonProperty("name") String name, + @JsonProperty("targeting_type") String targetingType, + @JsonProperty("targeting_value") String targetingValue) {} + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForLocationsQueryBuilder.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForLocationsQueryBuilder.java new file mode 100644 index 00000000..e58670ab --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForLocationsQueryBuilder.java @@ -0,0 +1,32 @@ +package org.springframework.social.twitter.api.impl.advertising; + +import org.springframework.social.twitter.api.advertising.LocationType; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForLocationsQuery; +import org.springframework.util.MultiValueMap; + +public class TargetingCriteriaDiscoveryForLocationsQueryBuilder + extends AbstractTwitterQueryForEntityBuilder + implements TargetingCriteriaDiscoveryForLocationsQuery { + private LocationType location; + private String countryCode; + + + @Override + public TargetingCriteriaDiscoveryForLocationsQuery withLocation(LocationType location) { + this.location = location; + return this; + } + + @Override + public TargetingCriteriaDiscoveryForLocationsQuery withCountryCode(String countryCode) { + this.countryCode = countryCode; + return this; + } + + @Override + protected void makeParameters(MultiValueMap map) { + appendParameter(map, "location_type", this.location); + appendParameter(map, "country_code", this.countryCode); + } + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForNetworkOperatorsMixin.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForNetworkOperatorsMixin.java new file mode 100644 index 00000000..5cec984b --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForNetworkOperatorsMixin.java @@ -0,0 +1,34 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import org.springframework.social.twitter.api.impl.TwitterObjectMixin; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +@JsonIgnoreProperties(ignoreUnknown = true) +public abstract class TargetingCriteriaDiscoveryForNetworkOperatorsMixin extends TwitterObjectMixin { + + @JsonCreator + TargetingCriteriaDiscoveryForNetworkOperatorsMixin( + @JsonProperty("country_code") String countryCode, + @JsonProperty("name") String name, + @JsonProperty("targeting_type") String targetingType, + @JsonProperty("targeting_value") String targetingValue) {} + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForNetworkOperatorsQueryBuilder.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForNetworkOperatorsQueryBuilder.java new file mode 100644 index 00000000..2896b97a --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForNetworkOperatorsQueryBuilder.java @@ -0,0 +1,22 @@ +package org.springframework.social.twitter.api.impl.advertising; + +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForNetworkOperatorsQuery; +import org.springframework.util.MultiValueMap; + +public class TargetingCriteriaDiscoveryForNetworkOperatorsQueryBuilder + extends AbstractTwitterQueryForEntityBuilder + implements TargetingCriteriaDiscoveryForNetworkOperatorsQuery { + private String countryCode; + + @Override + public TargetingCriteriaDiscoveryForNetworkOperatorsQuery withCountryCode(String countryCode) { + this.countryCode = countryCode; + return this; + } + + @Override + protected void makeParameters(MultiValueMap map) { + appendParameter(map, "country_code", this.countryCode); + } + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForPlatformVersionsMixin.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForPlatformVersionsMixin.java new file mode 100644 index 00000000..a3e19f0d --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForPlatformVersionsMixin.java @@ -0,0 +1,35 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import org.springframework.social.twitter.api.impl.TwitterObjectMixin; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +@JsonIgnoreProperties(ignoreUnknown = true) +public abstract class TargetingCriteriaDiscoveryForPlatformVersionsMixin extends TwitterObjectMixin { + + @JsonCreator + TargetingCriteriaDiscoveryForPlatformVersionsMixin( + @JsonProperty("name") String name, + @JsonProperty("number") String number, + @JsonProperty("platform") String platform, + @JsonProperty("targeting_type") String targetingType, + @JsonProperty("targeting_value") String targetingValue) {} + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForPlatformVersionsQueryBuilder.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForPlatformVersionsQueryBuilder.java new file mode 100644 index 00000000..12dc14c7 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForPlatformVersionsQueryBuilder.java @@ -0,0 +1,13 @@ +package org.springframework.social.twitter.api.impl.advertising; + +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForPlatformVersionsQuery; +import org.springframework.util.MultiValueMap; + +public class TargetingCriteriaDiscoveryForPlatformVersionsQueryBuilder + extends AbstractTwitterQueryForEntityBuilder + implements TargetingCriteriaDiscoveryForPlatformVersionsQuery { + + @Override + protected void makeParameters(MultiValueMap map) {} + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForPlatformsMixin.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForPlatformsMixin.java new file mode 100644 index 00000000..f4182594 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForPlatformsMixin.java @@ -0,0 +1,33 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import org.springframework.social.twitter.api.impl.TwitterObjectMixin; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +@JsonIgnoreProperties(ignoreUnknown = true) +public abstract class TargetingCriteriaDiscoveryForPlatformsMixin extends TwitterObjectMixin { + + @JsonCreator + TargetingCriteriaDiscoveryForPlatformsMixin( + @JsonProperty("name") String name, + @JsonProperty("targeting_type") String targetingType, + @JsonProperty("targeting_value") String targetingValue) {} + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForPlatformsQueryBuilder.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForPlatformsQueryBuilder.java new file mode 100644 index 00000000..bda7b605 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForPlatformsQueryBuilder.java @@ -0,0 +1,22 @@ +package org.springframework.social.twitter.api.impl.advertising; + +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForPlatformsQuery; +import org.springframework.util.MultiValueMap; + +public class TargetingCriteriaDiscoveryForPlatformsQueryBuilder + extends AbstractTwitterQueryForEntityBuilder + implements TargetingCriteriaDiscoveryForPlatformsQuery { + private String language; + + @Override + public TargetingCriteriaDiscoveryForPlatformsQuery withLanguage(String language) { + this.language = language; + return this; + } + + @Override + protected void makeParameters(MultiValueMap map) { + appendParameter(map, "lang", this.language); + } + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForTvChannelMixin.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForTvChannelMixin.java new file mode 100644 index 00000000..f9ae39ea --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForTvChannelMixin.java @@ -0,0 +1,32 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import org.springframework.social.twitter.api.impl.TwitterObjectMixin; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +@JsonIgnoreProperties(ignoreUnknown = true) +public abstract class TargetingCriteriaDiscoveryForTvChannelMixin extends TwitterObjectMixin { + + @JsonCreator + TargetingCriteriaDiscoveryForTvChannelMixin( + @JsonProperty("id") Long id, + @JsonProperty("name") String name) {} + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForTvChannelQueryBuilder.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForTvChannelQueryBuilder.java new file mode 100644 index 00000000..9febdebb --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForTvChannelQueryBuilder.java @@ -0,0 +1,12 @@ +package org.springframework.social.twitter.api.impl.advertising; + +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForTvChannelQuery; +import org.springframework.util.MultiValueMap; + +public class TargetingCriteriaDiscoveryForTvChannelQueryBuilder + extends AbstractTwitterQueryForEntityBuilder + implements TargetingCriteriaDiscoveryForTvChannelQuery { + + @Override + protected void makeParameters(MultiValueMap map) {} +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForTvGenreMixin.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForTvGenreMixin.java new file mode 100644 index 00000000..d77a541e --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForTvGenreMixin.java @@ -0,0 +1,32 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import org.springframework.social.twitter.api.impl.TwitterObjectMixin; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +@JsonIgnoreProperties(ignoreUnknown = true) +public abstract class TargetingCriteriaDiscoveryForTvGenreMixin extends TwitterObjectMixin { + + @JsonCreator + TargetingCriteriaDiscoveryForTvGenreMixin( + @JsonProperty("id") Long id, + @JsonProperty("name") String name) {} + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForTvGenreQueryBuilder.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForTvGenreQueryBuilder.java new file mode 100644 index 00000000..8aee001b --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForTvGenreQueryBuilder.java @@ -0,0 +1,12 @@ +package org.springframework.social.twitter.api.impl.advertising; + +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForTvGenreQuery; +import org.springframework.util.MultiValueMap; + +public class TargetingCriteriaDiscoveryForTvGenreQueryBuilder + extends AbstractTwitterQueryForEntityBuilder + implements TargetingCriteriaDiscoveryForTvGenreQuery { + + @Override + protected void makeParameters(MultiValueMap map) {} +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForTvMarketMixin.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForTvMarketMixin.java new file mode 100644 index 00000000..316b9a72 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForTvMarketMixin.java @@ -0,0 +1,34 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import org.springframework.social.twitter.api.impl.TwitterObjectMixin; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +@JsonIgnoreProperties(ignoreUnknown = true) +public abstract class TargetingCriteriaDiscoveryForTvMarketMixin extends TwitterObjectMixin { + + @JsonCreator + TargetingCriteriaDiscoveryForTvMarketMixin( + @JsonProperty("id") String id, + @JsonProperty("name") String name, + @JsonProperty("country_code") String countryCode, + @JsonProperty("locale") String locale) {} + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForTvMarketQueryBuilder.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForTvMarketQueryBuilder.java new file mode 100644 index 00000000..877497fb --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForTvMarketQueryBuilder.java @@ -0,0 +1,12 @@ +package org.springframework.social.twitter.api.impl.advertising; + +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForTvMarketQuery; +import org.springframework.util.MultiValueMap; + +public class TargetingCriteriaDiscoveryForTvMarketQueryBuilder + extends AbstractTwitterQueryForEntityBuilder + implements TargetingCriteriaDiscoveryForTvMarketQuery { + + @Override + protected void makeParameters(MultiValueMap map) {} +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForTvShowMixin.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForTvShowMixin.java new file mode 100644 index 00000000..dfa0fa89 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForTvShowMixin.java @@ -0,0 +1,34 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import org.springframework.social.twitter.api.impl.TwitterObjectMixin; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +@JsonIgnoreProperties(ignoreUnknown = true) +public abstract class TargetingCriteriaDiscoveryForTvShowMixin extends TwitterObjectMixin { + + @JsonCreator + TargetingCriteriaDiscoveryForTvShowMixin( + @JsonProperty("id") Long id, + @JsonProperty("estimated_users") Long estimatedUsers, + @JsonProperty("name") String name, + @JsonProperty("genre") String genre) {} + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForTvShowQueryBuilder.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForTvShowQueryBuilder.java new file mode 100644 index 00000000..55d45af0 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryForTvShowQueryBuilder.java @@ -0,0 +1,23 @@ +package org.springframework.social.twitter.api.impl.advertising; + +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForTvShowQuery; +import org.springframework.util.MultiValueMap; + +public class TargetingCriteriaDiscoveryForTvShowQueryBuilder + extends AbstractTwitterQueryForEntityBuilder + implements TargetingCriteriaDiscoveryForTvShowQuery { + + private String tvMarketLocale; + + @Override + public TargetingCriteriaDiscoveryForTvShowQuery withLocale(String tvMarketLocale) { + this.tvMarketLocale = tvMarketLocale; + return this; + } + + @Override + protected void makeParameters(MultiValueMap map) { + appendParameter(map, "tv_market_locale", this.tvMarketLocale); + + } +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryTemplate.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryTemplate.java new file mode 100644 index 00000000..4a9e6d88 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryTemplate.java @@ -0,0 +1,275 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpMethod; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForAppStoreCategories; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForAppStoreCategoriesQuery; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForBehaviorTaxonomies; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForBehaviorTaxonomiesQuery; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForBehaviors; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForBehaviorsQuery; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForDevices; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForDevicesQuery; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForEvents; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForEventsQuery; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForInterests; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForInterestsQuery; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForLanguages; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForLanguagesQuery; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForLocations; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForLocationsQuery; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForNetworkOperators; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForNetworkOperatorsQuery; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForPlatformVersions; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForPlatformVersionsQuery; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForPlatforms; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForPlatformsQuery; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForTvChannel; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForTvChannelQuery; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForTvGenre; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForTvGenreQuery; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForTvMarket; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForTvMarketQuery; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForTvShow; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForTvShowQuery; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryOperations; +import org.springframework.social.twitter.api.impl.AbstractTwitterOperations; +import org.springframework.social.twitter.api.impl.DataListHolder; +import org.springframework.social.twitter.api.impl.TwitterApiBuilderForUri; +import org.springframework.social.twitter.api.impl.TwitterApiUriResourceForAdvertising; +import org.springframework.web.client.RestTemplate; + +public class TargetingCriteriaDiscoveryTemplate extends AbstractTwitterOperations implements TargetingCriteriaDiscoveryOperations { + private final RestTemplate restTemplate; + + public TargetingCriteriaDiscoveryTemplate(RestTemplate restTemplate, boolean isUserAuthorized, boolean isAppAuthorized) { + super(isUserAuthorized, isAppAuthorized); + this.restTemplate = restTemplate; + } + + @Override + public DataListHolder appStoreCategories(TargetingCriteriaDiscoveryForAppStoreCategoriesQuery query) { + requireUserAuthorization(); + return restTemplate.exchange( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.TARGETINGS_DISCOVERY_APP_STORE_CATEGORIES) + .withArgument(query.toQueryParameters()) + .build(), + HttpMethod.GET, + null, + new ParameterizedTypeReference>() {} + ).getBody(); + } + + @Override + public DataListHolder behaviorTaxonomies(TargetingCriteriaDiscoveryForBehaviorTaxonomiesQuery query) { + requireUserAuthorization(); + return restTemplate.exchange( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.TARGETINGS_DISCOVERY_BEHAVIOR_TAXONOMIES) + .withArgument(query.toQueryParameters()) + .build(), + HttpMethod.GET, + null, + new ParameterizedTypeReference>() {} + ).getBody(); + } + + @Override + public DataListHolder behaviors(TargetingCriteriaDiscoveryForBehaviorsQuery query) { + requireUserAuthorization(); + return restTemplate.exchange( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.TARGETINGS_DISCOVERY_BEHAVIORS) + .withArgument(query.toQueryParameters()) + .build(), + HttpMethod.GET, + null, + new ParameterizedTypeReference>() {} + ).getBody(); + } + + @Override + public DataListHolder devices(TargetingCriteriaDiscoveryForDevicesQuery query) { + requireUserAuthorization(); + return restTemplate.exchange( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.TARGETINGS_DISCOVERY_DEVICES) + .withArgument(query.toQueryParameters()) + .build(), + HttpMethod.GET, + null, + new ParameterizedTypeReference>() {} + ).getBody(); + } + + @Override + public DataListHolder events(TargetingCriteriaDiscoveryForEventsQuery query) { + requireUserAuthorization(); + return restTemplate.exchange( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.TARGETINGS_DISCOVERY_EVENTS) + .withArgument(query.toQueryParameters()) + .build(), + HttpMethod.GET, + null, + new ParameterizedTypeReference>() {} + ).getBody(); + } + + @Override + public DataListHolder interests(TargetingCriteriaDiscoveryForInterestsQuery query) { + requireUserAuthorization(); + return restTemplate.exchange( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.TARGETINGS_DISCOVERY_INTERESTS) + .withArgument(query.toQueryParameters()) + .build(), + HttpMethod.GET, + null, + new ParameterizedTypeReference>() {} + ).getBody(); + } + + @Override + public DataListHolder languages(TargetingCriteriaDiscoveryForLanguagesQuery query) { + requireUserAuthorization(); + return restTemplate.exchange( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.TARGETINGS_DISCOVERY_LANGUAGES) + .withArgument(query.toQueryParameters()) + .build(), + HttpMethod.GET, + null, + new ParameterizedTypeReference>() {} + ).getBody(); + } + + @Override + public DataListHolder locations(TargetingCriteriaDiscoveryForLocationsQuery query) { + requireUserAuthorization(); + return restTemplate.exchange( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.TARGETINGS_DISCOVERY_LOCATIONS) + .withArgument(query.toQueryParameters()) + .build(), + HttpMethod.GET, + null, + new ParameterizedTypeReference>() {} + ).getBody(); + } + + @Override + public DataListHolder networkOperators(TargetingCriteriaDiscoveryForNetworkOperatorsQuery query) { + requireUserAuthorization(); + return restTemplate.exchange( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.TARGETINGS_DISCOVERY_NETWORK_OPERATORS) + .withArgument(query.toQueryParameters()) + .build(), + HttpMethod.GET, + null, + new ParameterizedTypeReference>() {} + ).getBody(); + } + + @Override + public DataListHolder platformVersions(TargetingCriteriaDiscoveryForPlatformVersionsQuery query) { + requireUserAuthorization(); + return restTemplate.exchange( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.TARGETINGS_DISCOVERY_PLATFORM_VERSIONS) + .withArgument(query.toQueryParameters()) + .build(), + HttpMethod.GET, + null, + new ParameterizedTypeReference>() {} + ).getBody(); + } + + @Override + public DataListHolder platforms(TargetingCriteriaDiscoveryForPlatformsQuery query) { + requireUserAuthorization(); + return restTemplate.exchange( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.TARGETINGS_DISCOVERY_PLATFORMS) + .withArgument(query.toQueryParameters()) + .build(), + HttpMethod.GET, + null, + new ParameterizedTypeReference>() {} + ).getBody(); + } + + @Override + public DataListHolder tvShow(TargetingCriteriaDiscoveryForTvShowQuery query) { + requireUserAuthorization(); + return restTemplate.exchange( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.TARGETINGS_DISCOVERY_TV_SHOWS) + .withArgument(query.toQueryParameters()) + .build(), + HttpMethod.GET, + null, + new ParameterizedTypeReference>() {} + ).getBody(); + } + + @Override + public DataListHolder tvMarkets(TargetingCriteriaDiscoveryForTvMarketQuery query) { + requireUserAuthorization(); + return restTemplate.exchange( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.TARGETINGS_DISCOVERY_TV_MARKETS) + .withArgument(query.toQueryParameters()) + .build(), + HttpMethod.GET, + null, + new ParameterizedTypeReference>() {} + ).getBody(); + } + + @Override + public DataListHolder tvGenres(TargetingCriteriaDiscoveryForTvGenreQuery query) { + requireUserAuthorization(); + return restTemplate.exchange( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.TARGETINGS_DISCOVERY_TV_GENRES) + .withArgument(query.toQueryParameters()) + .build(), + HttpMethod.GET, + null, + new ParameterizedTypeReference>() {} + ).getBody(); + } + + @Override + public DataListHolder tvChannels(TargetingCriteriaDiscoveryForTvChannelQuery query) { + requireUserAuthorization(); + return restTemplate.exchange( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.TARGETINGS_DISCOVERY_TV_CHANNELS) + .withArgument(query.toQueryParameters()) + .build(), + HttpMethod.GET, + null, + new ParameterizedTypeReference>() {} + ).getBody(); + } + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaFormBuilder.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaFormBuilder.java new file mode 100644 index 00000000..2656c8e2 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaFormBuilder.java @@ -0,0 +1,407 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.social.twitter.api.advertising.RetargetingEngagementType; +import org.springframework.social.twitter.api.advertising.TargetingCriterionAgeBucket; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaForm; +import org.springframework.social.twitter.api.advertising.TargetingCriterionGender; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +/** + * Provides fluent generation of post paramters for the operation + * + * @author Hudson Mendes + */ +public class TargetingCriteriaFormBuilder extends AbstractTwitterFormBuilder implements TargetingCriteriaForm { + + private String lineItemId; + private String eventId; + private String retargetingEngagementCampaignId; + private Long retargetingEngagementPromotedUserReferenceId; + private RetargetingEngagementType retargetingEngagementType; + private final List followedUserIds = new ArrayList<>(); + private final List similarToUserIds = new ArrayList<>(); + private final List broadKeywords = new ArrayList<>(); + private final List exactKeywords = new ArrayList<>(); + private final List unorderedKeywords = new ArrayList<>(); + private final List phraseKeywords = new ArrayList<>(); + private final List negativeExactKeywords = new ArrayList<>(); + private final List negativeUnorderedKeywords = new ArrayList<>(); + private final List negativePhraseKeywords = new ArrayList<>(); + private final List locations = new ArrayList<>(); + private final List interests = new ArrayList<>(); + private TargetingCriterionGender gender; + private final List ageBuckets = new ArrayList<>(); + private final List platforms = new ArrayList<>(); + private final List platformVersions = new ArrayList<>(); + private final List devices = new ArrayList<>(); + private Boolean wifiOnly; + private final List tvChannels = new ArrayList<>(); + private final List tvGenres = new ArrayList<>(); + private final List tvShows = new ArrayList<>(); + private final List tailoredAudiences = new ArrayList<>(); + private final List tailoredAudiencesExpanded = new ArrayList<>(); + private final List tailoredAudiencesExclusions = new ArrayList<>(); + private final List behaviors = new ArrayList<>(); + private final List behaviorsExpanded = new ArrayList<>(); + private final List behavioursNegative = new ArrayList<>(); + private final List languages = new ArrayList<>(); + private final List networkOperators = new ArrayList<>(); + private Integer networkActivationDurationLess; + private Integer networkActivationDurationMoreOrEqualsTo; + private final List appStoreCategories = new ArrayList<>(); + private final List appStoreCategiresLookAlike = new ArrayList<>(); + + @Override + public TargetingCriteriaForm forLineItem(String lineItemId) { + this.lineItemId = lineItemId; + return this; + } + + @Override + public TargetingCriteriaForm forEvent(String eventId) { + this.eventId = eventId; + return this; + } + + @Override + public TargetingCriteriaForm forRetargetingEngagementOfCampaign(String campaignId) { + retargetingEngagementCampaignId = campaignId; + return this; + } + + @Override + public TargetingCriteriaForm forRetargetingEngagementOfPromotedUser(Long userId) { + retargetingEngagementPromotedUserReferenceId = userId; + return this; + } + + @Override + public TargetingCriteriaForm forRetargetingEngagementType(RetargetingEngagementType type) { + retargetingEngagementType = type; + return this; + } + + @Override + public TargetingCriteriaForm followersOfUsers(Long... followedUserIds) { + if (followedUserIds != null) + for (final Long userId : followedUserIds) + this.followedUserIds.add(userId); + return this; + } + + @Override + public TargetingCriteriaForm similarToUsers(Long... similiarUserIds) { + if (similiarUserIds != null) + for (final Long userId : similiarUserIds) + similarToUserIds.add(userId); + return this; + } + + @Override + public TargetingCriteriaForm withBroadKeywords(String... keywords) { + if (keywords != null) + for (final String keyword : keywords) + broadKeywords.add(keyword); + return this; + } + + @Override + public TargetingCriteriaForm withExactKeywords(String... keywords) { + if (keywords != null) + for (final String keyword : keywords) + exactKeywords.add(keyword); + return this; + } + + @Override + public TargetingCriteriaForm withUnorderedKeywords(String... keywords) { + if (keywords != null) + for (final String keyword : keywords) + unorderedKeywords.add(keyword); + return this; + } + + @Override + public TargetingCriteriaForm withPhraseKeywords(String... keywords) { + if (keywords != null) + for (final String keyword : keywords) + phraseKeywords.add(keyword); + return this; + } + + @Override + public TargetingCriteriaForm withNegativeExactKeywords(String... keywords) { + if (keywords != null) + for (final String keyword : keywords) + negativeExactKeywords.add(keyword); + return this; + } + + @Override + public TargetingCriteriaForm withNegativeUnorderedKeywords(String... keywords) { + if (keywords != null) + for (final String keyword : keywords) + negativeUnorderedKeywords.add(keyword); + return this; + } + + @Override + public TargetingCriteriaForm withNegativePhraseKeywords(String... keywords) { + if (keywords != null) + for (final String keyword : keywords) + negativePhraseKeywords.add(keyword); + return this; + } + + @Override + public TargetingCriteriaForm withLocations(String... locations) { + if (locations != null) + for (final String location : locations) + this.locations.add(location); + return this; + } + + @Override + public TargetingCriteriaForm withInterests(String... interests) { + if (interests != null) + for (final String interest : interests) + this.interests.add(interest); + return this; + } + + @Override + public TargetingCriteriaForm withGender(TargetingCriterionGender gender) { + this.gender = gender; + return this; + } + + @Override + public TargetingCriteriaForm withAgeBuckets(TargetingCriterionAgeBucket... ageBuckets) { + if (ageBuckets != null) + for (final TargetingCriterionAgeBucket age : ageBuckets) + this.ageBuckets.add(age); + return this; + } + + @Override + public TargetingCriteriaForm withPlatforms(String... platforms) { + if (platforms != null) + for (final String platform : platforms) + this.platforms.add(platform); + return this; + } + + @Override + public TargetingCriteriaForm withPlatformVersions(String... versions) { + if (versions != null) + for (final String version : versions) + platformVersions.add(version); + return this; + } + + @Override + public TargetingCriteriaForm withDevices(String... devices) { + if (devices != null) + for (final String device : devices) + this.devices.add(device); + return this; + } + + @Override + public TargetingCriteriaForm onlyWify(Boolean wifiOnly) { + this.wifiOnly = wifiOnly; + return this; + } + + @Override + public TargetingCriteriaForm withTvChannels(String... channels) { + if (channels != null) + for (final String channel : channels) + tvChannels.add(channel); + return this; + } + + @Override + public TargetingCriteriaForm withTvGenres(String... genres) { + if (genres != null) + for (final String genre : genres) + tvGenres.add(genre); + return this; + } + + @Override + public TargetingCriteriaForm withTvShows(String... shows) { + if (shows != null) + for (final String show : shows) + tvShows.add(show); + return this; + } + + @Override + public TargetingCriteriaForm withTailoredAudiences(String... tailoredAudiences) { + if (tailoredAudiences != null) + for (final String tailoredAudience : tailoredAudiences) + this.tailoredAudiences.add(tailoredAudience); + return this; + } + + @Override + public TargetingCriteriaForm withTailoredAudiencesExpanded(String... tailoredAudiencesExpanded) { + if (tailoredAudiencesExpanded != null) + for (final String expanded : tailoredAudiencesExpanded) + this.tailoredAudiencesExpanded.add(expanded); + return this; + } + + @Override + public TargetingCriteriaForm withTailoredAudiencesExclusion(String... tailoredAudienceExclusions) { + if (tailoredAudienceExclusions != null) + for (final String exclusion : tailoredAudienceExclusions) + tailoredAudiencesExclusions.add(exclusion); + return this; + } + + @Override + public TargetingCriteriaForm withBehaviors(String... behaviors) { + if (behaviors != null) + for (final String behavior : behaviors) + this.behaviors.add(behavior); + return this; + } + + @Override + public TargetingCriteriaForm withBehaviorsExpaned(String... behaviorsExpanded) { + if (behaviorsExpanded != null) + for (final String expanded : behaviorsExpanded) + this.behaviorsExpanded.add(expanded); + return this; + } + + @Override + public TargetingCriteriaForm withBehaviorsNegative(String... behavioursNegative) { + if (behavioursNegative != null) + for (final String negative : behavioursNegative) + this.behavioursNegative.add(negative); + return this; + } + + @Override + public TargetingCriteriaForm withLanguages(String... languages) { + if (languages != null) + for (final String language : languages) + this.languages.add(language); + return this; + } + + @Override + public TargetingCriteriaForm withNetworkOperators(String... operators) { + if (operators != null) + for (final String operator : operators) + networkOperators.add(operator); + return this; + } + + @Override + public TargetingCriteriaForm withNetworkActivationDurationLess(Integer months) { + networkActivationDurationLess = months; + return this; + } + + @Override + public TargetingCriteriaForm withNetworkActivationDurationMoreOrEqualsTo(Integer months) { + networkActivationDurationMoreOrEqualsTo = months; + return this; + } + + @Override + public TargetingCriteriaForm withAppStoreCategories(String... categories) { + if (categories != null) + for (final String category : categories) + appStoreCategories.add(category); + return this; + } + + @Override + public TargetingCriteriaForm withAppStoreCategiresLookAlike(String... categories) { + if (categories != null) + for (final String category : categories) + appStoreCategiresLookAlike.add(category); + return this; + } + + @Override + public MultiValueMap toRequestBody() { + final MultiValueMap params = new LinkedMultiValueMap(); + + appendParameter(params, "line_item_id", lineItemId); + + appendParameter(params, "broad_keywords", broadKeywords); + appendParameter(params, "exact_keywords", exactKeywords); + appendParameter(params, "unordered_keywords", unorderedKeywords); + appendParameter(params, "phrase_keywords", phraseKeywords); + + appendParameter(params, "negative_exact_keywords", negativeExactKeywords); + appendParameter(params, "negative_unordered_keywords", negativeUnorderedKeywords); + appendParameter(params, "negative_phrase_keywords", negativePhraseKeywords); + + appendParameter(params, "locations", locations); + appendParameter(params, "interests", interests); + appendParameter(params, "gender", (gender != null ? gender.value() : null)); + appendParameter(params, "age_buckets", ageBuckets); + + appendParameter(params, "followers_of_users", followedUserIds); + appendParameter(params, "similar_to_followers_of_users", similarToUserIds); + appendParameter(params, "platforms", platforms); + appendParameter(params, "platform_versions", platformVersions); + appendParameter(params, "devices", devices); + appendParameter(params, "wifi_only", (wifiOnly != null ? (wifiOnly.booleanValue() ? 1 : 0) : "")); + + appendParameter(params, "tv_channels", tvChannels); + appendParameter(params, "tv_genres", tvGenres); + appendParameter(params, "tv_shows", tvShows); + + appendParameter(params, "tailored_audiences", tailoredAudiences); + appendParameter(params, "tailored_audiences_expanded", tailoredAudiencesExpanded); + appendParameter(params, "tailored_audiences_excluded", tailoredAudiencesExclusions); + + appendParameter(params, "behaviors", behaviors); + appendParameter(params, "behaviors_expanded", behaviorsExpanded); + appendParameter(params, "negative_behaviors", behavioursNegative); + + appendParameter(params, "languages", languages); + appendParameter(params, "event", eventId); + + appendParameter(params, "network_operators", networkOperators); + appendParameter(params, "network_activation_duration_lt", networkActivationDurationLess); + appendParameter(params, "network_activation_duration_gte", networkActivationDurationMoreOrEqualsTo); + + appendParameter(params, "app_store_categories", appStoreCategories); + appendParameter(params, "app_store_categories_lookalike", appStoreCategiresLookAlike); + + appendParameter(params, "campaign_engagement", retargetingEngagementCampaignId); + appendParameter(params, "user_engagement", retargetingEngagementPromotedUserReferenceId); + appendParameter(params, "engagement_type", retargetingEngagementType); + + return params; + } + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaTemplate.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaTemplate.java new file mode 100644 index 00000000..6fe1785a --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaTemplate.java @@ -0,0 +1,113 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpMethod; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaForm; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaOperations; +import org.springframework.social.twitter.api.advertising.TargetingCriterion; +import org.springframework.social.twitter.api.advertising.TargetingCriterionForm; +import org.springframework.social.twitter.api.advertising.TargetingCriterionQuery; +import org.springframework.social.twitter.api.impl.AbstractTwitterOperations; +import org.springframework.social.twitter.api.impl.DataListHolder; +import org.springframework.social.twitter.api.impl.DataSingleHolder; +import org.springframework.social.twitter.api.impl.TwitterApiBuilderForHttpEntity; +import org.springframework.social.twitter.api.impl.TwitterApiBuilderForUri; +import org.springframework.social.twitter.api.impl.TwitterApiUriResourceForAdvertising; +import org.springframework.web.client.RestTemplate; + +/** + * Implementation of {@link TargetingCriteriaOperations}, providing a binding to Twitter's direct message-oriented REST resources. + * + * @author Hudson Mendes + */ +public class TargetingCriteriaTemplate extends AbstractTwitterOperations implements TargetingCriteriaOperations { + private final RestTemplate restTemplate; + + public TargetingCriteriaTemplate(RestTemplate restTemplate, boolean isAuthorizedForUser, boolean isAuthorizedForApp) { + super(isAuthorizedForUser, isAuthorizedForApp); + this.restTemplate = restTemplate; + } + + @Override + public TargetingCriterion getTargetingCriterion(String accountId, String id) { + requireUserAuthorization(); + return restTemplate.exchange( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.TARGETING_CRITERIA) + .withArgument("account_id", accountId) + .withArgument("targeting_criteria_id", id) + .build(), + HttpMethod.GET, + null, + new ParameterizedTypeReference>() {} + ).getBody().getData(); + } + + @Override + public DataListHolder getTargetingCriterions(String accountId, TargetingCriterionQuery query) { + requireUserAuthorization(); + return restTemplate.exchange( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.TARGETING_CRITERIAS) + .withArgument("account_id", accountId) + .withArgument(query.toQueryParameters()) + .build(), + HttpMethod.GET, + null, + new ParameterizedTypeReference>() {} + ).getBody(); + } + + @Override + public TargetingCriterion createTargetingCriterion(String accountId, TargetingCriterionForm data) { + requireUserAuthorization(); + return restTemplate.exchange( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.TARGETING_CRITERIAS) + .withArgument("account_id", accountId) + .build(), + HttpMethod.POST, + new TwitterApiBuilderForHttpEntity<>(data.toRequestBody()).build(), + new ParameterizedTypeReference>() {} + ).getBody().getData(); + } + + @Override + public DataListHolder setTargetingCriteria(String accountId, TargetingCriteriaForm data) { + requireUserAuthorization(); + return restTemplate.exchange( + new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.TARGETING_CRITERIAS) + .withArgument("account_id", accountId) + .build(), + HttpMethod.PUT, + new TwitterApiBuilderForHttpEntity<>(data.toRequestBody()).build(), + new ParameterizedTypeReference>() {} + ).getBody(); + } + + @Override + public void deleteTargetingCriterion(String accountId, String id) { + requireUserAuthorization(); + restTemplate.delete(new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForAdvertising.TARGETING_CRITERIA) + .withArgument("account_id", accountId) + .withArgument("targeting_criteria_id", id) + .build()); + } +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriterionFormBuilder.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriterionFormBuilder.java new file mode 100644 index 00000000..99283ce1 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriterionFormBuilder.java @@ -0,0 +1,127 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import org.springframework.social.twitter.api.advertising.TailoredAudienceType; +import org.springframework.social.twitter.api.advertising.TargetingCriterion; +import org.springframework.social.twitter.api.advertising.TargetingCriterionForm; +import org.springframework.social.twitter.api.advertising.TargetingCriterionType; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +/** + * Facilitate the creation of the request body for post and put + * requests made to the management of {@link TargetingCriterion} data. + * + * @author Hudson Mendes + */ +public class TargetingCriterionFormBuilder extends AbstractTwitterFormBuilder implements TargetingCriterionForm { + private String lineItemId; + private String name; + private String targetingType; + private String targetingValue; + private Boolean deleted; + protected Boolean targetAudienceExpansion; + protected TailoredAudienceType tailoredAudienceType; + + /* (non-Javadoc) + * @see org.springframework.social.twitter.api.impl.advertising.TargetingCriteriaForm#withLineItem(java.lang.String) + */ + @Override + public TargetingCriterionForm withLineItem(String lineItemId) { + this.lineItemId = lineItemId; + return this; + } + + /* (non-Javadoc) + * @see org.springframework.social.twitter.api.impl.advertising.TargetingCriteriaForm#withName(java.lang.String) + */ + @Override + public TargetingCriterionForm withName(String name) { + this.name = name; + return this; + } + + /* (non-Javadoc) + * @see org.springframework.social.twitter.api.impl.advertising.TargetingCriteriaForm#targeting(java.lang.String, java.lang.String) + */ + @Override + public TargetingCriterionForm targeting(String targetingType, String targetingValue) { + this.targetingType = targetingType; + this.targetingValue = targetingValue; + return this; + } + + /* (non-Javadoc) + * @see org.springframework.social.twitter.api.impl.advertising.TargetingCriteriaForm#targeting(org.springframework.social.twitter.api.advertising.TargetingType, java.lang.String) + */ + @Override + public TargetingCriterionForm targeting(TargetingCriterionType targetingType, String targetingValue) { + return targeting(targetingType.toString(), targetingValue); + } + + /* (non-Javadoc) + * @see org.springframework.social.twitter.api.impl.advertising.TargetingCriteriaForm#active() + */ + @Override + public TargetingCriterionFormBuilder active() { + this.deleted = false; + return this; + } + + /* (non-Javadoc) + * @see org.springframework.social.twitter.api.impl.advertising.TargetingCriteriaForm#deleted() + */ + @Override + public TargetingCriterionForm deleted() { + this.deleted = true; + return this; + } + + /* (non-Javadoc) + * @see org.springframework.social.twitter.api.impl.advertising.TargetingCriteriaForm#withTargetedAudienceExpansion(java.lang.Boolean) + */ + @Override + public TargetingCriterionForm withTargetedAudienceExpansion(final Boolean targetAudienceExpansion) { + this.targetAudienceExpansion = targetAudienceExpansion; + return this; + } + + /* (non-Javadoc) + * @see org.springframework.social.twitter.api.impl.advertising.TargetingCriteriaForm#withTargetedAudienceType(org.springframework.social.twitter.api.advertising.TailoredAudienceType) + */ + @Override + public TargetingCriterionForm withTargetedAudienceType(final TailoredAudienceType tailoredAudienceType) { + this.tailoredAudienceType = tailoredAudienceType; + return this; + } + + @Override + public MultiValueMap toRequestBody() { + MultiValueMap params = new LinkedMultiValueMap(); + + appendParameter(params, "line_item_id", this.lineItemId); + appendParameter(params, "name", this.name); + appendParameter(params, "targeting_type", this.targetingType); + appendParameter(params, "targeting_value", this.targetingValue); + appendParameter(params, "deleted", this.deleted); + appendParameter(params, "tailored_audience_expansion", this.targetAudienceExpansion); + appendParameter(params, "tailored_audience_type", this.tailoredAudienceType); + + return params; + } + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriterionMixin.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriterionMixin.java new file mode 100644 index 00000000..c14fd77f --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriterionMixin.java @@ -0,0 +1,53 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import java.time.LocalDateTime; + +import org.springframework.social.twitter.api.advertising.TailoredAudienceType; +import org.springframework.social.twitter.api.advertising.TargetingCriterion; +import org.springframework.social.twitter.api.impl.LocalDateTimeDeserializer; +import org.springframework.social.twitter.api.impl.TwitterObjectMixin; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; + +/** + * Mixin class for adding Jackson annotations to {@link TargetingCriterion}. + * + * @author Hudson Mendes + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public abstract class TargetingCriterionMixin extends TwitterObjectMixin { + + @JsonCreator + TargetingCriterionMixin( + @JsonProperty("id") String id, + @JsonProperty("account_id") String accountId, + @JsonProperty("line_item_id") String lineItemId, + @JsonProperty("name") String name, + @JsonProperty("targeting_type") String targetingType, + @JsonProperty("targeting_value") String targetingValue, + @JsonProperty("tailored_audience_expansion") Boolean tailordAudienceExpansion, + @JsonProperty("tailored_audience_type") TailoredAudienceType tailoredAudienceType, + @JsonProperty("deleted") Boolean deleted, + @JsonProperty("created_at") @JsonDeserialize(using = LocalDateTimeDeserializer.class) LocalDateTime createdAt, + @JsonProperty("updated_at") @JsonDeserialize(using = LocalDateTimeDeserializer.class) LocalDateTime updatedAt) {} + + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriterionQueryBuilder.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriterionQueryBuilder.java new file mode 100644 index 00000000..9a7bb685 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriterionQueryBuilder.java @@ -0,0 +1,46 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import org.springframework.social.twitter.api.advertising.TargetingCriterion; +import org.springframework.social.twitter.api.advertising.TargetingCriterionQuery; +import org.springframework.social.twitter.api.advertising.TargetingCriterionSorting; +import org.springframework.util.MultiValueMap; + +/** + * Facilitates the creation of the query that will be + * used to filter results from the {@link TargetingCriterion} endpoint. + * + * @author Hudson Mendes + */ +public class TargetingCriterionQueryBuilder + extends AbstractTwitterQueryForSortableEntityBuilder + implements TargetingCriterionQuery { + + private String lineItemId; + + @Override + public TargetingCriterionQuery withLineItem(String lineItemId) { + this.lineItemId = lineItemId; + return this; + } + + @Override + protected void makeParameters(MultiValueMap map) { + appendParameter(map, "line_item_id", this.lineItemId); + } + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/ton/TonTemplate.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/ton/TonTemplate.java new file mode 100644 index 00000000..6dad5ac6 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/ton/TonTemplate.java @@ -0,0 +1,72 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.ton; + +import java.net.URI; +import java.time.LocalDateTime; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Arrays; + +import org.springframework.http.HttpEntity; +import org.springframework.social.twitter.api.ton.TonOperations; +import org.springframework.social.twitter.api.impl.AbstractTwitterOperations; +import org.springframework.social.twitter.api.impl.TwitterApiBuilderForHttpEntity; +import org.springframework.social.twitter.api.impl.TwitterApiBuilderForUri; +import org.springframework.social.twitter.api.impl.TwitterApiUriResourceForTon; +import org.springframework.web.client.RestTemplate; + +/** + * Implementation of {@link TonOperations}, providing a binding to the Twitter Object Nest. + * + * @author Chris Latko + */ +public class TonTemplate extends AbstractTwitterOperations implements TonOperations { + + private final RestTemplate restTemplate; + + public TonTemplate(RestTemplate restTemplate, boolean isAuthorizedForUser, boolean isAuthorizedForApp) { + super(isAuthorizedForUser, isAuthorizedForApp); + this.restTemplate = restTemplate; + } + + @Override + public URI uploadSingleChunk(final String bucketName, final byte[] data, final String contentType, final ZonedDateTime expiry) { + requireUserAuthorization(); + + URI uri = new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForTon.TWITTER_OBJECT_NEST) + .withArgument("bucket_name", bucketName) + .build(); + + HttpEntity entity = new TwitterApiBuilderForHttpEntity<>(data) + .addHeader("Content-Type", Arrays.asList(contentType)) + .addHeader("Content-Length", Arrays.asList(String.valueOf(data.length))) + .addHeader("X-TON-Expires", Arrays.asList(expiry.format(DateTimeFormatter.RFC_1123_DATE_TIME))) + .build(); + + return restTemplate.postForLocation(uri, entity); + } + + @Override + public void uploadResumable(final String bucketName, final String resumeId, final byte[] data, final String contentType, final LocalDateTime expiry) { + + } + + + + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/upload/ImageEntityMixin.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/upload/ImageEntityMixin.java new file mode 100644 index 00000000..87d85b03 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/upload/ImageEntityMixin.java @@ -0,0 +1,33 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.upload; + +import org.springframework.social.twitter.api.impl.TwitterObjectMixin; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +@JsonIgnoreProperties(ignoreUnknown = true) +public abstract class ImageEntityMixin extends TwitterObjectMixin { + + @JsonCreator + public ImageEntityMixin( + @JsonProperty("image_type") String imageType, + @JsonProperty("w") long w, + @JsonProperty("h") long h) {} + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/upload/UploadTemplate.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/upload/UploadTemplate.java new file mode 100644 index 00000000..a3feb6b2 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/upload/UploadTemplate.java @@ -0,0 +1,143 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.upload; + +import java.net.URI; +import java.util.List; + +import org.springframework.core.io.ByteArrayResource; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.social.twitter.api.impl.AbstractTwitterOperations; +import org.springframework.social.twitter.api.impl.TwitterApiBuilderForHttpEntity; +import org.springframework.social.twitter.api.impl.TwitterApiBuilderForUri; +import org.springframework.social.twitter.api.impl.TwitterApiUriResourceForUpload; +import org.springframework.social.twitter.api.upload.UploadOperations; +import org.springframework.social.twitter.api.upload.UploadedEntity; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.RestTemplate; + +/** + * Implementation of {@link UploadOperations}, providing single/chunked uploads. + * + * @author Chris Latko + */ +public class UploadTemplate extends AbstractTwitterOperations implements UploadOperations { + + private final RestTemplate restTemplate; + + public UploadTemplate(RestTemplate restTemplate, boolean isAuthorizedForUser, boolean isAuthorizedForApp) { + super(isAuthorizedForUser, isAuthorizedForApp); + this.restTemplate = restTemplate; + } + + @Override + public UploadedEntity uploadSimple(final byte[] data) { + requireUserAuthorization(); + + final MultiValueMap form = new LinkedMultiValueMap(); + form.add("media", new ByteArrayResource(data)); + + final HttpEntity entity = new TwitterApiBuilderForHttpEntity<>(form) + .multipart(true) + .build(); + + return restTemplate.exchange(getUri(), HttpMethod.POST, entity, UploadedEntity.class).getBody(); + } + + @Override + public UploadedEntity uploadChunkedInit(final int totalSize, String contentType) { + requireUserAuthorization(); + return uploadChunkedInit(totalSize, contentType, null); + } + + @Override + public UploadedEntity uploadChunkedInit(final int totalSize, String contentType, List ownerIds) { + requireUserAuthorization(); + + final MultiValueMap form = new LinkedMultiValueMap(); + form.add("command", "INIT"); + form.add("total_bytes", String.valueOf(totalSize)); + form.add("media_type", contentType); + if (null != ownerIds && ownerIds.size() > 0) + form.add("additional_owners", join(ownerIds, ",")); + + final HttpEntity entity = new TwitterApiBuilderForHttpEntity<>(form) + .multipart(true) + .build(); + + return restTemplate.exchange( + getUri(), + HttpMethod.POST, + entity, + UploadedEntity.class).getBody(); + } + + @Override + public HttpStatus uploadChunkedAppend(String mediaId, byte[] data, int segmentId) { + requireUserAuthorization(); + + final MultiValueMap form = new LinkedMultiValueMap(); + form.add("command", "APPEND"); + form.add("media_id", mediaId); + form.add("media", new ByteArrayResource(data)); + form.add("segment_index", String.valueOf(segmentId)); + + final HttpEntity entity = new TwitterApiBuilderForHttpEntity<>(form) + .multipart(true) + .build(); + + final ResponseEntity response = restTemplate.exchange(getUri(), HttpMethod.POST, entity, UploadedEntity.class); + return response.getStatusCode(); + } + + @Override + public UploadedEntity uploadChunkedFinalize(String mediaId) { + requireUserAuthorization(); + + final MultiValueMap form = new LinkedMultiValueMap(); + form.add("command", "FINALIZE"); + form.add("media_id", mediaId); + + final HttpEntity entity = new TwitterApiBuilderForHttpEntity<>(form) + .multipart(true) + .build(); + + final ResponseEntity response = restTemplate.exchange(getUri(), HttpMethod.POST, entity, UploadedEntity.class); + return response.getBody(); + } + + private URI getUri() { + return new TwitterApiBuilderForUri() + .withResource(TwitterApiUriResourceForUpload.UPLOAD) + .build(); + } + + private String join(List list, String delim) { + final StringBuilder sb = new StringBuilder(); + String loopDelim = ""; + for (final String s : list) { + sb.append(loopDelim); + sb.append(s); + loopDelim = delim; + } + return sb.toString(); + } + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/upload/UploadedEntityMixin.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/upload/UploadedEntityMixin.java new file mode 100644 index 00000000..bf16eaf6 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/upload/UploadedEntityMixin.java @@ -0,0 +1,38 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.upload; + +import org.springframework.social.twitter.api.impl.TwitterObjectMixin; +import org.springframework.social.twitter.api.upload.ImageEntity; +import org.springframework.social.twitter.api.upload.VideoEntity; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +@JsonIgnoreProperties(ignoreUnknown = true) +public abstract class UploadedEntityMixin extends TwitterObjectMixin { + + @JsonCreator + public UploadedEntityMixin( + @JsonProperty("media_id") long mediaId, + @JsonProperty("media_id_string")String mediaIdString, + @JsonProperty("size")long size, + @JsonProperty("expires_after_secs")long expiresAfterSecs, + @JsonProperty("image")ImageEntity imageEntity, + @JsonProperty("video")VideoEntity videoEntity) {} + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/upload/VideoEntityMixin.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/upload/VideoEntityMixin.java new file mode 100644 index 00000000..39d7dc01 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/impl/upload/VideoEntityMixin.java @@ -0,0 +1,31 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.upload; + +import org.springframework.social.twitter.api.impl.TwitterObjectMixin; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +@JsonIgnoreProperties(ignoreUnknown = true) +public abstract class VideoEntityMixin extends TwitterObjectMixin { + + @JsonCreator + public VideoEntityMixin( + @JsonProperty("video_type") String videoType) {} + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/package-info.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/package-info.java index 06e0ec38..7b23bb17 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/package-info.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/package-info.java @@ -1,4 +1,4 @@ /** * Spring Social's Service API for Twitter */ -package org.springframework.social.twitter.api; +package org.springframework.social.twitter.api; \ No newline at end of file diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/ton/TonOperations.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/ton/TonOperations.java new file mode 100644 index 00000000..ebc6b068 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/ton/TonOperations.java @@ -0,0 +1,58 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.ton; + +import java.net.URI; +import java.time.LocalDateTime; +import java.time.ZonedDateTime; + +import org.springframework.social.ApiException; +import org.springframework.social.MissingAuthorizationException; + +/** + * Interface defining the twitter object nest operations. + * + * @author Chris Latko + */ +public interface TonOperations { + + /** + * Photo uploads and small tailored audiences will typically be under 64MB and can use non-resumable upload. + * + * @param bucketName must be "ta_partner" for ads api + * @param data the binary data + * @param contentType mime type of data, must conform to http://www.iana.org/assignments/media-types/media-types.xhtml + * @param expiry TON expiry date, up to 7 days, but ruby script has 10 days. + * @throws ApiException if there is an error while communicating with Twitter. + * @throws MissingAuthorizationException if TwitterTemplate was not created with OAuth credentials. + * @return the URI generated from the file uploaded using TON. + */ + URI uploadSingleChunk(final String bucketName, final byte[] data, final String contentType, final ZonedDateTime expiry); + + /** + * Uploads larger than 64MB. They are chunked and uploaded via a resumeId. + * + * @param bucketName must be "ta_partner" for ads api + * @param resumeId identifier used to resume an upload + * @param data the binary data + * @param contentType mime type of data, must conform to http://www.iana.org/assignments/media-types/media-types.xhtml + * @param expiry TON expiry date, up to 7 days, but ruby script has 10 days. + * @throws ApiException if there is an error while communicating with Twitter. + * @throws MissingAuthorizationException if TwitterTemplate was not created with OAuth credentials. + */ + void uploadResumable(final String bucketName, final String resumeId, final byte[] data, final String contentType, final LocalDateTime expiry); + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/upload/ChunkCommandType.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/upload/ChunkCommandType.java new file mode 100644 index 00000000..506e3bf1 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/upload/ChunkCommandType.java @@ -0,0 +1,22 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.upload; + +public enum ChunkCommandType { + INIT, + APPEND, + FINALIZE; +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/upload/ImageEntity.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/upload/ImageEntity.java new file mode 100644 index 00000000..5625e0f6 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/upload/ImageEntity.java @@ -0,0 +1,49 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.upload; + +import org.springframework.social.twitter.api.TwitterObject; + +/** + *

A representation of uploaded media.

+ * @author clatko + */ +public class ImageEntity extends TwitterObject { + private static final long serialVersionUID = 1L; + private String imageType; + private long w; + private long h; + + public ImageEntity(String imageType, long w, long h) { + this.imageType = imageType; + this.w = w; + this.h = h; + } + + public String getImageType() { + return imageType; + } + + public long getW() { + return w; + } + + public long getH() { + return h; + } + + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/upload/UploadOperations.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/upload/UploadOperations.java new file mode 100644 index 00000000..f2888f05 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/upload/UploadOperations.java @@ -0,0 +1,79 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.upload; + +import java.util.List; + +import org.springframework.http.HttpStatus; +import org.springframework.social.ApiException; +import org.springframework.social.MissingAuthorizationException; + +/** + * Interface defining media uploads. + * + * @author Chris Latko + */ +public interface UploadOperations { + + /** + * Media to be used with tweets need to be uploaded here. Only media (not mediat_data) is supported. + * + * @param media the binary data + * @throws ApiException if there is an error while communicating with Twitter. + * @throws MissingAuthorizationException if TwitterTemplate was not created with OAuth credentials. + * @return MediaEntity a JSON representation of metadata of the uploaded media. + */ + UploadedEntity uploadSimple(final byte[] media); + + /** + * Video uploads. They are chunked, this is the init stage. + * For more info: https://dev.twitter.com/rest/reference/post/media/upload-chunked. + * + * @param totalSize the total size of the entire upload + * @param contentType mime type of data, must conform to http://www.iana.org/assignments/media-types/media-types.xhtml + * @param ownerIds Comma-separated string of user IDs to set as additional owners ; maximum of 100 + * @return UploadedEntity + * @throws ApiException if there is an error while communicating with Twitter. + * @throws MissingAuthorizationException if TwitterTemplate was not created with OAuth credentials. + */ + UploadedEntity uploadChunkedInit(final int totalSize, final String contentType, final List ownerIds); + UploadedEntity uploadChunkedInit(final int totalSize, final String contentType); + + /** + * Video uploads. They are chunked, this is the append stage. + * For more info: https://dev.twitter.com/rest/reference/post/media/upload-chunked. + * + * @param mediaId returned from INIT, this is needed to resume the upload + * @param data the binary data + * @param segmentId need to reassemble the appends in the proper order; 0-999 inclusive + * @return HttpStatus + * @throws ApiException if there is an error while communicating with Twitter. + * @throws MissingAuthorizationException if TwitterTemplate was not created with OAuth credentials. + */ + HttpStatus uploadChunkedAppend(final String mediaId, final byte[] data, final int segmentId); + + /** + * Video uploads. They are chunked, this is the finalize stage + * For more info: https://dev.twitter.com/rest/reference/post/media/upload-chunked. + * + * @param mediaId returned from INIT, this is needed to finalize the upload + * @return UploadedEntity + * @throws ApiException if there is an error while communicating with Twitter. + * @throws MissingAuthorizationException if TwitterTemplate was not created with OAuth credentials. + */ + UploadedEntity uploadChunkedFinalize(final String mediaId); + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/upload/UploadedEntity.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/upload/UploadedEntity.java new file mode 100644 index 00000000..2f5f03d2 --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/upload/UploadedEntity.java @@ -0,0 +1,67 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.upload; + +import org.springframework.social.twitter.api.TwitterObject; + +/** + *

A representation of uploaded media.

+ * @author clatko + */ +public class UploadedEntity extends TwitterObject { + private static final long serialVersionUID = 1L; + private long mediaId; + private String mediaIdString; + private long size; + private long expiresAfterSecs; + private ImageEntity image; + private VideoEntity video; + + public UploadedEntity(long mediaId, String mediaIdString, long size, long expiresAfterSecs, ImageEntity image, VideoEntity video) { + this.mediaId = mediaId; + this.mediaIdString = mediaIdString; + this.size = size; + this.expiresAfterSecs = expiresAfterSecs; + this.image = image; + this.video = video; + } + + public long getMediaId() { + return mediaId; + } + + public String getMediaIdString() { + return mediaIdString; + } + + public long getSize() { + return size; + } + + public long getExpiresAfterSecs() { + return expiresAfterSecs; + } + + public ImageEntity getImage() { + return image; + } + + public VideoEntity getVideo() { + return video; + } + + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/upload/VideoEntity.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/upload/VideoEntity.java new file mode 100644 index 00000000..df49b25a --- /dev/null +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/api/upload/VideoEntity.java @@ -0,0 +1,37 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.upload; + +import org.springframework.social.twitter.api.TwitterObject; + +/** + *

A representation of uploaded media.

+ * @author clatko + */ +public class VideoEntity extends TwitterObject { + private static final long serialVersionUID = 1L; + private String videoType; + + public VideoEntity(String videoType) { + this.videoType = videoType; + } + + public String getVideoType() { + return videoType; + } + + +} diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/connect/TwitterConnectionFactory.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/connect/TwitterConnectionFactory.java index fe04b67a..159a65c9 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/connect/TwitterConnectionFactory.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/connect/TwitterConnectionFactory.java @@ -1,12 +1,12 @@ /* * Copyright 2014 the original author or authors. - * + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * + * + * http://www.apache.org/licenses/LICENSE-2.0 + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -20,12 +20,17 @@ /** * Twitter ConnectionFactory implementation. + * * @author Keith Donald */ public class TwitterConnectionFactory extends OAuth1ConnectionFactory { - public TwitterConnectionFactory(String consumerKey, String consumerSecret) { - super("twitter", new TwitterServiceProvider(consumerKey, consumerSecret), new TwitterAdapter()); - } - + public TwitterConnectionFactory(String consumerKey, String consumerSecret) { + this(consumerKey, consumerSecret, null, null); + } + + public TwitterConnectionFactory(String consumerKey, String consumerSecret, String hostForStandardApi, String hostForAdsApi) { + super("twitter", new TwitterServiceProvider(consumerKey, consumerSecret, hostForStandardApi, hostForAdsApi), new TwitterAdapter()); + } + } diff --git a/spring-social-twitter/src/main/java/org/springframework/social/twitter/connect/TwitterServiceProvider.java b/spring-social-twitter/src/main/java/org/springframework/social/twitter/connect/TwitterServiceProvider.java index 1853d224..4aedf2f7 100644 --- a/spring-social-twitter/src/main/java/org/springframework/social/twitter/connect/TwitterServiceProvider.java +++ b/spring-social-twitter/src/main/java/org/springframework/social/twitter/connect/TwitterServiceProvider.java @@ -1,12 +1,12 @@ /* * Copyright 2014 the original author or authors. - * + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * + * + * http://www.apache.org/licenses/LICENSE-2.0 + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -22,21 +22,42 @@ /** * Twitter ServiceProvider implementation. + * * @author Keith Donald * @author Craig Walls */ public class TwitterServiceProvider extends AbstractOAuth1ServiceProvider { - public TwitterServiceProvider(String consumerKey, String consumerSecret) { - super(consumerKey, consumerSecret, new OAuth1Template(consumerKey, consumerSecret, - "https://api.twitter.com/oauth/request_token", - "https://api.twitter.com/oauth/authorize", - "https://api.twitter.com/oauth/authenticate", - "https://api.twitter.com/oauth/access_token")); - } + private String hostForStandardApi; + private String hostForAdsApi; - public Twitter getApi(String accessToken, String secret) { - return new TwitterTemplate(getConsumerKey(), getConsumerSecret(), accessToken, secret); - } + public TwitterServiceProvider(String consumerKey, String consumerSecret) { + super(consumerKey, consumerSecret, new OAuth1Template(consumerKey, consumerSecret, + "https://api.twitter.com/oauth/request_token", + "https://api.twitter.com/oauth/authorize", + "https://api.twitter.com/oauth/authenticate", + "https://api.twitter.com/oauth/access_token")); + } + + public TwitterServiceProvider( + String consumerKey, + String consumerSecret, + String hostForStandardApi, + String hostForAdsApi) { + this(consumerKey, consumerSecret); + this.hostForStandardApi = hostForStandardApi; + this.hostForAdsApi = hostForAdsApi; + } + + @Override + public Twitter getApi(String accessToken, String secret) { + return new TwitterTemplate( + getConsumerKey(), + getConsumerSecret(), + accessToken, + secret, + this.hostForStandardApi, + this.hostForAdsApi); + } } diff --git a/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/AbstractTwitterApiTest.java b/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/AbstractTwitterApiTest.java index 0d01b4b9..09b5deb8 100644 --- a/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/AbstractTwitterApiTest.java +++ b/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/AbstractTwitterApiTest.java @@ -1,12 +1,12 @@ /* * Copyright 2014 the original author or authors. - * + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * + * + * http://www.apache.org/licenses/LICENSE-2.0 + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -15,8 +15,16 @@ */ package org.springframework.social.twitter.api.impl; -import static org.junit.Assert.*; +import static org.hamcrest.CoreMatchers.hasItems; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import java.math.MathContext; +import java.util.ArrayList; import java.util.List; import org.junit.Before; @@ -24,110 +32,147 @@ import org.springframework.core.io.Resource; import org.springframework.social.twitter.api.Entities; import org.springframework.social.twitter.api.HashTagEntity; +import org.springframework.social.twitter.api.MediaEntity; import org.springframework.social.twitter.api.MentionEntity; import org.springframework.social.twitter.api.Tweet; import org.springframework.social.twitter.api.UrlEntity; import org.springframework.test.web.client.MockRestServiceServer; public abstract class AbstractTwitterApiTest { + protected static final String UTF8 = "utf-8"; + protected static final MathContext ROUNDER = MathContext.DECIMAL32; - protected TwitterTemplate twitter; - - protected TwitterTemplate appAuthTwitter; - - protected MockRestServiceServer mockServer; - - protected MockRestServiceServer appAuthMockServer; - - @Before - public void setup() { - twitter = new TwitterTemplate("API_KEY", "API_SECRET", "ACCESS_TOKEN", "ACCESS_TOKEN_SECRET"); - mockServer = MockRestServiceServer.createServer(twitter.getRestTemplate()); - appAuthTwitter = new TwitterTemplate("APP_ACCESS_TOKEN"); - appAuthMockServer = MockRestServiceServer.createServer(appAuthTwitter.getRestTemplate()); - } - - protected Resource jsonResource(String filename) { - return new ClassPathResource(filename + ".json", getClass()); - } - - protected void assertSingleTweet(Tweet tweet) { - assertSingleTweet(tweet, false); - } - - protected void assertSingleTweet(Tweet tweet, boolean isSearchResult) { - assertEquals(12345, tweet.getId()); - assertEquals("Tweet 1", tweet.getText()); - assertEquals("habuma", tweet.getFromUser()); - assertEquals(112233, tweet.getFromUserId()); - assertEquals("http://a3.twimg.com/profile_images/1205746571/me2_300.jpg", tweet.getProfileImageUrl()); - assertEquals("Spring Social Showcase", tweet.getSource()); - assertEquals(1279042701000L, tweet.getCreatedAt().getTime()); - assertEquals(Long.valueOf(123123123123L), tweet.getInReplyToStatusId()); - if (!isSearchResult) { - assertEquals(12, tweet.getRetweetCount().intValue()); - assertTrue(tweet.isRetweeted()); - } else { - assertNull(tweet.getRetweetCount()); - } - - assertEquals(1001, (int) tweet.getFavoriteCount()); - - assertTrue(tweet.isFavorited()); - Entities entities = tweet.getEntities(); - List hashtags = entities.getHashTags(); - assertEquals(1, hashtags.size()); - assertEquals(2, hashtags.get(0).getIndices().length); - assertEquals(89, hashtags.get(0).getIndices()[0]); - assertEquals(98, hashtags.get(0).getIndices()[1]); - assertEquals("testhash", hashtags.get(0).getText()); - List urls = entities.getUrls(); - assertEquals(1, urls.size()); - assertEquals(2, urls.get(0).getIndices().length); - assertEquals(10, urls.get(0).getIndices()[0]); - assertEquals(30, urls.get(0).getIndices()[1]); - assertEquals("fb.me/t35tur1", urls.get(0).getDisplayUrl()); - assertEquals("http://fb.me/t35tur1", urls.get(0).getExpandedUrl()); - assertEquals("http://t.co/t35tur1", urls.get(0).getUrl()); - List mentions = entities.getMentions(); - assertEquals(2, mentions.size()); - MentionEntity mention1 = mentions.get(0); - assertEquals(11223344, mention1.getId()); - assertEquals("Bucky Greenhorn", mention1.getName()); - assertEquals("ukuleleman", mention1.getScreenName()); - assertEquals(2, mention1.getIndices().length); - assertEquals(3, mention1.getIndices()[0]); - assertEquals(18, mention1.getIndices()[1]); - MentionEntity mention2 = mentions.get(1); - assertEquals(44332211, mention2.getId()); - assertEquals("Jack Diamond", mention2.getName()); - assertEquals("jackdiamond", mention2.getScreenName()); - assertEquals(2, mention2.getIndices().length); - assertEquals(23, mention2.getIndices()[0]); - assertEquals(37, mention2.getIndices()[1]); - } - - protected void assertTimelineTweets(List tweets) { - assertTimelineTweets(tweets, false); - } - - protected void assertTimelineTweets(List tweets, boolean isSearchResult) { - assertEquals(2, tweets.size()); - assertSingleTweet(tweets.get(0), isSearchResult); - Tweet tweet2 = tweets.get(1); - assertEquals(54321, tweet2.getId()); - assertEquals("Tweet 2", tweet2.getText()); - assertEquals("rclarkson", tweet2.getFromUser()); - assertEquals(332211, tweet2.getFromUserId()); - assertEquals("http://a3.twimg.com/profile_images/1205746571/me2_300.jpg", tweet2.getProfileImageUrl()); - assertEquals("Twitter", tweet2.getSource()); - assertEquals(1279654701000L, tweet2.getCreatedAt().getTime()); - if (!isSearchResult) { - assertEquals(0, tweet2.getRetweetCount().intValue()); - } else { - assertNull(tweet2.getRetweetCount()); - } - Entities entities = tweet2.getEntities(); - assertEquals(0, entities.getHashTags().size()); - } + protected TwitterTemplate twitter; + + protected TwitterTemplate appAuthTwitter; + + protected MockRestServiceServer mockServer; + + protected MockRestServiceServer appAuthMockServer; + + @Before + public void setup() { + twitter = new TwitterTemplate("API_KEY", "API_SECRET", "ACCESS_TOKEN", "ACCESS_TOKEN_SECRET"); + mockServer = MockRestServiceServer.createServer(twitter.getRestTemplate()); + appAuthTwitter = new TwitterTemplate("APP_ACCESS_TOKEN"); + appAuthMockServer = MockRestServiceServer.createServer(appAuthTwitter.getRestTemplate()); + } + + protected Resource jsonResource(String filename) { + return new ClassPathResource(filename + ".json", getClass()); + } + + protected Resource dataResource(String filename) { + return new ClassPathResource(filename, getClass()); + } + + protected void assertSingleTweet(Tweet tweet) { + assertSingleTweet(tweet, false); + } + + protected void assertSingleTweet(Tweet tweet, boolean isSearchResult) { + assertEquals(12345, tweet.getId()); + assertEquals("Tweet 1", tweet.getText()); + assertEquals("habuma", tweet.getFromUser()); + assertEquals(112233, tweet.getFromUserId()); + assertEquals("http://a3.twimg.com/profile_images/1205746571/me2_300.jpg", tweet.getProfileImageUrl()); + assertEquals("Spring Social Showcase", tweet.getSource()); + assertEquals(1279042701000L, tweet.getCreatedAt().getTime()); + assertEquals(Long.valueOf(123123123123L), tweet.getInReplyToStatusId()); + if (!isSearchResult) { + assertEquals(12, tweet.getRetweetCount().intValue()); + assertTrue(tweet.isRetweeted()); + } + else + assertNull(tweet.getRetweetCount()); + + assertEquals(1001, (int) tweet.getFavoriteCount()); + + assertTrue(tweet.isFavorited()); + + final Entities entities = tweet.getEntities(); + + final List hashtags = entities.getHashTags(); + assertEquals(1, hashtags.size()); + assertEquals(2, hashtags.get(0).getIndices().length); + assertEquals(89, hashtags.get(0).getIndices()[0]); + assertEquals(98, hashtags.get(0).getIndices()[1]); + assertEquals("testhash", hashtags.get(0).getText()); + + final List urls = entities.getUrls(); + assertEquals(1, urls.size()); + assertEquals(2, urls.get(0).getIndices().length); + assertEquals(10, urls.get(0).getIndices()[0]); + assertEquals(30, urls.get(0).getIndices()[1]); + assertEquals("fb.me/t35tur1", urls.get(0).getDisplayUrl()); + assertEquals("http://fb.me/t35tur1", urls.get(0).getExpandedUrl()); + assertEquals("http://t.co/t35tur1", urls.get(0).getUrl()); + + final List mentions = entities.getMentions(); + assertEquals(2, mentions.size()); + + final MentionEntity mention1 = mentions.get(0); + assertEquals(11223344, mention1.getId()); + assertEquals("Bucky Greenhorn", mention1.getName()); + assertEquals("ukuleleman", mention1.getScreenName()); + assertEquals(2, mention1.getIndices().length); + assertEquals(3, mention1.getIndices()[0]); + assertEquals(18, mention1.getIndices()[1]); + + final MentionEntity mention2 = mentions.get(1); + assertEquals(44332211, mention2.getId()); + assertEquals("Jack Diamond", mention2.getName()); + assertEquals("jackdiamond", mention2.getScreenName()); + assertEquals(2, mention2.getIndices().length); + assertEquals(23, mention2.getIndices()[0]); + assertEquals(37, mention2.getIndices()[1]); + + final Entities extendedEntities = tweet.getExtendedEntities(); + if (extendedEntities != null) { + final List extendedMedia = extendedEntities.getMedia(); + assertNotNull(extendedMedia); + assertEquals("pic.twitter.com/5lgOiglUgj", extendedMedia.get(0).getDisplayUrl()); + assertEquals("http://t.co/5lgOiglUgj", extendedMedia.get(0).getUrl()); + assertEquals("http://twitter.com/bxfsh/status/626061984052543489/photo/1", extendedMedia.get(0).getExpandedUrl()); + assertEquals("http://pbs.twimg.com/tweet_video_thumb/CLA4DfrWsAAkbie.png", extendedMedia.get(0).getMediaUrl()); + assertEquals("https://pbs.twimg.com/tweet_video_thumb/CLA4DfrWsAAkbie.png", extendedMedia.get(0).getMediaSecureUrl()); + assertEquals(Long.valueOf(626061980898603008L), Long.valueOf(extendedMedia.get(0).getId())); + + final List indices = new ArrayList<>(); + for (final long indice : extendedMedia.get(0).getIndices()) + indices.add(indice); + + assertThat(indices, hasItems(28L, 50L)); + + assertNotNull(extendedMedia.get(0).getVideoInfo()); + assertNotNull(extendedMedia.get(0).getVideoInfo().getVariants()); + assertNotEquals(0, extendedMedia.get(0).getVideoInfo().getVariants().size()); + assertEquals(extendedMedia.get(0).getVideoInfo().getVariants().get(0).getBitrate(), Long.valueOf(0L)); + assertEquals(extendedMedia.get(0).getVideoInfo().getVariants().get(0).getContentType(), "video/mp4"); + assertEquals(extendedMedia.get(0).getVideoInfo().getVariants().get(0).getUrl(), "https://pbs.twimg.com/tweet_video/CLA4DfrWsAAkbie.mp4"); + } + } + + protected void assertTimelineTweets(List tweets) { + assertTimelineTweets(tweets, false); + } + + protected void assertTimelineTweets(List tweets, boolean isSearchResult) { + assertEquals(2, tweets.size()); + assertSingleTweet(tweets.get(0), isSearchResult); + final Tweet tweet2 = tweets.get(1); + assertEquals(54321, tweet2.getId()); + assertEquals("Tweet 2", tweet2.getText()); + assertEquals("rclarkson", tweet2.getFromUser()); + assertEquals(332211, tweet2.getFromUserId()); + assertEquals("http://a3.twimg.com/profile_images/1205746571/me2_300.jpg", tweet2.getProfileImageUrl()); + assertEquals("Twitter", tweet2.getSource()); + assertEquals(1279654701000L, tweet2.getCreatedAt().getTime()); + if (!isSearchResult) + assertEquals(0, tweet2.getRetweetCount().intValue()); + else + assertNull(tweet2.getRetweetCount()); + final Entities entities = tweet2.getEntities(); + assertEquals(0, entities.getHashTags().size()); + } } diff --git a/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/ApiErrorTest.java b/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/ApiErrorTest.java index 7ae90c81..e76d4219 100644 --- a/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/ApiErrorTest.java +++ b/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/ApiErrorTest.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -15,12 +15,22 @@ */ package org.springframework.social.twitter.api.impl; -import static org.junit.Assert.*; -import static org.springframework.http.HttpMethod.*; -import static org.springframework.http.HttpStatus.*; -import static org.springframework.http.MediaType.*; -import static org.springframework.test.web.client.match.MockRestRequestMatchers.*; -import static org.springframework.test.web.client.response.MockRestResponseCreators.*; +import static org.junit.Assert.assertEquals; +import static org.springframework.http.HttpMethod.GET; +import static org.springframework.http.HttpMethod.POST; +import static org.springframework.http.HttpStatus.BAD_GATEWAY; +import static org.springframework.http.HttpStatus.FORBIDDEN; +import static org.springframework.http.HttpStatus.SERVICE_UNAVAILABLE; +import static org.springframework.http.HttpStatus.UNAUTHORIZED; +import static org.springframework.http.MediaType.APPLICATION_JSON; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.content; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.method; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo; +import static org.springframework.test.web.client.response.MockRestResponseCreators.withBadRequest; +import static org.springframework.test.web.client.response.MockRestResponseCreators.withServerError; +import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus; +import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess; +import static org.springframework.test.web.client.response.MockRestResponseCreators.withUnauthorizedRequest; import org.junit.Ignore; import org.junit.Test; @@ -37,131 +47,183 @@ public class ApiErrorTest extends AbstractTwitterApiTest { - @Test(expected = NotAuthorizedException.class) - @Ignore("Come back to this one") - public void badOrMissingAccessToken() { - mockServer.expect(requestTo("https://api.twitter.com/1.1/statuses/update.json")) - .andExpect(method(POST)) - .andExpect(content().string("status=Some+message")) - .andRespond(withStatus(UNAUTHORIZED).body("").contentType(APPLICATION_JSON)); - twitter.timelineOperations().updateStatus("Some message"); - } - - @Test(expected = InvalidAuthorizationException.class) - public void badAccessToken() { // token is fabricated or fails signature validation - mockServer.expect(requestTo("https://api.twitter.com/1.1/account/verify_credentials.json")) - .andExpect(method(GET)) - .andRespond(withStatus(UNAUTHORIZED).body(jsonResource("error-invalid-token")).contentType(APPLICATION_JSON)); - twitter.userOperations().getUserProfile(); - } - - @Test(expected = RevokedAuthorizationException.class) - public void revokedToken() { - mockServer.expect(requestTo("https://api.twitter.com/1.1/account/verify_credentials.json")) - .andExpect(method(GET)) - .andRespond(withStatus(UNAUTHORIZED).body(jsonResource("error-revoked-token")).contentType(APPLICATION_JSON)); - twitter.userOperations().getUserProfile(); - } - - @Test(expected = RateLimitExceededException.class) - public void enhanceYourCalm() { - mockServer.expect(requestTo("https://api.twitter.com/1.1/search/tweets.json?q=%23spring&count=50")) - .andExpect(method(GET)) - .andRespond(withStatus(HttpStatus.valueOf(420)).body("{\"error\":\"You have been rate limited. Enhance your calm.\"}").contentType(APPLICATION_JSON)); - twitter.searchOperations().search("#spring"); - } - - @Test(expected = RateLimitExceededException.class) - public void tooManyRequests() { - mockServer.expect(requestTo("https://api.twitter.com/1.1/search/tweets.json?q=%23spring&count=50")) - .andExpect(method(GET)) - .andRespond(withStatus(HttpStatus.valueOf(429)).body("{\"errors\":[ {\"code\":88, \"message\":\"Rate limit exceeded\"} ] }").contentType(APPLICATION_JSON)); - twitter.searchOperations().search("#spring"); - } - - @Test(expected = InternalServerErrorException.class) - public void twitterIsBroken() { - try { - mockServer.expect(requestTo("https://api.twitter.com/1.1/statuses/home_timeline.json?count=20&include_entities=true")) - .andExpect(method(GET)) - .andRespond(withServerError().body("Non-JSON body").contentType(APPLICATION_JSON)); - twitter.timelineOperations().getHomeTimeline(); - } catch (InternalServerErrorException e) { - assertEquals("Something is broken at Twitter. Please see http://dev.twitter.com/pages/support to report the issue.", e.getMessage()); - throw e; - } - } - - @Test(expected = ServerDownException.class) - public void twitterIsDownOrBeingUpgraded() { - try { - mockServer.expect(requestTo("https://api.twitter.com/1.1/statuses/home_timeline.json?count=20&include_entities=true")) - .andExpect(method(GET)) - .andRespond(withStatus(BAD_GATEWAY).body("Non-JSON body").contentType(APPLICATION_JSON)); - twitter.timelineOperations().getHomeTimeline(); - } catch (ServerDownException e) { - assertEquals("Twitter is down or is being upgraded.", e.getMessage()); - throw e; - } - } - - @Test(expected = ServerOverloadedException.class) - public void twitterIsOverloaded() { - try { - mockServer.expect(requestTo("https://api.twitter.com/1.1/statuses/home_timeline.json?count=20&include_entities=true")) - .andExpect(method(GET)) - .andRespond(withStatus(SERVICE_UNAVAILABLE).body("Non-JSON body").contentType(APPLICATION_JSON)); - twitter.timelineOperations().getHomeTimeline(); - } catch (ServerDownException e) { - assertEquals("Twitter is overloaded with requests. Try again later.", e.getMessage()); - throw e; - } - } - - @Test(expected = ApiException.class) - public void nonJSONErrorResponse() { - try { - mockServer.expect(requestTo("https://api.twitter.com/1.1/statuses/home_timeline.json?count=20&include_entities=true")) - .andExpect(method(GET)) - .andRespond(withBadRequest().body("

HTML response

").contentType(APPLICATION_JSON)); - twitter.timelineOperations().getHomeTimeline(); - } catch (ApiException e) { - assertEquals("Error consuming Twitter REST API", e.getMessage()); - throw e; - } - } - - @Test(expected = ApiException.class) - @Ignore("TODO: Need to handle cases where there isn't an error, but the body is unparseable.") - public void unparseableSuccessResponse() { - mockServer.expect(requestTo("https://api.twitter.com/1.1/statuses/home_timeline.json")) - .andExpect(method(GET)) - .andRespond(withSuccess("Unparseable {text}", APPLICATION_JSON)); - twitter.timelineOperations().getHomeTimeline(); - } - - @Test(expected = RateLimitExceededException.class) - public void dailyStatusLimitExceeded() { - mockServer.expect(requestTo("https://api.twitter.com/1.1/statuses/update.json")) - .andExpect(method(POST)) - .andExpect(content().string("status=Some+message")) - .andRespond(withStatus(FORBIDDEN).body("{\"error\":\"User is over daily status update limit.\", \"request\":\"/1/statuses/update.json\"}").contentType(APPLICATION_JSON)); - twitter.timelineOperations().updateStatus("Some message"); - } - - @Test(expected = RateLimitExceededException.class) - public void hourlyRateLimitExceeded() { - mockServer.expect(requestTo("https://api.twitter.com/1.1/account/verify_credentials.json")) - .andExpect(method(GET)) - .andRespond(withBadRequest().body("{\"error\":\"Rate limit exceeded. Clients may not make more than 350 requests per hour.\"}").contentType(APPLICATION_JSON)); - twitter.userOperations().getUserProfile(); - } - - @Test(expected = NotAuthorizedException.class) - public void streamingUnauthorizedWithEmptyBody() { - mockServer.expect(requestTo("https://stream.twitter.com/1.1/statuses/sample.json")) - .andExpect(method(GET)) - .andRespond(withUnauthorizedRequest().body(new ClassPathResource("401.html", getClass()))); - twitter.restOperations().getForObject("https://stream.twitter.com/1.1/statuses/sample.json", String.class); - } + @Test(expected = NotAuthorizedException.class) + @Ignore("Come back to this one") + public void badOrMissingAccessToken() { + mockServer + .expect(requestTo("https://api.twitter.com/1.1/statuses/update.json")) + .andExpect(method(POST)) + .andExpect(content().string("status=Some+message")) + .andRespond(withStatus(UNAUTHORIZED).body("").contentType(APPLICATION_JSON)); + twitter.timelineOperations().updateStatus("Some message"); + } + + @Test(expected = InvalidAuthorizationException.class) + public void badAccessToken() { // token is fabricated or fails signature validation + mockServer + .expect(requestTo("https://api.twitter.com/1.1/account/verify_credentials.json")) + .andExpect(method(GET)) + .andRespond(withStatus(UNAUTHORIZED).body(jsonResource("error-invalid-token")).contentType(APPLICATION_JSON)); + twitter.userOperations().getUserProfile(); + } + + @Test(expected = RevokedAuthorizationException.class) + public void revokedToken() { + mockServer + .expect(requestTo("https://api.twitter.com/1.1/account/verify_credentials.json")) + .andExpect(method(GET)) + .andRespond(withStatus(UNAUTHORIZED).body(jsonResource("error-revoked-token")).contentType(APPLICATION_JSON)); + twitter.userOperations().getUserProfile(); + } + + @Test(expected = RateLimitExceededException.class) + public void enhanceYourCalm() { + mockServer + .expect(requestTo("https://api.twitter.com/1.1/search/tweets.json?q=%23spring&count=50")) + .andExpect(method(GET)) + .andRespond( + withStatus(HttpStatus.valueOf(420)).body("{\"error\":\"You have been rate limited. Enhance your calm.\"}").contentType( + APPLICATION_JSON)); + twitter.searchOperations().search("#spring"); + } + + @Test(expected = RateLimitExceededException.class) + public void tooManyRequests() { + mockServer + .expect(requestTo("https://api.twitter.com/1.1/search/tweets.json?q=%23spring&count=50")) + .andExpect(method(GET)) + .andRespond( + withStatus(HttpStatus.valueOf(429)) + .body("{\"errors\":[ {\"code\":88, \"message\":\"Rate limit exceeded\"} ] }") + .contentType(APPLICATION_JSON)); + twitter.searchOperations().search("#spring"); + } + + @Test(expected = InvalidInputDataException.class) + public void requiredErrors() { + mockServer + .expect(requestTo("https://api.twitter.com/1.1/search/tweets.json?q=%23spring&count=50")) + .andExpect(method(GET)) + .andRespond( + withStatus(HttpStatus.valueOf(400)).body( + "{\"errors\":[ {\"code\":\"INVALID_PARAMETER\", \"message\":\"'start_time' is required.\"} ] }").contentType( + APPLICATION_JSON)); + twitter.searchOperations().search("#spring"); + } + + @Test(expected = InvalidInputDataException.class) + public void validationErrors() { + mockServer + .expect(requestTo("https://api.twitter.com/1.1/search/tweets.json?q=%23spring&count=50")) + .andExpect(method(GET)) + .andRespond( + withStatus(HttpStatus.valueOf(400)).body( + "{\"errors\":[ {\"code\":\"INVALID\", \"message\":\"'start_time' is required.\"} ] }").contentType( + APPLICATION_JSON)); + twitter.searchOperations().search("#spring"); + } + + @Test(expected = InternalServerErrorException.class) + public void twitterIsBroken() { + try { + mockServer + .expect(requestTo("https://api.twitter.com/1.1/statuses/home_timeline.json?count=20&include_entities=true")) + .andExpect(method(GET)) + .andRespond(withServerError().body("Non-JSON body").contentType(APPLICATION_JSON)); + twitter.timelineOperations().getHomeTimeline(); + } + catch (final InternalServerErrorException e) { + assertEquals("Something is broken at Twitter. Please see http://dev.twitter.com/pages/support to report the issue.", e.getMessage()); + throw e; + } + } + + @Test(expected = ServerDownException.class) + public void twitterIsDownOrBeingUpgraded() { + try { + mockServer + .expect(requestTo("https://api.twitter.com/1.1/statuses/home_timeline.json?count=20&include_entities=true")) + .andExpect(method(GET)) + .andRespond(withStatus(BAD_GATEWAY).body("Non-JSON body").contentType(APPLICATION_JSON)); + twitter.timelineOperations().getHomeTimeline(); + } + catch (final ServerDownException e) { + assertEquals("Twitter is down or is being upgraded.", e.getMessage()); + throw e; + } + } + + @Test(expected = ServerOverloadedException.class) + public void twitterIsOverloaded() { + try { + mockServer + .expect(requestTo("https://api.twitter.com/1.1/statuses/home_timeline.json?count=20&include_entities=true")) + .andExpect(method(GET)) + .andRespond(withStatus(SERVICE_UNAVAILABLE).body("Non-JSON body").contentType(APPLICATION_JSON)); + twitter.timelineOperations().getHomeTimeline(); + } + catch (final ServerDownException e) { + assertEquals("Twitter is overloaded with requests. Try again later.", e.getMessage()); + throw e; + } + } + + @Test(expected = ApiException.class) + public void nonJSONErrorResponse() { + try { + mockServer + .expect(requestTo("https://api.twitter.com/1.1/statuses/home_timeline.json?count=20&include_entities=true")) + .andExpect(method(GET)) + .andRespond(withBadRequest().body("

HTML response

").contentType(APPLICATION_JSON)); + twitter.timelineOperations().getHomeTimeline(); + } + catch (final ApiException e) { + assertEquals("Error consuming Twitter REST API", e.getMessage()); + throw e; + } + } + + @Test(expected = ApiException.class) + @Ignore("TODO: Need to handle cases where there isn't an error, but the body is unparseable.") + public void unparseableSuccessResponse() { + mockServer + .expect(requestTo("https://api.twitter.com/1.1/statuses/home_timeline.json")) + .andExpect(method(GET)) + .andRespond(withSuccess("Unparseable {text}", APPLICATION_JSON)); + twitter.timelineOperations().getHomeTimeline(); + } + + @Test(expected = RateLimitExceededException.class) + public void dailyStatusLimitExceeded() { + mockServer + .expect(requestTo("https://api.twitter.com/1.1/statuses/update.json")) + .andExpect(method(POST)) + .andExpect(content().string("status=Some+message")) + .andRespond( + withStatus(FORBIDDEN) + .body("{\"error\":\"User is over daily status update limit.\", \"request\":\"/1/statuses/update.json\"}") + .contentType(APPLICATION_JSON)); + twitter.timelineOperations().updateStatus("Some message"); + } + + @Test(expected = RateLimitExceededException.class) + public void hourlyRateLimitExceeded() { + mockServer + .expect(requestTo("https://api.twitter.com/1.1/account/verify_credentials.json")) + .andExpect(method(GET)) + .andRespond( + withBadRequest() + .body("{\"error\":\"Rate limit exceeded. Clients may not make more than 350 requests per hour.\"}") + .contentType(APPLICATION_JSON)); + twitter.userOperations().getUserProfile(); + } + + @Test(expected = NotAuthorizedException.class) + public void streamingUnauthorizedWithEmptyBody() { + mockServer + .expect(requestTo("https://stream.twitter.com/1.1/statuses/sample.json")) + .andExpect(method(GET)) + .andRespond(withUnauthorizedRequest().body(new ClassPathResource("401.html", getClass()))); + twitter.restOperations().getForObject("https://stream.twitter.com/1.1/statuses/sample.json", String.class); + } } diff --git a/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/GeoTemplateTest.java b/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/GeoTemplateTest.java index 1545ca8c..4e5ca18b 100644 --- a/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/GeoTemplateTest.java +++ b/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/GeoTemplateTest.java @@ -25,12 +25,12 @@ import org.junit.Test; import org.springframework.social.twitter.api.Place; -import org.springframework.social.twitter.api.Place.GeoPoint; -import org.springframework.social.twitter.api.Place.Geometry; -import org.springframework.social.twitter.api.Place.GeometryType; import org.springframework.social.twitter.api.PlacePrototype; import org.springframework.social.twitter.api.PlaceType; import org.springframework.social.twitter.api.SimilarPlaces; +import org.springframework.social.twitter.api.Place.GeoPoint; +import org.springframework.social.twitter.api.Place.Geometry; +import org.springframework.social.twitter.api.Place.GeometryType; public class GeoTemplateTest extends AbstractTwitterApiTest { diff --git a/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/MockStream.java b/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/MockStream.java index 4f8ef65a..54169179 100644 --- a/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/MockStream.java +++ b/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/MockStream.java @@ -17,6 +17,7 @@ import org.springframework.social.twitter.api.StreamingException; + public class MockStream implements StreamReader { private boolean open = true; private int messagesInStream; diff --git a/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/TwitterApiUriBuilderTest.java b/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/TwitterApiUriBuilderTest.java new file mode 100644 index 00000000..6e9d8116 --- /dev/null +++ b/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/TwitterApiUriBuilderTest.java @@ -0,0 +1,174 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.junit.Assert.assertThat; + +import java.net.URI; +import java.util.Arrays; + +import org.junit.Test; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +/** + * @author Hudson Mendes + */ +public class TwitterApiUriBuilderTest { + + @Test + public void build_standardHost() { + String anyResource = "any.json"; + URI standardResult = new TwitterApiBuilderForUri().withResource(anyResource).build(); + assertThat(standardResult.getHost(), equalTo("api.twitter.com")); + } + + @Test + public void build_automaticHosts() { + URI result1 = new TwitterApiBuilderForUri().withResource(TwitterApiUriResourceForAdvertising.ACCOUNTS).build(); + URI result2 = new TwitterApiBuilderForUri().withResource(TwitterApiUriResourceForStandard.BLOCKS).build(); + assertThat(result1.getHost(), not(equalTo(result2.getHost()))); + } + + @Test + public void build_specificHosts() { + String anyResource = "any.json"; + URI result1 = new TwitterApiBuilderForUri().forStandardApi().withResource(anyResource).build(); + URI result2 = new TwitterApiBuilderForUri().forAdCampaignsApi().withResource(anyResource).build(); + assertThat(result1.getHost(), not(equalTo(result2.getHost()))); + } + + @Test(expected = IllegalArgumentException.class) + public void build_fails_missingResource() { + new TwitterApiBuilderForUri().build(); + } + + @Test(expected = IllegalArgumentException.class) + public void build_fails_invalidResource() { + new TwitterApiBuilderForUri().withResource((String) null).build(); + } + + @Test + public void build_resourceOnly() { + String resource1 = "standard_api_resource_1.js"; + URI result1 = new TwitterApiBuilderForUri().forStandardApi().withResource(resource1).build(); + + String resource2 = "standard_api_resource_2.js"; + URI result2 = new TwitterApiBuilderForUri().forStandardApi().withResource(resource2).build(); + + assertThat(versionFreePath(result1.getPath()), equalTo(resource1)); + assertThat(versionFreePath(result2.getPath()), equalTo(resource2)); + assertThat(result1.getPath(), not(equalTo(result2.getPath()))); + } + + @Test + public void build_oneArgument() { + String anyResource = "standard_api_resource.json"; + String argName = "argument_name"; + String argValue = "argument_value"; + URI result = new TwitterApiBuilderForUri() + .withResource(anyResource) + .withArgument(argName, argValue) + .build(); + + assertThat(result, not(nullValue())); + assertThat(versionFreePath(result.getPath()), equalTo(anyResource)); + assertThat(result.getQuery(), equalTo(argName + "=" + argValue)); + } + + @Test + public void build_multipleArguments_chained() { + String anyResource = "standard_api_resource.json"; + URI result = new TwitterApiBuilderForUri() + .withResource(anyResource) + .withArgument("argument_name_1", "argument_value_1") + .withArgument("argument_name_2", "argument_value_2") + .withArgument("argument_name_3", "argument_value_3") + .build(); + + String chainedQuery = + "argument_name_1" + "=" + "argument_value_1" + "&" + + "argument_name_2" + "=" + "argument_value_2" + "&" + + "argument_name_3" + "=" + "argument_value_3"; + + assertThat(result, not(nullValue())); + assertThat(versionFreePath(result.getPath()), equalTo(anyResource)); + assertThat(result.getQuery(), equalTo(chainedQuery)); + } + + @Test + public void build_multipleArguments_array() { + String anyResource = "standard_api_resource.json"; + + MultiValueMap arguments = new LinkedMultiValueMap<>(); + arguments.add("argument_name_A", "argument_value_A"); + arguments.add("argument_name_B", "argument_value_B"); + arguments.add("argument_name_C", "argument_value_C"); + + URI result = new TwitterApiBuilderForUri() + .withResource(anyResource) + .withArgument(arguments) + .build(); + + String chainedQuery = + "argument_name_A" + "=" + "argument_value_A" + "&" + + "argument_name_B" + "=" + "argument_value_B" + "&" + + "argument_name_C" + "=" + "argument_value_C"; + + assertThat(result, not(nullValue())); + assertThat(versionFreePath(result.getPath()), equalTo(anyResource)); + assertThat(result.getQuery(), equalTo(chainedQuery)); + } + + @Test + public void build_implicitArguments_array() { + String anyResource = "user/:implicit_id/standard_api_resource.json"; + String implicitArgumentName = "implicit_id"; + String implicitArgumentValue = "831hgk"; + + MultiValueMap arguments = new LinkedMultiValueMap<>(); + arguments.add(implicitArgumentName, implicitArgumentValue); + + URI result = new TwitterApiBuilderForUri() + .withResource(anyResource) + .withArgument(arguments) + .build(); + + String expectedQuery = anyResource.replace(":" + implicitArgumentName, implicitArgumentValue); + assertThat(result, not(nullValue())); + assertThat(versionFreePath(result.getPath()), equalTo(expectedQuery)); + } + + private String versionFreePath(String path) { + String splitter = "/"; + StringBuilder newPath = new StringBuilder(); + Arrays.stream(path.split(splitter)) + .filter(frag -> !frag.isEmpty()) + .skip(1) + .forEach(frag -> { + if (newPath.length() != 0) { + newPath.append(splitter); + } + + newPath.append(frag); + }); + + return newPath.toString(); + } +} diff --git a/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/TwitterTemplateTest.java b/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/TwitterTemplateTest.java index 3239426a..01dd3c0d 100644 --- a/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/TwitterTemplateTest.java +++ b/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/TwitterTemplateTest.java @@ -18,6 +18,7 @@ import static org.junit.Assert.*; import org.junit.Test; +import org.springframework.social.twitter.api.impl.TwitterTemplate; public class TwitterTemplateTest { diff --git a/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/UserTemplateTest.java b/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/UserTemplateTest.java index 0571d15a..1e6e3623 100644 --- a/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/UserTemplateTest.java +++ b/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/UserTemplateTest.java @@ -30,6 +30,7 @@ import org.springframework.social.twitter.api.ResourceFamily; import org.springframework.social.twitter.api.SuggestionCategory; import org.springframework.social.twitter.api.TwitterProfile; +import org.springframework.social.twitter.api.impl.AccountSettingsData; /** * @author Craig Walls diff --git a/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/advertising/AdvertisingTemplateTest.java b/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/advertising/AdvertisingTemplateTest.java new file mode 100644 index 00000000..89058e79 --- /dev/null +++ b/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/advertising/AdvertisingTemplateTest.java @@ -0,0 +1,265 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import static org.junit.Assert.assertEquals; +import static org.springframework.http.HttpMethod.GET; +import static org.springframework.http.MediaType.APPLICATION_JSON; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.method; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo; +import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess; + +import java.io.UnsupportedEncodingException; +import java.math.BigDecimal; +import java.math.MathContext; +import java.net.URLEncoder; +import java.time.LocalDateTime; +import java.time.Month; +import java.util.List; +import java.util.TimeZone; + +import org.junit.Assert; +import org.junit.Test; +import org.springframework.social.twitter.api.advertising.AdvertisingAccount; +import org.springframework.social.twitter.api.advertising.AdvertisingAccountPermissions; +import org.springframework.social.twitter.api.advertising.AdvertisingAccountSorting; +import org.springframework.social.twitter.api.advertising.ApprovalStatus; +import org.springframework.social.twitter.api.advertising.FeatureKey; +import org.springframework.social.twitter.api.advertising.FundingInstrument; +import org.springframework.social.twitter.api.advertising.FundingInstrumentType; +import org.springframework.social.twitter.api.advertising.SortDirection; +import org.springframework.social.twitter.api.impl.AbstractTwitterApiTest; +import org.springframework.social.twitter.api.impl.DataListHolder; + +/** + * @author Hudson mendes + */ +public class AdvertisingTemplateTest extends AbstractTwitterApiTest { + + @Test + public void getAccounts() { + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/accounts?with_deleted=true&sort_by=updated_at-desc")) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("ad-accounts"), APPLICATION_JSON)); + + + final DataListHolder accounts = twitter.advertisingOperations().getAccounts( + new AdvertisingAccountQueryBuilder() + .includeDeleted(true) + .sortBy(AdvertisingAccountSorting.updated_at, SortDirection.desc)); + + assertAdvertisingAccountContents(accounts.getList()); + } + + @Test + public void getAccount() { + final String mockedAccountId = "gq0vqj"; + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/accounts/" + mockedAccountId)) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("ad-accounts-single"), APPLICATION_JSON)); + + + final AdvertisingAccount account = twitter.advertisingOperations().getAccount(mockedAccountId); + + assertAdvertisingAccountSingleContents(account); + } + + private void assertAdvertisingAccountSingleContents(AdvertisingAccount account) { + Assert.assertNotNull(account); + Assert.assertEquals("gq0vqj", account.getId()); + Assert.assertEquals("Account for the user @unkown", account.getName()); + Assert.assertEquals("abababababababababababababababab", account.getSalt()); + Assert.assertEquals(TimeZone.getTimeZone("America/Los_Angeles"), account.getTimeZone()); + Assert.assertEquals("2015-04-13T20:42:39", account.getCreatedAt().toString()); + Assert.assertEquals("2015-07-13T20:17:34", account.getUpdatedAt().toString()); + } + + @Test + public void getAccountFeatures() { + final String mockedAccountId = "gq0vqj"; + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/accounts/" + mockedAccountId + "/features")) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("ad-accounts-features"), APPLICATION_JSON)); + + + final DataListHolder features = twitter.advertisingOperations().getAccountFeatures( + mockedAccountId, + new AdvertisingAccountFeatureQueryBuilder()); + + assertAdvertisingAccountFeatureContents(features.getList()); + } + + @Test + public void getAccountFeaturesWithParams() { + final String mockedAccountId = "gq0vqj"; + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/accounts/" + mockedAccountId + + "/features?feature_keys=MOBILE_CONVERSION_TRANSACTION_VALUE%2CVIDEO_VIEWS_OBJECTIVE")) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("ad-accounts-features"), APPLICATION_JSON)); + + + final DataListHolder features = twitter.advertisingOperations().getAccountFeatures( + mockedAccountId, + new AdvertisingAccountFeatureQueryBuilder() + .withFeatureKey(FeatureKey.MOBILE_CONVERSION_TRANSACTION_VALUE, FeatureKey.VIDEO_VIEWS_OBJECTIVE)); + + assertAdvertisingAccountFeatureContents(features.getList()); + } + + private void assertAdvertisingAccountFeatureContents(List features) { + Assert.assertNotNull(features); + assertEquals(2, features.size()); + + assertEquals("MOBILE_CONVERSION_TRANSACTION_VALUE", features.get(0)); + assertEquals("INSTALLED_APP_CATEGORY_TARGETING", features.get(1)); + } + + @Test + public void getAccountPermissions() { + final String mockedAccountId = "gq0vqj"; + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/accounts/" + mockedAccountId + "/authenticated_user_access")) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("ad-accounts-permissions"), APPLICATION_JSON)); + + + final AdvertisingAccountPermissions permissions = twitter.advertisingOperations().getAccountPermissions(mockedAccountId); + + Assert.assertNotNull(permissions); + assertEquals("390472547", permissions.getUserId().toString()); + assertEquals("ACCOUNT_ADMIN", permissions.getPermissions().get(0).name()); + } + + @Test + public void getFundingInstruments() throws UnsupportedEncodingException { + final String mockedAccountId = "hkk5"; + final String mockedFundingInstrumentId1 = "h2459"; + final String mockedFundingInstrumentId2 = "95jll"; + mockServer + .expect(requestTo( + "https://ads-api.twitter.com/0/accounts/" + mockedAccountId + "/funding_instruments" + + "?funding_instrument_ids=" + URLEncoder.encode(mockedFundingInstrumentId1 + "," + mockedFundingInstrumentId2, UTF8) + + "&with_deleted=false")) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("ad-funding-instruments"), APPLICATION_JSON)); + + final DataListHolder fundingInstruments = twitter.advertisingOperations().getFundingInstruments( + mockedAccountId, + new FundingInstrumentQueryBuilder() + .withFundingInstruments(mockedFundingInstrumentId1, mockedFundingInstrumentId2) + .includeDeleted(false)); + + assertFundingInstrumentContents(fundingInstruments.getList()); + } + + @Test + public void getFundingInstrument() throws UnsupportedEncodingException { + final String mockedAccountId = "hkk5"; + final String mockedFundingInstrumentId = "h2459"; + mockServer + .expect(requestTo( + "https://ads-api.twitter.com/0/accounts/" + mockedAccountId + "/funding_instruments/" + mockedFundingInstrumentId)) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("ad-funding-instruments-single"), APPLICATION_JSON)); + + final FundingInstrument fundingInstrument = twitter + .advertisingOperations() + .getFundingInstrument(mockedAccountId, mockedFundingInstrumentId); + + assertSingleFundingInstrumentContents(fundingInstrument); + } + + private void assertSingleFundingInstrumentContents(FundingInstrument fundingInstrument) { + Assert.assertNotNull(fundingInstrument); + + Assert.assertEquals("hxcnv", fundingInstrument.getId()); + Assert.assertEquals("gq0vqj", fundingInstrument.getAccountId()); + Assert.assertEquals(FundingInstrumentType.CREDIT_CARD, fundingInstrument.getType()); + Assert.assertEquals("(no payment method has been set up yet)", fundingInstrument.getDescription()); + Assert.assertEquals("USD", fundingInstrument.getCurrency()); + Assert.assertEquals(false, fundingInstrument.isDeleted()); + Assert.assertEquals(false, fundingInstrument.isCancelled()); + Assert.assertNull(fundingInstrument.getCreditRemaining()); + Assert.assertEquals(BigDecimal.valueOf(0), fundingInstrument.getCreditLimit()); + Assert.assertEquals("2015-04-13T20:42:39", fundingInstrument.getStartTime().toString()); + Assert.assertNull(fundingInstrument.getEndTime()); + Assert.assertEquals("2015-04-13T20:42:39", fundingInstrument.getCreatedAt().toString()); + Assert.assertEquals("2015-04-13T20:42:39", fundingInstrument.getUpdatedAt().toString()); + } + + private void assertAdvertisingAccountContents(List accounts) { + assertEquals(2, accounts.size()); + + assertEquals("l0l0l0", accounts.get(0).getId()); + assertEquals("h1234jasd", accounts.get(0).getName()); + assertEquals("699169a7693e571000000fef0ef0ef09", accounts.get(0).getSalt()); + assertEquals(ApprovalStatus.ACCEPTED, accounts.get(0).getApprovalStatus()); + assertEquals(TimeZone.getTimeZone("America/Los_Angeles"), accounts.get(0).getTimeZone()); + assertEquals(LocalDateTime.of(2013, Month.MAY, 22, 07, 00, 00), accounts.get(0).getTimeZoneSwitchAt()); + assertEquals(LocalDateTime.of(2013, Month.MARCH, 05, 21, 57, 11), accounts.get(0).getCreatedAt()); + assertEquals(LocalDateTime.of(2015, Month.FEBRUARY, 21, 03, 15, 30), accounts.get(0).getUpdatedAt()); + assertEquals(false, accounts.get(0).isDeleted()); + + assertEquals("l1l1l1", accounts.get(1).getId()); + assertEquals("test02483", accounts.get(1).getName()); + assertEquals("abababababababababababababababab", accounts.get(1).getSalt()); + assertEquals(ApprovalStatus.ACCEPTED, accounts.get(1).getApprovalStatus()); + assertEquals(TimeZone.getTimeZone("America/Los_Angeles"), accounts.get(1).getTimeZone()); + assertEquals(LocalDateTime.of(2013, Month.JANUARY, 01, 01, 01, 01), accounts.get(1).getTimeZoneSwitchAt()); + assertEquals(LocalDateTime.of(2011, Month.JANUARY, 01, 01, 01, 01), accounts.get(1).getCreatedAt()); + assertEquals(LocalDateTime.of(2012, Month.JANUARY, 01, 01, 01, 01), accounts.get(1).getUpdatedAt()); + assertEquals(false, accounts.get(0).isDeleted()); + } + + private void assertFundingInstrumentContents(List fundingInstruments) { + assertEquals(2, fundingInstruments.size()); + + assertEquals("hw6ie", fundingInstruments.get(0).getId()); + assertEquals(FundingInstrumentType.CREDIT_CARD, fundingInstruments.get(0).getType()); + assertEquals("hkk5", fundingInstruments.get(0).getAccountId()); + assertEquals("MasterCard ending in 1234", fundingInstruments.get(0).getDescription()); + assertEquals("USD", fundingInstruments.get(0).getCurrency()); + assertEquals(new BigDecimal(1000.00), fundingInstruments.get(0).getCreditLimit()); + assertEquals(null, fundingInstruments.get(0).getCreditRemaining()); + assertEquals(new BigDecimal(100.00), fundingInstruments.get(0).getFundedAmount()); + assertEquals(LocalDateTime.of(2012, Month.NOVEMBER, 8, 02, 31, 46), fundingInstruments.get(0).getStartTime()); + assertEquals(null, fundingInstruments.get(0).getEndTime()); + assertEquals(LocalDateTime.of(2012, Month.NOVEMBER, 8, 02, 31, 46), fundingInstruments.get(0).getCreatedAt()); + assertEquals(LocalDateTime.of(2012, Month.NOVEMBER, 20, 23, 20, 35), fundingInstruments.get(0).getUpdatedAt()); + assertEquals(false, fundingInstruments.get(0).isCancelled()); + assertEquals(true, fundingInstruments.get(0).isDeleted()); + + assertEquals("i1234", fundingInstruments.get(1).getId()); + assertEquals(FundingInstrumentType.CREDIT_LINE, fundingInstruments.get(1).getType()); + assertEquals("hkk5", fundingInstruments.get(1).getAccountId()); + assertEquals("FakeNike - Credit Line", fundingInstruments.get(1).getDescription()); + assertEquals("GBP", fundingInstruments.get(1).getCurrency()); + assertEquals(new BigDecimal(150000.00).round(MathContext.DECIMAL32), fundingInstruments.get(1).getCreditLimit()); + assertEquals(new BigDecimal(123661.919751).round(MathContext.DECIMAL32), fundingInstruments.get(1).getCreditRemaining()); + assertEquals(new BigDecimal(0.00).round(MathContext.DECIMAL32), fundingInstruments.get(1).getFundedAmount()); + assertEquals(LocalDateTime.of(2013, Month.MAY, 30, 04, 00, 00), fundingInstruments.get(1).getStartTime()); + assertEquals(null, fundingInstruments.get(1).getEndTime()); + assertEquals(LocalDateTime.of(2013, Month.MAY, 30, 18, 16, 38), fundingInstruments.get(1).getCreatedAt()); + assertEquals(LocalDateTime.of(2013, Month.MAY, 30, 18, 16, 38), fundingInstruments.get(1).getUpdatedAt()); + assertEquals(false, fundingInstruments.get(1).isCancelled()); + assertEquals(false, fundingInstruments.get(1).isDeleted()); + } + +} diff --git a/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/advertising/CampaignTemplateTest.java b/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/advertising/CampaignTemplateTest.java new file mode 100644 index 00000000..c611b7cb --- /dev/null +++ b/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/advertising/CampaignTemplateTest.java @@ -0,0 +1,260 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import static org.hamcrest.CoreMatchers.hasItem; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.Matchers.empty; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.springframework.http.HttpMethod.DELETE; +import static org.springframework.http.HttpMethod.GET; +import static org.springframework.http.HttpMethod.POST; +import static org.springframework.http.HttpMethod.PUT; +import static org.springframework.http.MediaType.APPLICATION_JSON; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.content; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.method; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo; +import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess; + +import java.io.UnsupportedEncodingException; +import java.math.BigDecimal; +import java.net.URLEncoder; +import java.time.LocalDateTime; +import java.time.Month; +import java.time.ZoneOffset; +import java.time.temporal.ChronoUnit; +import java.util.List; + +import org.junit.Test; +import org.springframework.social.twitter.api.advertising.Campaign; +import org.springframework.social.twitter.api.advertising.ReasonNotServable; +import org.springframework.social.twitter.api.impl.AbstractTwitterApiTest; +import org.springframework.social.twitter.api.impl.DataListHolder; + +/** + * @author Hudson mendes + */ +public class CampaignTemplateTest extends AbstractTwitterApiTest { + + @Test + public void getCampaign() { + String mockedAccountId = "0ga0yn"; + String mockedCampaignId = "92ph"; + mockServer + .expect(requestTo( + "https://ads-api.twitter.com/0/accounts/" + mockedAccountId + "/campaigns" + + "/" + mockedCampaignId + + "?with_deleted=true")) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("ad-campaigns-single"), APPLICATION_JSON)); + + Campaign campaign = twitter.campaignOperations().getCampaign(mockedAccountId, mockedCampaignId); + assertSingleCampaignContents(campaign); + } + + @Test + public void getCampaigns() throws UnsupportedEncodingException { + String mockedAccountId = "0ga0yn"; + String mockedCampaignId1 = "x945j"; + String mockedCampaignId2 = "1jvrj"; + String mockedFundingInstrumentId1 = "jrtjh4"; + String mockedFundingInstrumentId2 = "ekffd"; + mockServer + .expect(requestTo( + "https://ads-api.twitter.com/0/accounts/" + mockedAccountId + "/campaigns" + + "?campaign_ids=" + URLEncoder.encode(mockedCampaignId1 + "," + mockedCampaignId2, UTF8) + + "&funding_instrument_ids=" + URLEncoder.encode(mockedFundingInstrumentId1 + "," + mockedFundingInstrumentId2, UTF8) + + "&with_deleted=false")) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("ad-campaigns"), APPLICATION_JSON)); + + DataListHolder campaigns = twitter.campaignOperations().getCampaigns( + mockedAccountId, + new CampaignQueryBuilder() + .withCampaigns(mockedCampaignId1, mockedCampaignId2) + .withFundingInstruments(mockedFundingInstrumentId1, mockedFundingInstrumentId2) + .includeDeleted(false)); + + assertCampaignContents(campaigns.getList()); + } + + @Test + public void createCampaign() throws UnsupportedEncodingException { + String doesntMatterString = "doesn-matter"; + BigDecimal doesntMatterDecimal = new BigDecimal(1.00); + LocalDateTime doesntMatterDate = LocalDateTime.now(); + Boolean doesntMatterBool = false; + String mockedAccountId = "1ga1yn"; + + String chainedPostContent = + "name=" + + doesntMatterString + + "&" + + + "currency=" + + doesntMatterString + + "&" + + + "funding_instrument_id=" + + doesntMatterString + + "&" + + + "total_budget_amount_local_micro=" + + doesntMatterDecimal.multiply(new BigDecimal(1000000L)) + + "&" + + + "daily_budget_amount_local_micro=" + + doesntMatterDecimal.add(new BigDecimal(15)).multiply(new BigDecimal(1000000L)) + + "&" + + + "start_time=" + + URLEncoder.encode(doesntMatterDate.toInstant(ZoneOffset.UTC).truncatedTo(ChronoUnit.SECONDS).toString(), "UTF-8") + + "&" + + + "end_time=" + + URLEncoder.encode(doesntMatterDate.plusDays(1).toInstant(ZoneOffset.UTC).truncatedTo(ChronoUnit.SECONDS).toString(), + "UTF-8") + "&" + + "standard_delivery=" + doesntMatterBool + "&" + + "paused=" + !doesntMatterBool + "&" + + "deleted=" + !doesntMatterBool; + + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/accounts/" + mockedAccountId + "/campaigns")) + .andExpect(method(POST)) + .andExpect(content().string(chainedPostContent)) + .andRespond(withSuccess(jsonResource("ad-campaigns-single"), APPLICATION_JSON)); + + Campaign campaign = twitter.campaignOperations().createCampaign( + mockedAccountId, + new CampaignFormBuilder() + .withName(doesntMatterString) + .withCurrency(doesntMatterString) + .withFundingInstrument(doesntMatterString) + .withBudget(doesntMatterDecimal.toString(), doesntMatterDecimal.add(new BigDecimal(15)).toString()) + .activeBetween(doesntMatterDate, doesntMatterDate.plusDays(1)) + .withStandardDelivery(doesntMatterBool) + .paused() + .deleted()); + + assertSingleCampaignContents(campaign); + } + + @Test + public void updateCampaign() throws UnsupportedEncodingException { + String doesntMatterString = "doesn-matter-altered"; + BigDecimal doesntMatterDecimal = new BigDecimal(2.00); + LocalDateTime doesntMatterDate = LocalDateTime.now(); + Boolean doesntMatterBool = false; + String mockedCampaignId = "92ph"; + String mockedAccountId = "1ga1yn"; + + String chainedPostContent = + "name=" + doesntMatterString + "&" + + "currency=" + doesntMatterString + "&" + + "funding_instrument_id=" + doesntMatterString + "&" + + "total_budget_amount_local_micro=" + doesntMatterDecimal.multiply(new BigDecimal(1000000L)) + "&" + + "daily_budget_amount_local_micro=" + doesntMatterDecimal.add(new BigDecimal(3)).multiply(new BigDecimal(1000000L)) + "&" + + "start_time=" + + URLEncoder.encode(doesntMatterDate.toInstant(ZoneOffset.UTC).truncatedTo(ChronoUnit.SECONDS).toString(), "UTF-8") + + "&" + + + "end_time=" + + URLEncoder.encode(doesntMatterDate.plusDays(3).toInstant(ZoneOffset.UTC).truncatedTo(ChronoUnit.SECONDS).toString(), + "UTF-8") + "&" + + "standard_delivery=" + !doesntMatterBool + "&" + + "paused=" + doesntMatterBool + "&" + + "deleted=" + doesntMatterBool; + + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/accounts/" + mockedAccountId + "/campaigns/" + mockedCampaignId)) + .andExpect(method(PUT)) + .andExpect(content().string(chainedPostContent)) + .andRespond(withSuccess()); + + twitter.campaignOperations().updateCampaign( + mockedAccountId, + mockedCampaignId, + new CampaignFormBuilder() + .withName(doesntMatterString) + .withCurrency(doesntMatterString) + .withFundingInstrument(doesntMatterString) + .withBudget(doesntMatterDecimal.toString(), doesntMatterDecimal.add(new BigDecimal(3)).toString()) + .activeBetween(doesntMatterDate, doesntMatterDate.plusDays(3)) + .withStandardDelivery(!doesntMatterBool) + .unpaused() + .active()); + } + + @Test + public void deleteCampaign() { + String mockedAccountId = "0ga0yn"; + String mockedCampaignId = "92ph"; + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/accounts/" + mockedAccountId + "/campaigns/" + mockedCampaignId)) + .andExpect(method(DELETE)) + .andRespond(withSuccess()); + + twitter.campaignOperations().deleteCampaign(mockedAccountId, mockedCampaignId); + } + + private void assertCampaignContents(List campaigns) { + assertEquals(1, campaigns.size()); + + assertEquals("1850jm", campaigns.get(0).getId()); + assertEquals("C1-oldlalala-generic", campaigns.get(0).getName()); + assertEquals("0ga0yn", campaigns.get(0).getAccountId()); + assertEquals("USD", campaigns.get(0).getCurrency()); + + assertEquals(new BigDecimal(45.00), campaigns.get(0).getTotalBudget()); + assertEquals(new BigDecimal(10.00), campaigns.get(0).getDailyBudget()); + + assertEquals(LocalDateTime.of(2014, Month.MAY, 15, 00, 12, 00), campaigns.get(0).getStartTime()); + assertEquals(LocalDateTime.of(2014, Month.MAY, 16, 22, 00, 00), campaigns.get(0).getEndTime()); + assertEquals(LocalDateTime.of(2014, Month.MAY, 15, 01, 17, 47), campaigns.get(0).getCreatedAt()); + assertEquals(LocalDateTime.of(2014, Month.MAY, 16, 20, 41, 38), campaigns.get(0).getUpdatedAt()); + + assertThat(campaigns.get(0).getReasonsNotServable(), not(hasItem(ReasonNotServable.DELETED))); + assertThat(campaigns.get(0).getReasonsNotServable(), hasItem(ReasonNotServable.EXPIRED)); + assertThat(campaigns.get(0).getReasonsNotServable(), hasItem(ReasonNotServable.PAUSED_BY_ADVERTISER)); + + assertEquals(true, campaigns.get(0).isStandardDelivery()); + assertEquals(false, campaigns.get(0).isServable()); + assertEquals(true, campaigns.get(0).isPaused()); + assertEquals(false, campaigns.get(0).isDeleted()); + } + + private void assertSingleCampaignContents(Campaign campaign) { + assertEquals("1ga1yn", campaign.getAccountId()); + assertEquals("92ph", campaign.getId()); + assertEquals("My First Campaign", campaign.getName()); + assertEquals("USD", campaign.getCurrency()); + assertEquals("yyyy", campaign.getFundingInstrumentId()); + + assertEquals(new BigDecimal(500.00), campaign.getTotalBudget()); + assertEquals(new BigDecimal(40.00), campaign.getDailyBudget()); + + assertEquals(LocalDateTime.of(2015, Month.FEBRUARY, 9, 00, 00, 00), campaign.getStartTime()); + assertEquals(null, campaign.getEndTime()); + + assertThat(campaign.getReasonsNotServable(), empty()); + assertEquals(true, campaign.isStandardDelivery()); + assertEquals(false, campaign.isPaused()); + assertEquals(true, campaign.isServable()); + assertEquals(false, campaign.isDeleted()); + } + +} diff --git a/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/advertising/DataListHolderTest.java b/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/advertising/DataListHolderTest.java new file mode 100644 index 00000000..b2c32b6e --- /dev/null +++ b/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/advertising/DataListHolderTest.java @@ -0,0 +1,49 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import java.io.IOException; + +import org.junit.Assert; +import org.junit.Test; +import org.springframework.core.io.ClassPathResource; +import org.springframework.social.twitter.api.advertising.Campaign; +import org.springframework.social.twitter.api.impl.DataListHolder; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; + +/** + * @author Hudson Mendes + */ +public class DataListHolderTest { + + @Test + public void pagingParse() throws JsonParseException, JsonMappingException, IOException { + ObjectMapper mapper = new ObjectMapper(); + mapper.addMixIn(Campaign.class, CampaignMixin.class); + ClassPathResource resource = new ClassPathResource("ad-campaigns.json", getClass()); + + DataListHolder holder = mapper.readValue( + resource.getFile(), + new TypeReference>() {}); + + Assert.assertEquals(new Long("71"), holder.getTotalCount()); + Assert.assertEquals("18l3ms5c", holder.getNextCursor()); + } +} diff --git a/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/advertising/LineItemTemplateTest.java b/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/advertising/LineItemTemplateTest.java new file mode 100644 index 00000000..0661c388 --- /dev/null +++ b/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/advertising/LineItemTemplateTest.java @@ -0,0 +1,279 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.springframework.http.HttpMethod.DELETE; +import static org.springframework.http.HttpMethod.GET; +import static org.springframework.http.HttpMethod.POST; +import static org.springframework.http.HttpMethod.PUT; +import static org.springframework.http.MediaType.APPLICATION_JSON; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.content; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.method; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo; +import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess; + +import java.io.UnsupportedEncodingException; +import java.math.BigDecimal; +import java.math.MathContext; +import java.net.URLEncoder; +import java.time.LocalDateTime; +import java.time.Month; +import java.util.ArrayList; +import java.util.List; + +import org.hamcrest.CoreMatchers; +import org.junit.Test; +import org.springframework.social.twitter.api.advertising.AdvertisingObjective; +import org.springframework.social.twitter.api.advertising.AdvertisingPlacement; +import org.springframework.social.twitter.api.advertising.AdvertisingProductType; +import org.springframework.social.twitter.api.advertising.AdvertisingSentiment; +import org.springframework.social.twitter.api.advertising.BidUnit; +import org.springframework.social.twitter.api.advertising.LineItem; +import org.springframework.social.twitter.api.advertising.LineItemOptimization; +import org.springframework.social.twitter.api.advertising.LineItemPlacements; +import org.springframework.social.twitter.api.impl.AbstractTwitterApiTest; +import org.springframework.social.twitter.api.impl.DataListHolder; + +/** + * @author Hudson mendes + */ +public class LineItemTemplateTest extends AbstractTwitterApiTest { + + @Test + public void getLineItem() { + String mockedAccountId = "hkk5"; + String mockedLineItem = "5woz"; + mockServer + .expect(requestTo( + "https://ads-api.twitter.com/0/accounts/" + mockedAccountId + "/line_items" + + "/" + mockedLineItem + + "?with_deleted=true")) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("line-items-single"), APPLICATION_JSON)); + + LineItem lineItem = twitter.lineItemOperations().getLineItem(mockedAccountId, mockedLineItem); + assertSingleLineItemContents(lineItem); + } + + @Test + public void getLineItems() throws UnsupportedEncodingException { + String mockedAccountId = "hkk5"; + String mockedCampaignId1 = "x945j"; + String mockedCampaignId2 = "1jvrj"; + String mockedFundingInstrumentId1 = "jrtjh4"; + String mockedFundingInstrumentId2 = "ekffd"; + String mockedLineItemId1 = "z9j"; + String mockedLineItemId2 = "045k"; + mockServer + .expect(requestTo( + "https://ads-api.twitter.com/0/accounts/" + mockedAccountId + "/line_items" + + "?campaign_ids=" + URLEncoder.encode(mockedCampaignId1 + "," + mockedCampaignId2, UTF8) + + "&funding_instrument_ids=" + URLEncoder.encode(mockedFundingInstrumentId1 + "," + mockedFundingInstrumentId2, UTF8) + + "&line_item_ids=" + URLEncoder.encode(mockedLineItemId1 + "," + mockedLineItemId2, UTF8) + + "&with_deleted=false")) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("line-items"), APPLICATION_JSON)); + + DataListHolder lineItems = twitter.lineItemOperations().getLineItems( + mockedAccountId, + new LineItemQueryBuilder() + .withCampaigns(mockedCampaignId1, mockedCampaignId2) + .withFundingInstruments(mockedFundingInstrumentId1, mockedFundingInstrumentId2) + .withLineItems(mockedLineItemId1, mockedLineItemId2) + .includeDeleted(false)); + + assertLineItemContents(lineItems.getList()); + } + + @Test + public void createLineItem() throws UnsupportedEncodingException { + String mockedAccountId = "hkk5"; + String doesntMatterString = "doesn-matter-altered"; + BigDecimal doesntMatterDecimal = new BigDecimal(1.00); + Boolean doesntMatterBool = false; + + String chainedPostContent = "campaign_id=" + doesntMatterString + "&" + + "name=" + doesntMatterString + "&" + + "objective=" + AdvertisingObjective.APP_INSTALLS + "&" + + "include_sentiment=" + AdvertisingSentiment.POSITIVE_ONLY + "&" + + "optimization=" + LineItemOptimization.WEBSITE_CONVERSIONS + "&" + + "bid_unit=" + BidUnit.LINK_CLICK + "&" + + "product_type=" + AdvertisingProductType.PROMOTED_ACCOUNT + "&" + + "placements=" + URLEncoder.encode(AdvertisingPlacement.ALL_ON_TWITTER + "," + AdvertisingPlacement.PUBLISHER_NETWORK, UTF8) + "&" + + "automatically_select_bid=" + doesntMatterBool + "&" + + "paused=" + !doesntMatterBool + "&" + + "deleted=" + doesntMatterBool + "&" + + "total_budget_amount_local_micro=" + doesntMatterDecimal.multiply(new BigDecimal(1000000L)) + "&" + + "bid_amount_local_micro=" + doesntMatterDecimal.multiply(new BigDecimal(1000000L)); + + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/accounts/" + mockedAccountId + "/line_items")) + .andExpect(method(POST)) + .andExpect(content().string(chainedPostContent)) + .andRespond(withSuccess(jsonResource("line-items-single"), APPLICATION_JSON)); + + LineItem lineItem = twitter.lineItemOperations().createLineItem( + mockedAccountId, + new LineItemFormBuilder() + .forCampaign(doesntMatterString) + .named(doesntMatterString) + .totalBudget(doesntMatterDecimal.toString()) + .bidAmount(doesntMatterDecimal.toString()) + .bidUnit(BidUnit.LINK_CLICK) + .productType(AdvertisingProductType.PROMOTED_ACCOUNT) + .placedOn(AdvertisingPlacement.ALL_ON_TWITTER, AdvertisingPlacement.PUBLISHER_NETWORK) + .objective(AdvertisingObjective.APP_INSTALLS) + .optimizedFor(LineItemOptimization.WEBSITE_CONVERSIONS) + .includingSentiment(AdvertisingSentiment.POSITIVE_ONLY) + .paused() + .active()); + + assertSingleLineItemContents(lineItem); + } + + @Test + public void updateLineItem() { + String mockedAccountId = "hkk5"; + String mockedLineItemId = "l13r"; + String doesntMatterString = "doesn-matter-altered"; + BigDecimal doesntMatterDecimal = new BigDecimal(2.00); + Boolean doesntMatterBool = true; + + String chainedPostContent = "name=" + doesntMatterString + "&" + + "include_sentiment=" + AdvertisingSentiment.ALL + "&" + + "optimization=" + LineItemOptimization.DEFAULT + "&" + + "automatically_select_bid=" + !doesntMatterBool + "&" + + "paused=" + !doesntMatterBool + "&" + + "deleted=" + doesntMatterBool + "&" + + "bid_amount_local_micro=" + doesntMatterDecimal.multiply(new BigDecimal(1000000L)); + + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/accounts/" + mockedAccountId + "/line_items/" + mockedLineItemId)) + .andExpect(method(PUT)) + .andExpect(content().string(chainedPostContent)) + .andRespond(withSuccess(jsonResource("line-items-single"), APPLICATION_JSON)); + + twitter.lineItemOperations().updateLineItem( + mockedAccountId, + mockedLineItemId, + new LineItemFormBuilder() + .named(doesntMatterString) + .bidAmount(doesntMatterDecimal.toString()) + .optimizedFor(LineItemOptimization.DEFAULT) + .includingSentiment(AdvertisingSentiment.ALL) + .unpaused() + .deleted()); + } + + @Test + public void deleteLineItem() { + String mockedAccountId = "0ga0yn"; + String mockedLineItemId = "92ph"; + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/accounts/" + mockedAccountId + "/line_items/" + mockedLineItemId)) + .andExpect(method(DELETE)) + .andRespond(withSuccess()); + + twitter.lineItemOperations().deleteLineItem(mockedAccountId, mockedLineItemId); + } + + @Test + public void getLineItemPlacements() throws UnsupportedEncodingException { + mockServer + .expect(requestTo( + "https://ads-api.twitter.com/0/line_items/placements")) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("line-item-placements"), APPLICATION_JSON)); + + DataListHolder lineItemPlacements = twitter.lineItemOperations().getLineItemPlacements( + new LineItemPlacementsQueryBuilder() + .withProductTypes(null)); + + assertLineItemPlacementsContents(lineItemPlacements.getList()); + } + + @Test + public void getLineItemPlacementsWithParams() throws UnsupportedEncodingException { + mockServer + .expect(requestTo( + "https://ads-api.twitter.com/0/line_items/placements?product_type=PROMOTED_ACCOUNT")) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("line-item-placements-params"), APPLICATION_JSON)); + + List productTypes = new ArrayList(); + productTypes.add(AdvertisingProductType.PROMOTED_ACCOUNT); + DataListHolder lineItemPlacements = twitter.lineItemOperations().getLineItemPlacements( + new LineItemPlacementsQueryBuilder() + .withProductTypes(productTypes)); + + assertLineItemPlacementsWithParamsContents(lineItemPlacements.getList()); + } + + private void assertLineItemPlacementsContents(List lineItemPlacements) { + assertEquals(2, lineItemPlacements.size()); + assertEquals(6, lineItemPlacements.get(0).getPlacements().size()); + assertEquals(AdvertisingPlacement.TWITTER_TIMELINE, lineItemPlacements.get(0).getPlacements().get(3).get(1)); + } + + private void assertLineItemPlacementsWithParamsContents(List lineItemPlacements) { + assertEquals(1, lineItemPlacements.size()); + assertEquals(1, lineItemPlacements.get(0).getPlacements().size()); + assertEquals(AdvertisingPlacement.ALL_ON_TWITTER, lineItemPlacements.get(0).getPlacements().get(0).get(0)); + } + + private void assertLineItemContents(List lineItems) { + assertEquals(22, lineItems.size()); + + assertEquals("awvv", lineItems.get(0).getId()); + assertEquals("gq0vqj", lineItems.get(0).getAccountId()); + assertEquals("e094", lineItems.get(0).getCampaignId()); + assertEquals(BidUnit.APP_CLICK, lineItems.get(0).getBidUnit()); + assertEquals(LineItemOptimization.DEFAULT, lineItems.get(0).getOptimization()); + assertEquals(AdvertisingObjective.APP_ENGAGEMENTS, lineItems.get(0).getObjective()); + assertEquals(AdvertisingSentiment.POSITIVE_ONLY, lineItems.get(0).getIncludeSentiment()); + assertEquals(AdvertisingProductType.PROMOTED_TWEETS, lineItems.get(0).getProductType()); + assertThat(lineItems.get(0).getPlacements(), CoreMatchers.hasItem(AdvertisingPlacement.ALL_ON_TWITTER)); + assertEquals("USD", lineItems.get(0).getCurrency()); + assertEquals(BigDecimal.valueOf(100), lineItems.get(0).getTotalBudgetAmount()); + assertEquals(BigDecimal.valueOf(10), lineItems.get(0).getBidAmount()); + assertEquals(false, lineItems.get(0).isAutomaticallySetBid()); + assertEquals(true, lineItems.get(0).isPaused()); + assertEquals(false, lineItems.get(0).isDeleted()); + assertEquals(LocalDateTime.of(2015, Month.MAY, 29, 20, 32, 20), lineItems.get(0).getCreatedAt()); + assertEquals(LocalDateTime.of(2015, Month.MAY, 29, 20, 38, 43), lineItems.get(0).getUpdatedAt()); + } + + private void assertSingleLineItemContents(LineItem lineItem) { + assertEquals("69ob", lineItem.getId()); + assertEquals("hkk5", lineItem.getAccountId()); + assertEquals("7wdy", lineItem.getCampaignId()); + assertEquals("GBP", lineItem.getCurrency()); + assertEquals(AdvertisingProductType.PROMOTED_ACCOUNT, lineItem.getProductType()); + assertThat(lineItem.getPlacements(), CoreMatchers.hasItem(AdvertisingPlacement.ALL_ON_TWITTER)); + assertThat(lineItem.getPlacements(), CoreMatchers.hasItem(AdvertisingPlacement.PUBLISHER_NETWORK)); + assertEquals(AdvertisingObjective.FOLLOWERS, lineItem.getObjective()); + assertEquals(null, lineItem.getIncludeSentiment()); + assertEquals(LineItemOptimization.DEFAULT, lineItem.getOptimization()); + assertEquals(null, lineItem.getTotalBudgetAmount()); + assertEquals(new BigDecimal(1.75).round(MathContext.DECIMAL32), lineItem.getBidAmount()); + assertEquals(false, lineItem.isPaused()); + assertEquals(false, lineItem.isDeleted()); + assertEquals(LocalDateTime.of(2012, Month.NOVEMBER, 30, 22, 58, 11), lineItem.getCreatedAt()); + assertEquals(LocalDateTime.of(2012, Month.NOVEMBER, 30, 22, 58, 11), lineItem.getUpdatedAt()); + } +} diff --git a/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/advertising/PromotionsTemplateTest.java b/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/advertising/PromotionsTemplateTest.java new file mode 100644 index 00000000..400e911b --- /dev/null +++ b/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/advertising/PromotionsTemplateTest.java @@ -0,0 +1,313 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import static org.springframework.http.HttpMethod.DELETE; +import static org.springframework.http.HttpMethod.GET; +import static org.springframework.http.HttpMethod.POST; +import static org.springframework.http.MediaType.APPLICATION_JSON; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.content; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.method; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo; +import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess; + +import java.util.Arrays; +import java.util.List; + +import org.hamcrest.CoreMatchers; +import org.junit.Assert; +import org.junit.Test; +import org.springframework.social.twitter.api.Tweet; +import org.springframework.social.twitter.api.advertising.ApprovalStatus; +import org.springframework.social.twitter.api.advertising.PromotableUser; +import org.springframework.social.twitter.api.advertising.PromotedTweetReference; +import org.springframework.social.twitter.api.advertising.PromotedUserReference; +import org.springframework.social.twitter.api.impl.AbstractTwitterApiTest; + +/** + * @author Hudson Mendes + */ +public class PromotionsTemplateTest extends AbstractTwitterApiTest { + + @Test + public void getPromotableUsers() { + final String mockedAccountId = "0ga0yn"; + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/accounts/" + mockedAccountId + "/promotable_users?with_deleted=true")) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("ad-promotable-users"), APPLICATION_JSON)); + + final List promotables = twitter.promotionOperations().getPromotableUsers( + mockedAccountId, + new PromotableUserQueryBuilder().includeDeleted(true)).getList(); + + Assert.assertNotEquals(0, promotables.size()); + Assert.assertEquals("13phg", promotables.get(0).getId()); + Assert.assertEquals("gq0vqj", promotables.get(0).getAccountId()); + Assert.assertEquals(new Long("390472547"), promotables.get(0).getUserId()); + Assert.assertEquals("FULL", promotables.get(0).getPromotableUserType()); + Assert.assertEquals(false, promotables.get(0).isDeleted()); + Assert.assertEquals("2015-04-13T20:42:39", promotables.get(0).getCreatedAt().toString()); + Assert.assertEquals("2015-04-13T20:42:39", promotables.get(0).getUpdatedAt().toString()); + } + + @Test + public void getSponsoredTweets() { + final String mockedAccountId = "0ga0yn"; + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/accounts/" + + mockedAccountId + + "/scoped_timeline?scoped_to=none&user_ids=390472547&trim_user=true&count=1")) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("ad-sponsored-tweets"), APPLICATION_JSON)); + + final List tweets = twitter + .promotionOperations() + .getSponsoredTweets( + mockedAccountId, + new SponsoredTweetQueryBuilder() + .ofUsers(new Long("390472547")) + .pagedBy(null, 1) + .trimUser(true)) + .getList(); + + assertTweetsContents(tweets); + } + + private void assertTweetsContents(List tweets) { + Assert.assertEquals(3, tweets.size()); + + Assert.assertEquals(new Long("540565364179226624").longValue(), tweets.get(0).getId()); + Assert.assertEquals(new Long("390472547").longValue(), tweets.get(0).getFromUserId()); + Assert.assertEquals("en", tweets.get(0).getLanguageCode()); + Assert.assertEquals("MemeTV wants to bring meme-worthy TV clips to Tumblr and... http://t.co/cfxJOQ9zpF", tweets.get(0).getText()); + Assert.assertEquals("IFTTT", tweets.get(0).getSource()); + Assert.assertEquals(false, tweets.get(0).isFavorited()); + Assert.assertEquals(Integer.valueOf(0), tweets.get(0).getFavoriteCount()); + Assert.assertEquals(false, tweets.get(0).isRetweeted()); + Assert.assertEquals(Integer.valueOf(0), tweets.get(0).getRetweetCount()); + Assert.assertEquals(false, tweets.get(0).isTruncated()); + Assert.assertEquals(false, tweets.get(0).isPossiblySensitive()); + Assert.assertEquals(0, tweets.get(0).getEntities().getHashTags().size()); + Assert.assertEquals(0, tweets.get(0).getEntities().getTickerSymbols().size()); + Assert.assertEquals(1, tweets.get(0).getEntities().getUrls().size()); + Assert.assertEquals("http://t.co/cfxJOQ9zpF", tweets.get(0).getEntities().getUrls().get(0).getUrl()); + Assert.assertEquals("http://ift.tt/1tLavU9", tweets.get(0).getEntities().getUrls().get(0).getExpandedUrl()); + Assert.assertEquals("ift.tt/1tLavU9", tweets.get(0).getEntities().getUrls().get(0).getDisplayUrl()); + Assert.assertEquals("Thu Dec 04 17:56:40 GMT 2014", tweets.get(0).getCreatedAt().toString()); + Assert.assertThat( + Arrays.asList(Arrays + .stream(tweets.get(0).getEntities().getUrls().get(0).getIndices()) + .mapToObj(i -> Integer.valueOf(i)) + .toArray(size -> new Integer[size])), + CoreMatchers.hasItems(Integer.valueOf(60), Integer.valueOf(82))); + } + + @Test + public void createSponsoredTweet() { + final String mockedAccountId = "hkk5"; + final String mockedTweetText = "Hey, here is a sponsored tweet that we are creating via #ads API."; + final long mockedUserId = 390472547L; + + final String chainedPostContent = "status=Hey%2C+here+is+a+sponsored+tweet+that+we+are+creating+via+%23ads+API.&as_user_id=390472547"; + + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/accounts/" + mockedAccountId + "/tweet")) + .andExpect(method(POST)) + .andExpect(content().string(chainedPostContent)) + .andRespond(withSuccess(jsonResource("ad-sponsored-tweets-single"), APPLICATION_JSON)); + + final Tweet tweet = twitter.promotionOperations().createSponsoredTweet( + mockedAccountId, + new SponsoredTweetFormBuilder() + .asUser(mockedUserId) + .withStatus(mockedTweetText)); + + Assert.assertEquals(mockedUserId, tweet.getFromUserId()); + Assert.assertEquals(mockedTweetText, tweet.getText()); + Assert.assertThat( + Arrays.asList(tweet.getEntities().getHashTags().stream().map(i -> i.getText()).toArray(size -> new String[size])), + CoreMatchers.hasItems("ads")); + } + + @Test + public void getPromotedTweetReferences() { + final String mockedAccountId = "0ga0yn"; + final String mockedLineItemId = "u4h4"; + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/accounts/" + mockedAccountId + "/promoted_tweets?line_item_id=" + mockedLineItemId)) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("ad-promoted-tweet-reference"), APPLICATION_JSON)); + + final List references = twitter.promotionOperations().getPromotedTweetReferences( + mockedAccountId, + mockedLineItemId, + new PromotedTweetReferenceQueryBuilder()).getList(); + + Assert.assertNotEquals(0, references.size()); + Assert.assertEquals("tifo", references.get(0).getId()); + Assert.assertEquals("b51j", references.get(0).getLineItemId()); + Assert.assertEquals(Long.valueOf(614564626060062720L), references.get(0).getTweetId()); + Assert.assertEquals(ApprovalStatus.ACCEPTED, references.get(0).getApprovalStatus()); + Assert.assertEquals(false, references.get(0).isPaused()); + Assert.assertEquals(false, references.get(0).isDeleted()); + Assert.assertEquals("2015-06-27T00:21:53", references.get(0).getCreatedAt().toString()); + Assert.assertEquals("2015-06-30T00:21:53", references.get(0).getUpdatedAt().toString()); + } + + @Test + public void getPromotedTweetReferencesWithoutLineItemId() { + final String mockedAccountId = "0ga0yn"; + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/accounts/" + mockedAccountId + "/promoted_tweets")) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("ad-promoted-tweet-reference"), APPLICATION_JSON)); + + final List references = twitter + .promotionOperations() + .getPromotedTweetReferences(mockedAccountId, new PromotedTweetReferenceQueryBuilder()) + .getList(); + + Assert.assertNotEquals(0, references.size()); + Assert.assertEquals("tifo", references.get(0).getId()); + Assert.assertEquals("b51j", references.get(0).getLineItemId()); + Assert.assertEquals(Long.valueOf(614564626060062720L), references.get(0).getTweetId()); + Assert.assertEquals(ApprovalStatus.ACCEPTED, references.get(0).getApprovalStatus()); + Assert.assertEquals(false, references.get(0).isPaused()); + Assert.assertEquals(false, references.get(0).isDeleted()); + Assert.assertEquals("2015-06-27T00:21:53", references.get(0).getCreatedAt().toString()); + Assert.assertEquals("2015-06-30T00:21:53", references.get(0).getUpdatedAt().toString()); + } + + @Test + public void createPromotedTweetReference() { + final String mockedAccountId = "0ga0yn"; + final String mockedLineItemId = "u4h4"; + final Long tweetId = 614564626060062720L; + + final String chainedPostContent = "line_item_id=" + mockedLineItemId + "&tweet_ids=" + tweetId; + + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/accounts/" + mockedAccountId + "/promoted_tweets")) + .andExpect(method(POST)) + .andExpect(content().string(chainedPostContent)) + .andRespond(withSuccess(jsonResource("ad-promoted-tweet-reference-creation"), APPLICATION_JSON)); + + final List references = twitter + .promotionOperations() + .createPromotedTweetReference( + mockedAccountId, + new PromotedTweetReferenceFormBuilder() + .onLineItem(mockedLineItemId) + .forTweets(tweetId)) + .getList(); + + Assert.assertNotEquals(0, references.size()); + Assert.assertEquals("tifo", references.get(0).getId()); + Assert.assertEquals("u4h4", references.get(0).getLineItemId()); + Assert.assertEquals(Long.valueOf(614564626060062720L), references.get(0).getTweetId()); + Assert.assertEquals(ApprovalStatus.ACCEPTED, references.get(0).getApprovalStatus()); + Assert.assertEquals(false, references.get(0).isPaused()); + Assert.assertEquals(false, references.get(0).isDeleted()); + Assert.assertEquals("2015-06-27T00:21:53", references.get(0).getCreatedAt().toString()); + Assert.assertEquals("2015-06-30T00:21:53", references.get(0).getUpdatedAt().toString()); + } + + @Test + public void deletePromotedTweetReference() { + final String mockedAccountId = "0ga0yn"; + final String mockedPromotedTweetId = "ak34"; + + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/accounts/" + mockedAccountId + "/promoted_tweets/" + mockedPromotedTweetId)) + .andExpect(method(DELETE)) + .andRespond(withSuccess()); + + twitter.promotionOperations().deletePromotedTweetReference( + mockedAccountId, + mockedPromotedTweetId); + } + + @Test + public void getPromotedUserReferences() { + final String mockedAccountId = "0ga0yn"; + final String mockedLineItemId = "u4h4"; + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/accounts/" + mockedAccountId + "/promoted_accounts?line_item_id=" + mockedLineItemId)) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("ad-promoted-accounts-reference"), APPLICATION_JSON)); + + final List references = twitter.promotionOperations().getPromotedUserReferences( + mockedAccountId, + mockedLineItemId, + new PromotedUserReferenceQueryBuilder()).getList(); + + Assert.assertNotEquals(0, references.size()); + Assert.assertEquals("3goc", references.get(0).getId()); + Assert.assertEquals("b6im", references.get(0).getLineItemId()); + Assert.assertEquals("390472547", references.get(0).getUserId()); + Assert.assertEquals(false, references.get(0).isDeleted()); + Assert.assertEquals(false, references.get(0).isPaused()); + Assert.assertEquals("2015-07-02T00:51:44", references.get(0).getCreatedAt().toString()); + Assert.assertEquals("2015-07-02T00:51:44", references.get(0).getUpdatedAt().toString()); + Assert.assertEquals(ApprovalStatus.ACCEPTED, references.get(0).getApprovalStatus()); + } + + @Test + public void createPromotedUserReference() { + final String mockedAccountId = "0ga0yn"; + final String mockedLineItemId = "u4h4"; + final String mockedUserId = "13phg"; + + final String chainedPostContent = "line_item_id=" + mockedLineItemId + "&user_id=" + mockedUserId; + + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/accounts/" + mockedAccountId + "/promoted_accounts")) + .andExpect(method(POST)) + .andExpect(content().string(chainedPostContent)) + .andRespond(withSuccess(jsonResource("ad-promoted-accounts-reference-creation"), APPLICATION_JSON)); + + final PromotedUserReference reference = twitter.promotionOperations().createPromotedUserReferences( + mockedAccountId, + new PromotedUserReferenceFormBuilder() + .onLineItem(mockedLineItemId) + .forUser(mockedUserId)); + + Assert.assertEquals("3goc", reference.getId()); + Assert.assertEquals("b6im", reference.getLineItemId()); + Assert.assertEquals("390472547", reference.getUserId()); + Assert.assertEquals(false, reference.isDeleted()); + Assert.assertEquals(false, reference.isPaused()); + Assert.assertEquals("2015-07-02T00:51:44", reference.getCreatedAt().toString()); + Assert.assertEquals("2015-07-02T00:51:44", reference.getUpdatedAt().toString()); + Assert.assertEquals(ApprovalStatus.ACCEPTED, reference.getApprovalStatus()); + } + + @Test + public void deletePromotedUserReference() { + final String mockedAccountId = "0ga0yn"; + final String mockedPromotedTweetId = "ak34"; + + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/accounts/" + mockedAccountId + "/promoted_accounts/" + mockedPromotedTweetId)) + .andExpect(method(DELETE)) + .andRespond(withSuccess()); + + twitter.promotionOperations().deletePromotedUserReference( + mockedAccountId, + mockedPromotedTweetId); + } +} diff --git a/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/advertising/StatisticsTemplateTest.java b/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/advertising/StatisticsTemplateTest.java new file mode 100644 index 00000000..1c2ab7fb --- /dev/null +++ b/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/advertising/StatisticsTemplateTest.java @@ -0,0 +1,462 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import static org.hamcrest.CoreMatchers.hasItem; +import static org.hamcrest.CoreMatchers.hasItems; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; +import static org.springframework.http.HttpMethod.GET; +import static org.springframework.http.MediaType.APPLICATION_JSON; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.method; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo; +import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.time.LocalDateTime; +import java.time.Month; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.junit.Assert; +import org.junit.Test; +import org.springframework.social.twitter.api.advertising.StatisticsGranularity; +import org.springframework.social.twitter.api.advertising.StatisticsMetric; +import org.springframework.social.twitter.api.advertising.StatisticsSegmentationType; +import org.springframework.social.twitter.api.advertising.StatisticsSnapshot; +import org.springframework.social.twitter.api.advertising.StatisticsSnapshotMetric; +import org.springframework.social.twitter.api.impl.AbstractTwitterApiTest; +import org.springframework.test.web.client.MockRestServiceServer; + +/** + * @author Hudson mendes + */ +public class StatisticsTemplateTest extends AbstractTwitterApiTest { + + @Test + public void segmentedAndUnsegmented() throws UnsupportedEncodingException { + String mockedAccountId = "0ga0yn"; + + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/stats/accounts/" + mockedAccountId + "?granularity=DAY")) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("ad-stats-non-segmented"), APPLICATION_JSON)); + + List snapshots1 = twitter.statisticsOperations().byAccounts( + mockedAccountId, + new StatisticsOfAccountQueryBuilder() + .withGranularity(StatisticsGranularity.DAY)); + + MockRestServiceServer mockServer2 = MockRestServiceServer.createServer(twitter.getRestTemplate()); + mockServer2 + .expect(requestTo("https://ads-api.twitter.com/0/stats/accounts/" + mockedAccountId + "?segmentation_type=GENDER&granularity=DAY")) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("ad-stats-segmented"), APPLICATION_JSON)); + + List snapshots2 = twitter.statisticsOperations().byAccounts( + mockedAccountId, + new StatisticsOfAccountQueryBuilder() + .withGranularity(StatisticsGranularity.DAY) + .withSegmentationType(StatisticsSegmentationType.GENDER)); + + Assert.assertNotEquals(snapshots1.size(), snapshots2.size()); + Assert.assertEquals(1, snapshots1.size()); + + Assert.assertNotNull(snapshots2.get(0).getSegmentation()); + Assert.assertEquals(StatisticsSegmentationType.GENDER, snapshots2.get(0).getSegmentation().getType()); + Assert.assertEquals("f", snapshots2.get(0).getSegmentation().getValue()); + Assert.assertEquals("Female", snapshots2.get(0).getSegmentation().getDescription()); + + Assert.assertNotNull(snapshots2.get(1).getSegmentation()); + Assert.assertEquals(StatisticsSegmentationType.GENDER, snapshots2.get(1).getSegmentation().getType()); + Assert.assertEquals("m", snapshots2.get(1).getSegmentation().getValue()); + Assert.assertEquals("Male", snapshots2.get(1).getSegmentation().getDescription()); + + Assert.assertNotNull(snapshots2.get(2).getSegmentation()); + Assert.assertEquals(StatisticsSegmentationType.GENDER, snapshots2.get(2).getSegmentation().getType()); + Assert.assertEquals("unknown", snapshots2.get(2).getSegmentation().getValue()); + Assert.assertEquals("Unknown", snapshots2.get(2).getSegmentation().getDescription()); + + List metrics1 = extractMetricsFromStatisticSnapshots(snapshots1); + List metrics2 = extractMetricsFromStatisticSnapshots(snapshots1); + Assert.assertEquals(metrics1.size(), metrics2.size()); + } + + private List extractMetricsFromStatisticSnapshots(List snapshots) { + List metrics = new ArrayList<>(); + for (StatisticsSnapshot snapshot : snapshots) + for (StatisticsSnapshotMetric snapshotMetric : snapshot.getMetrics()) + metrics.add(snapshotMetric.getName()); + return metrics; + } + + @Test + public void byAccounts() throws UnsupportedEncodingException { + String mockedAccountId = "0ga0yn"; + mockServer + .expect(requestTo( + "https://ads-api.twitter.com/0/stats/accounts/" + mockedAccountId + + "?granularity=DAY" + + "&start_time=" + URLEncoder.encode("2015-05-01T07:00:00Z", UTF8) + + "&end_time=" + URLEncoder.encode("2015-05-04T07:00:00Z", UTF8))) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("statistics-snapshot"), APPLICATION_JSON)); + + List snapshots = twitter.statisticsOperations().byAccounts( + mockedAccountId, + new StatisticsOfAccountQueryBuilder() + .withGranularity(StatisticsGranularity.DAY) + .activeBetween(LocalDateTime.of(2015, Month.MAY, 01, 07, 00, 00), LocalDateTime.of(2015, Month.MAY, 4, 07, 00, 00))); + + assertSnapshotContents(snapshots); + } + + @Test + public void byCampaigns() throws UnsupportedEncodingException { + String mockedAccountId = "0ga0yn"; + String mockedCampaignId1 = "92ph"; + String mockedCampaignId2 = "x902"; + mockServer + .expect(requestTo( + "https://ads-api.twitter.com/0/stats/accounts/" + mockedAccountId + "/campaigns" + + "?campaign_ids=" + URLEncoder.encode(mockedCampaignId1 + "," + mockedCampaignId2, UTF8) + + "&granularity=HOUR" + + "&metrics=billed_follows" + + "&start_time=" + URLEncoder.encode("2015-03-06T07:00:00Z", UTF8) + + "&end_time=" + URLEncoder.encode("2015-03-13T07:00:00Z", UTF8))) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("statistics-snapshot"), APPLICATION_JSON)); + + List snapshots = twitter.statisticsOperations().byCampaigns( + mockedAccountId, + new StatisticsOfCampaignQueryBuilder() + .withCampaigns(mockedCampaignId1, mockedCampaignId2) + .withGranularity(StatisticsGranularity.HOUR) + .withStatisticalMetric(StatisticsMetric.billed_follows) + .activeBetween(LocalDateTime.of(2015, Month.MARCH, 06, 07, 00, 00), LocalDateTime.of(2015, Month.MARCH, 13, 07, 00, 00))); + + assertSnapshotContents(snapshots); + } + + @Test + public void byCampaign() throws UnsupportedEncodingException { + String mockedAccountId = "0ga0yn"; + String mockedCampaignId = "92ph"; + mockServer + .expect(requestTo( + "https://ads-api.twitter.com/0/stats/accounts/" + + mockedAccountId + + "/campaigns/" + + mockedCampaignId + + "?granularity=HOUR" + + "&metrics=" + + URLEncoder.encode("billed_follows,promoted_account_follow_rate,billed_charge_local_micro,mobile_conversion_rated", + UTF8) + + "&start_time=" + URLEncoder.encode("2015-03-06T07:00:00Z", UTF8) + + "&end_time=" + URLEncoder.encode("2015-03-13T07:00:00Z", UTF8))) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("statistics-snapshot"), APPLICATION_JSON)); + + List snapshot = twitter.statisticsOperations().byCampaign( + mockedAccountId, + mockedCampaignId, + new StatisticsOfCampaignQueryBuilder() + .withGranularity(StatisticsGranularity.HOUR) + .withStatisticalMetric( + StatisticsMetric.billed_follows, + StatisticsMetric.promoted_account_follow_rate, + StatisticsMetric.billed_charge_local_micro, + StatisticsMetric.mobile_conversion_rated) + .activeBetween(LocalDateTime.of(2015, Month.MARCH, 06, 07, 00, 00), LocalDateTime.of(2015, Month.MARCH, 13, 07, 00, 00))); + + assertSnapshotSingleContents(snapshot); + } + + @Test + public void byFundingInstruments() throws UnsupportedEncodingException { + String mockedAccountId = "0ga0yn"; + String mockedFundingInstrument1 = "92ph"; + String mockedFundingInstrument2 = "x902"; + + mockServer + .expect(requestTo( + "https://ads-api.twitter.com/0/stats/accounts/" + mockedAccountId + "/funding_instruments" + + "?funding_instrument_ids=" + URLEncoder.encode(mockedFundingInstrument1 + "," + mockedFundingInstrument2, UTF8) + + "&granularity=HOUR" + + "&metrics=" + URLEncoder.encode("billed_follows", UTF8) + + "&start_time=" + URLEncoder.encode("2015-03-06T07:00:00Z", UTF8) + + "&end_time=" + URLEncoder.encode("2015-03-13T07:00:00Z", UTF8))) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("statistics-snapshot"), APPLICATION_JSON)); + + List campaigns = twitter.statisticsOperations().byFundingInstruments( + mockedAccountId, + new StatisticsOfFundingInstrumentQueryBuilder() + .withFundingInstruments(mockedFundingInstrument1, mockedFundingInstrument2) + .withGranularity(StatisticsGranularity.HOUR) + .withStatisticalMetric(StatisticsMetric.billed_follows) + .activeBetween(LocalDateTime.of(2015, Month.MARCH, 06, 07, 00, 00), LocalDateTime.of(2015, Month.MARCH, 13, 07, 00, 00))); + + assertSnapshotContents(campaigns); + } + + @Test + public void byFundingInstrument() throws UnsupportedEncodingException { + String mockedAccountId = "0ga0yn"; + String mockedFundingInstrumentId = "92ph"; + + mockServer + .expect(requestTo( + "https://ads-api.twitter.com/0/stats/accounts/" + mockedAccountId + "/funding_instruments" + + "/" + mockedFundingInstrumentId + + "?granularity=HOUR" + + "&metrics=" + URLEncoder.encode("billed_follows", UTF8) + + "&start_time=" + URLEncoder.encode("2015-03-06T07:00:00Z", UTF8) + + "&end_time=" + URLEncoder.encode("2015-03-13T07:00:00Z", UTF8))) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("statistics-snapshot"), APPLICATION_JSON)); + + List snapshot = twitter.statisticsOperations().byFundingInstrument( + mockedAccountId, + mockedFundingInstrumentId, + new StatisticsOfFundingInstrumentQueryBuilder() + .withGranularity(StatisticsGranularity.HOUR) + .withStatisticalMetric(StatisticsMetric.billed_follows) + .activeBetween(LocalDateTime.of(2015, Month.MARCH, 06, 07, 00, 00), LocalDateTime.of(2015, Month.MARCH, 13, 07, 00, 00))); + + assertSnapshotSingleContents(snapshot); + } + + @Test + public void byLineItems() throws UnsupportedEncodingException { + String mockedAccountId = "0ga0yn"; + String mockedLineItemId1 = "92ph"; + String mockedLineItemId2 = "x902"; + mockServer + .expect(requestTo( + "https://ads-api.twitter.com/0/stats/accounts/" + mockedAccountId + "/line_items" + + "?line_item_ids=" + URLEncoder.encode(mockedLineItemId1 + "," + mockedLineItemId2, UTF8) + + "&granularity=DAY" + + "&start_time=" + URLEncoder.encode("2015-03-06T07:00:00Z", UTF8) + + "&end_time=" + URLEncoder.encode("2015-03-13T07:00:00Z", UTF8))) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("statistics-snapshot"), APPLICATION_JSON)); + + List snapshots = twitter.statisticsOperations().byLineItems( + mockedAccountId, + new StatisticsOfLineItemQueryBuilder() + .withLineItems(mockedLineItemId1, mockedLineItemId2) + .withGranularity(StatisticsGranularity.DAY) + .activeFrom(LocalDateTime.of(2015, Month.MARCH, 06, 07, 00, 00)) + .activeUntil(LocalDateTime.of(2015, Month.MARCH, 13, 07, 00, 00))); + + assertSnapshotContents(snapshots); + } + + @Test + public void byLineItem() throws UnsupportedEncodingException { + String mockedAccountId = "0ga0yn"; + String mockedLineItemId = "92ph"; + + mockServer + .expect(requestTo( + "https://ads-api.twitter.com/0/stats/accounts/" + mockedAccountId + "/line_items" + + "/" + mockedLineItemId + + "?granularity=HOUR" + + "&metrics=" + URLEncoder.encode("billed_follows", UTF8) + + "&start_time=" + URLEncoder.encode("2015-03-06T07:00:00Z", UTF8) + + "&end_time=" + URLEncoder.encode("2015-03-13T07:00:00Z", UTF8))) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("statistics-snapshot"), APPLICATION_JSON)); + + List snapshot = twitter.statisticsOperations().byLineItem( + mockedAccountId, + mockedLineItemId, + new StatisticsOfLineItemQueryBuilder() + .withGranularity(StatisticsGranularity.HOUR) + .withStatisticalMetric(StatisticsMetric.billed_follows) + .activeBetween(LocalDateTime.of(2015, Month.MARCH, 06, 07, 00, 00), LocalDateTime.of(2015, Month.MARCH, 13, 07, 00, 00))); + + assertSnapshotSingleContents(snapshot); + } + + @Test + public void byPromotedAccounts() throws UnsupportedEncodingException { + String mockedAccountId = "0ga0yn"; + String mockedPromotedAccountId1 = "92ph"; + String mockedPromotedAccountId2 = "x902"; + mockServer + .expect(requestTo( + "https://ads-api.twitter.com/0/stats/accounts/" + mockedAccountId + "/promoted_accounts" + + "?promoted_account_ids=" + URLEncoder.encode(mockedPromotedAccountId1 + "," + mockedPromotedAccountId2, UTF8) + + "&granularity=HOUR" + + "&metrics=" + URLEncoder.encode("billed_follows", UTF8) + + "&start_time=" + URLEncoder.encode("2015-03-06T07:00:00Z", UTF8) + + "&end_time=" + URLEncoder.encode("2015-03-13T07:00:00Z", UTF8))) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("statistics-snapshot"), APPLICATION_JSON)); + + List snapshots = twitter.statisticsOperations().byPromotedAccounts( + mockedAccountId, + new StatisticsOfPromotedAccountQueryBuilder() + .withPromotedAccounts(mockedPromotedAccountId1, mockedPromotedAccountId2) + .withGranularity(StatisticsGranularity.HOUR) + .withStatisticalMetric(StatisticsMetric.billed_follows) + .activeFrom(LocalDateTime.of(2015, Month.MARCH, 06, 07, 00, 00)) + .activeUntil(LocalDateTime.of(2015, Month.MARCH, 13, 07, 00, 00))); + + assertSnapshotContents(snapshots); + } + + @Test + public void byPromotedAccount() throws UnsupportedEncodingException { + String mockedAccountId = "0ga0yn"; + String mockedPromotedAccountId = "92ph"; + + mockServer + .expect(requestTo( + "https://ads-api.twitter.com/0/stats/accounts/" + mockedAccountId + "/promoted_accounts" + + "/" + mockedPromotedAccountId + + "?granularity=HOUR" + + "&metrics=" + URLEncoder.encode("billed_follows", UTF8) + + "&start_time=" + URLEncoder.encode("2015-03-06T07:00:00Z", UTF8) + + "&end_time=" + URLEncoder.encode("2015-03-13T07:00:00Z", UTF8))) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("statistics-snapshot"), APPLICATION_JSON)); + + List snapshot = twitter.statisticsOperations().byPromotedAccount( + mockedAccountId, + mockedPromotedAccountId, + new StatisticsOfPromotedAccountQueryBuilder() + .withGranularity(StatisticsGranularity.HOUR) + .withStatisticalMetric(StatisticsMetric.billed_follows) + .activeBetween(LocalDateTime.of(2015, Month.MARCH, 06, 07, 00, 00), LocalDateTime.of(2015, Month.MARCH, 13, 07, 00, 00))); + + assertSnapshotSingleContents(snapshot); + } + + @Test + public void byPromotedTweets() throws UnsupportedEncodingException { + String mockedAccountId = "0ga0yn"; + String mockedPromotedTweetId1 = "92ph"; + String mockedPromotedTweetId2 = "x902"; + mockServer + .expect(requestTo( + "https://ads-api.twitter.com/0/stats/accounts/" + mockedAccountId + "/promoted_tweets" + + "?promoted_tweet_ids=" + URLEncoder.encode(mockedPromotedTweetId1 + "," + mockedPromotedTweetId2, UTF8) + + "&granularity=HOUR" + + "&metrics=" + URLEncoder.encode("billed_follows", UTF8) + + "&start_time=" + URLEncoder.encode("2015-03-06T07:00:00Z", UTF8) + + "&end_time=" + URLEncoder.encode("2015-03-13T07:00:00Z", UTF8))) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("statistics-snapshot"), APPLICATION_JSON)); + + List snapshots = twitter.statisticsOperations().byPromotedTweets( + mockedAccountId, + new StatisticsOfPromotedTweetQueryBuilder() + .withPromotedTweets(mockedPromotedTweetId1, mockedPromotedTweetId2) + .withGranularity(StatisticsGranularity.HOUR) + .withStatisticalMetric(StatisticsMetric.billed_follows) + .activeFrom(LocalDateTime.of(2015, Month.MARCH, 06, 07, 00, 00)) + .activeUntil(LocalDateTime.of(2015, Month.MARCH, 13, 07, 00, 00))); + + assertSnapshotContents(snapshots); + } + + @Test + public void byPromotedTweet() throws UnsupportedEncodingException { + String mockedAccountId = "0ga0yn"; + String mockedPromotedTweetId = "92ph"; + + mockServer + .expect(requestTo( + "https://ads-api.twitter.com/0/stats/accounts/" + mockedAccountId + "/promoted_tweets" + + "/" + mockedPromotedTweetId + + "?granularity=HOUR" + + "&metrics=" + URLEncoder.encode("billed_follows", UTF8) + + "&start_time=" + URLEncoder.encode("2015-03-06T07:00:00Z", UTF8) + + "&end_time=" + URLEncoder.encode("2015-03-13T07:00:00Z", UTF8))) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("statistics-snapshot"), APPLICATION_JSON)); + + List snapshot = twitter.statisticsOperations().byPromotedTweet( + mockedAccountId, + mockedPromotedTweetId, + new StatisticsOfPromotedTweetQueryBuilder() + .withGranularity(StatisticsGranularity.HOUR) + .withStatisticalMetric(StatisticsMetric.billed_follows) + .activeBetween(LocalDateTime.of(2015, Month.MARCH, 06, 07, 00, 00), LocalDateTime.of(2015, Month.MARCH, 13, 07, 00, 00))); + + assertSnapshotSingleContents(snapshot); + } + + private void assertSnapshotContents(List snapshots) { + + StatisticsSnapshot snapshot = snapshots.get(0); + + assertEquals("8484d", snapshot.getId()); + assertEquals(StatisticsGranularity.DAY, snapshot.getGranularity()); + assertEquals("2015-05-01T07:00", snapshot.getStartTime().toString()); + assertEquals("2015-05-04T07:00", snapshot.getEndTime().toString()); + + List metrics = Arrays.asList(Arrays + .stream(snapshot.getMetrics()) + .map(i -> i.getName()) + .toArray(size -> new StatisticsMetric[size])); + + assertThat(metrics, hasItem(StatisticsMetric.billed_engagements)); + assertThat(metrics, hasItem(StatisticsMetric.billed_follows)); + assertThat(metrics, hasItem(StatisticsMetric.promoted_account_follow_rate)); + assertThat(metrics, hasItem(StatisticsMetric.promoted_account_follows)); + assertThat(metrics, hasItem(StatisticsMetric.promoted_account_impressions)); + assertThat(metrics, hasItem(StatisticsMetric.promoted_account_profile_visits)); + assertThat(metrics, hasItem(StatisticsMetric.promoted_tweet_app_install_attempts)); + assertThat(metrics, hasItem(StatisticsMetric.promoted_tweet_app_open_attempts)); + assertThat(metrics, hasItem(StatisticsMetric.promoted_tweet_search_clicks)); + assertThat(metrics, hasItem(StatisticsMetric.promoted_tweet_search_engagement_rate)); + assertThat(metrics, hasItem(StatisticsMetric.promoted_tweet_search_engagements)); + assertThat(metrics, hasItem(StatisticsMetric.promoted_tweet_search_favorites)); + assertThat(metrics, hasItem(StatisticsMetric.promoted_tweet_search_follows)); + assertThat(metrics, hasItem(StatisticsMetric.promoted_tweet_search_impressions)); + assertThat(metrics, hasItem(StatisticsMetric.promoted_tweet_search_replies)); + assertThat(metrics, hasItem(StatisticsMetric.promoted_tweet_search_retweets)); + assertThat(metrics, hasItem(StatisticsMetric.promoted_tweet_search_url_clicks)); + assertThat(metrics, hasItem(StatisticsMetric.promoted_tweet_timeline_clicks)); + assertThat(metrics, hasItem(StatisticsMetric.promoted_tweet_timeline_engagement_rate)); + assertThat(metrics, hasItem(StatisticsMetric.promoted_tweet_timeline_engagements)); + assertThat(metrics, hasItem(StatisticsMetric.promoted_tweet_timeline_favorites)); + assertThat(metrics, hasItem(StatisticsMetric.promoted_tweet_timeline_follows)); + assertThat(metrics, hasItem(StatisticsMetric.promoted_tweet_timeline_impressions)); + assertThat(metrics, hasItem(StatisticsMetric.promoted_tweet_timeline_replies)); + assertThat(metrics, hasItem(StatisticsMetric.promoted_tweet_timeline_retweets)); + assertThat(metrics, hasItem(StatisticsMetric.promoted_tweet_timeline_url_clicks)); + + } + + private void assertSnapshotSingleContents(List snapshots) { + StatisticsSnapshot snapshot = snapshots.get(0); + + assertEquals("8484d", snapshot.getId()); + + assertNotNull(snapshot.getMetric(StatisticsMetric.billed_follows)); + assertThat( + snapshot.getMetric(StatisticsMetric.billed_follows).entries(), + hasItems(new Long[] {0L})); + } +} diff --git a/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/advertising/TailoredAudienceTemplateTest.java b/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/advertising/TailoredAudienceTemplateTest.java new file mode 100644 index 00000000..19b35d0f --- /dev/null +++ b/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/advertising/TailoredAudienceTemplateTest.java @@ -0,0 +1,216 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.springframework.http.HttpMethod.DELETE; +import static org.springframework.http.HttpMethod.GET; +import static org.springframework.http.HttpMethod.POST; +import static org.springframework.http.HttpMethod.PUT; +import static org.springframework.http.MediaType.APPLICATION_JSON; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.content; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.method; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo; +import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess; + +import java.util.Arrays; +import java.util.List; + +import org.hamcrest.CoreMatchers; +import org.junit.Test; +import org.springframework.social.twitter.api.advertising.TailoredAudience; +import org.springframework.social.twitter.api.advertising.TailoredAudienceChange; +import org.springframework.social.twitter.api.advertising.TailoredAudienceChangeOperation; +import org.springframework.social.twitter.api.advertising.TailoredAudienceChangeState; +import org.springframework.social.twitter.api.advertising.TailoredAudienceListType; +import org.springframework.social.twitter.api.advertising.TailoredAudienceType; +import org.springframework.social.twitter.api.impl.AbstractTwitterApiTest; +import org.springframework.social.twitter.api.impl.DataListHolder; + +/** + * @author Hudson Mendes + */ +public class TailoredAudienceTemplateTest extends AbstractTwitterApiTest { + + @Test + public void getTailoredAudience() { + String mockedAccountId = "hkk5"; + String mockedTailoredAudience = "qq4u"; + mockServer + .expect(requestTo( + "https://ads-api.twitter.com/0/accounts/" + mockedAccountId + "/tailored_audiences" + + "/" + mockedTailoredAudience + + "?with_deleted=true")) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("ad-tailored-audiences-single"), APPLICATION_JSON)); + + TailoredAudience tailoredAudience = twitter.tailoredAudienceOperations().getTailoredAudience(mockedAccountId, mockedTailoredAudience); + assertSingleTailoredAudienceContents(tailoredAudience); + } + + @Test + public void getTailoredAudiences() { + String mockedAccountId = "hkk5"; + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/accounts/" + mockedAccountId + "/tailored_audiences?with_deleted=false")) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("ad-tailored-audiences"), APPLICATION_JSON)); + + DataListHolder tailoredAudiences = twitter.tailoredAudienceOperations() + .getTailoredAudiences( + mockedAccountId, + new TailoredAudienceQueryBuilder().includeDeleted(false)); + + assertTailoredAudienceContents(tailoredAudiences.getList()); + } + + @Test + public void createTailoredAudience() { + String mockedAccountId = "hkk5"; + String doesntMatterString = "doesn-matter"; + + String chainedPostContent = + "name=" + doesntMatterString + "&" + + "list_type=" + TailoredAudienceListType.TWITTER_ID; + + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/accounts/" + mockedAccountId + "/tailored_audiences")) + .andExpect(method(POST)) + .andExpect(content().string(chainedPostContent)) + .andRespond(withSuccess(jsonResource("ad-tailored-audiences-single"), APPLICATION_JSON)); + + TailoredAudience tailoredAudience = twitter.tailoredAudienceOperations().createTailoredAudience( + mockedAccountId, + new TailoredAudienceFormBuilder() + .named(doesntMatterString) + .ofListType(TailoredAudienceListType.TWITTER_ID)); + + assertSingleTailoredAudienceContents(tailoredAudience); + } + + @Test + public void deleteTailoredAudience() { + String mockedAccountId = "0ga0yn"; + String mockedTailoredAudienceId = "qq4u"; + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/accounts/" + mockedAccountId + "/tailored_audiences/" + mockedTailoredAudienceId)) + .andExpect(method(DELETE)) + .andRespond(withSuccess()); + + twitter.tailoredAudienceOperations().deleteTailoredAudience(mockedAccountId, mockedTailoredAudienceId); + } + + private void assertSingleTailoredAudienceContents(TailoredAudience audience) { + assertEquals("qq4u", audience.getId()); + assertEquals("twitter%20ids", audience.getName()); + + assertEquals("OTHER", audience.getPartnerSource()); + assertEquals(TailoredAudienceListType.TWITTER_ID, audience.getListType()); + + for (String reason : new String[] {"PROCESSING", "TOO_SMALL"}) + assertThat(Arrays.asList(audience.getReasonsNotTargetable()), CoreMatchers.hasItem(reason)); + + for (String targetableType : new String[] {"CRM", "EXCLUDED_CRM"}) + assertThat(Arrays.asList(audience.getTargetableTypes()), CoreMatchers.hasItem(targetableType)); + + assertEquals(null, audience.getAudienceSize()); + assertEquals(TailoredAudienceType.CRM, audience.getAudienceType()); + + assertEquals(false, audience.isDeleted()); + assertEquals(false, audience.isTargetable()); + + assertEquals("2015-06-08T20:13:40", audience.getCreatedAt().toString()); + assertEquals("2015-06-08T20:13:40", audience.getUpdatedAt().toString()); + } + + private void assertTailoredAudienceContents(List audiences) { + assertEquals(1, audiences.size()); + + assertEquals("qq4u", audiences.get(0).getId()); + assertEquals("twitter%20ids", audiences.get(0).getName()); + + assertEquals("OTHER", audiences.get(0).getPartnerSource()); + assertEquals(TailoredAudienceListType.TWITTER_ID, audiences.get(0).getListType()); + + for (String reason : new String[] {"PROCESSING", "TOO_SMALL"}) + assertThat(Arrays.asList(audiences.get(0).getReasonsNotTargetable()), CoreMatchers.hasItem(reason)); + + for (String targetableType : new String[] {"CRM", "EXCLUDED_CRM"}) + assertThat(Arrays.asList(audiences.get(0).getTargetableTypes()), CoreMatchers.hasItem(targetableType)); + + assertEquals(null, audiences.get(0).getAudienceSize()); + assertEquals(TailoredAudienceType.CRM, audiences.get(0).getAudienceType()); + + assertEquals(false, audiences.get(0).isDeleted()); + assertEquals(false, audiences.get(0).isTargetable()); + + assertEquals("2015-06-08T20:13:40", audiences.get(0).getCreatedAt().toString()); + assertEquals("2015-06-08T20:13:40", audiences.get(0).getUpdatedAt().toString()); + } + + @Test + public void createTailoredAudienceFile() { + String mockedAccountId = "0ga0yn"; + String mockedTailoredAudienceId = "13sf"; + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/accounts/" + mockedAccountId + "/tailored_audience_changes")) + .andExpect(method(POST)) + .andRespond(withSuccess(jsonResource("ad-tailored-audience-changes"), APPLICATION_JSON)); + + twitter.tailoredAudienceOperations().createTailoredAudienceChange( + mockedAccountId, + new TailoredAudienceChangeFormBuilder() + .withTailoredAudience(mockedTailoredAudienceId) + .withOperation(TailoredAudienceChangeOperation.ADD) + .withInputFilePath("/1.1/ton/data/ta_partner/390472547/oNJvLHs-6e2NUNa.txt")); + } + + @Test + public void getTailoredAudienceFile() { + String mockedAccountId = "0ga0yn"; + String mockedTailoredAudienceChangeId = "13sf"; + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/accounts/" + mockedAccountId + "/tailored_audience_changes/" + + mockedTailoredAudienceChangeId)) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("ad-tailored-audience-changes"), APPLICATION_JSON)); + + TailoredAudienceChange change = twitter.tailoredAudienceOperations().getTailoredAudienceChange( + mockedAccountId, + mockedTailoredAudienceChangeId); + + assertEquals("13sf", change.getTailoredAudienceId()); + assertEquals("/ta_partner/3wyo1gwuqF7_Lhr", change.getInputFilePath()); + assertEquals(TailoredAudienceChangeOperation.ADD, change.getOperation()); + assertEquals(TailoredAudienceChangeState.COMPLETED, change.getState()); + } + + @Test + public void createGlobalOptOut() { + String mockedAccountId = "0ga0yn"; + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/accounts/" + mockedAccountId + "/tailored_audiences/global_opt_out")) + .andExpect(method(PUT)) + .andRespond(withSuccess(jsonResource("ad-global-opt-out"), APPLICATION_JSON)); + + twitter.tailoredAudienceOperations().createGlobalOptOut( + mockedAccountId, + new GlobalOptOutFormBuilder() + .withListType(TailoredAudienceListType.TWITTER_ID) + .withInputFilePath("/1.1/ton/data/ta_partner/390472547/oNJvLHs-6e2NUNa.txt")); + } +} diff --git a/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryTemplateTest.java b/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryTemplateTest.java new file mode 100644 index 00000000..ee31f40c --- /dev/null +++ b/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaDiscoveryTemplateTest.java @@ -0,0 +1,751 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import static org.springframework.http.HttpMethod.GET; +import static org.springframework.http.MediaType.APPLICATION_JSON; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.method; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo; +import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +import org.junit.Assert; +import org.junit.Test; +import org.springframework.social.twitter.api.advertising.AppStore; +import org.springframework.social.twitter.api.advertising.EventType; +import org.springframework.social.twitter.api.advertising.SortDirection; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForAppStoreCategories; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForBehaviorTaxonomies; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForBehaviors; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForDevices; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForEvents; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForInterests; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForLanguages; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForLocations; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForNetworkOperators; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForPlatformVersions; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForPlatforms; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForTvChannel; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForTvGenre; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForTvMarket; +import org.springframework.social.twitter.api.advertising.TargetingCriteriaDiscoveryForTvShow; +import org.springframework.social.twitter.api.impl.AbstractTwitterApiTest; +import org.springframework.social.twitter.api.impl.DataListHolder; + +/** + * @author Hudson Mendes + */ +public class TargetingCriteriaDiscoveryTemplateTest extends AbstractTwitterApiTest { + + @Test + public void appStoreCategories() { + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/targeting_criteria/app_store_categories")) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("ad-targetings-app_store_categories"), APPLICATION_JSON)); + + final DataListHolder discoveries = + twitter.targetingCriteriaDiscoveryOperations().appStoreCategories( + new TargetingCriteriaDiscoveryForAppStoreCategoriesQueryBuilder()); + + assertAppStoreCategoriesDiscoveries(discoveries.getList()); + } + + private void assertAppStoreCategoriesDiscoveries(List actual) { + Assert.assertEquals(84, actual.size()); + + Assert.assertEquals("Food & Drink", actual.get(13).getName()); + Assert.assertEquals("IOS", actual.get(13).getOsType()); + Assert.assertEquals("APP_STORE_CATEGORY", actual.get(13).getTargetingType()); + Assert.assertEquals("qouf", actual.get(13).getTargetingValue()); + + Assert.assertEquals("Games: Card", actual.get(23).getName()); + Assert.assertEquals("ANDROID", actual.get(23).getOsType()); + Assert.assertEquals("APP_STORE_CATEGORY", actual.get(23).getTargetingType()); + Assert.assertEquals("qowi", actual.get(23).getTargetingValue()); + } + + @Test + public void appStoreCategoriesWithParams() { + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/targeting_criteria/app_store_categories?store=GOOGLE_PLAY&q=music")) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("ad-targetings-app_store_categories-params"), APPLICATION_JSON)); + + final DataListHolder discoveries = + twitter.targetingCriteriaDiscoveryOperations().appStoreCategories( + new TargetingCriteriaDiscoveryForAppStoreCategoriesQueryBuilder() + .inAppStore(AppStore.GOOGLE_PLAY) + .withQuery("music")); + + assertAppStoreCategoriesDiscoveriesWithParams(discoveries.getList()); + } + + private void assertAppStoreCategoriesDiscoveriesWithParams(List actual) { + Assert.assertEquals(2, actual.size()); + + Assert.assertEquals("Music & Audio", actual.get(1).getName()); + Assert.assertEquals("ANDROID", actual.get(1).getOsType()); + Assert.assertEquals("APP_STORE_CATEGORY", actual.get(1).getTargetingType()); + Assert.assertEquals("qox2", actual.get(1).getTargetingValue()); + } + + @Test + public void behaviorTaxonomies() { + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/targeting_criteria/behavior_taxonomies")) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("ad-targetings-behavior_taxonomies"), APPLICATION_JSON)); + + final DataListHolder discoveries = + twitter.targetingCriteriaDiscoveryOperations().behaviorTaxonomies( + new TargetingCriteriaDiscoveryForBehaviorTaxonomiesQueryBuilder()); + + assertBehaviorTaxonomiesDiscoveries(discoveries.getList()); + } + + private void assertBehaviorTaxonomiesDiscoveries(List actual) { + Assert.assertEquals(194, actual.size()); + + Assert.assertEquals("CPG brands", actual.get(8).getName()); + Assert.assertEquals("2014-12-08T21:55:58Z", actual.get(8).getCreatedAt()); + Assert.assertEquals("9", actual.get(8).getId()); + Assert.assertEquals(null, actual.get(8).getParentId()); + Assert.assertEquals("2015-01-21T21:47:09Z", actual.get(8).getUpdatedAt()); + + Assert.assertEquals("DMA", actual.get(49).getName()); + Assert.assertEquals("2014-12-08T21:55:58Z", actual.get(49).getCreatedAt()); + Assert.assertEquals("1e", actual.get(49).getId()); + Assert.assertEquals("1a", actual.get(49).getParentId()); + Assert.assertEquals("2015-01-21T21:47:13Z", actual.get(49).getUpdatedAt()); + } + + @Test + public void behaviorTaxonomiesWithParams() { + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/targeting_criteria/behavior_taxonomies?behavior_taxonomy_ids=33&parent_behavior_taxonomy_ids=31")) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("ad-targetings-behavior_taxonomies-params"), APPLICATION_JSON)); + + final DataListHolder discoveries = + twitter.targetingCriteriaDiscoveryOperations().behaviorTaxonomies( + new TargetingCriteriaDiscoveryForBehaviorTaxonomiesQueryBuilder() + .ofParentTaxonomyIds("31") + .ofTaxonomyIds("33")); + + assertBehaviorTaxonomiesDiscoveriesWithParams(discoveries.getList()); + } + + private void assertBehaviorTaxonomiesDiscoveriesWithParams(List actual) { + Assert.assertEquals(1, actual.size()); + + Assert.assertEquals("Frequent flyers", actual.get(0).getName()); + Assert.assertEquals("2015-01-21T21:47:24Z", actual.get(0).getCreatedAt()); + Assert.assertEquals("33", actual.get(0).getId()); + Assert.assertEquals("31", actual.get(0).getParentId()); + Assert.assertEquals("2015-01-21T21:47:24Z", actual.get(0).getUpdatedAt()); + } + + @Test + public void behaviors() { + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/targeting_criteria/behaviors")) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("ad-targetings-behaviors"), APPLICATION_JSON)); + + final DataListHolder discoveries = twitter.targetingCriteriaDiscoveryOperations().behaviors( + new TargetingCriteriaDiscoveryForBehaviorsQueryBuilder()); + + assertBehaviorsDiscoveries(discoveries.getList()); + } + + private void assertBehaviorsDiscoveries(List actual) { + Assert.assertEquals(200, actual.size()); + + Assert.assertEquals("Pasta sauce", actual.get(4).getName()); + Assert.assertEquals("5331840", actual.get(4).getAudienceSize()); + Assert.assertEquals("w", actual.get(4).getBehaviorTaxonomyId()); + Assert.assertEquals("lfmj", actual.get(4).getId()); + Assert.assertEquals("Datalogix", actual.get(4).getPartnerSource()); + + Assert.assertEquals("Deli condiments", actual.get(8).getName()); + Assert.assertEquals("964380", actual.get(8).getAudienceSize()); + Assert.assertEquals("y", actual.get(8).getBehaviorTaxonomyId()); + Assert.assertEquals("lfmn", actual.get(8).getId()); + Assert.assertEquals("Datalogix", actual.get(8).getPartnerSource()); + } + + @Test + public void behaviorsWithParams() { + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/targeting_criteria/behaviors?behavior_ids=lfrz&sort_by=name-asc")) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("ad-targetings-behaviors-params"), APPLICATION_JSON)); + + final DataListHolder discoveries = twitter.targetingCriteriaDiscoveryOperations().behaviors( + new TargetingCriteriaDiscoveryForBehaviorsQueryBuilder() + .ofBehaviors("lfrz") + .sortBy("name", SortDirection.asc)); + + assertBehaviorsDiscoveriesWithParams(discoveries.getList()); + } + + private void assertBehaviorsDiscoveriesWithParams(List actual) { + Assert.assertEquals(2, actual.size()); + + Assert.assertEquals("In market: new vehicle", actual.get(0).getName()); + Assert.assertEquals("4521480", actual.get(0).getAudienceSize()); + Assert.assertEquals("3", actual.get(0).getBehaviorTaxonomyId()); + Assert.assertEquals("lfs0", actual.get(0).getId()); + Assert.assertEquals("Datalogix", actual.get(0).getPartnerSource()); + } + + @Test + public void devices() { + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/targeting_criteria/devices")) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("ad-targetings-devices"), APPLICATION_JSON)); + + final DataListHolder discoveries = twitter.targetingCriteriaDiscoveryOperations().devices( + new TargetingCriteriaDiscoveryForDevicesQueryBuilder()); + + assertDevicesDiscoveries(discoveries.getList()); + } + + private void assertDevicesDiscoveries(List actual) { + Assert.assertEquals(132, actual.size()); + + Assert.assertEquals("HTC Butterfly", actual.get(12).getName()); + Assert.assertEquals("iPad 4", actual.get(35).getName()); + } + + @Test + public void devicesWithParams() { + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/targeting_criteria/devices?q=apple")) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("ad-targetings-devices-params"), APPLICATION_JSON)); + + final DataListHolder discoveries = twitter.targetingCriteriaDiscoveryOperations().devices( + new TargetingCriteriaDiscoveryForDevicesQueryBuilder() + .withQuery("apple")); + + assertDevicesDiscoveriesWithParams(discoveries.getList()); + } + + private void assertDevicesDiscoveriesWithParams(List actual) { + Assert.assertEquals(8, actual.size()); + + Assert.assertEquals("iPhone 4", actual.get(1).getName()); + Assert.assertEquals("iPhone 4S", actual.get(2).getName()); + } + + @Test + public void events() { + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/targeting_criteria/events")) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("ad-targetings-events"), APPLICATION_JSON)); + + final DataListHolder discoveries = twitter.targetingCriteriaDiscoveryOperations().events( + new TargetingCriteriaDiscoveryForEventsQueryBuilder()); + + assertEventsDiscoveries(discoveries.getList()); + } + + private void assertEventsDiscoveries(List actual) { +// Assert.assertEquals(132, actual.size()); + +// Assert.assertEquals("HTC Butterfly", actual.get(12).getName()); +// Assert.assertEquals("iPad 4", actual.get(35).getName()); + } + + @Test + public void eventsWithParams() { + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/targeting_criteria/events?event_types=MUSIC_AND_ENTERTAINMENT&country_codes=JP&start_time=2015-07-17T00%3A00%3A00Z&end_time=2015-07-25T00%3A00%3A00Z")) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("ad-targetings-events-params"), APPLICATION_JSON)); + List eventTypes = new ArrayList(); + eventTypes.add(EventType.MUSIC_AND_ENTERTAINMENT); + List countryCodes = new ArrayList(); + countryCodes.add("JP"); + LocalDateTime startTime = LocalDateTime.parse("2015-07-17T00:00:00"); + LocalDateTime endTime = LocalDateTime.parse("2015-07-25T00:00:00"); + + + final DataListHolder discoveries = twitter.targetingCriteriaDiscoveryOperations().events( + new TargetingCriteriaDiscoveryForEventsQueryBuilder() + .withEventTypes(eventTypes) + .withCountryCodes(countryCodes) + .withStartTime(startTime) + .withEndTime(endTime)); + + assertEventsDiscoveriesWithParams(discoveries.getList()); + } + + private void assertEventsDiscoveriesWithParams(List actual) { + Assert.assertEquals(2, actual.size()); + + Assert.assertEquals(92, actual.get(0).getCountryBreakdownPercentage().size()); + Assert.assertEquals("0.02", actual.get(0).getCountryBreakdownPercentage().get("HK").toString()); + Assert.assertEquals(null, actual.get(0).getCountryCode()); + Assert.assertEquals("43.77", actual.get(0).getDeviceBreakdownPercentage().get("IOS").toString()); + Assert.assertEquals("2015-07-27T00:00:00Z", actual.get(0).getEndTime()); + Assert.assertEquals(EventType.MUSIC_AND_ENTERTAINMENT, actual.get(0).getEventType()); + Assert.assertEquals("47.17", actual.get(0).getGenderBreakdownPercentage().get("female").toString()); + Assert.assertEquals("1w", actual.get(0).getId()); + Assert.assertEquals(true, actual.get(0).isGlobal()); + Assert.assertEquals("Tomorrowland", actual.get(0).getName()); + Assert.assertEquals("122426138", actual.get(0).getReach().get("total_impressions").toString()); + Assert.assertEquals("2015-07-24T00:00:00Z", actual.get(0).getStartTime()); + Assert.assertEquals(0, actual.get(0).getTopHashTags().size()); + Assert.assertEquals(1000, actual.get(0).getTopTweets().size()); + Assert.assertEquals(100, actual.get(0).getTopUsers().size()); + } + + @Test + public void interests() { + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/targeting_criteria/interests")) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("ad-targetings-interests"), APPLICATION_JSON)); + + final DataListHolder discoveries = twitter.targetingCriteriaDiscoveryOperations().interests( + new TargetingCriteriaDiscoveryForInterestsQueryBuilder()); + + assertInterestsDiscoveries(discoveries.getList()); + } + + private void assertInterestsDiscoveries(List actual) { + Assert.assertEquals(200, actual.size()); + + Assert.assertEquals("Books and literature/Cookbooks, food, and wine", actual.get(3).getName()); + Assert.assertEquals("INTEREST", actual.get(3).getTargetingType()); + Assert.assertEquals("1004", actual.get(3).getTargetingValue()); + + Assert.assertEquals("Gaming/Roleplaying games", actual.get(52).getName()); + Assert.assertEquals("INTEREST", actual.get(52).getTargetingType()); + Assert.assertEquals("4006", actual.get(52).getTargetingValue()); + } + + @Test + public void interestsWithParams() { + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/targeting_criteria/interests?q=bird")) + + + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("ad-targetings-interests-params"), APPLICATION_JSON)); + + final DataListHolder discoveries = twitter.targetingCriteriaDiscoveryOperations().interests( + new TargetingCriteriaDiscoveryForInterestsQueryBuilder() + .withQuery("bird")); + + assertInterestsDiscoveriesWithParams(discoveries.getList()); + } + + private void assertInterestsDiscoveriesWithParams(List actual) { + Assert.assertEquals(2, actual.size()); + + Assert.assertEquals("Hobbies and interests/Birdwatching", actual.get(0).getName()); + Assert.assertEquals("INTEREST", actual.get(0).getTargetingType()); + Assert.assertEquals("13002", actual.get(0).getTargetingValue()); + } + + @Test + public void languages() { + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/targeting_criteria/languages")) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("ad-targetings-languages"), APPLICATION_JSON)); + + final DataListHolder discoveries = twitter.targetingCriteriaDiscoveryOperations().languages( + new TargetingCriteriaDiscoveryForLanguagesQueryBuilder()); + + assertLanguagesDiscoveries(discoveries.getList()); + } + + private void assertLanguagesDiscoveries(List actual) { + Assert.assertEquals(21, actual.size()); + + Assert.assertEquals("Farsi", actual.get(4).getName()); + Assert.assertEquals("LANGUAGE", actual.get(4).getTargetingType()); + Assert.assertEquals("fa", actual.get(4).getTargetingValue()); + + Assert.assertEquals("French", actual.get(6).getName()); + Assert.assertEquals("LANGUAGE", actual.get(6).getTargetingType()); + Assert.assertEquals("fr", actual.get(6).getTargetingValue()); + } + + @Test + public void languagesWithParams() { + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/targeting_criteria/languages?q=norwegian")) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("ad-targetings-languages-params"), APPLICATION_JSON)); + + final DataListHolder discoveries = twitter.targetingCriteriaDiscoveryOperations().languages( + new TargetingCriteriaDiscoveryForLanguagesQueryBuilder() + .withQuery("norwegian")); + + assertLanguagesDiscoveriesWithParams(discoveries.getList()); + } + + private void assertLanguagesDiscoveriesWithParams(List actual) { + Assert.assertEquals(1, actual.size()); + + Assert.assertEquals("Norwegian", actual.get(0).getName()); + Assert.assertEquals("LANGUAGE", actual.get(0).getTargetingType()); + Assert.assertEquals("no", actual.get(0).getTargetingValue()); + } + + @Test + public void locations() { + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/targeting_criteria/locations")) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("ad-targetings-locations"), APPLICATION_JSON)); + + final DataListHolder discoveries = twitter.targetingCriteriaDiscoveryOperations().locations( + new TargetingCriteriaDiscoveryForLocationsQueryBuilder()); + + assertLocationsDiscoveries(discoveries.getList()); + } + + private void assertLocationsDiscoveries(List actual) { + Assert.assertEquals(200, actual.size()); + + Assert.assertEquals("00603, PR, US", actual.get(2).getName()); + Assert.assertEquals("POSTAL_CODE", actual.get(2).getLocationType()); + Assert.assertEquals("LOCATION", actual.get(2).getTargetingType()); + Assert.assertEquals("84e681a9fb76656f", actual.get(2).getTargetingValue()); + + Assert.assertEquals("01012, BR", actual.get(145).getName()); + Assert.assertEquals("POSTAL_CODE", actual.get(145).getLocationType()); + Assert.assertEquals("LOCATION", actual.get(145).getTargetingType()); + Assert.assertEquals("2bb6204f6b9fcfb7", actual.get(145).getTargetingValue()); + } + + @Test + public void locationsWithParams() { + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/targeting_criteria/locations?q=Palo%2BAlto")) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("ad-targetings-locations-params"), APPLICATION_JSON)); + + final DataListHolder discoveries = twitter.targetingCriteriaDiscoveryOperations().locations( + new TargetingCriteriaDiscoveryForLocationsQueryBuilder() + .withQuery("Palo Alto")); + + assertLocationsDiscoveriesWithParams(discoveries.getList()); + } + + private void assertLocationsDiscoveriesWithParams(List actual) { + Assert.assertEquals(8, actual.size()); + + Assert.assertEquals("94301, CA, USA", actual.get(6).getName()); + Assert.assertEquals("POSTAL_CODE", actual.get(6).getLocationType()); + Assert.assertEquals("LOCATION", actual.get(6).getTargetingType()); + Assert.assertEquals("205edf12aa812e1c", actual.get(6).getTargetingValue()); + } + + @Test + public void networkOperators() { + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/targeting_criteria/network_operators")) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("ad-targetings-network_operators"), APPLICATION_JSON)); + + final DataListHolder discoveries = + twitter.targetingCriteriaDiscoveryOperations().networkOperators( + new TargetingCriteriaDiscoveryForNetworkOperatorsQueryBuilder()); + + assertNetworkOperatorsDiscoveries(discoveries.getList()); + } + + private void assertNetworkOperatorsDiscoveries(List actual) { + Assert.assertEquals(200, actual.size()); + + Assert.assertEquals("BC Tel Mobility (Telus)", actual.get(61).getName()); + Assert.assertEquals("CA", actual.get(61).getCountryCode()); + Assert.assertEquals("NETWORK_OPERATOR", actual.get(61).getTargetingType()); + Assert.assertEquals("5k", actual.get(61).getTargetingValue()); + + Assert.assertEquals("Cellular One of East Texas", actual.get(99).getName()); + Assert.assertEquals("US", actual.get(99).getCountryCode()); + Assert.assertEquals("NETWORK_OPERATOR", actual.get(99).getTargetingType()); + Assert.assertEquals("2k", actual.get(99).getTargetingValue()); + } + + @Test + public void networkOperatorsWithParams() { + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/targeting_criteria/network_operators?country_code=US&q=Mobile")) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("ad-targetings-network_operators-params"), APPLICATION_JSON)); + + final DataListHolder discoveries = + twitter.targetingCriteriaDiscoveryOperations().networkOperators( + new TargetingCriteriaDiscoveryForNetworkOperatorsQueryBuilder() + .withQuery("Mobile") + .withCountryCode("US")); + + assertNetworkOperatorsDiscoveriesWithParams(discoveries.getList()); + } + + private void assertNetworkOperatorsDiscoveriesWithParams(List actual) { + Assert.assertEquals(7, actual.size()); + + Assert.assertEquals("SeaMobile", actual.get(3).getName()); + Assert.assertEquals("US", actual.get(3).getCountryCode()); + Assert.assertEquals("NETWORK_OPERATOR", actual.get(3).getTargetingType()); + Assert.assertEquals("1x", actual.get(3).getTargetingValue()); + } + + @Test + public void platformVersions() { + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/targeting_criteria/platform_versions")) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("ad-targetings-platform_versions"), APPLICATION_JSON)); + + final DataListHolder discoveries = + twitter.targetingCriteriaDiscoveryOperations().platformVersions( + new TargetingCriteriaDiscoveryForPlatformVersionsQueryBuilder()); + + assertPlatformVersionsDiscoveries(discoveries.getList()); + } + + private void assertPlatformVersionsDiscoveries(List actual) { + Assert.assertEquals(22, actual.size()); + + Assert.assertEquals("4.2", actual.get(2).getName()); + Assert.assertEquals("4.2", actual.get(2).getNumber()); + Assert.assertEquals("iOS", actual.get(2).getPlatform()); + Assert.assertEquals("PLATFORM_VERSION", actual.get(2).getTargetingType()); + Assert.assertEquals("3", actual.get(2).getTargetingValue()); + + Assert.assertEquals("Honeycomb", actual.get(17).getName()); + Assert.assertEquals("3.0", actual.get(17).getNumber()); + Assert.assertEquals("Android", actual.get(17).getPlatform()); + Assert.assertEquals("PLATFORM_VERSION", actual.get(17).getTargetingType()); + Assert.assertEquals("g", actual.get(17).getTargetingValue()); + } + + @Test + public void platformVersionsWithParams() { + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/targeting_criteria/platform_versions?q=cupcake")) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("ad-targetings-platform_versions-params"), APPLICATION_JSON)); + + final DataListHolder discoveries = + twitter.targetingCriteriaDiscoveryOperations().platformVersions( + new TargetingCriteriaDiscoveryForPlatformVersionsQueryBuilder() + .withQuery("cupcake")); + + assertPlatformVersionsDiscoveriesWithParams(discoveries.getList()); + } + + private void assertPlatformVersionsDiscoveriesWithParams(List actual) { + Assert.assertEquals(1, actual.size()); + + Assert.assertEquals("Cupcake", actual.get(0).getName()); + Assert.assertEquals("1.5", actual.get(0).getNumber()); + Assert.assertEquals("Android", actual.get(0).getPlatform()); + Assert.assertEquals("PLATFORM_VERSION", actual.get(0).getTargetingType()); + Assert.assertEquals("b", actual.get(0).getTargetingValue()); + } + + @Test + public void platforms() { + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/targeting_criteria/platforms")) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("ad-targetings-platforms"), APPLICATION_JSON)); + + final DataListHolder discoveries = twitter.targetingCriteriaDiscoveryOperations().platforms( + new TargetingCriteriaDiscoveryForPlatformsQueryBuilder()); + + assertPlatformsDiscoveries(discoveries.getList()); + } + + private void assertPlatformsDiscoveries(List actual) { + Assert.assertEquals(5, actual.size()); + + Assert.assertEquals("iOS", actual.get(0).getName()); + Assert.assertEquals("PLATFORM", actual.get(0).getTargetingType()); + Assert.assertEquals("0", actual.get(0).getTargetingValue()); + + Assert.assertEquals("Desktop and laptop computers", actual.get(4).getName()); + Assert.assertEquals("PLATFORM", actual.get(4).getTargetingType()); + Assert.assertEquals("4", actual.get(4).getTargetingValue()); + } + + @Test + public void platformsWithParams() { + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/targeting_criteria/platforms?q=blackberry")) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("ad-targetings-platforms-params"), APPLICATION_JSON)); + + final DataListHolder discoveries = twitter.targetingCriteriaDiscoveryOperations().platforms( + new TargetingCriteriaDiscoveryForPlatformsQueryBuilder() + .withQuery("blackberry")); + + assertPlatformsDiscoveriesWithParams(discoveries.getList()); + } + + private void assertPlatformsDiscoveriesWithParams(List actual) { + Assert.assertEquals(1, actual.size()); + + Assert.assertEquals("BlackBerry phones and tablets", actual.get(0).getName()); + Assert.assertEquals("PLATFORM", actual.get(0).getTargetingType()); + Assert.assertEquals("2", actual.get(0).getTargetingValue()); + } + + @Test + public void tvShows() { + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/targeting_criteria/tv_shows?tv_market_locale=pt-BR")) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("ad-targetings-tv_shows"), APPLICATION_JSON)); + + final DataListHolder discoveries = twitter.targetingCriteriaDiscoveryOperations().tvShow( + new TargetingCriteriaDiscoveryForTvShowQueryBuilder() + .withLocale("pt-BR")); + + assertTvShowsDiscoveries(discoveries.getList()); + } + + private void assertTvShowsDiscoveries(List actual) { + Assert.assertEquals(50, actual.size()); + + Assert.assertEquals(new Long("10032876335"), actual.get(0).getId()); + Assert.assertEquals(new Long("1000"), actual.get(0).getEstimatedUsers()); + Assert.assertEquals("Debate 2014 - Presidente", actual.get(0).getName()); + Assert.assertEquals("SPECIAL", actual.get(0).getGenre()); + + Assert.assertEquals(new Long("10032994279"), actual.get(1).getId()); + Assert.assertEquals(new Long("1000"), actual.get(1).getEstimatedUsers()); + Assert.assertEquals("2014 FIBA World Cup", actual.get(1).getName()); + Assert.assertEquals("SPORTS", actual.get(1).getGenre()); + } + + @Test + public void tvShowsWithQuery() { + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/targeting_criteria/tv_shows?tv_market_locale=pt-BR&q=Glee")) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("ad-targetings-tv_shows-params"), APPLICATION_JSON)); + + final DataListHolder discoveries = twitter.targetingCriteriaDiscoveryOperations().tvShow( + new TargetingCriteriaDiscoveryForTvShowQueryBuilder() + .withLocale("pt-BR") + .withQuery("Glee")); + + assertTvShowsDiscoveriesWithSearch(discoveries.getList()); + } + + private void assertTvShowsDiscoveriesWithSearch(List actual) { + Assert.assertEquals(1, actual.size()); + + Assert.assertEquals(new Long("10028587441"), actual.get(0).getId()); + Assert.assertEquals(new Long("99754"), actual.get(0).getEstimatedUsers()); + Assert.assertEquals("Glee", actual.get(0).getName()); + Assert.assertEquals("DRAMA", actual.get(0).getGenre()); + } + + @Test + public void tvMarkets() { + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/targeting_criteria/tv_markets")) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("ad-targetings-tv_markets"), APPLICATION_JSON)); + + final DataListHolder discoveries = twitter.targetingCriteriaDiscoveryOperations().tvMarkets( + new TargetingCriteriaDiscoveryForTvMarketQueryBuilder()); + + assertTvMarketsDiscoveries(discoveries.getList()); + } + + private void assertTvMarketsDiscoveries(List actual) { + Assert.assertEquals(17, actual.size()); + + Assert.assertEquals("6", actual.get(0).getId()); + Assert.assertEquals("France", actual.get(0).getName()); + Assert.assertEquals("FR", actual.get(0).getCountryCode()); + Assert.assertEquals("fr-FR", actual.get(0).getLocale()); + + Assert.assertEquals("i", actual.get(1).getId()); + Assert.assertEquals("Chile", actual.get(1).getName()); + Assert.assertEquals("CL", actual.get(1).getCountryCode()); + Assert.assertEquals("es-CL", actual.get(1).getLocale()); + } + + @Test + public void tvGenres() { + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/targeting_criteria/tv_genres")) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("ad-targetings-tv_genres"), APPLICATION_JSON)); + + final DataListHolder discoveries = twitter.targetingCriteriaDiscoveryOperations().tvGenres( + new TargetingCriteriaDiscoveryForTvGenreQueryBuilder()); + + assertTvGenresDiscoveries(discoveries.getList()); + } + + private void assertTvGenresDiscoveries(List actual) { + Assert.assertEquals(20, actual.size()); + + Assert.assertEquals(new Long("2"), actual.get(0).getId()); + Assert.assertEquals("COMEDY", actual.get(0).getName()); + + Assert.assertEquals(new Long("11"), actual.get(1).getId()); + Assert.assertEquals("SPORTS", actual.get(1).getName()); + } + + @Test + public void tvChannels() { + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/targeting_criteria/tv_channels")) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("ad-targetings-tv_channels"), APPLICATION_JSON)); + + final DataListHolder discoveries = twitter.targetingCriteriaDiscoveryOperations().tvChannels( + new TargetingCriteriaDiscoveryForTvChannelQueryBuilder()); + + assertTvChannelsDiscoveries(discoveries.getList()); + } + + private void assertTvChannelsDiscoveries(List actual) { + Assert.assertEquals(200, actual.size()); + + Assert.assertEquals(new Long("1003"), actual.get(0).getId()); + Assert.assertEquals("ESPN", actual.get(0).getName()); + + Assert.assertEquals(new Long("1004"), actual.get(1).getId()); + Assert.assertEquals("Cartoon Network", actual.get(1).getName()); + } + + +} diff --git a/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaTemplateTest.java b/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaTemplateTest.java new file mode 100644 index 00000000..bb9919e5 --- /dev/null +++ b/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/advertising/TargetingCriteriaTemplateTest.java @@ -0,0 +1,276 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.advertising; + +import static org.junit.Assert.assertEquals; +import static org.springframework.http.HttpMethod.DELETE; +import static org.springframework.http.HttpMethod.GET; +import static org.springframework.http.HttpMethod.POST; +import static org.springframework.http.HttpMethod.PUT; +import static org.springframework.http.MediaType.APPLICATION_JSON; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.content; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.method; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo; +import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess; + +import java.time.LocalDateTime; +import java.time.Month; +import java.util.List; + +import org.junit.Test; +import org.springframework.social.twitter.api.advertising.RetargetingEngagementType; +import org.springframework.social.twitter.api.advertising.TailoredAudienceType; +import org.springframework.social.twitter.api.advertising.TargetingCriterionAgeBucket; +import org.springframework.social.twitter.api.advertising.TargetingCriterionGender; +import org.springframework.social.twitter.api.advertising.TargetingCriterion; +import org.springframework.social.twitter.api.impl.AbstractTwitterApiTest; +import org.springframework.social.twitter.api.impl.DataListHolder; + +/** + * @author Hudson mendes + */ +public class TargetingCriteriaTemplateTest extends AbstractTwitterApiTest { + + @Test + public void getTargetingCriterions() { + final String mockedAccountId = "hkk5"; + final String mockedLineItemId = "oi4h5"; + mockServer + .expect(requestTo( + "https://ads-api.twitter.com/0/accounts/" + mockedAccountId + "/targeting_criteria" + + "?line_item_id=" + mockedLineItemId + + "&with_deleted=false")) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("ad-targeting-criteria"), APPLICATION_JSON)); + + final DataListHolder targetingCriterias = twitter.targetingCriteriaOperations().getTargetingCriterions( + mockedAccountId, + new TargetingCriterionQueryBuilder() + .withLineItem(mockedLineItemId) + .includeDeleted(false)); + + assertTargetCriterionContents(targetingCriterias.getList()); + } + + @Test + public void getTargetingCriterion() { + final String mockedAccountId = "hkk5"; + final String mockedTargetingCriteriaId = "2rqqn"; + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/accounts/" + mockedAccountId + "/targeting_criteria/" + mockedTargetingCriteriaId)) + .andExpect(method(GET)) + .andRespond(withSuccess(jsonResource("ad-targeting-criteria-single"), APPLICATION_JSON)); + + final TargetingCriterion criteria = twitter.targetingCriteriaOperations().getTargetingCriterion(mockedAccountId, mockedTargetingCriteriaId); + assertSingleTargetingCriterionContents(criteria); + } + + @Test + public void createTargetingCriterion() { + final String mockedAccountId = "hkk5"; + final String doesntMatterString = "doesnt-matter"; + final Boolean doesntMatterBool = false; + final String chainedPostContent = + "line_item_id=" + doesntMatterString + "&" + + "name=" + doesntMatterString + "&" + + "targeting_type=" + "APP_STORE_CATEGORY" + "&" + + "targeting_value=" + doesntMatterString + "&" + + "deleted=" + doesntMatterBool + "&" + + "tailored_audience_expansion=" + doesntMatterBool + "&" + + "tailored_audience_type=" + TailoredAudienceType.EXCLUDED_MOBILE; + + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/accounts/" + mockedAccountId + "/targeting_criteria")) + .andExpect(method(POST)) + .andExpect(content().string(chainedPostContent)) + .andRespond(withSuccess(jsonResource("ad-targeting-criteria-single"), APPLICATION_JSON)); + + final TargetingCriterion criteria = twitter.targetingCriteriaOperations().createTargetingCriterion( + mockedAccountId, + new TargetingCriterionFormBuilder() + .withLineItem(doesntMatterString) + .withName(doesntMatterString) + .withTargetedAudienceExpansion(doesntMatterBool) + .withTargetedAudienceType(TailoredAudienceType.EXCLUDED_MOBILE) + .targeting("APP_STORE_CATEGORY", doesntMatterString) + .active()); + + assertSingleTargetingCriterionContents(criteria); + } + + @Test + public void setTargetingCriteria() { + final String mockedAccountId = "hkk5"; + final String mockedLineItem = "45j45"; + final String chainedPostContent = + "line_item_id=" + mockedLineItem + "&" + + "broad_keywords=bkw1%2Cbkw2&" + + "exact_keywords=ekw1&" + + "unordered_keywords=&" + + "phrase_keywords=pkw0&" + + "negative_exact_keywords=nekw9&" + + "negative_unordered_keywords=&" + + "negative_phrase_keywords=npkw111&" + + "locations=b6b8d75a320f81d9%2C6c6fd550ac2d3d60&" + + "interests=19004%2C19002&" + + "gender=2&" + + "age_buckets=AGE_35_TO_44%2CAGE_OVER_65&" + + "followers_of_users=1324%2C297527452457&" + + "similar_to_followers_of_users=945%2C12%2C1%2C88888888888&" + + "platforms=0%2C4&" + + "platform_versions=10%2C14&" + + "devices=7%2C23&" + + "wifi_only=1&" + + "tv_channels=3113%2C6945&" + + "tv_genres=9%2C15&" + + "tv_shows=10024849207%2C10000271509&" + + "tailored_audiences=a6b8d%2Cac6fd&" + + "tailored_audiences_expanded=b6b8d%2Cbc6fd&" + + "tailored_audiences_excluded=c6b8d%2Ccc6fd&" + + "behaviors=afmj%2Cafrr&" + + "behaviors_expanded=bfmj%2Cbfrr&" + + "negative_behaviors=cfmj%2Ccfrr&" + + "languages=en%2Cfi&" + + "event=aj12b&" + + "network_operators=dfmj%2Cdfrr&" + + "network_activation_duration_lt=3&" + + "network_activation_duration_gte=3&" + + "app_store_categories=efmj%2Cefrr&" + + "app_store_categories_lookalike=ffmj%2Cffrr&" + + "campaign_engagement=7ako2&" + + "user_engagement=12345&" + + "engagement_type=ENGAGEMENT"; + + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/accounts/" + mockedAccountId + "/targeting_criteria")) + .andExpect(method(PUT)) + .andExpect(content().string(chainedPostContent)) + .andRespond(withSuccess(jsonResource("ad-targeting-criteria"), APPLICATION_JSON)); + + final DataListHolder criteria = twitter.targetingCriteriaOperations().setTargetingCriteria( + mockedAccountId, + new TargetingCriteriaFormBuilder() + .forLineItem(mockedLineItem) + .withBroadKeywords("bkw1", "bkw2") + .withExactKeywords("ekw1") + .withUnorderedKeywords((String) null) + .withPhraseKeywords("pkw0") + .withNegativeExactKeywords("nekw9") + .withNegativeUnorderedKeywords((String) null) + .withNegativePhraseKeywords("npkw111") + .withLocations("b6b8d75a320f81d9", "6c6fd550ac2d3d60") + .withInterests("19004", "19002") + .withGender(TargetingCriterionGender.FEMALE) + .withAgeBuckets(TargetingCriterionAgeBucket.AGE_35_TO_44, TargetingCriterionAgeBucket.AGE_OVER_65) + .followersOfUsers(1324L, 297527452457L) + .similarToUsers(945L, 12L, 1L, 88888888888L) + .withPlatforms("0", "4") + .withPlatformVersions("10", "14") + .withDevices("7", "23") + .onlyWify(true) + .withTvChannels("3113", "6945") + .withTvGenres("9", "15") + .withTvShows("10024849207", "10000271509") + .withTailoredAudiences("a6b8d", "ac6fd") + .withTailoredAudiencesExpanded("b6b8d", "bc6fd") + .withTailoredAudiencesExclusion("c6b8d", "cc6fd") + .withBehaviors("afmj", "afrr") + .withBehaviorsExpaned("bfmj", "bfrr") + .withBehaviorsNegative("cfmj", "cfrr") + .withLanguages("en", "fi") + .forEvent("aj12b") + .withNetworkOperators("dfmj", "dfrr") + .withNetworkActivationDurationLess(3) + .withNetworkActivationDurationMoreOrEqualsTo(3) + .withAppStoreCategories("efmj", "efrr") + .withAppStoreCategiresLookAlike("ffmj", "ffrr") + .forRetargetingEngagementOfCampaign("7ako2") + .forRetargetingEngagementOfPromotedUser(12345L) + .forRetargetingEngagementType(RetargetingEngagementType.ENGAGEMENT)); + + assertTargetCriterionContents(criteria.getList()); + } + + @Test + public void deleteTargetingCriterions() { + final String mockedAccountId = "hkk5"; + final String mockedTargetingCriterionId = "oi4h5"; + mockServer + .expect(requestTo("https://ads-api.twitter.com/0/accounts/" + mockedAccountId + "/targeting_criteria/" + mockedTargetingCriterionId)) + .andExpect(method(DELETE)) + .andRespond(withSuccess()); + + twitter.targetingCriteriaOperations().deleteTargetingCriterion(mockedAccountId, mockedTargetingCriterionId); + } + + private void assertTargetCriterionContents(List criterias) { + assertEquals(4, criterias.size()); + + assertEquals("2kzxf", criterias.get(0).getId()); + assertEquals("hkk5", criterias.get(0).getAccountId()); + assertEquals("69ob", criterias.get(0).getLineItemId()); + assertEquals("episod", criterias.get(0).getName()); + assertEquals("SIMILAR_TO_FOLLOWERS_OF_USER", criterias.get(0).getTargetingType()); + assertEquals("819797", criterias.get(0).getTargetingValue()); + assertEquals(false, criterias.get(0).isDeleted()); + assertEquals(LocalDateTime.of(2012, Month.NOVEMBER, 30, 22, 58, 11), criterias.get(0).getCreatedAt()); + assertEquals(LocalDateTime.of(2012, Month.NOVEMBER, 30, 22, 58, 11), criterias.get(0).getUpdatedAt()); + + assertEquals("2kzxi", criterias.get(1).getId()); + assertEquals("hkk5", criterias.get(1).getAccountId()); + assertEquals("69ob", criterias.get(1).getLineItemId()); + assertEquals("matrixsynth", criterias.get(1).getName()); + assertEquals("SIMILAR_TO_FOLLOWERS_OF_USER", criterias.get(1).getTargetingType()); + assertEquals("22231561", criterias.get(1).getTargetingValue()); + assertEquals(false, criterias.get(1).isDeleted()); + assertEquals(LocalDateTime.of(2012, Month.NOVEMBER, 30, 22, 58, 12), criterias.get(1).getCreatedAt()); + assertEquals(LocalDateTime.of(2012, Month.NOVEMBER, 30, 22, 58, 12), criterias.get(1).getUpdatedAt()); + + assertEquals("2kzxj", criterias.get(2).getId()); + assertEquals("hkk5", criterias.get(2).getAccountId()); + assertEquals("69ob", criterias.get(2).getLineItemId()); + assertEquals("Horse_ebooks", criterias.get(2).getName()); + assertEquals("SIMILAR_TO_FOLLOWERS_OF_USER", criterias.get(2).getTargetingType()); + assertEquals("174958347", criterias.get(2).getTargetingValue()); + assertEquals(false, criterias.get(2).isDeleted()); + assertEquals(LocalDateTime.of(2012, Month.NOVEMBER, 30, 22, 58, 12), criterias.get(2).getCreatedAt()); + assertEquals(LocalDateTime.of(2012, Month.NOVEMBER, 30, 22, 58, 12), criterias.get(2).getUpdatedAt()); + + assertEquals("2mq7j", criterias.get(3).getId()); + assertEquals("hkk5", criterias.get(3).getAccountId()); + assertEquals("69ob", criterias.get(3).getLineItemId()); + assertEquals("righteous dude", criterias.get(3).getName()); + assertEquals("PHRASE_KEYWORD", criterias.get(3).getTargetingType()); + assertEquals("righteous dude", criterias.get(3).getTargetingValue()); + assertEquals(true, criterias.get(3).isDeleted()); + assertEquals(LocalDateTime.of(2012, Month.DECEMBER, 05, 05, 11, 15), criterias.get(3).getCreatedAt()); + assertEquals(LocalDateTime.of(2012, Month.DECEMBER, 06, 05, 11, 15), criterias.get(3).getUpdatedAt()); + } + + private void assertSingleTargetingCriterionContents(TargetingCriterion criteria) { + assertEquals("31l8r", criteria.getId()); + assertEquals("gq0vqj", criteria.getAccountId()); + assertEquals("bcrv", criteria.getLineItemId()); + assertEquals("Mobile audience targeting", criteria.getName()); + assertEquals(false, criteria.isTailoredAudienceExpansion()); + assertEquals(TailoredAudienceType.EXCLUDED_MOBILE, criteria.getTailoredAudienceType()); + assertEquals("TAILORED_AUDIENCE", criteria.getTargetingType()); + assertEquals("qsb3", criteria.getTargetingValue()); + assertEquals(false, criteria.isDeleted()); + assertEquals(LocalDateTime.of(2015, Month.JULY, 23, 23, 14, 37), criteria.getCreatedAt()); + assertEquals(LocalDateTime.of(2015, Month.JULY, 23, 23, 14, 37), criteria.getUpdatedAt()); + } +} diff --git a/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/ton/TonTemplateTest.java b/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/ton/TonTemplateTest.java new file mode 100644 index 00000000..952f9d59 --- /dev/null +++ b/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/ton/TonTemplateTest.java @@ -0,0 +1,73 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.ton; + +import static org.junit.Assert.assertEquals; +import static org.springframework.http.HttpMethod.POST; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.method; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo; +import static org.springframework.test.web.client.response.MockRestResponseCreators.withCreatedEntity; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URLConnection; +import java.time.ZonedDateTime; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.Test; +import org.springframework.core.io.Resource; +import org.springframework.social.twitter.api.impl.AbstractTwitterApiTest; + +/** + * @author Chris Latko + */ +public class TonTemplateTest extends AbstractTwitterApiTest { + @SuppressWarnings("unused") + private final static Log logger = LogFactory.getLog(TonTemplateTest.class); + private final static String BUCKET_NAME = "ta_partner"; + private final static String RESPONSE_URI = "https://ton.twitter.com/1.1/ton/data/ta_partner/390472547/ffs.txt"; + + @Test + public void uploadChunk() throws IOException { + mockServer + .expect(requestTo("https://ton.twitter.com/1.1/ton/bucket/ta_partner")) + .andExpect(method(POST)) + .andRespond(withCreatedEntity(URI.create(RESPONSE_URI))); + + Resource resource = dataResource("hashed_twitter.txt"); + InputStream is = resource.getInputStream(); + String contentType = URLConnection.guessContentTypeFromName(resource.getFilename()); + byte[] data = bufferObj(is); + ZonedDateTime expiry = ZonedDateTime.now().plusDays(7); + URI uri = twitter.tonOperations().uploadSingleChunk(BUCKET_NAME, data, contentType, expiry); + assertEquals(uri.toString(),RESPONSE_URI); + } + + private byte[] bufferObj(final InputStream is) throws IOException { + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + int count; + byte[] data = new byte[16384]; + while((count = is.read(data, 0, data.length)) != -1) { + buffer.write(data, 0, count); + } + buffer.flush(); + return buffer.toByteArray(); + } + +} diff --git a/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/upload/UploadTemplateTest.java b/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/upload/UploadTemplateTest.java new file mode 100644 index 00000000..994225b8 --- /dev/null +++ b/spring-social-twitter/src/test/java/org/springframework/social/twitter/api/impl/upload/UploadTemplateTest.java @@ -0,0 +1,141 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.social.twitter.api.impl.upload; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.junit.Assert.assertEquals; +import static org.springframework.http.HttpMethod.POST; +import static org.springframework.http.MediaType.APPLICATION_JSON; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.content; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.method; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo; +import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess; +import static org.springframework.test.web.client.response.MockRestResponseCreators.withNoContent; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.Test; +import org.springframework.core.io.Resource; +import org.springframework.http.HttpStatus; +import org.springframework.social.twitter.api.impl.AbstractTwitterApiTest; +import org.springframework.social.twitter.api.upload.ChunkCommandType; +import org.springframework.social.twitter.api.upload.UploadedEntity; + +/** + * @author Chris Latko + */ +public class UploadTemplateTest extends AbstractTwitterApiTest { + @SuppressWarnings("unused") + private final static Log logger = LogFactory.getLog(UploadTemplateTest.class); + private final static String MEDIA_ID = "623694170260049925"; + + + @Test + public void uploadSimple_test() throws IOException { + mockServer + .expect(requestTo("https://upload.twitter.com/1.1/media/upload.json")) + .andExpect(method(POST)) + .andRespond(withSuccess(jsonResource("upload"), APPLICATION_JSON)); + + final Resource resource = dataResource("profilepic.gif"); + final InputStream is = resource.getInputStream(); + final byte[] data = bufferObj(is); + + final UploadedEntity uploadedEntity = twitter.uploadOperations().uploadSimple(data); + assertEquals(12302, uploadedEntity.getSize()); + assertEquals("image/png", uploadedEntity.getImage().getImageType()); + } + + @Test + public void uploadChunkedInit_test() { + final String command = ChunkCommandType.INIT.name(); + final String contentType = "video/mp4"; + final int totalSize = 383631; + + mockServer + .expect(requestTo("https://upload.twitter.com/1.1/media/upload.json")) + .andExpect(method(POST)) + .andExpect(content().string(containsString("Content-Disposition: form-data; name=\"command\""))) + .andExpect(content().string(containsString("Content-Disposition: form-data; name=\"media_type\""))) + .andExpect(content().string(containsString("Content-Disposition: form-data; name=\"total_bytes\""))) + .andExpect(content().string(containsString(command))) + .andExpect(content().string(containsString(contentType))) + .andExpect(content().string(containsString(String.valueOf(totalSize)))) + .andRespond(withSuccess(jsonResource("init"), APPLICATION_JSON)); + + final UploadedEntity uploadedEntity = twitter.uploadOperations().uploadChunkedInit(totalSize, contentType); + assertEquals(MEDIA_ID, uploadedEntity.getMediaIdString()); + assertEquals(3599, uploadedEntity.getExpiresAfterSecs()); + } + + @Test + public void uploadChunkedAppend_test() throws IOException { + final String command = ChunkCommandType.APPEND.name(); + final Resource resource = dataResource("small.mp4"); + final InputStream is = resource.getInputStream(); + final byte[] data = bufferObj(is); + + mockServer + .expect(requestTo("https://upload.twitter.com/1.1/media/upload.json")) + .andExpect(method(POST)) + .andExpect(content().string(containsString("Content-Disposition: form-data; name=\"command\""))) + .andExpect(content().string(containsString("Content-Disposition: form-data; name=\"media_id\""))) + .andExpect(content().string(containsString("Content-Disposition: form-data; name=\"segment_index\""))) + .andExpect(content().string(containsString("Content-Disposition: form-data; name=\"media\""))) + .andExpect(content().string(containsString(command))) + .andExpect(content().string(containsString(MEDIA_ID))) + .andRespond(withNoContent()); + + HttpStatus status = twitter.uploadOperations().uploadChunkedAppend(MEDIA_ID, data, 0); + assertEquals(204, status.value()); + } + + @Test + public void uploadChunkedFinalize_test() throws IOException { + final String command = ChunkCommandType.FINALIZE.name(); + + mockServer + .expect(requestTo("https://upload.twitter.com/1.1/media/upload.json")) + .andExpect(method(POST)) + .andExpect(content().string(containsString("Content-Disposition: form-data; name=\"command\""))) + .andExpect(content().string(containsString("Content-Disposition: form-data; name=\"media_id\""))) + .andExpect(content().string(containsString(command))) + .andExpect(content().string(containsString(MEDIA_ID))) + .andRespond(withSuccess(jsonResource("finalize"), APPLICATION_JSON)); + + final UploadedEntity uploadedEntity = twitter.uploadOperations().uploadChunkedFinalize(MEDIA_ID); + assertEquals(MEDIA_ID, uploadedEntity.getMediaIdString()); + assertEquals(3600, uploadedEntity.getExpiresAfterSecs()); + assertEquals(383631, uploadedEntity.getSize()); + assertEquals("video/mp4", uploadedEntity.getVideo().getVideoType()); + } + + + private byte[] bufferObj(final InputStream is) throws IOException { + final ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + int count; + final byte[] data = new byte[16384]; + while ((count = is.read(data, 0, data.length)) != -1) + buffer.write(data, 0, count); + buffer.flush(); + return buffer.toByteArray(); + } + +} diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-accounts-features.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-accounts-features.json new file mode 100644 index 00000000..1306db83 --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-accounts-features.json @@ -0,0 +1,12 @@ +{ + "data": [ + "MOBILE_CONVERSION_TRANSACTION_VALUE", + "INSTALLED_APP_CATEGORY_TARGETING" + ], + "data_type": "features", + "request": { + "params": { + "account_id": "gq0vqj" + } + } +} \ No newline at end of file diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-accounts-permissions.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-accounts-permissions.json new file mode 100644 index 00000000..3cff1686 --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-accounts-permissions.json @@ -0,0 +1,14 @@ +{ + "data": { + "permissions": [ + "ACCOUNT_ADMIN" + ], + "user_id": 390472547 + }, + "data_type": "user_access", + "request": { + "params": { + "account_id": "gq0vqj" + } + } +} \ No newline at end of file diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-accounts-single.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-accounts-single.json new file mode 100644 index 00000000..403e94ae --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-accounts-single.json @@ -0,0 +1,19 @@ +{ + "data": { + "approval_status": "ACCEPTED", + "created_at": "2015-04-13T20:42:39Z", + "deleted": false, + "id": "gq0vqj", + "name": "Account for the user @unkown", + "salt": "abababababababababababababababab", + "timezone": "America/Los_Angeles", + "timezone_switch_at": null, + "updated_at": "2015-07-13T20:17:34Z" + }, + "data_type": "account", + "request": { + "params": { + "account_id": "gq0vqj" + } + } +} diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-accounts.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-accounts.json new file mode 100644 index 00000000..e3a02715 --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-accounts.json @@ -0,0 +1,32 @@ +{ + "request": { + "params": {} + }, + "data": [ + { + "name": "h1234jasd", + "timezone": "America/Los_Angeles", + "timezone_switch_at": "2013-05-22T07:00:00Z", + "id": "l0l0l0", + "created_at": "2013-03-05T21:57:11Z", + "salt": "699169a7693e571000000fef0ef0ef09", + "updated_at": "2015-02-21T03:15:30Z", + "approval_status": "ACCEPTED", + "deleted": false + }, + { + "name": "test02483", + "timezone": "America/Los_Angeles", + "timezone_switch_at": "2013-01-01T01:01:01Z", + "id": "l1l1l1", + "created_at": "2011-01-01T01:01:01Z", + "salt": "abababababababababababababababab", + "updated_at": "2012-01-01T01:01:01Z", + "approval_status": "ACCEPTED", + "deleted": false + } + ], + "data_type": "account", + "total_count": 2, + "next_cursor": null +} \ No newline at end of file diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-campaigns-single.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-campaigns-single.json new file mode 100644 index 00000000..c5c58937 --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-campaigns-single.json @@ -0,0 +1,29 @@ +{ + "data": { + "account_id": "1ga1yn", + "created_at": "2015-02-09T00:00:00Z", + "currency": "USD", + "daily_budget_amount_local_micro": 40000000, + "deleted": false, + "end_time": null, + "funding_instrument_id": "yyyy", + "id": "92ph", + "name": "My First Campaign", + "paused": false, + "standard_delivery": true, + "start_time": "2015-02-09T00:00:00Z", + "total_budget_amount_local_micro": 500000000, + "updated_at": "2015-02-09T00:00:00Z" + }, + "data_type": "campaign", + "request": { + "params": { + "account_id": "1ga1yn", + "daily_budget_amount_local_micro": 50000000, + "funding_instrument_id": "yyyy", + "name": "My First Campaign", + "start_time": "2015-02-09T00:00:00Z", + "total_budget_amount_local_micro": 500000000 + } + } +} \ No newline at end of file diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-campaigns.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-campaigns.json new file mode 100644 index 00000000..a0473a95 --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-campaigns.json @@ -0,0 +1,33 @@ +{ + "request": { + "params": { + "account_id": "0ga0yn" + } + }, + "data": [ + { + "name": "C1-oldlalala-generic", + "start_time": "2014-05-15T00:12:00Z", + "reasons_not_servable": [ + "EXPIRED", + "PAUSED_BY_ADVERTISER" + ], + "servable": false, + "daily_budget_amount_local_micro": 10000000, + "end_time": "2014-05-16T22:00:00Z", + "funding_instrument_id": "ik58g", + "standard_delivery": true, + "total_budget_amount_local_micro": 45000000, + "id": "1850jm", + "paused": true, + "account_id": "0ga0yn", + "currency": "USD", + "created_at": "2014-05-15T01:17:47Z", + "updated_at": "2014-05-16T20:41:38Z", + "deleted": false + } + ], + "data_type": "campaign", + "total_count": 71, + "next_cursor": "18l3ms5c" +} \ No newline at end of file diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-funding-instruments-single.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-funding-instruments-single.json new file mode 100644 index 00000000..8a325f2c --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-funding-instruments-single.json @@ -0,0 +1,28 @@ +{ + "data": { + "able_to_fund": true, + "account_id": "gq0vqj", + "cancelled": false, + "created_at": "2015-04-13T20:42:39Z", + "credit_limit_local_micro": 0, + "credit_remaining_local_micro": null, + "currency": "USD", + "deleted": false, + "description": "(no payment method has been set up yet)", + "end_time": null, + "funded_amount_local_micro": 0, + "id": "hxcnv", + "paused": false, + "reasons_not_able_to_fund": [], + "start_time": "2015-04-13T20:42:39Z", + "type": "CREDIT_CARD", + "updated_at": "2015-04-13T20:42:39Z" + }, + "data_type": "funding_instrument", + "request": { + "params": { + "account_id": "gq0vqj", + "funding_instrument_id": "hxcnv" + } + } +} diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-funding-instruments.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-funding-instruments.json new file mode 100644 index 00000000..90c54ab7 --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-funding-instruments.json @@ -0,0 +1,46 @@ +{ + "data": [ + { + "account_id": "hkk5", + "cancelled": false, + "created_at": "2012-11-08T02:31:46Z", + "credit_limit_local_micro": 1000000000, + "currency": "USD", + "deleted": true, + "description": "MasterCard ending in 1234", + "end_time": null, + "funded_amount_local_micro": 100000000, + "id": "hw6ie", + "start_time": "2012-11-08T02:31:46Z", + "type": "CREDIT_CARD", + "updated_at": "2012-11-20T23:20:35Z" + }, + { + "account_id": "hkk5", + "cancelled": false, + "created_at": "2013-05-30T18:16:38Z", + "credit_limit_local_micro": 150000000000, + "credit_remaining_local_micro": 123661919751, + "currency": "GBP", + "deleted": false, + "description": "FakeNike - Credit Line", + "end_time": null, + "funded_amount_local_micro": 0, + "id": "i1234", + "start_time": "2013-05-30T04:00:00Z", + "type": "CREDIT_LINE", + "updated_at": "2013-05-30T18:16:38Z" + } + ], + "data_type": "funding_instrument", + "request": { + "params": { + "account_id": "hkk5", + "funding_instrument_ids": [ + "hw6ie" + ], + "with_deleted": true + } + }, + "total_count": 1 +} \ No newline at end of file diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-global-opt-out.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-global-opt-out.json new file mode 100644 index 00000000..4279ba41 --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-global-opt-out.json @@ -0,0 +1,14 @@ +{ + "data": { + "input_file_path": "/ta_partner/985495847/jvndHDh-482AdNa.txt", + "list_type": "HANDLE" + }, + "data_type": "global_opt_out", + "request": { + "params": { + "account_id": "0ga0yn", + "input_file_path": "/ta_partner/985495847/jvndHDh-482AdNa.txt", + "list_type": "HANDLE" + } + } +} \ No newline at end of file diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-promotable-users.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-promotable-users.json new file mode 100644 index 00000000..b5e5126b --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-promotable-users.json @@ -0,0 +1,21 @@ +{ + "data": [ + { + "account_id": "gq0vqj", + "created_at": "2015-04-13T20:42:39Z", + "deleted": false, + "id": "13phg", + "promotable_user_type": "FULL", + "updated_at": "2015-04-13T20:42:39Z", + "user_id": "390472547" + } + ], + "data_type": "promotable_user", + "next_cursor": null, + "request": { + "params": { + "account_id": "gq0vqj" + } + }, + "total_count": 1 +} diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-promoted-accounts-reference-creation.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-promoted-accounts-reference-creation.json new file mode 100644 index 00000000..fa95fc98 --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-promoted-accounts-reference-creation.json @@ -0,0 +1,20 @@ +{ + "data": { + "approval_status": "ACCEPTED", + "created_at": "2015-07-02T00:51:44Z", + "deleted": false, + "id": "3goc", + "line_item_id": "b6im", + "paused": false, + "updated_at": "2015-07-02T00:51:44Z", + "user_id": "390472547" + }, + "data_type": "promoted_account", + "request": { + "params": { + "account_id": "gq0vqj", + "line_item_id": "b6im", + "user_id": "390472547" + } + } +} diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-promoted-accounts-reference.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-promoted-accounts-reference.json new file mode 100644 index 00000000..d140d7fb --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-promoted-accounts-reference.json @@ -0,0 +1,22 @@ +{ + "data": [ + { + "approval_status": "ACCEPTED", + "created_at": "2015-07-02T00:51:44Z", + "deleted": false, + "id": "3goc", + "line_item_id": "b6im", + "paused": false, + "updated_at": "2015-07-02T00:51:44Z", + "user_id": "390472547" + } + ], + "data_type": "promoted_account", + "next_cursor": null, + "request": { + "params": { + "account_id": "gq0vqj" + } + }, + "total_count": 1 +} diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-promoted-tweet-reference-creation.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-promoted-tweet-reference-creation.json new file mode 100644 index 00000000..0d132aa1 --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-promoted-tweet-reference-creation.json @@ -0,0 +1,25 @@ +{ + "data": [ + { + "approval_status": "ACCEPTED", + "created_at": "2015-06-27T00:21:53Z", + "deleted": false, + "id": "tifo", + "line_item_id": "u4h4", + "paused": false, + "tweet_id": "614564626060062720", + "updated_at": "2015-06-30T00:21:53Z" + } + ], + "data_type": "promoted_tweet", + "request": { + "params": { + "account_id": "gq0vqj", + "line_item_id": "u4h4", + "tweet_ids": [ + 614564626060062720 + ] + } + }, + "total_count": 1 +} diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-promoted-tweet-reference.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-promoted-tweet-reference.json new file mode 100644 index 00000000..9bc8b1e7 --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-promoted-tweet-reference.json @@ -0,0 +1,22 @@ +{ + "data": [ + { + "approval_status": "ACCEPTED", + "created_at": "2015-06-27T00:21:53Z", + "deleted": false, + "id": "tifo", + "line_item_id": "b51j", + "paused": false, + "tweet_id": "614564626060062720", + "updated_at": "2015-06-30T00:21:53Z" + } + ], + "data_type": "promoted_tweet", + "next_cursor": null, + "request": { + "params": { + "account_id": "0ga0yn" + } + }, + "total_count": 1 +} diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-sponsored-tweets-single.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-sponsored-tweets-single.json new file mode 100644 index 00000000..0906022d --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-sponsored-tweets-single.json @@ -0,0 +1,54 @@ +{ + "data": { + "contributors": null, + "coordinates": null, + "created_at": "Thu Jun 25 03:45:00 +0000 2015", + "entities": { + "hashtags": [ + { + "indices": [ + 60, + 64 + ], + "text": "ads" + } + ], + "symbols": [], + "urls": [], + "user_mentions": [] + }, + "favorite_count": 0, + "favorited": false, + "geo": null, + "id": 613915770712514560, + "id_str": "613915770712514560", + "in_reply_to_screen_name": null, + "in_reply_to_status_id": null, + "in_reply_to_status_id_str": null, + "in_reply_to_user_id": null, + "in_reply_to_user_id_str": null, + "lang": "en", + "place": null, + "retweet_count": 0, + "retweeted": false, + "scopes": { + "followers": false + }, + "source": "Spring Website", + "text": "Hey, here is a sponsored tweet that we are creating via #ads API.", + "truncated": false, + "user": { + "id": 390472547, + "id_str": "390472547" + } + }, + "data_type": "status", + "request": { + "params": { + "account_id": "gq0vqj", + "as_user_id": 390472547, + "status": "Hey, here is a promoted-only tweet that we are creating via #ads API.", + "trim_user": true + } + } +} diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-sponsored-tweets.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-sponsored-tweets.json new file mode 100644 index 00000000..1c3ba9ec --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-sponsored-tweets.json @@ -0,0 +1,145 @@ +{ + "data": [ + { + "contributors": null, + "coordinates": null, + "created_at": "Thu Dec 04 17:56:40 +0000 2014", + "entities": { + "hashtags": [], + "symbols": [], + "urls": [ + { + "display_url": "ift.tt/1tLavU9", + "expanded_url": "http://ift.tt/1tLavU9", + "indices": [ + 60, + 82 + ], + "url": "http://t.co/cfxJOQ9zpF" + } + ], + "user_mentions": [] + }, + "favorite_count": 0, + "favorited": false, + "geo": null, + "id": 540565364179226624, + "id_str": "540565364179226624", + "in_reply_to_screen_name": null, + "in_reply_to_status_id": null, + "in_reply_to_status_id_str": null, + "in_reply_to_user_id": null, + "in_reply_to_user_id_str": null, + "lang": "en", + "place": null, + "possibly_sensitive": false, + "retweet_count": 0, + "retweeted": false, + "source": "IFTTT", + "text": "MemeTV wants to bring meme-worthy TV clips to Tumblr and... http://t.co/cfxJOQ9zpF", + "truncated": false, + "user": { + "id": 390472547, + "id_str": "390472547" + } + }, + { + "contributors": null, + "coordinates": null, + "created_at": "Wed Dec 03 18:16:12 +0000 2014", + "entities": { + "hashtags": [], + "symbols": [], + "urls": [ + { + "display_url": "ift.tt/1FNdtx9", + "expanded_url": "http://ift.tt/1FNdtx9", + "indices": [ + 65, + 87 + ], + "url": "http://t.co/KaDdqeiuEC" + } + ], + "user_mentions": [] + }, + "favorite_count": 1, + "favorited": false, + "geo": null, + "id": 540207892818046976, + "id_str": "540207892818046976", + "in_reply_to_screen_name": null, + "in_reply_to_status_id": null, + "in_reply_to_status_id_str": null, + "in_reply_to_user_id": null, + "in_reply_to_user_id_str": null, + "lang": "en", + "place": null, + "possibly_sensitive": false, + "retweet_count": 1, + "retweeted": false, + "source": "IFTTT", + "text": "Demand Founder Raises $20 Million at a $100 Million Valuation... http://t.co/KaDdqeiuEC", + "truncated": false, + "user": { + "id": 390472547, + "id_str": "390472547" + } + }, + { + "contributors": null, + "coordinates": null, + "created_at": "Wed Dec 03 05:37:46 +0000 2014", + "entities": { + "hashtags": [], + "symbols": [], + "urls": [ + { + "display_url": "ift.tt/1yHTS03", + "expanded_url": "http://ift.tt/1yHTS03", + "indices": [ + 63, + 85 + ], + "url": "http://t.co/euEvKnf2Dl" + } + ], + "user_mentions": [] + }, + "favorite_count": 0, + "favorited": false, + "geo": null, + "id": 540017026572750848, + "id_str": "540017026572750848", + "in_reply_to_screen_name": null, + "in_reply_to_status_id": null, + "in_reply_to_status_id_str": null, + "in_reply_to_user_id": null, + "in_reply_to_user_id_str": null, + "lang": "en", + "place": null, + "possibly_sensitive": false, + "retweet_count": 0, + "retweeted": false, + "source": "IFTTT", + "text": "FCC Commish Alleges That Netflix Is Working To \u201cEffectively... http://t.co/euEvKnf2Dl", + "truncated": false, + "user": { + "id": 390472547, + "id_str": "390472547" + } + } + ], + "data_type": "status", + "next_cursor": "c-43p4tt3bshs0", + "request": { + "params": { + "account_id": "gq0vqj", + "count": 3, + "trim_user": true, + "user_ids": [ + "390472547" + ] + } + } +} \ No newline at end of file diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-stats-non-segmented.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-stats-non-segmented.json new file mode 100644 index 00000000..1bc7b7ca --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-stats-non-segmented.json @@ -0,0 +1,147 @@ +{ + "data": { + "billed_engagements": [ + 4511 + ], + "billed_follows": [ + 0 + ], + "conversion_app_open": [ + 1 + ], + "conversion_custom": [ + 4624 + ], + "conversion_order_quantity": [ + 4946715236270000000 + ], + "conversion_sale_amount": [ + 4927653516583000000 + ], + "end_time": "2015-06-26T07:00:00Z", + "granularity": "DAY", + "id": "9q1o2", + "mobile_conversion_installs": [ + 1 + ], + "mobile_conversion_installs_breakdown": { + "assisted": [ + 0 + ], + "post_engagement": [ + 0 + ], + "post_view": [ + 1 + ], + "total": [ + 1 + ] + }, + "mobile_conversion_re_engages": [ + 1 + ], + "mobile_conversion_re_engages_breakdown": { + "assisted": [ + 0 + ], + "post_engagement": [ + 0 + ], + "post_view": [ + 1 + ], + "total": [ + 1 + ] + }, + "promoted_account_follow_rate": [ + 0.0 + ], + "promoted_account_follows": [ + 0 + ], + "promoted_account_impressions": [ + 0 + ], + "promoted_account_profile_visits": [ + 0 + ], + "promoted_tweet_app_install_attempts": [ + 0 + ], + "promoted_tweet_app_open_attempts": [ + 0 + ], + "promoted_tweet_search_card_engagements": [ + 0 + ], + "promoted_tweet_search_clicks": [ + 119 + ], + "promoted_tweet_search_engagement_rate": [ + 0.009953296072276243 + ], + "promoted_tweet_search_engagements": [ + 130 + ], + "promoted_tweet_search_favorites": [ + 7 + ], + "promoted_tweet_search_follows": [ + 7 + ], + "promoted_tweet_search_impressions": [ + 13061 + ], + "promoted_tweet_search_replies": [ + 0 + ], + "promoted_tweet_search_retweets": [ + 4 + ], + "promoted_tweet_search_url_clicks": [ + 27 + ], + "promoted_tweet_timeline_card_engagements": [ + 0 + ], + "promoted_tweet_timeline_clicks": [ + 13983 + ], + "promoted_tweet_timeline_engagement_rate": [ + 0.01598410105817524 + ], + "promoted_tweet_timeline_engagements": [ + 16705 + ], + "promoted_tweet_timeline_favorites": [ + 543 + ], + "promoted_tweet_timeline_follows": [ + 144 + ], + "promoted_tweet_timeline_impressions": [ + 1045101 + ], + "promoted_tweet_timeline_replies": [ + 38 + ], + "promoted_tweet_timeline_retweets": [ + 255 + ], + "promoted_tweet_timeline_url_clicks": [ + 6036 + ], + "start_time": "2015-06-25T07:00:00Z" + }, + "data_type": "stats", + "request": { + "params": { + "account_id": "9q1o2", + "end_time": "2015-06-26T07:00:00Z", + "granularity": "DAY", + "start_time": "2015-06-25T07:00:00Z" + } + } +} \ No newline at end of file diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-stats-segmented.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-stats-segmented.json new file mode 100644 index 00000000..3a068695 --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-stats-segmented.json @@ -0,0 +1,437 @@ +{ + "data": [ + { + "billed_engagements": [ + 580 + ], + "billed_follows": [ + 0 + ], + "conversion_app_open": [ + 0 + ], + "conversion_custom": [ + 787 + ], + "conversion_order_quantity": [ + 839859181793000000 + ], + "conversion_sale_amount": [ + 815929856027000000 + ], + "end_time": "2015-06-26T07:00:00Z", + "granularity": "DAY", + "id": "9q1o2", + "mobile_conversion_installs": [ + 0 + ], + "mobile_conversion_installs_breakdown": { + "assisted": [ + 0 + ], + "post_engagement": [ + 0 + ], + "post_view": [ + 0 + ], + "total": [ + 0 + ] + }, + "mobile_conversion_re_engages": [ + 0 + ], + "mobile_conversion_re_engages_breakdown": { + "assisted": [ + 0 + ], + "post_engagement": [ + 0 + ], + "post_view": [ + 0 + ], + "total": [ + 0 + ] + }, + "promoted_account_follow_rate": [ + 0.0 + ], + "promoted_account_follows": [ + 0 + ], + "promoted_account_impressions": [ + 0 + ], + "promoted_account_profile_visits": [ + 0 + ], + "promoted_tweet_app_install_attempts": [ + 0 + ], + "promoted_tweet_app_open_attempts": [ + 0 + ], + "promoted_tweet_search_card_engagements": [ + 0 + ], + "promoted_tweet_search_clicks": [ + 37 + ], + "promoted_tweet_search_engagement_rate": [ + 0.00763807285546416 + ], + "promoted_tweet_search_engagements": [ + 39 + ], + "promoted_tweet_search_favorites": [ + 4 + ], + "promoted_tweet_search_follows": [ + 1 + ], + "promoted_tweet_search_impressions": [ + 5106 + ], + "promoted_tweet_search_replies": [ + 0 + ], + "promoted_tweet_search_retweets": [ + 1 + ], + "promoted_tweet_search_url_clicks": [ + 7 + ], + "promoted_tweet_timeline_card_engagements": [ + 0 + ], + "promoted_tweet_timeline_clicks": [ + 2142 + ], + "promoted_tweet_timeline_engagement_rate": [ + 0.01030786792589964 + ], + "promoted_tweet_timeline_engagements": [ + 2411 + ], + "promoted_tweet_timeline_favorites": [ + 125 + ], + "promoted_tweet_timeline_follows": [ + 32 + ], + "promoted_tweet_timeline_impressions": [ + 233899 + ], + "promoted_tweet_timeline_replies": [ + 4 + ], + "promoted_tweet_timeline_retweets": [ + 52 + ], + "promoted_tweet_timeline_url_clicks": [ + 750 + ], + "segment": { + "name": "Female", + "segmentation_type": "GENDER", + "segmentation_value": "f" + }, + "start_time": "2015-06-25T07:00:00Z" + }, + { + "billed_engagements": [ + 3808 + ], + "billed_follows": [ + 0 + ], + "conversion_app_open": [ + 1 + ], + "conversion_custom": [ + 3730 + ], + "conversion_order_quantity": [ + 3991367805412000000 + ], + "conversion_sale_amount": [ + 4005833005824000000 + ], + "end_time": "2015-06-26T07:00:00Z", + "granularity": "DAY", + "id": "9q1o2", + "mobile_conversion_installs": [ + 1 + ], + "mobile_conversion_installs_breakdown": { + "assisted": [ + 0 + ], + "post_engagement": [ + 0 + ], + "post_view": [ + 1 + ], + "total": [ + 1 + ] + }, + "mobile_conversion_re_engages": [ + 1 + ], + "mobile_conversion_re_engages_breakdown": { + "assisted": [ + 0 + ], + "post_engagement": [ + 0 + ], + "post_view": [ + 1 + ], + "total": [ + 1 + ] + }, + "promoted_account_follow_rate": [ + 0.0 + ], + "promoted_account_follows": [ + 0 + ], + "promoted_account_impressions": [ + 0 + ], + "promoted_account_profile_visits": [ + 0 + ], + "promoted_tweet_app_install_attempts": [ + 0 + ], + "promoted_tweet_app_open_attempts": [ + 0 + ], + "promoted_tweet_search_card_engagements": [ + 0 + ], + "promoted_tweet_search_clicks": [ + 65 + ], + "promoted_tweet_search_engagement_rate": [ + 0.009875846501128669 + ], + "promoted_tweet_search_engagements": [ + 70 + ], + "promoted_tweet_search_favorites": [ + 1 + ], + "promoted_tweet_search_follows": [ + 2 + ], + "promoted_tweet_search_impressions": [ + 7088 + ], + "promoted_tweet_search_replies": [ + 0 + ], + "promoted_tweet_search_retweets": [ + 3 + ], + "promoted_tweet_search_url_clicks": [ + 14 + ], + "promoted_tweet_timeline_card_engagements": [ + 0 + ], + "promoted_tweet_timeline_clicks": [ + 11416 + ], + "promoted_tweet_timeline_engagement_rate": [ + 0.017759754600910973 + ], + "promoted_tweet_timeline_engagements": [ + 13791 + ], + "promoted_tweet_timeline_favorites": [ + 406 + ], + "promoted_tweet_timeline_follows": [ + 103 + ], + "promoted_tweet_timeline_impressions": [ + 776531 + ], + "promoted_tweet_timeline_replies": [ + 32 + ], + "promoted_tweet_timeline_retweets": [ + 193 + ], + "promoted_tweet_timeline_url_clicks": [ + 5112 + ], + "segment": { + "name": "Male", + "segmentation_type": "GENDER", + "segmentation_value": "m" + }, + "start_time": "2015-06-25T07:00:00Z" + }, + { + "billed_engagements": [ + 123 + ], + "billed_follows": [ + 0 + ], + "conversion_app_open": [ + 0 + ], + "conversion_custom": [ + 107 + ], + "conversion_order_quantity": [ + 115488249065000000 + ], + "conversion_sale_amount": [ + 105890654732000000 + ], + "end_time": "2015-06-26T07:00:00Z", + "granularity": "DAY", + "id": "9q1o2", + "mobile_conversion_installs": [ + 0 + ], + "mobile_conversion_installs_breakdown": { + "assisted": [ + 0 + ], + "post_engagement": [ + 0 + ], + "post_view": [ + 0 + ], + "total": [ + 0 + ] + }, + "mobile_conversion_re_engages": [ + 0 + ], + "mobile_conversion_re_engages_breakdown": { + "assisted": [ + 0 + ], + "post_engagement": [ + 0 + ], + "post_view": [ + 0 + ], + "total": [ + 0 + ] + }, + "promoted_account_follow_rate": [ + 0.0 + ], + "promoted_account_follows": [ + 0 + ], + "promoted_account_impressions": [ + 0 + ], + "promoted_account_profile_visits": [ + 0 + ], + "promoted_tweet_app_install_attempts": [ + 0 + ], + "promoted_tweet_app_open_attempts": [ + 0 + ], + "promoted_tweet_search_card_engagements": [ + 0 + ], + "promoted_tweet_search_clicks": [ + 17 + ], + "promoted_tweet_search_engagement_rate": [ + 0.02422145328719723 + ], + "promoted_tweet_search_engagements": [ + 21 + ], + "promoted_tweet_search_favorites": [ + 2 + ], + "promoted_tweet_search_follows": [ + 4 + ], + "promoted_tweet_search_impressions": [ + 867 + ], + "promoted_tweet_search_replies": [ + 0 + ], + "promoted_tweet_search_retweets": [ + 0 + ], + "promoted_tweet_search_url_clicks": [ + 6 + ], + "promoted_tweet_timeline_card_engagements": [ + 0 + ], + "promoted_tweet_timeline_clicks": [ + 425 + ], + "promoted_tweet_timeline_engagement_rate": [ + 0.014507801909376712 + ], + "promoted_tweet_timeline_engagements": [ + 503 + ], + "promoted_tweet_timeline_favorites": [ + 12 + ], + "promoted_tweet_timeline_follows": [ + 9 + ], + "promoted_tweet_timeline_impressions": [ + 34671 + ], + "promoted_tweet_timeline_replies": [ + 2 + ], + "promoted_tweet_timeline_retweets": [ + 10 + ], + "promoted_tweet_timeline_url_clicks": [ + 174 + ], + "segment": { + "name": "Unknown", + "segmentation_type": "GENDER", + "segmentation_value": "unknown" + }, + "start_time": "2015-06-25T07:00:00Z" + } + ], + "data_type": "stats", + "request": { + "params": { + "account_id": "9q1o2", + "end_time": "2015-06-26T07:00:00Z", + "granularity": "DAY", + "segmentation_type": "GENDER", + "start_time": "2015-06-25T07:00:00Z" + } + } +} \ No newline at end of file diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-tailored-audience-changes.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-tailored-audience-changes.json new file mode 100644 index 00000000..5c60bb16 --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-tailored-audience-changes.json @@ -0,0 +1,18 @@ +{ + "data_type": "tailored_audience_change", + "data": { + "input_file_path": "/ta_partner/3wyo1gwuqF7_Lhr", + "tailored_audience_id": "13sf", + "state": "COMPLETED", + "id": "9q0", + "operation": "ADD" + }, + "request": { + "params": { + "tailored_audience_id": "13sf", + "input_file_path": "/1.1/ton/data/ta_partner/3wyo1gwuqF7_Lhr", + "operation": "ADD", + "account_id": "abc1" + } + } +} \ No newline at end of file diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-tailored-audiences-single.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-tailored-audiences-single.json new file mode 100644 index 00000000..83668511 --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-tailored-audiences-single.json @@ -0,0 +1,29 @@ +{ + "data": { + "audience_size": null, + "audience_type": "CRM", + "created_at": "2015-06-08T20:13:40Z", + "deleted": false, + "id": "qq4u", + "list_type": "TWITTER_ID", + "name": "twitter%20ids", + "partner_source": "OTHER", + "reasons_not_targetable": [ + "PROCESSING", + "TOO_SMALL" + ], + "targetable": false, + "targetable_types": [ + "CRM", + "EXCLUDED_CRM" + ], + "updated_at": "2015-06-08T20:13:40Z" + }, + "data_type": "tailored_audiences", + "request": { + "params": { + "account_id": "gq0vqj", + "tailored_audience_id": "qq4u" + } + } +} \ No newline at end of file diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-tailored-audiences.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-tailored-audiences.json new file mode 100644 index 00000000..fe8caef2 --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-tailored-audiences.json @@ -0,0 +1,32 @@ +{ + "data": [ + { + "audience_size": null, + "audience_type": "CRM", + "created_at": "2015-06-08T20:13:40Z", + "deleted": false, + "id": "qq4u", + "list_type": "TWITTER_ID", + "name": "twitter%20ids", + "partner_source": "OTHER", + "reasons_not_targetable": [ + "PROCESSING", + "TOO_SMALL" + ], + "targetable": false, + "targetable_types": [ + "CRM", + "EXCLUDED_CRM" + ], + "updated_at": "2015-06-08T20:13:40Z" + } + ], + "data_type": "tailored_audiences", + "next_cursor": null, + "request": { + "params": { + "account_id": "gq0vqj" + } + }, + "total_count": 1 +} diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targeting-criteria-single.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targeting-criteria-single.json new file mode 100644 index 00000000..4e7573c3 --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targeting-criteria-single.json @@ -0,0 +1,26 @@ +{ + "data": { + "account_id": "gq0vqj", + "created_at": "2015-07-23T23:14:37Z", + "deleted": false, + "id": "31l8r", + "line_item_id": "bcrv", + "name": "Mobile audience targeting", + "tailored_audience_expansion": false, + "tailored_audience_type": "EXCLUDED_MOBILE", + "targeting_type": "TAILORED_AUDIENCE", + "targeting_value": "qsb3", + "updated_at": "2015-07-23T23:14:37Z" + }, + "data_type": "targeting_criterion", + "request": { + "params": { + "account_id": "gq0vqj", + "line_item_id": "bcrv", + "tailored_audience_expansion": false, + "tailored_audience_type": "EXCLUDED_MOBILE", + "targeting_type": "TAILORED_AUDIENCE", + "targeting_value": "qsb3" + } + } +} \ No newline at end of file diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targeting-criteria.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targeting-criteria.json new file mode 100644 index 00000000..68226a53 --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targeting-criteria.json @@ -0,0 +1,57 @@ +{ + "data": [ + { + "name": "episod", + "created_at": "2012-11-30T22:58:11Z", + "updated_at": "2012-11-30T22:58:11Z", + "account_id": "hkk5", + "id": "2kzxf", + "deleted": false, + "targeting_value": "819797", + "line_item_id": "69ob", + "targeting_type": "SIMILAR_TO_FOLLOWERS_OF_USER" + }, + { + "name": "matrixsynth", + "created_at": "2012-11-30T22:58:12Z", + "updated_at": "2012-11-30T22:58:12Z", + "account_id": "hkk5", + "deleted": false, + "id": "2kzxi", + "targeting_value": "22231561", + "line_item_id": "69ob", + "targeting_type": "SIMILAR_TO_FOLLOWERS_OF_USER" + }, + { + "name": "Horse_ebooks", + "created_at": "2012-11-30T22:58:12Z", + "updated_at": "2012-11-30T22:58:12Z", + "account_id": "hkk5", + "id": "2kzxj", + "targeting_value": "174958347", + "deleted": false, + "line_item_id": "69ob", + "targeting_type": "SIMILAR_TO_FOLLOWERS_OF_USER" + }, + { + "name": "righteous dude", + "created_at": "2012-12-05T05:11:15Z", + "updated_at": "2012-12-06T05:11:15Z", + "account_id": "hkk5", + "targeting_value": "righteous dude", + "deleted": true, + "id": "2mq7j", + "line_item_id": "69ob", + "targeting_type": "PHRASE_KEYWORD" + } + ], + "data_type": "targeting_criterion", + "request": { + "params": { + "with_deleted": true, + "account_id": "hkk5", + "line_item_id": "69ob" + } + }, + "total_count": 4 +} \ No newline at end of file diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-app_store_categories-params.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-app_store_categories-params.json new file mode 100644 index 00000000..b8599a46 --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-app_store_categories-params.json @@ -0,0 +1,23 @@ +{ + "data": [ + { + "name": "Games: Music", + "os_type": "ANDROID", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qown" + }, + { + "name": "Music & Audio", + "os_type": "ANDROID", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qox2" + } + ], + "data_type": "targeting_criterion", + "request": { + "params": { + "q": "music", + "store": "GOOGLE_PLAY" + } + } +} \ No newline at end of file diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-app_store_categories.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-app_store_categories.json new file mode 100644 index 00000000..8c05416d --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-app_store_categories.json @@ -0,0 +1,512 @@ +{ + "data": [ + { + "name": "Books", + "os_type": "IOS", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qou9" + }, + { + "name": "Books & References", + "os_type": "ANDROID", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qow6" + }, + { + "name": "Business", + "os_type": "IOS", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qoua" + }, + { + "name": "Business", + "os_type": "ANDROID", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qow7" + }, + { + "name": "Catalogs", + "os_type": "IOS", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qoub" + }, + { + "name": "Comics", + "os_type": "ANDROID", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qow8" + }, + { + "name": "Communication", + "os_type": "ANDROID", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qow9" + }, + { + "name": "Education", + "os_type": "IOS", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qouc" + }, + { + "name": "Education", + "os_type": "ANDROID", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qowa" + }, + { + "name": "Entertainment", + "os_type": "IOS", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qoud" + }, + { + "name": "Entertainment", + "os_type": "ANDROID", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qowb" + }, + { + "name": "Finance", + "os_type": "IOS", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qoue" + }, + { + "name": "Finance", + "os_type": "ANDROID", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qowc" + }, + { + "name": "Food & Drink", + "os_type": "IOS", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qouf" + }, + { + "name": "Games: Action", + "os_type": "IOS", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qouh" + }, + { + "name": "Games: Action", + "os_type": "ANDROID", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qowe" + }, + { + "name": "Games: Adventure", + "os_type": "IOS", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qoui" + }, + { + "name": "Games: Adventure", + "os_type": "ANDROID", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qowf" + }, + { + "name": "Games: Arcade", + "os_type": "IOS", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qouj" + }, + { + "name": "Games: Arcade", + "os_type": "ANDROID", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qowg" + }, + { + "name": "Games: Board", + "os_type": "IOS", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qouk" + }, + { + "name": "Games: Board", + "os_type": "ANDROID", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qowh" + }, + { + "name": "Games: Card", + "os_type": "IOS", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qoul" + }, + { + "name": "Games: Card", + "os_type": "ANDROID", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qowi" + }, + { + "name": "Games: Casino", + "os_type": "IOS", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qoum" + }, + { + "name": "Games: Casino", + "os_type": "ANDROID", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qowj" + }, + { + "name": "Games: Casual", + "os_type": "ANDROID", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qowk" + }, + { + "name": "Games: Dice", + "os_type": "IOS", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qoun" + }, + { + "name": "Games: Educational", + "os_type": "IOS", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qouo" + }, + { + "name": "Games: Educational", + "os_type": "ANDROID", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qowl" + }, + { + "name": "Games: Family", + "os_type": "IOS", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qoup" + }, + { + "name": "Games: Family", + "os_type": "ANDROID", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qowm" + }, + { + "name": "Games: Music", + "os_type": "IOS", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qouq" + }, + { + "name": "Games: Music", + "os_type": "ANDROID", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qown" + }, + { + "name": "Games: Puzzle", + "os_type": "IOS", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qour" + }, + { + "name": "Games: Puzzle", + "os_type": "ANDROID", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qowo" + }, + { + "name": "Games: Racing", + "os_type": "IOS", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qous" + }, + { + "name": "Games: Racing", + "os_type": "ANDROID", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qowp" + }, + { + "name": "Games: Role Playing", + "os_type": "IOS", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qout" + }, + { + "name": "Games: Role Playing", + "os_type": "ANDROID", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qowq" + }, + { + "name": "Games: Simulation", + "os_type": "IOS", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qouu" + }, + { + "name": "Games: Simulation", + "os_type": "ANDROID", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qowr" + }, + { + "name": "Games: Sports", + "os_type": "IOS", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qouv" + }, + { + "name": "Games: Sports", + "os_type": "ANDROID", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qows" + }, + { + "name": "Games: Strategy", + "os_type": "IOS", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qouw" + }, + { + "name": "Games: Strategy", + "os_type": "ANDROID", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qowt" + }, + { + "name": "Games: Trivia", + "os_type": "IOS", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qoux" + }, + { + "name": "Games: Trivia", + "os_type": "ANDROID", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qowu" + }, + { + "name": "Games: Word", + "os_type": "IOS", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qouy" + }, + { + "name": "Games: Word", + "os_type": "ANDROID", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qowv" + }, + { + "name": "Health & Fitness", + "os_type": "IOS", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qouz" + }, + { + "name": "Health & Fitness", + "os_type": "ANDROID", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qoww" + }, + { + "name": "Libraries & Demo", + "os_type": "ANDROID", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qowx" + }, + { + "name": "Lifestyle", + "os_type": "IOS", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qov0" + }, + { + "name": "Lifestyle", + "os_type": "ANDROID", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qowy" + }, + { + "name": "Live Wallpaper", + "os_type": "ANDROID", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qowz" + }, + { + "name": "Media & Video", + "os_type": "ANDROID", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qox0" + }, + { + "name": "Medical", + "os_type": "IOS", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qov1" + }, + { + "name": "Medical", + "os_type": "ANDROID", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qox1" + }, + { + "name": "Music", + "os_type": "IOS", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qov2" + }, + { + "name": "Music & Audio", + "os_type": "ANDROID", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qox2" + }, + { + "name": "Navigation", + "os_type": "IOS", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qov3" + }, + { + "name": "News", + "os_type": "IOS", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qov4" + }, + { + "name": "News & Magazines", + "os_type": "ANDROID", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qox3" + }, + { + "name": "Newsstand", + "os_type": "IOS", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qov5" + }, + { + "name": "Personalization", + "os_type": "ANDROID", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qox4" + }, + { + "name": "Photo & Video", + "os_type": "IOS", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qovy" + }, + { + "name": "Photography", + "os_type": "ANDROID", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qox5" + }, + { + "name": "Productivity", + "os_type": "IOS", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qovz" + }, + { + "name": "Productivity", + "os_type": "ANDROID", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qox6" + }, + { + "name": "Reference", + "os_type": "IOS", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qow0" + }, + { + "name": "Shopping", + "os_type": "ANDROID", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qox7" + }, + { + "name": "Social", + "os_type": "ANDROID", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qox8" + }, + { + "name": "Social Networking", + "os_type": "IOS", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qow1" + }, + { + "name": "Sports", + "os_type": "IOS", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qow2" + }, + { + "name": "Sports", + "os_type": "ANDROID", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qox9" + }, + { + "name": "Tools", + "os_type": "ANDROID", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qoxa" + }, + { + "name": "Transportation", + "os_type": "ANDROID", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qoxb" + }, + { + "name": "Travel", + "os_type": "IOS", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qow3" + }, + { + "name": "Travel & Local", + "os_type": "ANDROID", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qoxc" + }, + { + "name": "Utilities", + "os_type": "IOS", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qow4" + }, + { + "name": "Weather", + "os_type": "IOS", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qow5" + }, + { + "name": "Weather", + "os_type": "ANDROID", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qoxd" + }, + { + "name": "Widgets", + "os_type": "ANDROID", + "targeting_type": "APP_STORE_CATEGORY", + "targeting_value": "qoxe" + } + ], + "data_type": "targeting_criterion", + "request": { + "params": {} + } +} diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-behavior_taxonomies-params.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-behavior_taxonomies-params.json new file mode 100644 index 00000000..fdfce9a3 --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-behavior_taxonomies-params.json @@ -0,0 +1,24 @@ +{ + "data": [ + { + "created_at": "2015-01-21T21:47:24Z", + "id": "33", + "name": "Frequent flyers", + "parent_id": "31", + "updated_at": "2015-01-21T21:47:24Z" + } + ], + "data_type": "behavior_taxonomies", + "next_cursor": null, + "request": { + "params": { + "behavior_taxonomy_ids": [ + "33" + ], + "parent_behavior_taxonomy_ids": [ + "31" + ] + } + }, + "total_count": 1 +} \ No newline at end of file diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-behavior_taxonomies.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-behavior_taxonomies.json new file mode 100644 index 00000000..4143a19f --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-behavior_taxonomies.json @@ -0,0 +1,1368 @@ +{ + "data": [ + { + "created_at": "2014-12-08T21:55:58Z", + "id": "1", + "name": "Auto (DLX Auto powered by Polk)", + "parent_id": null, + "updated_at": "2015-01-21T21:47:24Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "2", + "name": "Aftermarket", + "parent_id": "1", + "updated_at": "2015-01-21T21:47:09Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "3", + "name": "In market", + "parent_id": "1", + "updated_at": "2015-01-21T21:47:09Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "4", + "name": "Max in market", + "parent_id": "1", + "updated_at": "2015-01-21T21:47:09Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "5", + "name": "Motorcycle", + "parent_id": "1", + "updated_at": "2015-01-21T21:47:09Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "6", + "name": "Near market", + "parent_id": "1", + "updated_at": "2015-01-21T21:47:09Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "7", + "name": "Owners", + "parent_id": "1", + "updated_at": "2015-01-21T21:47:09Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "8", + "name": "Vehicle price or age", + "parent_id": "1", + "updated_at": "2015-01-21T21:47:09Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "9", + "name": "CPG brands", + "parent_id": null, + "updated_at": "2015-01-21T21:47:09Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "a", + "name": "Bakery buyers", + "parent_id": "9", + "updated_at": "2015-01-21T21:47:10Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "b", + "name": "Baking & cooking supplies buyers", + "parent_id": "9", + "updated_at": "2015-01-21T21:47:10Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "c", + "name": "Beverage buyers", + "parent_id": "9", + "updated_at": "2015-01-21T21:47:10Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "d", + "name": "Cereal buyers", + "parent_id": "9", + "updated_at": "2015-01-21T21:47:10Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "e", + "name": "Children's food & product buyers", + "parent_id": "9", + "updated_at": "2015-01-21T21:47:10Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "f", + "name": "Condiments & sauces buyers", + "parent_id": "9", + "updated_at": "2015-01-21T21:47:10Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "g", + "name": "Dairy & egg buyers", + "parent_id": "9", + "updated_at": "2015-01-21T21:47:10Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "h", + "name": "Frozen food buyers", + "parent_id": "9", + "updated_at": "2015-01-21T21:47:10Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "i", + "name": "Health & beauty buyers", + "parent_id": "9", + "updated_at": "2015-01-21T21:47:10Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "j", + "name": "Household supplies buyers", + "parent_id": "9", + "updated_at": "2015-01-21T21:47:10Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "k", + "name": "Meat & seafood buyers", + "parent_id": "9", + "updated_at": "2015-01-21T21:47:10Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "l", + "name": "Pet care buyers", + "parent_id": "9", + "updated_at": "2015-01-21T21:47:10Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "m", + "name": "Soup buyers", + "parent_id": "9", + "updated_at": "2015-01-21T21:47:11Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "n", + "name": "Sweets & snack buyers", + "parent_id": "9", + "updated_at": "2015-01-21T21:47:11Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "o", + "name": "CPG BuyStyles", + "parent_id": null, + "updated_at": "2015-01-21T21:47:11Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "p", + "name": "CPG categories", + "parent_id": null, + "updated_at": "2015-01-21T21:47:11Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "q", + "name": "Alcohol beverage buyers", + "parent_id": "p", + "updated_at": "2015-01-21T21:47:11Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "r", + "name": "Bakery buyers", + "parent_id": "p", + "updated_at": "2015-01-21T21:47:11Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "s", + "name": "Baking & cooking supplies buyers", + "parent_id": "p", + "updated_at": "2015-01-21T21:47:11Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "t", + "name": "Beverage buyers", + "parent_id": "p", + "updated_at": "2015-01-21T21:47:11Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "u", + "name": "Cereal buyers", + "parent_id": "p", + "updated_at": "2015-01-21T21:47:11Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "v", + "name": "Children's food & product buyers", + "parent_id": "p", + "updated_at": "2015-01-21T21:47:11Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "w", + "name": "Condiments & sauces buyers", + "parent_id": "p", + "updated_at": "2015-01-21T21:47:11Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "x", + "name": "Dairy & egg buyers", + "parent_id": "p", + "updated_at": "2015-01-21T21:47:11Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "y", + "name": "Deli food buyers", + "parent_id": "p", + "updated_at": "2015-01-21T21:47:12Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "z", + "name": "Frozen food buyers", + "parent_id": "p", + "updated_at": "2015-01-21T21:47:12Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "10", + "name": "Gift & party supplies buyers", + "parent_id": "p", + "updated_at": "2015-01-21T21:47:12Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "11", + "name": "Grocery spending behavior", + "parent_id": "p", + "updated_at": "2015-01-21T21:47:12Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "12", + "name": "Health & beauty buyers", + "parent_id": "p", + "updated_at": "2015-01-21T21:47:12Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "13", + "name": "Health food buyers", + "parent_id": "p", + "updated_at": "2015-01-21T21:47:12Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "14", + "name": "Household supplies buyers", + "parent_id": "p", + "updated_at": "2015-01-21T21:47:12Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "15", + "name": "Meat & seafood buyers", + "parent_id": "p", + "updated_at": "2015-01-21T21:47:12Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "16", + "name": "Packaged meals, grains & pasta buyers", + "parent_id": "p", + "updated_at": "2015-01-21T21:47:12Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "17", + "name": "Pet care buyers", + "parent_id": "p", + "updated_at": "2015-01-21T21:47:12Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "18", + "name": "Soup buyers", + "parent_id": "p", + "updated_at": "2015-01-21T21:47:12Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "19", + "name": "Sweets & snack buyers", + "parent_id": "p", + "updated_at": "2015-01-21T21:47:12Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "1a", + "name": "Demographics", + "parent_id": null, + "updated_at": "2015-01-21T21:47:13Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "1b", + "name": "Age", + "parent_id": "1a", + "updated_at": "2015-01-21T21:47:13Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "1c", + "name": "Charitable donor", + "parent_id": "1a", + "updated_at": "2015-01-21T21:47:13Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "1d", + "name": "College graduate", + "parent_id": "1a", + "updated_at": "2015-01-21T21:47:13Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "1e", + "name": "DMA", + "parent_id": "1a", + "updated_at": "2015-01-21T21:47:13Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "1f", + "name": "Dwelling type", + "parent_id": "1a", + "updated_at": "2015-01-21T21:47:13Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "1g", + "name": "Family position", + "parent_id": "1a", + "updated_at": "2015-01-21T21:47:13Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "1h", + "name": "Gender", + "parent_id": "1a", + "updated_at": "2015-01-21T21:47:13Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "1i", + "name": "Generation", + "parent_id": "1a", + "updated_at": "2015-01-21T21:47:13Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "1j", + "name": "Heritage", + "parent_id": "1a", + "updated_at": "2015-01-21T21:47:13Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "1k", + "name": "Hobbies", + "parent_id": "1a", + "updated_at": "2015-01-21T21:47:13Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "1l", + "name": "Home ownership", + "parent_id": "1a", + "updated_at": "2015-01-21T21:47:24Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "1m", + "name": "Home renter", + "parent_id": "1a", + "updated_at": "2015-01-21T21:47:14Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "1n", + "name": "Length of residence", + "parent_id": "1a", + "updated_at": "2015-01-21T21:47:14Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "1o", + "name": "Marital status", + "parent_id": "1a", + "updated_at": "2015-01-21T21:47:24Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "1p", + "name": "Number of adults in household", + "parent_id": "1a", + "updated_at": "2015-01-21T21:47:14Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "1q", + "name": "Occupation", + "parent_id": "1a", + "updated_at": "2015-01-21T21:47:14Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "1r", + "name": "Occupation category", + "parent_id": "1a", + "updated_at": "2015-01-21T21:47:14Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "1s", + "name": "Pet owner", + "parent_id": "1a", + "updated_at": "2015-01-21T21:47:14Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "1t", + "name": "Political party affiliation", + "parent_id": "1a", + "updated_at": "2015-01-21T21:47:14Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "1u", + "name": "Presence in household", + "parent_id": "1a", + "updated_at": "2015-01-21T21:47:23Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "1v", + "name": "Presence of family member age", + "parent_id": "1a", + "updated_at": "2015-01-21T21:47:14Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "1w", + "name": "Spanish speaking", + "parent_id": "1a", + "updated_at": "2015-01-21T21:47:14Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "1x", + "name": "Personal travel", + "parent_id": "31", + "updated_at": "2015-01-21T21:47:24Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "1y", + "name": "Veteran in household", + "parent_id": "1a", + "updated_at": "2015-01-21T21:47:14Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "1z", + "name": "Finance", + "parent_id": null, + "updated_at": "2015-01-21T21:47:15Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "20", + "name": "Bank/credit activity", + "parent_id": "1z", + "updated_at": "2015-01-21T21:47:24Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "21", + "name": "Credit card holders", + "parent_id": "1z", + "updated_at": "2015-01-21T21:47:15Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "22", + "name": "Credit worthiness", + "parent_id": "1z", + "updated_at": "2015-01-21T21:47:15Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "23", + "name": "Estimated household income", + "parent_id": "1z", + "updated_at": "2015-01-21T21:47:15Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "24", + "name": "Financial services", + "parent_id": "1z", + "updated_at": "2015-01-21T21:47:15Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "25", + "name": "Home value", + "parent_id": "1z", + "updated_at": "2015-01-21T21:47:15Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "26", + "name": "Investments", + "parent_id": "1z", + "updated_at": "2015-01-21T21:47:15Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "27", + "name": "Net worth", + "parent_id": "1z", + "updated_at": "2015-01-21T21:47:15Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "28", + "name": "Lifestyles", + "parent_id": null, + "updated_at": "2015-01-21T21:47:15Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "29", + "name": "Philanthropy", + "parent_id": null, + "updated_at": "2015-01-21T21:47:15Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "2a", + "name": "Retail brands", + "parent_id": null, + "updated_at": "2015-01-21T21:47:15Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "2b", + "name": "Children's products", + "parent_id": "2a", + "updated_at": "2015-01-21T21:47:16Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "2c", + "name": "Clothing, shoes & accessories", + "parent_id": "2a", + "updated_at": "2015-01-21T21:47:16Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "2d", + "name": "Consumer electronics", + "parent_id": "2a", + "updated_at": "2015-01-21T21:47:16Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "2e", + "name": "Retail categories", + "parent_id": null, + "updated_at": "2015-01-21T21:47:16Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "2f", + "name": "Automotive products buyers", + "parent_id": "2e", + "updated_at": "2015-01-21T21:47:16Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "2g", + "name": "Children's products buyers", + "parent_id": "2e", + "updated_at": "2015-01-21T21:47:16Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "2h", + "name": "Consumer electronics buyers", + "parent_id": "2e", + "updated_at": "2015-01-21T21:47:16Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "2i", + "name": "Corporate attire buyers", + "parent_id": "2e", + "updated_at": "2015-01-21T21:47:16Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "2j", + "name": "Fitness buyers", + "parent_id": "2e", + "updated_at": "2015-01-21T21:47:16Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "2k", + "name": "Gift and flower buyers", + "parent_id": "2e", + "updated_at": "2015-01-21T21:47:16Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "2l", + "name": "Health & wellness buyers", + "parent_id": "2e", + "updated_at": "2015-01-21T21:47:16Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "2m", + "name": "Home & garden buyers", + "parent_id": "2e", + "updated_at": "2015-01-21T21:47:16Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "2n", + "name": "Home improvement buyers", + "parent_id": "2e", + "updated_at": "2015-01-21T21:47:17Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "2o", + "name": "Men's fashion & apparel buyers", + "parent_id": "2e", + "updated_at": "2015-01-21T21:47:17Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "2p", + "name": "Outdoor sports buyers", + "parent_id": "2e", + "updated_at": "2015-01-21T21:47:17Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "2q", + "name": "Pet supply buyers", + "parent_id": "2e", + "updated_at": "2015-01-21T21:47:17Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "2r", + "name": "Senior's products buyers", + "parent_id": "2e", + "updated_at": "2015-01-21T21:47:17Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "2s", + "name": "Small & home office product buyers", + "parent_id": "2e", + "updated_at": "2015-01-21T21:47:17Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "2t", + "name": "Women's accessories", + "parent_id": "2e", + "updated_at": "2015-01-21T21:47:17Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "2u", + "name": "Women's fashion & apparel buyers", + "parent_id": "2e", + "updated_at": "2015-01-21T21:47:17Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "2v", + "name": "Seasonal", + "parent_id": null, + "updated_at": "2015-01-21T21:47:17Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "2w", + "name": "Fall ", + "parent_id": "2v", + "updated_at": "2015-01-21T21:47:17Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "2x", + "name": "Spring", + "parent_id": "2v", + "updated_at": "2015-01-21T21:47:17Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "2y", + "name": "Summer", + "parent_id": "2v", + "updated_at": "2015-01-21T21:47:17Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "2z", + "name": "Winter", + "parent_id": "2v", + "updated_at": "2015-01-21T21:47:18Z" + }, + { + "created_at": "2014-12-08T21:55:58Z", + "id": "30", + "name": "Subscription services", + "parent_id": null, + "updated_at": "2015-01-21T21:47:18Z" + }, + { + "created_at": "2015-01-21T21:47:24Z", + "id": "31", + "name": "Travel", + "parent_id": null, + "updated_at": "2015-01-21T21:47:24Z" + }, + { + "created_at": "2015-01-21T21:47:24Z", + "id": "32", + "name": "Business travel", + "parent_id": "31", + "updated_at": "2015-01-21T21:47:24Z" + }, + { + "created_at": "2015-01-21T21:47:24Z", + "id": "33", + "name": "Frequent flyers", + "parent_id": "31", + "updated_at": "2015-01-21T21:47:24Z" + }, + { + "created_at": "2015-01-21T21:51:22Z", + "id": "34", + "name": "Auto", + "parent_id": null, + "updated_at": "2015-01-21T21:51:22Z" + }, + { + "created_at": "2015-01-21T21:51:22Z", + "id": "35", + "name": "Current vehicle", + "parent_id": "34", + "updated_at": "2015-01-21T21:51:22Z" + }, + { + "created_at": "2015-01-21T21:51:22Z", + "id": "36", + "name": "Likely country of origin", + "parent_id": "34", + "updated_at": "2015-01-21T21:51:22Z" + }, + { + "created_at": "2015-01-21T21:51:23Z", + "id": "37", + "name": "Likely in market", + "parent_id": "34", + "updated_at": "2015-01-21T21:51:23Z" + }, + { + "created_at": "2015-01-21T21:51:23Z", + "id": "38", + "name": "Likely in market timing", + "parent_id": "34", + "updated_at": "2015-01-21T21:51:23Z" + }, + { + "created_at": "2015-01-21T21:51:23Z", + "id": "39", + "name": "Likely new vehicle brand", + "parent_id": "34", + "updated_at": "2015-01-21T21:51:23Z" + }, + { + "created_at": "2015-01-21T21:51:23Z", + "id": "3a", + "name": "Likely new vehicle payment preference", + "parent_id": "34", + "updated_at": "2015-01-21T21:51:23Z" + }, + { + "created_at": "2015-01-21T21:51:23Z", + "id": "3b", + "name": "Likely purchase vehicle feature", + "parent_id": "34", + "updated_at": "2015-01-21T21:51:23Z" + }, + { + "created_at": "2015-01-21T21:51:23Z", + "id": "3c", + "name": "Likely purchase vehicle segment", + "parent_id": "34", + "updated_at": "2015-01-21T21:51:23Z" + }, + { + "created_at": "2015-01-21T21:51:23Z", + "id": "3d", + "name": "New car purchase activity", + "parent_id": "34", + "updated_at": "2015-01-21T21:51:23Z" + }, + { + "created_at": "2015-01-21T21:51:23Z", + "id": "3e", + "name": "Country of origin", + "parent_id": "1a", + "updated_at": "2015-01-21T21:51:23Z" + }, + { + "created_at": "2015-01-21T21:51:23Z", + "id": "3f", + "name": "Education", + "parent_id": "1a", + "updated_at": "2015-01-21T21:51:23Z" + }, + { + "created_at": "2015-01-21T21:51:23Z", + "id": "3g", + "name": "Ethnicity", + "parent_id": "1a", + "updated_at": "2015-01-21T21:51:23Z" + }, + { + "created_at": "2015-01-21T21:51:23Z", + "id": "3h", + "name": "Home age", + "parent_id": "1a", + "updated_at": "2015-01-21T21:51:23Z" + }, + { + "created_at": "2015-01-21T21:51:23Z", + "id": "3i", + "name": "Home date", + "parent_id": "1a", + "updated_at": "2015-01-21T21:51:23Z" + }, + { + "created_at": "2015-01-21T21:51:23Z", + "id": "3j", + "name": "Home loan", + "parent_id": "1a", + "updated_at": "2015-01-21T21:51:23Z" + }, + { + "created_at": "2015-01-21T21:51:23Z", + "id": "3k", + "name": "Home purchase amount", + "parent_id": "1a", + "updated_at": "2015-01-21T21:51:23Z" + }, + { + "created_at": "2015-01-21T21:51:23Z", + "id": "3l", + "name": "Home size", + "parent_id": "1a", + "updated_at": "2015-01-21T21:51:23Z" + }, + { + "created_at": "2015-01-21T21:51:24Z", + "id": "3m", + "name": "Household size", + "parent_id": "1a", + "updated_at": "2015-01-21T21:51:24Z" + }, + { + "created_at": "2015-01-21T21:51:24Z", + "id": "3n", + "name": "Income", + "parent_id": "1a", + "updated_at": "2015-01-21T21:51:24Z" + }, + { + "created_at": "2015-01-21T21:51:24Z", + "id": "3o", + "name": "Life event", + "parent_id": "1a", + "updated_at": "2015-01-21T21:51:24Z" + }, + { + "created_at": "2015-01-21T21:51:24Z", + "id": "3p", + "name": "Net worth", + "parent_id": "1a", + "updated_at": "2015-01-21T21:51:24Z" + }, + { + "created_at": "2015-01-21T21:51:24Z", + "id": "3q", + "name": "Property type", + "parent_id": "1a", + "updated_at": "2015-01-21T21:51:24Z" + }, + { + "created_at": "2015-01-21T21:51:24Z", + "id": "3r", + "name": "Residence characteristics", + "parent_id": "1a", + "updated_at": "2015-01-21T21:51:24Z" + }, + { + "created_at": "2015-01-21T21:51:24Z", + "id": "3s", + "name": "Telephone behavior", + "parent_id": "1a", + "updated_at": "2015-01-21T21:51:24Z" + }, + { + "created_at": "2015-01-21T21:51:24Z", + "id": "3t", + "name": "Work role/location", + "parent_id": "1a", + "updated_at": "2015-01-21T21:51:24Z" + }, + { + "created_at": "2015-01-21T21:51:24Z", + "id": "3u", + "name": "Affluency", + "parent_id": "1z", + "updated_at": "2015-01-21T21:51:24Z" + }, + { + "created_at": "2015-01-21T21:51:24Z", + "id": "3v", + "name": "Auto insurance", + "parent_id": "1z", + "updated_at": "2015-01-21T21:51:24Z" + }, + { + "created_at": "2015-01-21T21:51:24Z", + "id": "3w", + "name": "Credit card type", + "parent_id": "1z", + "updated_at": "2015-01-21T21:51:24Z" + }, + { + "created_at": "2015-01-21T21:51:24Z", + "id": "3x", + "name": "Health insurance", + "parent_id": "1z", + "updated_at": "2015-01-21T21:51:24Z" + }, + { + "created_at": "2015-01-21T21:51:24Z", + "id": "3y", + "name": "Home insurance", + "parent_id": "1z", + "updated_at": "2015-01-21T21:51:24Z" + }, + { + "created_at": "2015-01-21T21:51:24Z", + "id": "3z", + "name": "Life insurance", + "parent_id": "1z", + "updated_at": "2015-01-21T21:51:24Z" + }, + { + "created_at": "2015-01-21T21:51:24Z", + "id": "40", + "name": "Likely retirement/college savings plan ownership", + "parent_id": "1z", + "updated_at": "2015-01-21T21:51:24Z" + }, + { + "created_at": "2015-01-21T21:51:24Z", + "id": "41", + "name": "Likely securities ownership", + "parent_id": "1z", + "updated_at": "2015-01-21T21:51:24Z" + }, + { + "created_at": "2015-01-21T21:51:25Z", + "id": "42", + "name": "Method of payment", + "parent_id": "1z", + "updated_at": "2015-01-21T21:51:25Z" + }, + { + "created_at": "2015-01-21T21:51:25Z", + "id": "43", + "name": "Other insurance", + "parent_id": "1z", + "updated_at": "2015-01-21T21:51:25Z" + }, + { + "created_at": "2015-01-21T21:51:25Z", + "id": "44", + "name": "Geo", + "parent_id": null, + "updated_at": "2015-01-21T21:51:25Z" + }, + { + "created_at": "2015-01-21T21:51:25Z", + "id": "45", + "name": "DMA", + "parent_id": "44", + "updated_at": "2015-01-21T21:51:25Z" + }, + { + "created_at": "2015-01-21T21:51:25Z", + "id": "46", + "name": "States", + "parent_id": "44", + "updated_at": "2015-01-21T21:51:25Z" + }, + { + "created_at": "2015-01-21T21:51:25Z", + "id": "47", + "name": "Entertainment", + "parent_id": "28", + "updated_at": "2015-01-21T21:51:25Z" + }, + { + "created_at": "2015-01-21T21:51:25Z", + "id": "48", + "name": "Home improvement", + "parent_id": "28", + "updated_at": "2015-01-21T21:51:25Z" + }, + { + "created_at": "2015-01-21T21:51:25Z", + "id": "49", + "name": "Interest", + "parent_id": "28", + "updated_at": "2015-01-21T21:51:25Z" + }, + { + "created_at": "2015-01-21T21:51:25Z", + "id": "4a", + "name": "Investing / finance", + "parent_id": "28", + "updated_at": "2015-01-21T21:51:25Z" + }, + { + "created_at": "2015-01-21T21:51:25Z", + "id": "4b", + "name": "Likely behavior", + "parent_id": "28", + "updated_at": "2015-01-21T21:51:25Z" + }, + { + "created_at": "2015-01-21T21:51:25Z", + "id": "4c", + "name": "Likely magazine", + "parent_id": "28", + "updated_at": "2015-01-21T21:51:25Z" + }, + { + "created_at": "2015-01-21T21:51:25Z", + "id": "4d", + "name": "Likely magazine type", + "parent_id": "28", + "updated_at": "2015-01-21T21:51:25Z" + }, + { + "created_at": "2015-01-21T21:51:25Z", + "id": "4e", + "name": "Likely newspaper", + "parent_id": "28", + "updated_at": "2015-01-21T21:51:25Z" + }, + { + "created_at": "2015-01-21T21:51:25Z", + "id": "4f", + "name": "Likely radio format", + "parent_id": "28", + "updated_at": "2015-01-21T21:51:25Z" + }, + { + "created_at": "2015-01-21T21:51:25Z", + "id": "4g", + "name": "Likely radio type", + "parent_id": "28", + "updated_at": "2015-01-21T21:51:25Z" + }, + { + "created_at": "2015-01-21T21:51:26Z", + "id": "4h", + "name": "Likely television channel", + "parent_id": "28", + "updated_at": "2015-01-21T21:51:26Z" + }, + { + "created_at": "2015-01-21T21:51:26Z", + "id": "4i", + "name": "Likely television pay-per-view", + "parent_id": "28", + "updated_at": "2015-01-21T21:51:26Z" + }, + { + "created_at": "2015-01-21T21:51:26Z", + "id": "4j", + "name": "Likely television pay-per-view last 12 months", + "parent_id": "28", + "updated_at": "2015-01-21T21:51:26Z" + }, + { + "created_at": "2015-01-21T21:51:26Z", + "id": "4k", + "name": "Likely television technology", + "parent_id": "28", + "updated_at": "2015-01-21T21:51:26Z" + }, + { + "created_at": "2015-01-21T21:51:26Z", + "id": "4l", + "name": "Outdoor activities", + "parent_id": "28", + "updated_at": "2015-01-21T21:51:26Z" + }, + { + "created_at": "2015-01-21T21:51:26Z", + "id": "4m", + "name": "Personicx", + "parent_id": "28", + "updated_at": "2015-01-21T21:51:26Z" + }, + { + "created_at": "2015-01-21T21:51:26Z", + "id": "4n", + "name": "Reading", + "parent_id": "28", + "updated_at": "2015-01-21T21:51:26Z" + }, + { + "created_at": "2015-01-21T21:51:26Z", + "id": "4o", + "name": "Sports", + "parent_id": "28", + "updated_at": "2015-01-21T21:51:26Z" + }, + { + "created_at": "2015-01-21T21:51:26Z", + "id": "4p", + "name": "Causes supported financially", + "parent_id": "29", + "updated_at": "2015-01-21T21:51:26Z" + }, + { + "created_at": "2015-01-21T21:51:26Z", + "id": "4q", + "name": "Likely contribution method", + "parent_id": "29", + "updated_at": "2015-01-21T21:51:26Z" + }, + { + "created_at": "2015-01-21T21:51:26Z", + "id": "4r", + "name": "Likely contribution organization", + "parent_id": "29", + "updated_at": "2015-01-21T21:51:26Z" + }, + { + "created_at": "2015-01-21T21:51:26Z", + "id": "4s", + "name": "Likely participation", + "parent_id": "29", + "updated_at": "2015-01-21T21:51:26Z" + }, + { + "created_at": "2015-01-21T21:51:26Z", + "id": "4t", + "name": "Politics", + "parent_id": null, + "updated_at": "2015-01-21T21:51:26Z" + }, + { + "created_at": "2015-01-21T21:51:26Z", + "id": "4u", + "name": "Likely political, public or civic activities", + "parent_id": "4t", + "updated_at": "2015-01-21T21:51:26Z" + }, + { + "created_at": "2015-01-21T21:51:26Z", + "id": "4v", + "name": "Political party", + "parent_id": "4t", + "updated_at": "2015-01-21T21:51:26Z" + }, + { + "created_at": "2015-01-21T21:51:26Z", + "id": "4w", + "name": "State political districts", + "parent_id": "4t", + "updated_at": "2015-01-21T21:51:26Z" + }, + { + "created_at": "2015-01-21T21:51:27Z", + "id": "4x", + "name": "Apparel", + "parent_id": "2e", + "updated_at": "2015-01-21T21:51:27Z" + }, + { + "created_at": "2015-01-21T21:51:27Z", + "id": "4y", + "name": "Apparel type", + "parent_id": "2e", + "updated_at": "2015-01-21T21:51:27Z" + }, + { + "created_at": "2015-01-21T21:51:27Z", + "id": "4z", + "name": "Automotive", + "parent_id": "2e", + "updated_at": "2015-01-21T21:51:27Z" + }, + { + "created_at": "2015-01-21T21:51:27Z", + "id": "50", + "name": "Baby products", + "parent_id": "2e", + "updated_at": "2015-01-21T21:51:27Z" + }, + { + "created_at": "2015-01-21T21:51:27Z", + "id": "51", + "name": "Beauty", + "parent_id": "2e", + "updated_at": "2015-01-21T21:51:27Z" + }, + { + "created_at": "2015-01-21T21:51:27Z", + "id": "52", + "name": "Retailer type", + "parent_id": "2e", + "updated_at": "2015-01-21T21:51:27Z" + }, + { + "created_at": "2015-01-21T21:51:27Z", + "id": "53", + "name": "Specialty store buyer", + "parent_id": "2e", + "updated_at": "2015-01-21T21:51:27Z" + }, + { + "created_at": "2015-01-21T21:51:27Z", + "id": "54", + "name": "Standard retail store buyer", + "parent_id": "2e", + "updated_at": "2015-01-21T21:51:27Z" + }, + { + "created_at": "2015-01-21T21:51:27Z", + "id": "55", + "name": "Tools", + "parent_id": "2e", + "updated_at": "2015-01-21T21:51:27Z" + }, + { + "created_at": "2015-01-21T21:51:27Z", + "id": "56", + "name": "Upscale store buyer", + "parent_id": "2e", + "updated_at": "2015-01-21T21:51:27Z" + }, + { + "created_at": "2015-01-21T21:51:27Z", + "id": "57", + "name": "Technology", + "parent_id": null, + "updated_at": "2015-01-21T21:51:27Z" + }, + { + "created_at": "2015-01-21T21:51:27Z", + "id": "58", + "name": "Consumer electronics & accessories", + "parent_id": "57", + "updated_at": "2015-01-21T21:51:27Z" + }, + { + "created_at": "2015-01-21T21:51:27Z", + "id": "59", + "name": "Electronics / computers", + "parent_id": "57", + "updated_at": "2015-01-21T21:51:27Z" + }, + { + "created_at": "2015-01-21T21:51:27Z", + "id": "5a", + "name": "Gaming consoles, video games and accessories", + "parent_id": "57", + "updated_at": "2015-01-21T21:51:27Z" + }, + { + "created_at": "2015-01-21T21:51:27Z", + "id": "5b", + "name": "Television & video", + "parent_id": "57", + "updated_at": "2015-01-21T21:51:27Z" + }, + { + "created_at": "2015-01-21T21:51:27Z", + "id": "5c", + "name": "Airline", + "parent_id": "31", + "updated_at": "2015-01-21T21:51:27Z" + }, + { + "created_at": "2015-01-21T21:51:28Z", + "id": "5d", + "name": "Hotel", + "parent_id": "31", + "updated_at": "2015-01-21T21:51:28Z" + }, + { + "created_at": "2015-01-21T21:51:28Z", + "id": "5e", + "name": "Travel services", + "parent_id": "31", + "updated_at": "2015-01-21T21:51:28Z" + } + ], + "data_type": "behavior_taxonomies", + "next_cursor": null, + "request": { + "params": {} + }, + "total_count": 194 +} \ No newline at end of file diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-behaviors-params.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-behaviors-params.json new file mode 100644 index 00000000..6090e9be --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-behaviors-params.json @@ -0,0 +1,42 @@ +{ + "data": [ + { + "audience_size": 4521480, + "behavior_taxonomy_id": "3", + "id": "lfs0", + "name": "In market: new vehicle", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 2420480, + "behavior_taxonomy_id": "2", + "id": "lfrz", + "name": "Vehicle purchase: 48+ months ago", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + } + ], + "data_type": "behaviors", + "next_cursor": null, + "request": { + "params": { + "behavior_ids": [ + "lfrz", + "lfs0" + ], + "sort_by": [ + "name-asc" + ] + } + }, + "total_count": 2 +} \ No newline at end of file diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-behaviors.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-behaviors.json new file mode 100644 index 00000000..e7345b16 --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-behaviors.json @@ -0,0 +1,2410 @@ +{ + "data": [ + { + "audience_size": 6713220, + "behavior_taxonomy_id": "y", + "id": "lfls", + "name": "Deli food buyers", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 7092400, + "behavior_taxonomy_id": "16", + "id": "lflt", + "name": "Packaged meals, grains & pasta buyers", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 4961940, + "behavior_taxonomy_id": "w", + "id": "lfmh", + "name": "Marinades & sauces", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 5357680, + "behavior_taxonomy_id": "w", + "id": "lfmi", + "name": "Mayonnaise & spreads", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 5331840, + "behavior_taxonomy_id": "w", + "id": "lfmj", + "name": "Pasta sauce", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 2656320, + "behavior_taxonomy_id": "w", + "id": "lfmk", + "name": "Pickles & olives", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 3443680, + "behavior_taxonomy_id": "x", + "id": "lfml", + "name": "Cottage cheese & sour cream", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 4093000, + "behavior_taxonomy_id": "y", + "id": "lfmm", + "name": "Deli bulk meat", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 964380, + "behavior_taxonomy_id": "y", + "id": "lfmn", + "name": "Deli condiments", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 3531120, + "behavior_taxonomy_id": "y", + "id": "lfmo", + "name": "Deli dips/spreads/toppings", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 2256160, + "behavior_taxonomy_id": "y", + "id": "lfmp", + "name": "Deli entrees", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 5695360, + "behavior_taxonomy_id": "y", + "id": "lfmq", + "name": "Deli prepared/pre-packaged", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 951660, + "behavior_taxonomy_id": "y", + "id": "lfmr", + "name": "Deli pre-sliced cheese", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 1510080, + "behavior_taxonomy_id": "y", + "id": "lfms", + "name": "Deli pre-sliced meat", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 3309980, + "behavior_taxonomy_id": "y", + "id": "lfmt", + "name": "Deli salads", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 2264480, + "behavior_taxonomy_id": "z", + "id": "lfmu", + "name": "Frozen appetizers & snacks", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 2228060, + "behavior_taxonomy_id": "z", + "id": "lfmv", + "name": "Frozen bread & dough", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 3118420, + "behavior_taxonomy_id": "z", + "id": "lfmw", + "name": "Frozen breakfast", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 1393620, + "behavior_taxonomy_id": "z", + "id": "lfmx", + "name": "Frozen desserts", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 692040, + "behavior_taxonomy_id": "z", + "id": "lfmy", + "name": "Frozen ethnic foods", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 1863060, + "behavior_taxonomy_id": "z", + "id": "lfmz", + "name": "Frozen fruit", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 1706400, + "behavior_taxonomy_id": "z", + "id": "lfn0", + "name": "Frozen pasta", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 3502520, + "behavior_taxonomy_id": "z", + "id": "lfn1", + "name": "Frozen pizza", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 3781600, + "behavior_taxonomy_id": "12", + "id": "lfn2", + "name": "Antiperspirants & deodorants", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 1225200, + "behavior_taxonomy_id": "12", + "id": "lfn3", + "name": "Eye care", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 4295080, + "behavior_taxonomy_id": "12", + "id": "lfn4", + "name": "Feminine care", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 2539460, + "behavior_taxonomy_id": "12", + "id": "lfn5", + "name": "First aid", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 1931200, + "behavior_taxonomy_id": "12", + "id": "lfn6", + "name": "Gastrointestinal", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 1965240, + "behavior_taxonomy_id": "12", + "id": "lfn7", + "name": "Men's grooming", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 2274920, + "behavior_taxonomy_id": "12", + "id": "lfn8", + "name": "Shaving care & hair removal", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 2831720, + "behavior_taxonomy_id": "12", + "id": "lfn9", + "name": "Skin care", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 2772480, + "behavior_taxonomy_id": "14", + "id": "lfna", + "name": "Air deodorizers & fresheners", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 4187760, + "behavior_taxonomy_id": "14", + "id": "lfnb", + "name": "Bath tissue", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 2026880, + "behavior_taxonomy_id": "14", + "id": "lfnc", + "name": "Batteries", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 3754880, + "behavior_taxonomy_id": "14", + "id": "lfnd", + "name": "Dish & dishwasher detergent", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 2165620, + "behavior_taxonomy_id": "14", + "id": "lfne", + "name": "Disposable serveware", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 2764420, + "behavior_taxonomy_id": "14", + "id": "lfnf", + "name": "Facial tissue", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 4161340, + "behavior_taxonomy_id": "14", + "id": "lfng", + "name": "Paper towels", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 2866340, + "behavior_taxonomy_id": "14", + "id": "lfnh", + "name": "Trash bags", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 5088620, + "behavior_taxonomy_id": "16", + "id": "lfni", + "name": "Dry pasta", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 3483880, + "behavior_taxonomy_id": "16", + "id": "lfnj", + "name": "Mac & cheese", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 2204780, + "behavior_taxonomy_id": "16", + "id": "lfnk", + "name": "Packaged noodle & rice dishes", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 3825060, + "behavior_taxonomy_id": "16", + "id": "lfnl", + "name": "Rice", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 1570480, + "behavior_taxonomy_id": "17", + "id": "lfnm", + "name": "Cat litter", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 671320, + "behavior_taxonomy_id": "17", + "id": "lfnn", + "name": "Cat treats", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 2962700, + "behavior_taxonomy_id": "17", + "id": "lfno", + "name": "Dog treats", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 1934580, + "behavior_taxonomy_id": "17", + "id": "lfnp", + "name": "Natural pet food & products", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 2543520, + "behavior_taxonomy_id": "17", + "id": "lfnq", + "name": "Pet accessories", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 4568580, + "behavior_taxonomy_id": "12", + "id": "lfnr", + "name": "Oral care", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 3251460, + "behavior_taxonomy_id": "4", + "id": "lfns", + "name": "Max in market: body style: crossover vehicle", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 3426440, + "behavior_taxonomy_id": "4", + "id": "lfnt", + "name": "Max in market: body style: entry/economy/compact", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 1225140, + "behavior_taxonomy_id": "4", + "id": "lfnu", + "name": "Max in market: body style: full-size sedan", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 1728940, + "behavior_taxonomy_id": "4", + "id": "lfnv", + "name": "Max in market: body style: full-size SUV", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 2197020, + "behavior_taxonomy_id": "4", + "id": "lfnw", + "name": "Max in market: body style: hybrid/alternative fuel", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 2726640, + "behavior_taxonomy_id": "4", + "id": "lfnx", + "name": "Max in market: body style: luxury sedan", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 2584960, + "behavior_taxonomy_id": "4", + "id": "lfny", + "name": "Max in market: body style: luxury SUV", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 3222940, + "behavior_taxonomy_id": "4", + "id": "lfnz", + "name": "Max in market: body style: midsize car", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 1636760, + "behavior_taxonomy_id": "4", + "id": "lfo0", + "name": "Max in market: body style: minivan", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 2802760, + "behavior_taxonomy_id": "4", + "id": "lfo1", + "name": "Max in market: body style: pickup truck", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 3459640, + "behavior_taxonomy_id": "4", + "id": "lfo2", + "name": "Max in market: body style: small/mid-size SUV", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 2121560, + "behavior_taxonomy_id": "4", + "id": "lfo3", + "name": "Max in market: body style: sports car/convertible", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 4930080, + "behavior_taxonomy_id": "4", + "id": "lfo4", + "name": "Max in market: all body styles", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 236580, + "behavior_taxonomy_id": "7", + "id": "lfo5", + "name": "Owners: make: Acura", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 137300, + "behavior_taxonomy_id": "7", + "id": "lfo6", + "name": "Owners: make: Audi", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 339980, + "behavior_taxonomy_id": "7", + "id": "lfo7", + "name": "Owners: make: BMW", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 327460, + "behavior_taxonomy_id": "7", + "id": "lfo8", + "name": "Owners: make: Buick", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 218900, + "behavior_taxonomy_id": "7", + "id": "lfo9", + "name": "Owners: make: Cadillac", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 948920, + "behavior_taxonomy_id": "7", + "id": "lfoa", + "name": "Owners: make: Chevrolet car", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 1682700, + "behavior_taxonomy_id": "7", + "id": "lfob", + "name": "Owners: make: Chevrolet truck", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 2348760, + "behavior_taxonomy_id": "7", + "id": "lfoc", + "name": "Owners: make: Chrysler", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 293620, + "behavior_taxonomy_id": "7", + "id": "lfod", + "name": "Owners: make: Dodge car", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 864180, + "behavior_taxonomy_id": "7", + "id": "lfoe", + "name": "Owners: make: RAM truck", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 900440, + "behavior_taxonomy_id": "7", + "id": "lfof", + "name": "Owners: make: Ford car", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 1924940, + "behavior_taxonomy_id": "7", + "id": "lfog", + "name": "Owners: make: Ford truck", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 589840, + "behavior_taxonomy_id": "7", + "id": "lfoh", + "name": "Owners: make: GMC", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 1702340, + "behavior_taxonomy_id": "7", + "id": "lfoi", + "name": "Owners: make: Honda", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 21580, + "behavior_taxonomy_id": "7", + "id": "lfoj", + "name": "Owners: make: Hummer", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 454380, + "behavior_taxonomy_id": "7", + "id": "lfok", + "name": "Owners: make: Hyundai", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 142120, + "behavior_taxonomy_id": "7", + "id": "lfol", + "name": "Owners: make: Infiniti", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 43920, + "behavior_taxonomy_id": "7", + "id": "lfom", + "name": "Owners: make: Isuzu", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 35660, + "behavior_taxonomy_id": "7", + "id": "lfon", + "name": "Owners: make: Jaguar", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 691840, + "behavior_taxonomy_id": "7", + "id": "lfoo", + "name": "Owners: make: Jeep", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 304160, + "behavior_taxonomy_id": "7", + "id": "lfop", + "name": "Owners: make: Kia", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 57020, + "behavior_taxonomy_id": "7", + "id": "lfoq", + "name": "Owners: make: Land Rover", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 313960, + "behavior_taxonomy_id": "7", + "id": "lfor", + "name": "Owners: make: Lexus", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 142720, + "behavior_taxonomy_id": "7", + "id": "lfos", + "name": "Owners: make: Lincoln", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 351580, + "behavior_taxonomy_id": "7", + "id": "lfot", + "name": "Owners: make: Mazda", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 299460, + "behavior_taxonomy_id": "7", + "id": "lfou", + "name": "Owners: make: Mercedes", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 224700, + "behavior_taxonomy_id": "7", + "id": "lfov", + "name": "Owners: make: Mercury", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 51500, + "behavior_taxonomy_id": "7", + "id": "lfow", + "name": "Owners: make: Mini", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 170760, + "behavior_taxonomy_id": "7", + "id": "lfox", + "name": "Owners: make: Mitsubishi", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 1041160, + "behavior_taxonomy_id": "7", + "id": "lfoy", + "name": "Owners: make: Nissan", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 427100, + "behavior_taxonomy_id": "7", + "id": "lfoz", + "name": "Owners: make: Pontiac", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 46300, + "behavior_taxonomy_id": "7", + "id": "lfp0", + "name": "Owners: make: Porsche", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 42260, + "behavior_taxonomy_id": "7", + "id": "lfp1", + "name": "Owners: make: Saab", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 211280, + "behavior_taxonomy_id": "7", + "id": "lfp2", + "name": "Owners: make: Saturn", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 274020, + "behavior_taxonomy_id": "7", + "id": "lfp3", + "name": "Owners: make: Subaru", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 54260, + "behavior_taxonomy_id": "7", + "id": "lfp4", + "name": "Owners: make: Suzuki", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 2203500, + "behavior_taxonomy_id": "7", + "id": "lfp5", + "name": "Owners: make: Toyota", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 392280, + "behavior_taxonomy_id": "7", + "id": "lfp6", + "name": "Owners: make: Volkswagen", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 168100, + "behavior_taxonomy_id": "7", + "id": "lfp7", + "name": "Owners: make: Volvo", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 157620, + "behavior_taxonomy_id": "3", + "id": "lfp8", + "name": "Make: Acura", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 106320, + "behavior_taxonomy_id": "3", + "id": "lfp9", + "name": "Make: Audi", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 227600, + "behavior_taxonomy_id": "3", + "id": "lfpa", + "name": "Make: BMW", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 207740, + "behavior_taxonomy_id": "3", + "id": "lfpb", + "name": "Make: Buick", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 144440, + "behavior_taxonomy_id": "3", + "id": "lfpc", + "name": "Make: Cadillac", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 586380, + "behavior_taxonomy_id": "3", + "id": "lfpd", + "name": "Make: Chevrolet car", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 1171280, + "behavior_taxonomy_id": "3", + "id": "lfpe", + "name": "Make: Chevrolet truck", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 1555720, + "behavior_taxonomy_id": "3", + "id": "lfpf", + "name": "Make: Chrysler", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 210560, + "behavior_taxonomy_id": "3", + "id": "lfpg", + "name": "Make: Dodge car", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 563740, + "behavior_taxonomy_id": "3", + "id": "lfph", + "name": "Make: RAM truck", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 553100, + "behavior_taxonomy_id": "3", + "id": "lfpi", + "name": "Make: Ford car", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 1327100, + "behavior_taxonomy_id": "3", + "id": "lfpj", + "name": "Make: Ford truck", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 407060, + "behavior_taxonomy_id": "3", + "id": "lfpk", + "name": "Make: GMC", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 1153220, + "behavior_taxonomy_id": "3", + "id": "lfpl", + "name": "Make: Honda", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 335040, + "behavior_taxonomy_id": "3", + "id": "lfpm", + "name": "Make: Hyundai", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 94160, + "behavior_taxonomy_id": "3", + "id": "lfpn", + "name": "Make: Infiniti", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 23960, + "behavior_taxonomy_id": "3", + "id": "lfpp", + "name": "Make: Jaguar", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 454120, + "behavior_taxonomy_id": "3", + "id": "lfpq", + "name": "Make: Jeep", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 218280, + "behavior_taxonomy_id": "3", + "id": "lfpr", + "name": "Make: Kia", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 39140, + "behavior_taxonomy_id": "3", + "id": "lfps", + "name": "Make: Land Rover", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 215500, + "behavior_taxonomy_id": "3", + "id": "lfpt", + "name": "Make: Lexus", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 93220, + "behavior_taxonomy_id": "3", + "id": "lfpu", + "name": "Make: Lincoln", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 222180, + "behavior_taxonomy_id": "3", + "id": "lfpv", + "name": "Make: Mazda", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 204020, + "behavior_taxonomy_id": "3", + "id": "lfpw", + "name": "Make: Mercedes", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 38000, + "behavior_taxonomy_id": "3", + "id": "lfpy", + "name": "Make: Mini", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 104240, + "behavior_taxonomy_id": "3", + "id": "lfpz", + "name": "Make: Mitsubishi", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 650220, + "behavior_taxonomy_id": "3", + "id": "lfq0", + "name": "Make: Nissan", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 30760, + "behavior_taxonomy_id": "3", + "id": "lfq2", + "name": "Make: Porsche", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 202020, + "behavior_taxonomy_id": "3", + "id": "lfq5", + "name": "Make: Subaru", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 1448040, + "behavior_taxonomy_id": "3", + "id": "lfq7", + "name": "Make: Toyota", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 250780, + "behavior_taxonomy_id": "3", + "id": "lfq8", + "name": "Make: Volkswagen", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 113300, + "behavior_taxonomy_id": "3", + "id": "lfq9", + "name": "Make: Volvo", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 82420, + "behavior_taxonomy_id": "3", + "id": "lfqa", + "name": "Used: make: Acura", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 42820, + "behavior_taxonomy_id": "3", + "id": "lfqb", + "name": "Used: make: Audi", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 122300, + "behavior_taxonomy_id": "3", + "id": "lfqc", + "name": "Used: make: BMW", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 161900, + "behavior_taxonomy_id": "3", + "id": "lfqd", + "name": "Used: make: Buick", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 103700, + "behavior_taxonomy_id": "3", + "id": "lfqe", + "name": "Used: make: Cadillac", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 511780, + "behavior_taxonomy_id": "3", + "id": "lfqf", + "name": "Used: make: Chevrolet car", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 850480, + "behavior_taxonomy_id": "3", + "id": "lfqg", + "name": "Used: make: Chevrolet truck", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 1163080, + "behavior_taxonomy_id": "3", + "id": "lfqh", + "name": "Used: make: Chrysler", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 164300, + "behavior_taxonomy_id": "3", + "id": "lfqi", + "name": "Used: make: Dodge car", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 436320, + "behavior_taxonomy_id": "3", + "id": "lfqj", + "name": "Used: make: RAM truck", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 474300, + "behavior_taxonomy_id": "3", + "id": "lfqk", + "name": "Used: make: Ford car", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 994880, + "behavior_taxonomy_id": "3", + "id": "lfql", + "name": "Used: make: Ford truck", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 297060, + "behavior_taxonomy_id": "3", + "id": "lfqm", + "name": "Used: make: GMC", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 792000, + "behavior_taxonomy_id": "3", + "id": "lfqn", + "name": "Used: make: Honda", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 209640, + "behavior_taxonomy_id": "3", + "id": "lfqp", + "name": "Used: make: Hyundai", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 52800, + "behavior_taxonomy_id": "3", + "id": "lfqq", + "name": "Used: make: Infiniti", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 13920, + "behavior_taxonomy_id": "3", + "id": "lfqs", + "name": "Used: make: Jaguar", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 344720, + "behavior_taxonomy_id": "3", + "id": "lfqt", + "name": "Used: make: Jeep", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 141600, + "behavior_taxonomy_id": "3", + "id": "lfqu", + "name": "Used: make: Kia", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 20360, + "behavior_taxonomy_id": "3", + "id": "lfqv", + "name": "Used: make: Land Rover", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 113940, + "behavior_taxonomy_id": "3", + "id": "lfqw", + "name": "Used: make: Lexus", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 67880, + "behavior_taxonomy_id": "3", + "id": "lfqx", + "name": "Used: make: Lincoln", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 169660, + "behavior_taxonomy_id": "3", + "id": "lfqy", + "name": "Used: make: Mazda", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 106840, + "behavior_taxonomy_id": "3", + "id": "lfqz", + "name": "Used: make: Mercedes", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 18760, + "behavior_taxonomy_id": "3", + "id": "lfr1", + "name": "Used: make: Mini", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 78800, + "behavior_taxonomy_id": "3", + "id": "lfr2", + "name": "Used: make: Mitsubishi", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 501060, + "behavior_taxonomy_id": "3", + "id": "lfr3", + "name": "Used: make: Nissan", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 16160, + "behavior_taxonomy_id": "3", + "id": "lfr5", + "name": "Used: make: Porsche", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 112480, + "behavior_taxonomy_id": "3", + "id": "lfr8", + "name": "Used: make: Subaru", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 1072180, + "behavior_taxonomy_id": "3", + "id": "lfra", + "name": "Used: make: Toyota", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 134480, + "behavior_taxonomy_id": "3", + "id": "lfrb", + "name": "Used: make: Volkswagen", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 58940, + "behavior_taxonomy_id": "3", + "id": "lfrc", + "name": "Used: make: Volvo", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 3186440, + "behavior_taxonomy_id": "3", + "id": "lfrd", + "name": "Used: body style: entry/economy/compact", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 4161740, + "behavior_taxonomy_id": "3", + "id": "lfre", + "name": "Used: body style: midsize car", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 4351200, + "behavior_taxonomy_id": "3", + "id": "lfrf", + "name": "Used: body style: small/mid-size SUV", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 3522660, + "behavior_taxonomy_id": "3", + "id": "lfrg", + "name": "Used: body style: full-size SUV", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 4068280, + "behavior_taxonomy_id": "3", + "id": "lfrh", + "name": "Used: body style: luxury sedan", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 3549680, + "behavior_taxonomy_id": "3", + "id": "lfri", + "name": "Used: body style: pickup truck", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 2975040, + "behavior_taxonomy_id": "3", + "id": "lfrj", + "name": "Used: body style: minivan", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 4359140, + "behavior_taxonomy_id": "3", + "id": "lfrk", + "name": "Used: body style: sports car/convertible", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 7308760, + "behavior_taxonomy_id": "8", + "id": "lfrl", + "name": "Vehicle price: $20k or under", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 4370600, + "behavior_taxonomy_id": "8", + "id": "lfrm", + "name": "Vehicle price: $20k to $30k", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 622160, + "behavior_taxonomy_id": "8", + "id": "lfrn", + "name": "Vehicle price: $30k to $40k", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 572780, + "behavior_taxonomy_id": "8", + "id": "lfro", + "name": "Vehicle price: $40k to $50k", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 339260, + "behavior_taxonomy_id": "8", + "id": "lfrp", + "name": "Vehicle price: $50k to $75k", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 33320, + "behavior_taxonomy_id": "8", + "id": "lfrq", + "name": "Vehicle price: $75k or higher", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 800800, + "behavior_taxonomy_id": "5", + "id": "lfrr", + "name": "Motorcycle owner", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 5615180, + "behavior_taxonomy_id": "2", + "id": "lfrs", + "name": "Auto parts buyer", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 5712240, + "behavior_taxonomy_id": "2", + "id": "lfrt", + "name": "Auto service buyer", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 1721020, + "behavior_taxonomy_id": "2", + "id": "lfru", + "name": "Vehicle purchase: 0-6 months ago", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 1274580, + "behavior_taxonomy_id": "2", + "id": "lfrv", + "name": "Vehicle purchase: 7-12 months ago", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 1705440, + "behavior_taxonomy_id": "2", + "id": "lfrw", + "name": "Vehicle purchase: 13-24 months ago", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 1039480, + "behavior_taxonomy_id": "2", + "id": "lfrx", + "name": "Vehicle purchase: 25-36 months ago", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 637840, + "behavior_taxonomy_id": "2", + "id": "lfry", + "name": "Vehicle purchase: 37-48 months ago", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 2420480, + "behavior_taxonomy_id": "2", + "id": "lfrz", + "name": "Vehicle purchase: 48+ months ago", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 4521480, + "behavior_taxonomy_id": "3", + "id": "lfs0", + "name": "In market: new vehicle", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 7871600, + "behavior_taxonomy_id": "3", + "id": "lfs1", + "name": "In market: new or used vehicle", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 5101140, + "behavior_taxonomy_id": "3", + "id": "lfs2", + "name": "In market: used vehicle", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 3236800, + "behavior_taxonomy_id": "3", + "id": "lfs3", + "name": "Used: body style: crossover vehicle", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 931500, + "behavior_taxonomy_id": "3", + "id": "lfs4", + "name": "Used: body style: full-size sedan", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 1375080, + "behavior_taxonomy_id": "3", + "id": "lfs5", + "name": "Used: body style: hybrid/alternative fuel", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 863560, + "behavior_taxonomy_id": "3", + "id": "lfs6", + "name": "Used: body style: luxury SUV", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 1796160, + "behavior_taxonomy_id": "8", + "id": "lfs7", + "name": "Vehicle age: 0-1 years old", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 1175900, + "behavior_taxonomy_id": "8", + "id": "lfs8", + "name": "Vehicle age: 2 years old", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 1126800, + "behavior_taxonomy_id": "8", + "id": "lfs9", + "name": "Vehicle age: 3 years old", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 2013800, + "behavior_taxonomy_id": "8", + "id": "lfsa", + "name": "Vehicle age: 4-5 years old", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + }, + { + "audience_size": 6862540, + "behavior_taxonomy_id": "8", + "id": "lfsb", + "name": "Vehicle age: 6-10 years old", + "partner_source": "Datalogix", + "targetable_types": [ + "BEHAVIOR", + "NEGATIVE_BEHAVIOR", + "BEHAVIOR_LOOKALIKE_EXPANDED" + ] + } + ], + "data_type": "behaviors", + "next_cursor": "1927jmyo", + "request": { + "params": {} + }, + "total_count": 1082 +} \ No newline at end of file diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-devices-params.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-devices-params.json new file mode 100644 index 00000000..91df3923 --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-devices-params.json @@ -0,0 +1,66 @@ +{ + "data": [ + { + "manufacturer": "Apple", + "name": "iPhone 3GS", + "platform": "iOS", + "targeting_type": "DEVICE", + "targeting_value": "1q" + }, + { + "manufacturer": "Apple", + "name": "iPhone 4", + "platform": "iOS", + "targeting_type": "DEVICE", + "targeting_value": "1r" + }, + { + "manufacturer": "Apple", + "name": "iPhone 4S", + "platform": "iOS", + "targeting_type": "DEVICE", + "targeting_value": "1s" + }, + { + "manufacturer": "Apple", + "name": "iPhone 5", + "platform": "iOS", + "targeting_type": "DEVICE", + "targeting_value": "1t" + }, + { + "manufacturer": "Apple", + "name": "iPhone 5C", + "platform": "iOS", + "targeting_type": "DEVICE", + "targeting_value": "22" + }, + { + "manufacturer": "Apple", + "name": "iPhone 5S", + "platform": "iOS", + "targeting_type": "DEVICE", + "targeting_value": "21" + }, + { + "manufacturer": "Apple", + "name": "iPhone 6", + "platform": "iOS", + "targeting_type": "DEVICE", + "targeting_value": "46" + }, + { + "manufacturer": "Apple", + "name": "iPhone 6 Plus", + "platform": "iOS", + "targeting_type": "DEVICE", + "targeting_value": "47" + } + ], + "data_type": "targeting_criterion", + "request": { + "params": { + "q": "iphone" + } + } +} \ No newline at end of file diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-devices.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-devices.json new file mode 100644 index 00000000..c67b5f2f --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-devices.json @@ -0,0 +1,932 @@ +{ + "data": [ + { + "manufacturer": "Amazon", + "name": "Amazon Kindle Fire", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "1l" + }, + { + "manufacturer": "Amazon", + "name": "Amazon Kindle Fire 10\"", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "1k" + }, + { + "manufacturer": "Amazon", + "name": "Amazon Kindle Fire HD 7\"", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "d" + }, + { + "manufacturer": "Amazon", + "name": "Amazon Kindle Fire HD 8.9\"", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "1m" + }, + { + "manufacturer": "Fujitsu", + "name": "Fujitsu Arrows V", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "30" + }, + { + "manufacturer": "Fujitsu", + "name": "Fujitsu Arrows X", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "2x" + }, + { + "manufacturer": "Google", + "name": "Google Droid Bionic", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "1h" + }, + { + "manufacturer": "Google", + "name": "Google Droid Razr", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "2i" + }, + { + "manufacturer": "Google", + "name": "Google Galaxy Nexus", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "11" + }, + { + "manufacturer": "Google", + "name": "Google Nexus 4", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "j" + }, + { + "manufacturer": "Google", + "name": "Google Nexus 5", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "2k" + }, + { + "manufacturer": "Google", + "name": "Google Nexus 7", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "b" + }, + { + "manufacturer": "HTC", + "name": "HTC Butterfly", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "2l" + }, + { + "manufacturer": "HTC", + "name": "HTC Desire", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "41" + }, + { + "manufacturer": "HTC", + "name": "HTC Desire 500", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "3g" + }, + { + "manufacturer": "HTC", + "name": "HTC Desire C", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "1c" + }, + { + "manufacturer": "HTC", + "name": "HTC Desire HD", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "1a" + }, + { + "manufacturer": "HTC", + "name": "HTC Desire S", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "10" + }, + { + "manufacturer": "HTC", + "name": "HTC Desire X", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "2h" + }, + { + "manufacturer": "HTC", + "name": "HTC Evo", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "28" + }, + { + "manufacturer": "HTC", + "name": "HTC Evo 4G", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "1e" + }, + { + "manufacturer": "HTC", + "name": "HTC J", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "2p" + }, + { + "manufacturer": "HTC", + "name": "HTC J Butterfly", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "1b" + }, + { + "manufacturer": "HTC", + "name": "HTC One", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "a" + }, + { + "manufacturer": "HTC", + "name": "HTC One M8", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "34" + }, + { + "manufacturer": "HTC", + "name": "HTC One Mini", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "2o" + }, + { + "manufacturer": "HTC", + "name": "HTC One S", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "y" + }, + { + "manufacturer": "HTC", + "name": "HTC One V", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "1d" + }, + { + "manufacturer": "HTC", + "name": "HTC One X", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "c" + }, + { + "manufacturer": "HTC", + "name": "HTC One X+", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "2q" + }, + { + "manufacturer": "HTC", + "name": "HTC Sensation", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "2m" + }, + { + "manufacturer": "Huawei", + "name": "Huawei Ascend", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "32" + }, + { + "manufacturer": "Apple", + "name": "iPad", + "platform": "iOS", + "targeting_type": "DEVICE", + "targeting_value": "1v" + }, + { + "manufacturer": "Apple", + "name": "iPad 2", + "platform": "iOS", + "targeting_type": "DEVICE", + "targeting_value": "1w" + }, + { + "manufacturer": "Apple", + "name": "iPad 3", + "platform": "iOS", + "targeting_type": "DEVICE", + "targeting_value": "1x" + }, + { + "manufacturer": "Apple", + "name": "iPad 4", + "platform": "iOS", + "targeting_type": "DEVICE", + "targeting_value": "1y" + }, + { + "manufacturer": "Apple", + "name": "iPad Air", + "platform": "iOS", + "targeting_type": "DEVICE", + "targeting_value": "20" + }, + { + "manufacturer": "Apple", + "name": "iPad Air 2", + "platform": "iOS", + "targeting_type": "DEVICE", + "targeting_value": "48" + }, + { + "manufacturer": "Apple", + "name": "iPad mini", + "platform": "iOS", + "targeting_type": "DEVICE", + "targeting_value": "1z" + }, + { + "manufacturer": "Apple", + "name": "iPad mini 2", + "platform": "iOS", + "targeting_type": "DEVICE", + "targeting_value": "49" + }, + { + "manufacturer": "Apple", + "name": "iPad mini 3", + "platform": "iOS", + "targeting_type": "DEVICE", + "targeting_value": "4a" + }, + { + "manufacturer": "Apple", + "name": "iPhone 3GS", + "platform": "iOS", + "targeting_type": "DEVICE", + "targeting_value": "1q" + }, + { + "manufacturer": "Apple", + "name": "iPhone 4", + "platform": "iOS", + "targeting_type": "DEVICE", + "targeting_value": "1r" + }, + { + "manufacturer": "Apple", + "name": "iPhone 4S", + "platform": "iOS", + "targeting_type": "DEVICE", + "targeting_value": "1s" + }, + { + "manufacturer": "Apple", + "name": "iPhone 5", + "platform": "iOS", + "targeting_type": "DEVICE", + "targeting_value": "1t" + }, + { + "manufacturer": "Apple", + "name": "iPhone 5C", + "platform": "iOS", + "targeting_type": "DEVICE", + "targeting_value": "22" + }, + { + "manufacturer": "Apple", + "name": "iPhone 5S", + "platform": "iOS", + "targeting_type": "DEVICE", + "targeting_value": "21" + }, + { + "manufacturer": "Apple", + "name": "iPhone 6", + "platform": "iOS", + "targeting_type": "DEVICE", + "targeting_value": "46" + }, + { + "manufacturer": "Apple", + "name": "iPhone 6 Plus", + "platform": "iOS", + "targeting_type": "DEVICE", + "targeting_value": "47" + }, + { + "manufacturer": "Apple", + "name": "iPod Touch", + "platform": "iOS", + "targeting_type": "DEVICE", + "targeting_value": "1u" + }, + { + "manufacturer": "LG", + "name": "LG G2", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "3h" + }, + { + "manufacturer": "LG", + "name": "LG Motion 4G", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "p" + }, + { + "manufacturer": "LG", + "name": "LG Optimus G Pro", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "3l" + }, + { + "manufacturer": "LG", + "name": "LG Optimus L3", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "r" + }, + { + "manufacturer": "LG", + "name": "LG Optimus L5", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "s" + }, + { + "manufacturer": "LG", + "name": "LG Optimus L5 II", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "3t" + }, + { + "manufacturer": "LG", + "name": "LG Optimus L7", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "1f" + }, + { + "manufacturer": "LG", + "name": "LG Optimus L7 II", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "2u" + }, + { + "manufacturer": "LG", + "name": "LG Optimus L9", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "1i" + }, + { + "manufacturer": "Google", + "name": "Motorola Droid Razr HD", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "z" + }, + { + "manufacturer": "Google", + "name": "Motorola Droid Razr M", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "m" + }, + { + "manufacturer": "Google", + "name": "Motorola Droid Ultra", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "3c" + }, + { + "manufacturer": "Google", + "name": "Motorola Moto G", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "33" + }, + { + "manufacturer": "Google", + "name": "Motorola Moto X", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "39" + }, + { + "manufacturer": "Google", + "name": "Motorola Motoluxe", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "1j" + }, + { + "manufacturer": "Google", + "name": "Motorola RAZR D3", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "3o" + }, + { + "manufacturer": "Google", + "name": "Motorola Razr i", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "1n" + }, + { + "manufacturer": "Samsung", + "name": "Samsung Ace", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "23" + }, + { + "manufacturer": "Samsung", + "name": "Samsung Galaxy A3", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "4d" + }, + { + "manufacturer": "Samsung", + "name": "Samsung Galaxy A5", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "4e" + }, + { + "manufacturer": "Samsung", + "name": "Samsung Galaxy Ace", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "7" + }, + { + "manufacturer": "Samsung", + "name": "Samsung Galaxy Ace 2", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "9" + }, + { + "manufacturer": "Samsung", + "name": "Samsung Galaxy Ace 3", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "3i" + }, + { + "manufacturer": "Samsung", + "name": "Samsung Galaxy Ace II X", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "3j" + }, + { + "manufacturer": "Samsung", + "name": "Samsung Galaxy Ace Plus", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "t" + }, + { + "manufacturer": "Samsung", + "name": "Samsung Galaxy Core", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "2w" + }, + { + "manufacturer": "Samsung", + "name": "Samsung Galaxy Exhibit", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "3v" + }, + { + "manufacturer": "Samsung", + "name": "Samsung Galaxy Grand", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "i" + }, + { + "manufacturer": "Samsung", + "name": "Samsung Galaxy Grand 2", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "3q" + }, + { + "manufacturer": "Samsung", + "name": "Samsung Galaxy Grand Duos", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "26" + }, + { + "manufacturer": "Samsung", + "name": "Samsung Galaxy Grand Quattro", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "3d" + }, + { + "manufacturer": "Samsung", + "name": "Samsung Galaxy Mega", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "3f" + }, + { + "manufacturer": "Samsung", + "name": "Samsung Galaxy Mini", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "l" + }, + { + "manufacturer": "Samsung", + "name": "Samsung Galaxy Mini 2", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "x" + }, + { + "manufacturer": "Samsung", + "name": "Samsung Galaxy Nexus", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "25" + }, + { + "manufacturer": "Samsung", + "name": "Samsung Galaxy Note", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "k" + }, + { + "manufacturer": "Samsung", + "name": "Samsung Galaxy Note 4", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "4f" + }, + { + "manufacturer": "Samsung", + "name": "Samsung Galaxy Note II", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "2" + }, + { + "manufacturer": "Samsung", + "name": "Samsung Galaxy Note III", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "2g" + }, + { + "manufacturer": "Samsung", + "name": "Samsung Galaxy Pocket", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "w" + }, + { + "manufacturer": "Samsung", + "name": "Samsung Galaxy S", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "1g" + }, + { + "manufacturer": "Samsung", + "name": "Samsung Galaxy S Advance", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "8" + }, + { + "manufacturer": "Samsung", + "name": "Samsung Galaxy S Duos", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "15" + }, + { + "manufacturer": "Samsung", + "name": "Samsung Galaxy S II", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "3" + }, + { + "manufacturer": "Samsung", + "name": "Samsung Galaxy S III", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "1" + }, + { + "manufacturer": "Samsung", + "name": "Samsung Galaxy S III Alpha", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "18" + }, + { + "manufacturer": "Samsung", + "name": "Samsung Galaxy S III mini", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "4" + }, + { + "manufacturer": "Samsung", + "name": "Samsung Galaxy S Plus", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "h" + }, + { + "manufacturer": "Samsung", + "name": "Samsung Galaxy S2 Duos", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "3y" + }, + { + "manufacturer": "Samsung", + "name": "Samsung Galaxy S2 Plus", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "40" + }, + { + "manufacturer": "Samsung", + "name": "Samsung Galaxy S4", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "2r" + }, + { + "manufacturer": "Samsung", + "name": "Samsung Galaxy S4 Mini", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "2n" + }, + { + "manufacturer": "Samsung", + "name": "Samsung Galaxy S4 Mini Duos", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "36" + }, + { + "manufacturer": "Samsung", + "name": "Samsung Galaxy S5", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "35" + }, + { + "manufacturer": "Samsung", + "name": "Samsung Galaxy S6", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "4b" + }, + { + "manufacturer": "Samsung", + "name": "Samsung Galaxy S6 Edge", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "4c" + }, + { + "manufacturer": "Samsung", + "name": "Samsung Galaxy Tab", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "v" + }, + { + "manufacturer": "Samsung", + "name": "Samsung Galaxy Tab 2", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "e" + }, + { + "manufacturer": "Samsung", + "name": "Samsung Galaxy Trend", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "38" + }, + { + "manufacturer": "Samsung", + "name": "Samsung Galaxy Trend Plus", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "42" + }, + { + "manufacturer": "Samsung", + "name": "Samsung Galaxy W", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "u" + }, + { + "manufacturer": "Samsung", + "name": "Samsung Galaxy Win Duos", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "3k" + }, + { + "manufacturer": "Samsung", + "name": "Samsung Galaxy Y", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "6" + }, + { + "manufacturer": "Sharp", + "name": "Sharp Aquos EX", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "2z" + }, + { + "manufacturer": "Sharp", + "name": "Sharp Aquos Zeta", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "3s" + }, + { + "manufacturer": "Sony", + "name": "Sony Xperia A", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "n" + }, + { + "manufacturer": "Sony", + "name": "Sony Xperia Acro", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "19" + }, + { + "manufacturer": "Sony", + "name": "Sony Xperia Acro HD", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "o" + }, + { + "manufacturer": "Sony", + "name": "Sony Xperia AX", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "14" + }, + { + "manufacturer": "Sony", + "name": "Sony Xperia J", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "2y" + }, + { + "manufacturer": "Sony", + "name": "Sony Xperia L", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "3e" + }, + { + "manufacturer": "Sony", + "name": "Sony Xperia M", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "45" + }, + { + "manufacturer": "Sony", + "name": "Sony Xperia miro", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "13" + }, + { + "manufacturer": "Sony", + "name": "Sony Xperia P", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "24" + }, + { + "manufacturer": "Sony", + "name": "Sony Xperia S", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "q" + }, + { + "manufacturer": "Sony", + "name": "Sony Xperia SP", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "2s" + }, + { + "manufacturer": "Sony", + "name": "Sony Xperia Tipo", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "16" + }, + { + "manufacturer": "Sony", + "name": "Sony Xperia U", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "f" + }, + { + "manufacturer": "Sony", + "name": "Sony Xperia UL", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "3n" + }, + { + "manufacturer": "Sony", + "name": "Sony Xperia VL", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "31" + }, + { + "manufacturer": "Sony", + "name": "Sony Xperia Z", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "g" + }, + { + "manufacturer": "Sony", + "name": "Sony Xperia Z1", + "platform": "Android", + "targeting_type": "DEVICE", + "targeting_value": "2t" + } + ], + "data_type": "targeting_criterion", + "request": { + "params": {} + } +} \ No newline at end of file diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-events-params.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-events-params.json new file mode 100644 index 00000000..a9b8fa3f --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-events-params.json @@ -0,0 +1,1260 @@ +{ + "cursor": null, + "data": [ + { + "country_breakdown_percentage": { + "AE": 0.09, + "AR": 5.3, + "AT": 0.05, + "AU": 0.79, + "AW": 0.02, + "BE": 0.54, + "BG": 0.05, + "BN": 0.02, + "BO": 0.02, + "BR": 7.31, + "CA": 2.72, + "CH": 0.19, + "CL": 0.6, + "CO": 2.0, + "CR": 0.14, + "CY": 0.02, + "CZ": 0.02, + "DE": 0.35, + "DK": 0.05, + "DO": 0.12, + "DZ": 0.02, + "EC": 0.47, + "EE": 0.02, + "EG": 0.28, + "ES": 10.56, + "FI": 0.07, + "FR": 2.49, + "GB": 10.1, + "GN": 0.02, + "GR": 0.19, + "GT": 0.67, + "HK": 0.02, + "HN": 0.23, + "HR": 0.14, + "HT": 0.02, + "HU": 0.05, + "ID": 0.35, + "IE": 0.67, + "IL": 0.07, + "IN": 0.4, + "IQ": 0.07, + "IT": 0.54, + "JE": 0.02, + "JM": 0.05, + "JP": 4.98, + "KH": 0.02, + "KR": 0.05, + "KW": 0.12, + "KY": 0.02, + "LB": 0.07, + "LU": 0.02, + "LV": 0.02, + "LY": 0.02, + "MA": 0.02, + "MK": 0.02, + "MQ": 0.02, + "MT": 0.02, + "MX": 5.63, + "MY": 1.3, + "NG": 0.02, + "NI": 0.05, + "NL": 2.12, + "NO": 0.05, + "NP": 0.02, + "NZ": 0.07, + "OM": 0.02, + "PA": 0.16, + "PE": 0.3, + "PH": 0.81, + "PK": 0.09, + "PL": 0.09, + "PS": 0.05, + "PT": 0.4, + "PY": 0.63, + "RO": 0.02, + "RS": 0.02, + "RU": 0.26, + "SA": 0.37, + "SE": 0.72, + "SG": 0.67, + "SI": 0.02, + "SV": 0.16, + "TH": 0.37, + "TR": 1.7, + "TT": 0.02, + "UA": 0.02, + "UG": 0.02, + "US": 27.71, + "UY": 0.35, + "VE": 2.14, + "VI": 0.05, + "ZA": 0.19 + }, + "country_code": null, + "device_breakdown_percentage": { + "ANDROID": 18.89, + "BLACKBERRY": 0.08, + "DESKTOP": 36.8, + "IOS": 43.77, + "OTHER_MOBILE": 0.46 + }, + "end_time": "2015-07-27T00:00:00Z", + "event_type": "MUSIC_AND_ENTERTAINMENT", + "gender_breakdown_percentage": { + "female": 47.17, + "male": 52.83 + }, + "id": "1w", + "is_global": true, + "name": "Tomorrowland", + "reach": { + "total_impressions": 122426138, + "total_number_of_tweets": 4193759, + "total_reach": 11176262 + }, + "start_time": "2015-07-24T00:00:00Z", + "top_hashtags": [], + "top_tweets": [ + 490647488299548672, + 491261434337046529, + 492098498482143232, + 489767149989535744, + 490867432995561474, + 490412600061341696, + 491936005797462017, + 491037116697038849, + 490960426793197569, + 491090032640667648, + 494099324398489600, + 490209832931426304, + 490159038127034368, + 491281605005443072, + 490151000226156544, + 494315900703490050, + 490925007812300801, + 490557352844607488, + 490433219750141952, + 490956431638921217, + 493147571301666816, + 490958849709727745, + 492572672153620480, + 493368267659304960, + 490481474219823104, + 489825556717129728, + 490949082597572609, + 489353492298207232, + 491025533514166272, + 493022588596412416, + 491027771586797568, + 490476386029944832, + 490072553734803456, + 490480378571153409, + 490593193222627330, + 490247850736250881, + 490151848284680193, + 492823826686701568, + 494191452973711360, + 490402843216449536, + 493074867215159296, + 490295123327336449, + 490164614349737984, + 490797081410285568, + 490576453701210112, + 493468348177342465, + 490534020879753216, + 490571639696805888, + 490243592708165632, + 490257896500760576, + 490858928784564224, + 490558811561017344, + 489736137749975042, + 494997613419446272, + 490825797381672961, + 490698519326388224, + 489730986750791680, + 492313870896087040, + 490831442679959552, + 490408773119266816, + 490218985107906560, + 490503495577903105, + 494657868767842304, + 490511409575256065, + 493129911075217408, + 493438496846413824, + 493108502492360704, + 490586458286473216, + 492848175347412992, + 493518813598842880, + 493229384925315073, + 490778026020335616, + 490752365533081600, + 490612326157254656, + 490916155167498241, + 490619610979663872, + 492722507099942912, + 490780884518576129, + 490198693002231809, + 490569662103834625, + 490226633085710336, + 489872923214106624, + 493402096444506112, + 493129438062968832, + 490923028566376448, + 490507982501732353, + 493213502719283201, + 490669515949502464, + 491875160862244864, + 492982968202166272, + 490846234748669952, + 490247550054989824, + 490893343883161600, + 495037059154063360, + 493440416789053440, + 490629572505780224, + 490141800544223232, + 490835013940690944, + 490932651206123521, + 490942548282966016, + 490170708996001792, + 490524564732915712, + 490571964419801088, + 490865048164642816, + 493433597446328321, + 493033076360892418, + 490285522456444928, + 490658209435508736, + 490918835457769472, + 494151933699977218, + 493507057174470656, + 490066151008133120, + 490649220467396608, + 493445700538335232, + 491042092106645507, + 491750058346684416, + 493015254541295616, + 489816765166522368, + 492161471812341760, + 493219084398374912, + 490878426555744256, + 494859063767744513, + 490907769747173377, + 494848636782514177, + 491296589101547520, + 490973919940472833, + 493002445497593859, + 490881962454704128, + 492470623675748352, + 492986037761605632, + 490799637365006336, + 490651132931604480, + 490140477111689216, + 489594311127105536, + 489432503632285696, + 492937763717533696, + 490601859879800832, + 490183183657213953, + 489739745459965952, + 493461194725130240, + 491448483606724608, + 489832013256724481, + 490114913084649472, + 493446149840183296, + 490453181366042624, + 490092880519004160, + 493207210957086720, + 490688918686138368, + 490590830852591617, + 490519674484838401, + 493453964151914496, + 492545086245568513, + 491933288529813506, + 493484771431825410, + 495959681530347520, + 490573032717430784, + 491010976456904704, + 489469095705075713, + 490882610814410753, + 490359174182621184, + 490857590403117056, + 493382707049549824, + 490579809722830848, + 493142519274696704, + 490907332147032065, + 490725846723084288, + 491117194374156288, + 490208813249609728, + 495024565454905346, + 490058029677572096, + 490762028492259330, + 491227037424971776, + 490205649347682304, + 493082979116146688, + 490597728221548545, + 492525810625282048, + 493457426067120128, + 493531624873918464, + 493343627104354304, + 489783455916376066, + 490466973093228544, + 490208196284256256, + 494494745805488128, + 495887326803800065, + 490541255940509696, + 489721292954673152, + 494533765616500736, + 490485480039780352, + 490614755627778048, + 491051357315805184, + 490472911762104320, + 493033832149311488, + 490497791429332992, + 490482917681156096, + 490145646029328384, + 489737253363933184, + 490712417492824064, + 490564195482488832, + 493141615695781888, + 490895011538432000, + 492723331322621952, + 490608055902806017, + 493383007772766208, + 490232269173309440, + 489856000380653568, + 489782576203440129, + 493388085699567616, + 492701662004264962, + 494188685118951425, + 490448470482755585, + 492725607730786304, + 490473365199933440, + 490460609297674240, + 493023608625573889, + 491763490194202625, + 492712623389958144, + 492038812705779712, + 490980847579709440, + 493005843692912641, + 493103878809088000, + 492939617684168704, + 494556682237018112, + 493425122490200064, + 490996623343104002, + 490469505362309120, + 491066661962014721, + 491634439366385664, + 492989767059914752, + 495195024397971457, + 491791124672282625, + 490938411671224321, + 490850485474459650, + 490125608836685824, + 492696025426305024, + 490816996083105792, + 490092058137616384, + 493026122854969344, + 493126465441898496, + 489352658600202240, + 490248652477059072, + 490398771713306624, + 492289116894425088, + 493381209766899715, + 490398911069442048, + 490414863282614272, + 492387545276092416, + 493002669557317632, + 490121185536274432, + 490202516693319680, + 490912404478648322, + 492000348962566144, + 493069271023370242, + 490181140788314112, + 490908868944613376, + 493105101800611840, + 493495829249130497, + 493378434345607169, + 493480999272345600, + 490932510671785986, + 491184621976297473, + 490780428769296385, + 490695937451655168, + 491803015599636481, + 493014214278402048, + 490953616485019648, + 492975155304357889, + 490293025797455872, + 493074154740924417, + 491191757452091392, + 494442191767760896, + 493912741493489664, + 490946451053494272, + 490857519452258305, + 490197047640068097, + 494673114480259072, + 491300325505372160, + 494573895924461570, + 492692499094585344, + 490146541894914048, + 490655690072281088, + 494580206531665921, + 490648629691293696, + 494829925510430720, + 490476263627587585, + 490433937681182720, + 492262678531162113, + 490420262324928512, + 490431284381229056, + 491757846091292672, + 491954245915013120, + 495635611207081984, + 493342555958816768, + 492338534204710913, + 493089053303001089, + 493081820167430145, + 492041538147336192, + 490813521807278080, + 490144620048056322, + 490090904469114880, + 490498194531684353, + 490496318104555520, + 491189452598157312, + 490496287477731328, + 490585476714496000, + 491567378350620675, + 489453624465321986, + 492290643604307968, + 492397110726098944, + 490252408518623232, + 493363875946172416, + 493018869376630784, + 492995328895758336, + 490399356580007936, + 490511635123941377, + 492713377408352257, + 492859949605978112, + 494741795864326144, + 490882856021807104, + 490823430858891264, + 490938244729958400, + 494412912602402816, + 492958775486476288, + 489872019182608384, + 492252880938991616, + 493103379246100482, + 493489778818813954, + 489779640803008513, + 492643904895078400, + 495635185657192448, + 490037395899686912, + 491057514101112833, + 491339107327832064, + 491151797080571904, + 492794702232825857, + 496011025150668800, + 493474278931578880, + 494190824507588608, + 490779472547704832, + 492957830136074240, + 491285526453174272, + 493504198009716736, + 489710767428861952, + 490496982042284032, + 492696539023024128, + 493361444420079617, + 491303440526876672, + 492369462960869377, + 492733442300203008, + 490549406333411329, + 493269212392357888, + 490252415430828034, + 493404144041218050, + 492062957460004864, + 494051285356670978, + 490660141293776896, + 490552817321799682, + 491702588752920576, + 490979672415809536, + 491066158351908864, + 492223455220486145, + 493426044029112320, + 493027356106584064, + 492668051100557312, + 492949631618531329, + 490451057844035586, + 490164457268854784, + 489847568038645761, + 492688989707448320, + 491811311693860864, + 493353163307876352, + 490175091167490048, + 493504541057630208, + 493505834161561600, + 492426708528537601, + 492767919642656769, + 489992159815548928, + 490515047706529792, + 490528208102490112, + 489751913617842176, + 492725450272419840, + 494253340679995392, + 492717451553931264, + 493042429650403328, + 495751345425899520, + 493477596265316352, + 494399531933794304, + 490094370629386240, + 489992152030531584, + 491811326638170112, + 492756674331951104, + 491755868648521730, + 489614904383782912, + 490585128163631104, + 490525272861835264, + 493486565922861057, + 494557374733352960, + 493079151180410880, + 490817381728796672, + 490208111106334722, + 493512212880039937, + 490664957080784896, + 490330431494311936, + 493483926648668160, + 494856115180830721, + 490191821927362560, + 491736512698925056, + 490934208743747584, + 490645253830230016, + 489952148504195073, + 491241861005451264, + 491266555607785472, + 492985816621522944, + 493239070143700992, + 491036934731739137, + 490530915941355520, + 491271326410485760, + 489486490637201408, + 492995442247208960, + 493140666000478208, + 492749954713018368, + 491539268591169536, + 492711182978285569, + 492983908539961344, + 492739885829079040, + 490929182839697408, + 494476667373371393, + 490262326608920576, + 491932234002497536, + 491013585158819842, + 492686762440142848, + 490210969394503680, + 493086798839443456, + 494089914863349760, + 492669082647289856, + 492596945396174848, + 492823708197998593, + 492416262811549696, + 489935247434612736, + 492746151230054400, + 490412448269496321, + 489805335272890368, + 490949459044745216, + 493129654556172288, + 490968186276159488, + 490166321070768128, + 490566136212516864, + 491399747706834944, + 490331936162717696, + 490323496539406336, + 490187448668790784, + 492764157200961536, + 492893273716162560, + 489975557099368448, + 490580343611994112, + 491291092193923072, + 491739572473458688, + 492742801550213120, + 492661716933541889, + 490527805948452864, + 492648565525577728, + 492668333469483009, + 493137758550900736, + 491079353443553280, + 493123753014861824, + 493192069830410240, + 490975482439925760, + 490959046598729728, + 491066976174104576, + 492624216148410368, + 491409411374858240, + 490594501367316480, + 490958710060371968, + 493524909436698624, + 490697509996855296, + 492745771653939200, + 491360361820725249, + 493442333418225664, + 493441563335622656, + 490207852233887744, + 494360750001901568, + 491283028807667713, + 490592092272340992, + 491750888705634304, + 495917121646243840, + 492722100059537409, + 492716678321410051, + 491753976011165697, + 489730886083309568, + 495636658810015745, + 490069119761678336, + 490474966870421504, + 490602478560608257, + 493068743245709312, + 495762432565190656, + 493418251779833856, + 489979083929833472, + 490908245087633410, + 492801266964496384, + 493936609209757696, + 490166813758865409, + 494382422692069376, + 490974865139052544, + 493013417288937472, + 490615450196508673, + 491012874882777088, + 490519627949408256, + 493405505814278145, + 490593976131780608, + 492878341939421185, + 492683819410264064, + 492827325646770177, + 493460699008729088, + 490608516827463681, + 493070963513491456, + 492617276210683904, + 490593313108799488, + 492378732389474305, + 490491059630534656, + 490970194412859392, + 493001057300004864, + 494656989772128258, + 493136858239750144, + 493520009931407362, + 491056623272865793, + 490986088798773248, + 492672887485366274, + 493068361085898752, + 492363398693523456, + 489818145365164033, + 491654825541898240, + 491339275485851648, + 491017313836335104, + 490619201003216897, + 489747747008831488, + 490218484777750529, + 495709238212435968, + 489607224852221953, + 494493389682126848, + 491217536172974081, + 491057761208500224, + 490841067403882496, + 492021345031430144, + 491154764051144705, + 491419274523975680, + 492658536808054785, + 490595502606782464, + 490415478566027264, + 490537500310372354, + 491287102756503552, + 490294746003144704, + 490652116294569984, + 492061475058774016, + 491053804453134336, + 492652803525849088, + 490968087806500864, + 493082666690805762, + 489734217950318592, + 493452064690044928, + 490527117554511873, + 493164175607496705, + 490261577501642752, + 493121110372667393, + 490214168952602624, + 491027205988679681, + 494100353970089984, + 492248944534360065, + 492742712735846400, + 490844072420966400, + 490259175390605312, + 490213359753904128, + 493124935767048192, + 489330878964051968, + 490701482321121280, + 490408598758236160, + 491204338006917120, + 490517159420784640, + 490298250738827264, + 492658507238637568, + 492609494015574018, + 490212652954554368, + 495497939536842752, + 493082981137805312, + 490626183114264576, + 490202117807017984, + 491763270131650560, + 490452606825672704, + 490635076603219968, + 491364907049570304, + 490219824321028096, + 491394149686317056, + 489522448165904385, + 493068141648281601, + 492361196428083200, + 494854471277899776, + 490211009593085952, + 493127422540120064, + 490067696265203712, + 495661621436760064, + 492728731761672193, + 490608330448965632, + 490280166577696769, + 491691201238933505, + 490378437786619904, + 491385973373415426, + 491323117793341440, + 493086346496315392, + 491894252654575617, + 489459480912875520, + 490524129138061313, + 490201857206128640, + 490913649255809024, + 489748954880286721, + 490361515229589504, + 490644134982856704, + 493540232311345152, + 494995972779298816, + 494153341320978432, + 495645760227405825, + 492059424480329729, + 493020794776477696, + 494844813385404416, + 492499491740975105, + 492006508260229120, + 490959049958367232, + 491016229403238400, + 490237590428483584, + 494803888743391232, + 493486158702080000, + 490255774703026177, + 495901339864805376, + 490592266210541569, + 495213007874846720, + 491248772215607296, + 490987516615348224, + 490282475805884416, + 492807855213641728, + 495537584534474752, + 492710332721545216, + 492988219806715904, + 495079002210836480, + 495368327410487296, + 492746911909027840, + 490869440792514561, + 490986053168164864, + 490164447521284096, + 493050148487188480, + 490523352566480896, + 491757809084932096, + 491529526422552577, + 493071770489192450, + 490295012987789312, + 492676851157196802, + 489453861497995264, + 490986977752518656, + 490958239539163137, + 490235310333493248, + 493532778731159552, + 490236172229017600, + 492348668604059649, + 490510614817964032, + 489917231447289856, + 490320364527190016, + 493409453711310848, + 490985753921740801, + 493469626043727873, + 493085755816677376, + 494236201281282049, + 490457157209690112, + 490144079872016384, + 494212611622178818, + 492676512470933504, + 493085877761892353, + 489749595878981634, + 494967621784453122, + 490997481581600769, + 492744248958398464, + 491413792971321344, + 489811493769478144, + 494082636130680832, + 490421144973877248, + 492709667101876224, + 490353983240675328, + 492648433095041024, + 490563119404441601, + 491013328308027393, + 491387350552162305, + 491047256804843520, + 491947144505339904, + 489782650597437440, + 490573689482924032, + 489516080235155457, + 490223894834315264, + 492363371682213888, + 490966883328589824, + 492153088544112640, + 494479273479393280, + 493015028426354689, + 492625131005427712, + 493028403424272385, + 491311313839472641, + 491926990732025857, + 493053739972849664, + 492972850182361088, + 490611155363442689, + 490968196351262720, + 492398981088313344, + 490268661966315520, + 492504694036901888, + 492101714032754688, + 490883016374624257, + 490210515692843008, + 492025186141499392, + 490985609411182593, + 493329614019002369, + 490907460379500544, + 492125562002231296, + 492984768594968576, + 491707799651745792, + 492805387952095232, + 491035795848196097, + 490288556284575744, + 490361102484525057, + 490438726347423745, + 490292067151917056, + 492782085229518848, + 490095270475358208, + 491790543068725249, + 489877569680838656, + 490355778692608001, + 489963708219936768, + 490152135099559936, + 493382044227862529, + 492989521181835264, + 491215722186821633, + 490352714614718464, + 490986638143549442, + 490156390871494656, + 492055375139454976, + 491332118417772544, + 492821831590506496, + 490969972911636480, + 490848761984593921, + 489981593994682368, + 493201124657496064, + 490758751742590976, + 492825111326490625, + 491648810096275456, + 492934759853858816, + 493502203487739906, + 492055335956660224, + 490966266996596736, + 490584470748426240, + 493395745689845760, + 491311359863586816, + 489788961683165184, + 494833749667110912, + 490470988992110595, + 492466986442838016, + 491726145885585408, + 490581889187459072, + 490178255740100608, + 493078790479024128, + 493027725251067909, + 495165468257157120, + 490873805972045824, + 492881535721553920, + 490480428222918657, + 490986180729921536, + 492825708595785728, + 489741446258245632, + 489790119097139201, + 491346091011756032, + 490503899866857472, + 490907828170006528, + 492041071560761344, + 491355995734814720, + 490211671492030464, + 490616478979219456, + 493361427353051137, + 490467489487519744, + 491591764936261632, + 492956798203461632, + 495437269977673728, + 492115996308537344, + 490249999662739456, + 493425287686651904, + 490446439215292416, + 492712384377913344, + 490983546748948480, + 490940702289702912, + 494244315070472193, + 491308465097568256, + 489826157320081408, + 490351712226791424, + 491046092285706240, + 493318656294944768, + 490354871389126656, + 491341075291070464, + 490258755049635840, + 493109062167310336, + 495246566832496643, + 490239759675949059, + 491789200979918848, + 492327094979162112, + 490924682317930499, + 490992506528858113, + 493114876630282240, + 489574010733072384, + 489515218209214465, + 493529494691799040, + 490298589693104128, + 490063007612170240, + 495630116337098752, + 489575211311071232, + 490287186940788736, + 492853316917792768, + 494202096301133824, + 492712510018301952, + 489543002655059968, + 491010074727702528, + 492051551981416448, + 490990042140389377, + 493442174835773440, + 493185115300696064, + 490324710866300929, + 493101248317751296, + 491577286656008193, + 492026767205748736, + 492503008165761026, + 490945272944807937, + 490356801691340800, + 492129753403367424, + 490210951418085377, + 490771650095644672, + 490364195154980864, + 490957874085249024, + 490161627355185152, + 490425678828171264, + 492791514930884608, + 491433901726789632, + 493257684310065152, + 490804601885450240, + 491662697633972224, + 489933216426774528, + 489483983844286464, + 490672322081476608, + 493006659351224320, + 492130724091146242, + 492013985659486208, + 494565068173234176, + 490572029318275072, + 492817839892754432, + 492787622327357440, + 493125136095010816, + 490288942961655809, + 490110624874364928, + 493028863958458368, + 492997071180681216, + 490669394130120704, + 491739757421297664, + 495027969887576064, + 492021914307923968, + 493528718200283136, + 490244304242483200, + 491629757956882432, + 492888740604690432, + 492730210333126656, + 493494350966685696, + 493054997790482432, + 490791782163439616, + 492059462925291520, + 495914443394797568, + 491388025067565056, + 489745048733376513, + 490141562844618752, + 490886638852001792, + 491218966006988800, + 491643037366243328, + 490659657489580034, + 490481567933161472, + 489490743955034112, + 491324339116326913, + 491606214602547202, + 491623337051693057, + 494656273770889216, + 493077232370589696, + 490613432904073216, + 490276303040688129, + 490227212352618496, + 490939747758796800, + 491229941212925952, + 490533889975148544, + 490723615634374656, + 490820232077144064, + 490301496308011009, + 495537745583165440, + 490959140941230081, + 494959913152835584, + 490433026510557184, + 489487300741853185, + 492990785194065920, + 491976312328699905, + 490197075267977216, + 491287812142923777, + 490228254897606656, + 489875767120392195, + 490055247902306304, + 493185027724046336, + 491383321499541504, + 490145165106245632, + 493245639267209216, + 489746946106478593, + 490939705782185985, + 492751539782418432, + 491245436314071041, + 490351367878234114, + 492987884614737920, + 490224325715562496, + 492726894102859777, + 490623755194867712, + 491599304549998593, + 491630674902659072, + 490913814531936257, + 490514238142967809, + 490221998187233280, + 491813982714359808, + 491257383805812736, + 490939958690316289, + 490636359401766912, + 491444785191067648, + 493505756465872899, + 494120438990376960, + 491221321804943361, + 489700003817201664, + 491765103449341952, + 494555500952825856, + 490214805614391297, + 490961714167312384, + 491769639194873856, + 493500820835405825, + 492739904036941824, + 490647723721650176, + 491692630456422400, + 491463302979928065, + 492985610756689920, + 491018548748492801, + 490252298254561280, + 490613432795009024, + 490556223901544449, + 492469300167327744, + 492326143513862145, + 492678237475332097, + 493025940260528128, + 492651453261938688, + 492761216432218112, + 490212172312477696, + 491408712729645056, + 490246362152595456, + 490670447663779841, + 492387788507983873, + 490274603810689025, + 490657920313344000, + 492519677713604608, + 490520007617417216, + 490226269205045248, + 490033117550223361, + 493468138500263937, + 490231103593406464, + 490251629586046976, + 492744505527779328, + 490214349701939200, + 494796538619510784, + 490662736763031553, + 490251341499879424, + 493024685458984960, + 490084717954600960, + 491604526973984768, + 491021942791897089, + 490268292293332994, + 490952127238668288, + 490520300317331456, + 493075814830067712, + 495638378021658624, + 490488587901624320, + 490266651854897153, + 492007144355790848, + 490284928974606336, + 490934187579305984, + 491086551921983488, + 491031377912291328, + 490518744910032897, + 493081904124796928, + 490878976655888385, + 491751168729939968, + 491786141205807105, + 490212389682282496, + 490605802579714048, + 495235234464804864, + 490303527319642112, + 492942459270209536 + ], + "top_users": [ + "69542069", + "21787625", + "40101400", + "2284275066", + "148759764", + "17019152", + "134234000", + "1216258832", + "130151627", + "2402304913", + "28987332", + "18750157", + "1537877701", + "361594753", + "21568477", + "34914032", + "17174309", + "122556667", + "443196382", + "35727881", + "331311644", + "2551472479", + "59399268", + "18776605", + "2208949903", + "23976386", + "22611082", + "398306220", + "2620189999", + "31369541", + "543078828", + "790915958", + "73365668", + "19520983", + "14569981", + "1254582336", + "58576769", + "24693705", + "18980519", + "51086473", + "10228272", + "964212584", + "759251", + "21174888", + "21001379", + "488751763", + "156735736", + "295070534", + "635787453", + "290243668", + "2307425070", + "412536926", + "19388771", + "294636267", + "2222143400", + "9695312", + "701423664", + "2373475078", + "1901426832", + "44150093", + "2214937387", + "7736222", + "582907105", + "23733354", + "400489504", + "2332348778", + "237737133", + "495110565", + "23027648", + "14098533", + "794364504", + "358974434", + "41784974", + "129356981", + "1379083118", + "101477788", + "416500384", + "366452430", + "21086501", + "17865039", + "185702760", + "188478643", + "52270992", + "37718134", + "9317502", + "846523069", + "2658187867", + "754823287", + "225895204", + "592202860", + "1393084334", + "20696985", + "1558141890", + "1869691568", + "126971226", + "990845760", + "135414892", + "28358543", + "1209565878", + "2564148836" + ] + }, + { + "country_breakdown_percentage": {}, + "country_code": null, + "device_breakdown_percentage": {}, + "end_time": "2015-07-27T00:00:00Z", + "event_type": "MUSIC_AND_ENTERTAINMENT", + "gender_breakdown_percentage": {}, + "id": "2c", + "is_global": true, + "name": "Fuji Rock Festival", + "reach": { + "total_reach": null + }, + "start_time": "2015-07-24T00:00:00Z", + "top_hashtags": [], + "top_tweets": [], + "top_users": [] + } + ], + "data_type": "events", + "request": { + "params": { + "country_codes": [ + "JP" + ], + "end_time": "2015-07-25T00:00:00Z", + "event_types": [ + "MUSIC_AND_ENTERTAINMENT" + ], + "start_time": "2015-07-17T00:00:00Z" + } + } +} \ No newline at end of file diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-events.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-events.json new file mode 100644 index 00000000..3ca5469a --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-events.json @@ -0,0 +1,23740 @@ +{ + "cursor": null, + "data": [ + { + "country_breakdown_percentage": {}, + "country_code": null, + "device_breakdown_percentage": {}, + "end_time": "2015-07-18T00:00:00Z", + "event_type": "HOLIDAY", + "gender_breakdown_percentage": {}, + "id": "1p", + "is_global": true, + "name": "Ramadan", + "reach": { + "total_reach": null + }, + "start_time": "2015-06-17T00:00:00Z", + "top_hashtags": [], + "top_tweets": [], + "top_users": [] + }, + { + "country_breakdown_percentage": { + "AD": 0.02, + "AE": 0.28, + "AF": 0.02, + "AR": 1.15, + "AT": 0.07, + "AU": 1.53, + "AW": 0.05, + "BD": 0.02, + "BE": 0.49, + "BG": 0.02, + "BM": 0.02, + "BN": 0.02, + "BR": 1.46, + "BS": 0.02, + "BY": 0.02, + "CA": 3.5, + "CH": 0.33, + "CL": 0.68, + "CM": 0.02, + "CN": 0.02, + "CO": 1.22, + "CR": 0.14, + "CW": 0.02, + "CY": 0.07, + "CZ": 0.09, + "DE": 0.77, + "DK": 0.26, + "DM": 0.02, + "DO": 0.19, + "DZ": 0.02, + "EC": 0.21, + "EE": 0.02, + "EG": 0.09, + "ES": 7.61, + "FI": 0.14, + "FR": 4.16, + "GB": 19.23, + "GG": 0.02, + "GH": 0.07, + "GI": 0.02, + "GR": 0.23, + "GT": 0.23, + "HK": 0.05, + "HN": 0.09, + "HR": 0.09, + "HT": 0.02, + "HU": 0.05, + "ID": 0.59, + "IE": 1.08, + "IL": 0.07, + "IN": 0.35, + "IS": 0.02, + "IT": 1.62, + "JE": 0.02, + "JO": 0.02, + "JP": 2.77, + "KE": 0.05, + "KH": 0.05, + "KR": 0.14, + "KW": 0.31, + "LB": 0.09, + "MA": 0.05, + "MF": 0.02, + "MG": 0.02, + "MK": 0.02, + "MN": 0.02, + "MQ": 0.05, + "MT": 0.02, + "MX": 3.05, + "MY": 0.77, + "NC": 0.02, + "NG": 0.23, + "NI": 0.02, + "NL": 3.03, + "NO": 0.42, + "NP": 0.02, + "NZ": 0.09, + "OM": 0.09, + "PA": 0.12, + "PE": 0.09, + "PH": 0.52, + "PK": 0.02, + "PL": 0.26, + "PS": 0.02, + "PT": 0.12, + "PY": 0.16, + "QA": 0.05, + "RU": 0.26, + "SA": 0.99, + "SE": 0.59, + "SG": 0.35, + "SK": 0.05, + "SV": 0.12, + "TH": 0.49, + "TR": 2.18, + "TW": 0.07, + "TZ": 0.02, + "UA": 0.07, + "UG": 0.07, + "US": 31.35, + "UY": 0.14, + "VE": 1.29, + "VI": 0.02, + "ZA": 0.45, + "ZM": 0.02 + }, + "country_code": null, + "device_breakdown_percentage": { + "ANDROID": 15.31, + "BLACKBERRY": 0.12, + "DESKTOP": 37.64, + "IOS": 46.39, + "OTHER_MOBILE": 0.54 + }, + "end_time": "2015-07-27T00:00:00Z", + "event_type": "SPORTS", + "gender_breakdown_percentage": { + "female": 36.08, + "male": 63.92 + }, + "id": "1t", + "is_global": true, + "name": "Tour de France", + "reach": { + "total_impressions": 1239342441, + "total_number_of_tweets": 7914358, + "total_reach": 19969207 + }, + "start_time": "2015-07-04T00:00:00Z", + "top_hashtags": [], + "top_tweets": [ + 494207884310614017, + 493455817912635392, + 493481455226728449, + 488298889351806976, + 485702370438160384, + 493467254164832256, + 491657713425088512, + 491754341406355456, + 490876497872564224, + 485807903748939776, + 493444759772725249, + 490892378082123777, + 488715351338024960, + 487984885341364224, + 486422958991486976, + 485449055410323456, + 486058065830350848, + 485473279239413760, + 486883779500580865, + 493058607614021632, + 488725801102499840, + 486219784758239232, + 486099669307883520, + 491258141599080448, + 486868498766102528, + 488676717448286208, + 488344595731058688, + 485701922020925440, + 484566580677074944, + 486869248296648705, + 486869541985988608, + 490397878607937536, + 493214210848219136, + 485813846607949824, + 488911052751781888, + 491602326751563776, + 485714280508317698, + 488697798536482816, + 489052785301020672, + 485807237164982272, + 491966419429769216, + 487465669685161984, + 486129748746457088, + 485809417024438274, + 487127082703802368, + 486477499506126849, + 486892019865120768, + 487254454925004800, + 492329134480437248, + 493336410821500928, + 486165197888159744, + 486825182716493824, + 486535557263421440, + 489432106251325440, + 485469543402196992, + 488511289044795393, + 488674324845699072, + 486404204257632256, + 484709339073363968, + 485705136522928129, + 485449292275253248, + 486485633599561728, + 488714447054442496, + 485807357948354562, + 490876587752292352, + 491601469725245441, + 486234336887586816, + 493444704944799744, + 486880526629101569, + 487952380382949376, + 484800546160017408, + 485353108349136896, + 486902526605012992, + 486967298448949250, + 485886120929275904, + 485162686179983360, + 488688233534853121, + 486875266955096065, + 486125864170835968, + 489320265382633473, + 486102126964510720, + 493171430994227200, + 485320968219688960, + 486159571967553536, + 494905518297989120, + 485392543182782464, + 487413231359918080, + 485834663332945921, + 485387613785042945, + 489429178006384640, + 485320721032544256, + 485867802280988673, + 488377843370708993, + 485399556721762304, + 493202316531486721, + 485683206633832448, + 485765040868704257, + 486525949920681984, + 487793518401060864, + 489430477192036352, + 485703724665675776, + 490518451304529920, + 486431024289959936, + 493071176483479552, + 485736589990309888, + 489135634209329152, + 486157682823274496, + 488750911138037760, + 487223894378807296, + 491966499528400896, + 485350045165056000, + 493444642399346688, + 485875373448912896, + 487212693850701824, + 485325215791321088, + 487233958925860864, + 489140033866432513, + 493446079497900032, + 485449872242659328, + 485740080904941569, + 489154039436025856, + 487254254705713152, + 483497188073689088, + 486482032361750528, + 493349245152686081, + 485524484137713665, + 493058222132305920, + 493408231650107392, + 488684390055419904, + 485443701003812865, + 486892015314276352, + 485293764467261440, + 493076585457524736, + 492422866781368321, + 489781374787018752, + 486851977541058560, + 491923305671426048, + 488358360836997121, + 490952285552660480, + 488284572275466240, + 486914057837223938, + 491441693552820226, + 490494288707325953, + 489575246551191553, + 485702616115318784, + 486959509441875968, + 486840283850870784, + 485902029764984833, + 485118447094083584, + 485346162464284672, + 493445568019300352, + 489828694673092609, + 485791082228502528, + 490537540773244928, + 485843270224736256, + 490912273402458112, + 485366680546459648, + 486165430130970624, + 485449617321250817, + 487171735956238337, + 490949297764978688, + 488714429929123840, + 485496003777134592, + 488754643120717824, + 486868442126241792, + 486144389539184640, + 485453977379934208, + 486330119732994048, + 485850320690741248, + 486900169003511808, + 485363241821155328, + 488344401094385664, + 493057371485536256, + 486198151557447681, + 485444031246520321, + 493445532426465280, + 486089711392653312, + 484429948854484992, + 490549170416394240, + 490504292193685504, + 486228976957157376, + 485687330968444929, + 486965981789839360, + 493444242308874240, + 486851272566665216, + 493475376631652353, + 485803354426458112, + 490914501056012288, + 485453132529672192, + 488665022252720128, + 491274645577158656, + 488286130539102208, + 485677075752579072, + 485363361006510080, + 492689312254021632, + 490911333374640128, + 485834069201399808, + 493042139212025856, + 493460519882592257, + 484582180950392832, + 493379760018710528, + 491111426640330752, + 486217733840076800, + 486066759448166400, + 490480448750243840, + 489440757519228928, + 485377474084491264, + 486969507370766337, + 488006995920695297, + 486144459156246528, + 492285536560631810, + 488289804397076480, + 491283919263002625, + 490551021161414656, + 493142219818561536, + 484272385953382400, + 485607841580199937, + 490518957447970819, + 488746050669531136, + 490085583679922176, + 485337240412098560, + 486914517226749952, + 486189949986029568, + 490514675499806720, + 489163834729697280, + 493397100991102976, + 488720620721819648, + 490832784563634176, + 489385189450481664, + 486557800626388992, + 485727726218006528, + 490886831597428736, + 483208862255042560, + 485449099962245120, + 485798764125646848, + 486201944462340097, + 484993770505928704, + 486256451380609025, + 487933644003344384, + 485797207149666304, + 484749228984782850, + 484740729034768384, + 485813377114312705, + 485449178932580352, + 490560985913360384, + 485778139927547904, + 485704235594833920, + 484443894042882048, + 486521535591874560, + 487983659937693696, + 493477123517341696, + 493445061083136000, + 487056127507435525, + 487923779377852416, + 487616712700071936, + 490851494514950147, + 487330638400602112, + 485760950071746561, + 491948514339868672, + 485731815676981248, + 487924449438887937, + 486000681652736001, + 483575521662754816, + 485716077322964992, + 489798767651340288, + 485388139658493952, + 488694013240016896, + 490610572983943168, + 486534416370790400, + 489044102110277632, + 485496632923152386, + 495950963854016514, + 487188485858942976, + 490528258983620608, + 485355214359506944, + 486171573758332931, + 490571548303310850, + 492001330329051136, + 490548160520261632, + 484253998783156224, + 488722393951911936, + 485815268690903040, + 485418288726704128, + 486099237550444544, + 491620109296091136, + 493435212760899585, + 493021941335592960, + 485477290936369152, + 485786331189379073, + 485508565860634624, + 489393423523528704, + 489467119403560961, + 485343218150944768, + 487647714201833472, + 490869444617707520, + 488348433280163840, + 485816110277988352, + 488708562324324354, + 485745228834668544, + 484762593010384896, + 485498773779791872, + 490450287996715008, + 484403665793740800, + 489429185845534720, + 486821573329182720, + 493451559423184896, + 484736665219764224, + 491601103432474625, + 493068959282114560, + 493398161525067776, + 487938362637312000, + 483308952197689344, + 493428015356186624, + 492309946177175552, + 491645111953285120, + 485900428853669888, + 485789639790194689, + 486874798795276288, + 488651518716178432, + 485450758515863552, + 487207040205344769, + 493059174121889793, + 487671500045316096, + 489440329377263617, + 486946937577684993, + 489446699761676288, + 493086851373481984, + 488676707688517632, + 488332029101363200, + 489834028099321856, + 489429304686940162, + 485487074116894720, + 488010694672281600, + 483598631682207744, + 488022064679645184, + 487969282207535105, + 487299106155802624, + 486172106355654657, + 490185037997158400, + 484379766347546624, + 489805386854453249, + 488676579539976193, + 482849055341809664, + 486578040202604544, + 491642207200636928, + 487711122779148288, + 485829435892170752, + 488689753760751617, + 485403990663114752, + 491588156765274112, + 486833094436327425, + 486520589507919872, + 490493450861965312, + 491150066150014976, + 485377550739595266, + 489039225841410048, + 489788045311619072, + 489404290935844864, + 490858705873682434, + 488352788754481152, + 485401805300703234, + 491542950468669440, + 486587614045028352, + 485715744924393473, + 487302041576812544, + 485505056696205312, + 491708681533145088, + 485421979525476353, + 491675449375076352, + 486853454804295680, + 487647541639786496, + 487679063927296000, + 491919417765146624, + 487949655540785152, + 491612729053310976, + 494850728679469056, + 488969450860072960, + 489826546317029376, + 488741135737950209, + 490142788814897152, + 485131054467284992, + 489419407110987776, + 485458986226171904, + 486152593631363072, + 489373579784749056, + 491976688012890112, + 493023322939338753, + 486546431541792769, + 491075330011299842, + 491870930965381120, + 485095969491800064, + 486530522215370752, + 487994498681942017, + 485440720971792384, + 491954877313343489, + 492364120600350721, + 487254277917011969, + 490191733528207360, + 486419348727541760, + 486934567048458240, + 487624975609004032, + 489018153167765505, + 493421038748057600, + 493365342375518208, + 485438727175798784, + 484291185893474304, + 490154328695779328, + 490154543565787136, + 493498964323598336, + 486515337236865025, + 487295244510056448, + 486901278057185280, + 484977334064537600, + 486622750099144705, + 487228855107993600, + 486945493625622528, + 491173645730209792, + 486130795573436416, + 485410588554985472, + 489525531264569344, + 485411536358604801, + 484983644449439745, + 483573343862673408, + 485919566929743872, + 485450090522624000, + 485413738884120576, + 486572027403567105, + 486891357794230272, + 487616213808607232, + 488373670747078656, + 482876916220055553, + 485416026927284225, + 489975389943783425, + 484766042321723392, + 485423298776662016, + 486511139262828545, + 493422398247825409, + 486918018963095552, + 490141385279172609, + 492372461665923072, + 493421325227425792, + 490834186576883712, + 492367223424839680, + 485440793046683648, + 488725010656141313, + 486839590603747328, + 491913388369674240, + 484709865102012418, + 491965866775691264, + 487670434780168192, + 491949833046224896, + 484462265077612544, + 485770416787820544, + 486887757571432448, + 485859831916810240, + 493066813774000128, + 488684147834380289, + 484993856602406913, + 486072276505624576, + 486880019592261633, + 484305497361620993, + 485792814408925184, + 490163427579793409, + 484660556004331520, + 485430319827656704, + 486109847474417664, + 483641102273355776, + 491222873387048960, + 487198271497310208, + 489782040188174336, + 492309812890578944, + 487250866123333632, + 485459770535841793, + 486511542331252736, + 485422937160552448, + 487235468778827776, + 486851669104525312, + 486480962906492928, + 484996433310150656, + 495460413698752512, + 488358087825571840, + 492336680779907072, + 487207697897762816, + 493040525013172224, + 489731072352342016, + 486873215118344193, + 483295611400495104, + 484293310706884609, + 485096182902169603, + 484798071906500608, + 493432846355558401, + 489032175745253376, + 484697558833717248, + 485054450135224321, + 487331215964639232, + 486498624457961472, + 488380230261043200, + 492317360901341184, + 486868325402939392, + 493447138836500480, + 492328420224040960, + 486916804066164736, + 485468409245990912, + 486795976859209728, + 485794591237341185, + 487265194918551554, + 487143868828504064, + 490149241667727360, + 492563662394380288, + 485475520512266240, + 486962322599342080, + 485119855444905984, + 485703379239591936, + 485746829683089408, + 492297533293473792, + 487608945297883136, + 485346196257800193, + 487545984520814592, + 487184166682120192, + 486163657794273280, + 485481032758870017, + 486246271842525184, + 485792344210296832, + 483606497256300544, + 484642493989146624, + 488504878244048896, + 490519483493396480, + 486113713544769536, + 485771105844879360, + 484998758963621888, + 485463205951840256, + 485060846104883200, + 484694831315574784, + 495958030492917760, + 485477504526712832, + 493508653325246465, + 484683013280653312, + 484680665078972416, + 490088366512562177, + 484638318907650048, + 488622834902925312, + 488754118979485696, + 485016988419649536, + 487237876787478528, + 484725476158865408, + 493922657742516226, + 486104924137455616, + 488743675191894017, + 491430619407060992, + 485311713961848832, + 488710787696164864, + 492588555412451329, + 485036320205864960, + 493468843080425472, + 486238227263922176, + 485380112050044929, + 485970232947654656, + 485329396732289024, + 486143818589544448, + 486871998573051904, + 486864151416147968, + 484988096690544641, + 485343557373689856, + 486918037678067712, + 485363470091952128, + 487553845586055168, + 489865464848601089, + 491267405071790080, + 485460190549262336, + 495959549300711424, + 488754652117491712, + 495948889049272320, + 487584829241036800, + 485383743688179712, + 486203889273020418, + 486868515883057152, + 486234636201525248, + 485351528962998272, + 487169744060305408, + 486617366504411137, + 492726192412590080, + 485418609519632384, + 495952713147244546, + 490196717745504256, + 485061356501344256, + 485808183219589120, + 495908548581543936, + 486003405765509121, + 485100498744541185, + 486261878554120192, + 490155980337201152, + 495946092425773056, + 495951170301870080, + 490545203665989633, + 495935354663616512, + 486609017079595009, + 488676311465230336, + 488684188850454528, + 487616302081929216, + 488345801849331712, + 484335728612999168, + 494232487686836224, + 492682387965612033, + 485884443769724928, + 492275701454602240, + 490155763244232704, + 485720931613282305, + 484443015357149184, + 485093980875784192, + 486194902720864256, + 488622562554155008, + 485384129073410048, + 490876502763110400, + 488767681651572737, + 485301415666278400, + 493446519753048064, + 492346372272967680, + 485815314677256193, + 485441004238307328, + 486166579819061248, + 485450791151362049, + 495921915694174208, + 485348250128777216, + 490128876472115200, + 485845635493797888, + 485786444536217601, + 484996415459164160, + 486167184100843520, + 485797601779138560, + 488328538547056640, + 485365785746210816, + 492645115937443840, + 495841669515067393, + 493114028986998784, + 486137594716377089, + 488677608163663872, + 486174536501833729, + 492664956786311168, + 485444902780948480, + 485092952117506050, + 485445498913177600, + 485286849695739904, + 492991946252890112, + 486162798238789632, + 495951213645807617, + 486211046445944832, + 485312792334200832, + 485754396857622528, + 485460217661235200, + 493375234343723008, + 486605016544071681, + 490905624809467905, + 493090153796501505, + 488344434766258176, + 485889368335605760, + 485456964726849536, + 489464871621513216, + 492565070262833152, + 492328433939382272, + 492693029086842880, + 488754828185989120, + 493086176669335552, + 490227174302314496, + 486206320773562368, + 494939803327418369, + 488657822444691456, + 486189924245573632, + 488582429524103168, + 491194224491368450, + 493453865422159873, + 485445775808557056, + 491996705999831041, + 485750695111712768, + 485815146917294080, + 485814396590243840, + 486549969026154496, + 490879738718982144, + 494950696266240000, + 485449408201256962, + 488664115624161280, + 485378670006378496, + 485472933838852096, + 493431652778250241, + 491576380501803008, + 485306371198685184, + 488059504345759744, + 488684274833711105, + 493074789574377473, + 484771702652809216, + 486193373787979776, + 486055179381641216, + 493448688162074624, + 488305215050088448, + 490870247030001664, + 485462216582238208, + 485819270849634305, + 491926003829460992, + 492688341281026048, + 493448390022545408, + 486089650436849665, + 493037535199633411, + 485301600584749056, + 494550546292809730, + 490902622036299776, + 492668602685075456, + 488684233926639616, + 485430400915750912, + 490902415160664064, + 489037755851493376, + 485786567244775424, + 488333739576270848, + 493392098159493120, + 491664817812295680, + 493459124680548352, + 491244017490075648, + 493444343357657088, + 491892451293282304, + 484593562496282624, + 486015233853763584, + 489140202062241792, + 485102678511329280, + 493448267632353283, + 494766974996844544, + 485013397332066304, + 484701586355400704, + 486909114753486848, + 491130973657251842, + 485536600848621568, + 485515751269601281, + 484763860243841024, + 493087159822581760, + 487255118006726656, + 490523365955088384, + 486247657933795329, + 487012685138382850, + 486495833291235328, + 487967217787883520, + 493409120956215296, + 492311094132625408, + 493461539614384129, + 491917227852333056, + 491676571867303936, + 488715599074177024, + 486482617882390528, + 485871838107430912, + 493056259076419584, + 487333922649702400, + 486903538266935296, + 489859627103031296, + 494924074997780482, + 486869139525746690, + 485302095491633152, + 486856086985900032, + 485424705030336512, + 493459859916869632, + 487982238198665217, + 490147991073075200, + 493084626358112256, + 488373822719287296, + 486691263391870976, + 485003232214016000, + 485449576686845953, + 486201234492125185, + 492303261572272128, + 488344130972815361, + 485357855596642304, + 488367813686722560, + 485833436691984386, + 488656235630460928, + 490111944100429824, + 484687510241832962, + 490905156460875776, + 485885976829378560, + 493085938093158402, + 492697925626363904, + 486493058780102656, + 491978744140427264, + 488697180912648192, + 485833747502481408, + 493503892882477056, + 485380354681757697, + 494806564961001472, + 486863197559734272, + 491644493746036736, + 485449513533190145, + 484627347803762688, + 485310610196803584, + 485704409654259712, + 490541519229947904, + 489443236747173888, + 490150307838820352, + 485674702263046144, + 488363272555757568, + 493057764462436352, + 485783097871699968, + 485830044057874432, + 485369961272328193, + 495660610273968128, + 485807453704302592, + 492315986973179904, + 493476115865153536, + 484796299531669504, + 493449027107950592, + 489802214685556736, + 485464934529384448, + 492328164841259008, + 490615112471166976, + 492333788664700928, + 485430067565432833, + 492535181035581441, + 489798896789766144, + 487961134721687552, + 491658390121508864, + 485488673321144320, + 491624499872542721, + 489437509005611009, + 488705548234526721, + 486464383913299968, + 488397832257568768, + 492763891404111872, + 484041247829786625, + 492692779630616576, + 488350988487520256, + 486895800384253953, + 486534309818662913, + 486484768994131968, + 493475675874295809, + 485795995482324992, + 493286233154396160, + 488768958229917696, + 490110569798959104, + 485838989421998080, + 491966607976333312, + 485450186794500096, + 486502777128902658, + 485432210884149248, + 485390953008857088, + 485543676785860609, + 494849201705349120, + 485721007450497024, + 486226616843268096, + 485462401253638144, + 485136021189718018, + 493446082202853376, + 490161670770405376, + 488715115550998528, + 488716383338115072, + 489090801058971648, + 493367041764913153, + 490221989206835202, + 488298221442445313, + 485714235432120320, + 489428992181944321, + 485461018496090112, + 489774036050665473, + 492329389183750144, + 486340162511593472, + 487200652540399616, + 486821312254713856, + 486537347723718656, + 485414470064549888, + 483561916066201600, + 494863768653148160, + 490176686336802816, + 487678275104567296, + 492251528338870272, + 492297604336988160, + 486827370259947520, + 488735746820694016, + 485359300039417856, + 494859393453031424, + 485328370918756352, + 487983713343795200, + 487589687549521920, + 491600710317133824, + 493097690733875202, + 485497109618368513, + 485792832427290624, + 492596417119416320, + 490541709903036416, + 486868258663190528, + 485441148065177601, + 488362630416191489, + 483539590725500930, + 485746302345818112, + 483936425403232256, + 487999182767423489, + 488347345747443712, + 490814104337391616, + 485713330146131968, + 493444500497637376, + 485785298144485376, + 486579938548793344, + 491894481302876160, + 486045199043674112, + 486024064415182848, + 486534844126859264, + 493479490790883328, + 483720187284574208, + 485459624569884672, + 488719499102007296, + 485747506693697536, + 485737730652270593, + 486854762613460994, + 484760037014118400, + 485808067020587008, + 486748842243538944, + 486164826943926272, + 486891383236853760, + 494843363439677440, + 486891045746397184, + 484427101022715904, + 486077205567770624, + 488734412084092928, + 485420951564451840, + 486005053338451969, + 491863278558412800, + 487256929992208384, + 485377947369742336, + 488726623811043328, + 493475538921848832, + 484781882245414912, + 482901367896674304, + 483946196441264128, + 485454871651684352, + 488345964936441856, + 485728301936168960, + 485330555786235904, + 493480612775604224, + 484004802100461568, + 486275828250976256, + 485358250611965953, + 486521046443761664, + 487946262936059904, + 485819480401272834, + 493296086623461376, + 486870313230417920, + 485661676977418240, + 493361489492070402, + 493429752037113856, + 493326518131904512, + 485459777544544256, + 485745219367735296, + 490865163248336896, + 493449862932086785, + 486550334848761856, + 486205441765294081, + 493461733227659264, + 488675528757346304, + 485449279214194690, + 490877158827765760, + 485866046621233152, + 488743624373702657, + 489475458673954816, + 485012683704778752, + 485447012649664512, + 493060038215606274, + 490522746774769664, + 485010349528059904, + 485875714559062017, + 485704172466356224, + 485447800768180224, + 485696674170691584, + 485457749871190016, + 487995284602224640, + 489232028756230144, + 489515572472737792, + 489091094215680002, + 483190429383684096, + 486916121367691265, + 490519508004921345, + 490876179243864064, + 486868089712431104, + 493430797630976001, + 486617004384997377, + 488262334637670400, + 490807871047598081, + 485373067041189888, + 493445226006970369, + 488761216773681152, + 487836004296843264, + 485446334447509504, + 485117463177469952, + 486903137144688641, + 485468758786715648, + 485004664141008897, + 493328927071682560, + 486878280742895616, + 485762282782466048, + 493484276609204224, + 488686859443519488, + 485299288704970752, + 488370101486637056, + 483296450361958401, + 485787606710771712, + 485725796632641537, + 486149927991803904, + 487778424576942080, + 488388693938688000, + 494223738611589121 + ], + "top_users": [ + "1168582039", + "265902729", + "108568373", + "15095537", + "7589572", + "153403071", + "807095", + "89483276", + "25084872", + "19230601", + "275575393", + "890891", + "26257166", + "331311644", + "140062928", + "14387275", + "23746926", + "428333", + "13213122", + "435225922", + "46195370", + "63525135", + "1598644159", + "425989199", + "507672047", + "18936161", + "1582853809", + "51241574", + "906852535", + "612473", + "87416722", + "2451113930", + "110758975", + "2557521", + "166767883", + "27660239", + "14075928", + "299201079", + "291438698", + "1375289149", + "325461522", + "180505807", + "742143", + "14920785", + "14293310", + "158334874", + "28454994", + "5402612", + "16303106", + "47945492", + "160926944", + "25589776", + "87818409", + "21866939", + "6017542", + "2883841", + "19777398", + "17471979", + "155642429", + "95465386", + "19923144", + "23925153", + "352145373", + "1652541", + "170591249", + "69962890", + "59426484", + "156380350", + "46618990", + "40642369", + "5988062", + "106779124", + "216299334", + "25567231", + "558797310", + "264896706", + "1068121346", + "461796015", + "52344859", + "23464695", + "538031518", + "1937534894", + "36118300", + "236488883", + "305506258", + "3108351", + "19485464", + "972651", + "416653681", + "19339713", + "97893963", + "208545538", + "476770786", + "171117515", + "36324032", + "564686965", + "361501426", + "166697016", + "307478701", + "620221175" + ] + }, + { + "country_breakdown_percentage": {}, + "country_code": null, + "device_breakdown_percentage": {}, + "end_time": "2015-07-27T00:00:00Z", + "event_type": "SPORTS", + "gender_breakdown_percentage": {}, + "id": "3e", + "is_global": true, + "name": "Gold Cup", + "reach": { + "total_reach": null + }, + "start_time": "2015-07-07T00:00:00Z", + "top_hashtags": [], + "top_tweets": [], + "top_users": [] + }, + { + "country_breakdown_percentage": {}, + "country_code": "GB", + "device_breakdown_percentage": {}, + "end_time": "2015-08-21T00:00:00Z", + "event_type": "SPORTS", + "gender_breakdown_percentage": {}, + "id": "1f", + "is_global": false, + "name": "The Ashes Cricket", + "reach": { + "total_reach": null + }, + "start_time": "2015-07-08T00:00:00Z", + "top_hashtags": [], + "top_tweets": [], + "top_users": [] + }, + { + "country_breakdown_percentage": {}, + "country_code": null, + "device_breakdown_percentage": {}, + "end_time": "2015-07-27T00:00:00Z", + "event_type": "SPORTS", + "gender_breakdown_percentage": {}, + "id": "27", + "is_global": true, + "name": "Jogos Pan-Americanos", + "reach": { + "total_reach": null + }, + "start_time": "2015-07-10T00:00:00Z", + "top_hashtags": [], + "top_tweets": [], + "top_users": [] + }, + { + "country_breakdown_percentage": {}, + "country_code": "JP", + "device_breakdown_percentage": {}, + "end_time": "2015-08-16T00:00:00Z", + "event_type": "OTHER", + "gender_breakdown_percentage": {}, + "id": "3b", + "is_global": false, + "name": "\u82b1\u706b\u5927\u4f1a (Fireworks festivals)", + "reach": { + "total_reach": null + }, + "start_time": "2015-07-13T00:00:00Z", + "top_hashtags": [], + "top_tweets": [], + "top_users": [] + }, + { + "country_breakdown_percentage": { + "AE": 0.09, + "AR": 1.55, + "AU": 0.52, + "AW": 0.02, + "BE": 0.14, + "BH": 0.02, + "BN": 0.05, + "BR": 1.46, + "CA": 1.79, + "CH": 0.07, + "CL": 0.92, + "CN": 0.02, + "CO": 2.75, + "CR": 0.16, + "CY": 0.02, + "CZ": 0.05, + "DE": 0.09, + "DK": 0.02, + "DO": 0.71, + "EC": 0.45, + "EG": 0.14, + "ES": 3.15, + "FI": 0.07, + "FJ": 0.02, + "FR": 0.61, + "GB": 2.12, + "GG": 0.02, + "GR": 0.12, + "GT": 0.47, + "HK": 0.02, + "HN": 0.16, + "HT": 0.02, + "HU": 0.07, + "ID": 0.31, + "IE": 0.19, + "IN": 0.05, + "IT": 0.38, + "JO": 0.05, + "JP": 1.36, + "KW": 0.07, + "LB": 0.02, + "LK": 0.02, + "LT": 0.02, + "LU": 0.02, + "LY": 0.02, + "MN": 0.02, + "MX": 7.27, + "MY": 0.26, + "NG": 0.05, + "NI": 0.14, + "NL": 0.21, + "NO": 0.05, + "NZ": 0.02, + "PA": 0.21, + "PE": 0.26, + "PH": 0.38, + "PK": 0.05, + "PL": 0.05, + "PS": 0.07, + "PT": 0.09, + "PY": 0.07, + "QA": 0.09, + "RS": 0.02, + "RU": 0.05, + "SA": 0.33, + "SE": 0.16, + "SG": 0.12, + "SV": 0.31, + "TH": 0.14, + "TR": 0.21, + "TT": 0.02, + "US": 63.65, + "UY": 0.19, + "VE": 4.99, + "VI": 0.05, + "ZA": 0.02 + }, + "country_code": "US", + "device_breakdown_percentage": { + "ANDROID": 11.71, + "BLACKBERRY": 0.18, + "DESKTOP": 37.3, + "IOS": 50.47, + "OTHER_MOBILE": 0.33 + }, + "end_time": "2015-07-17T00:00:00Z", + "event_type": "MUSIC_AND_ENTERTAINMENT", + "gender_breakdown_percentage": { + "female": 60.62, + "male": 39.38 + }, + "id": "10", + "is_global": false, + "name": "Premios Juventud 2015", + "reach": { + "total_impressions": 64148387, + "total_number_of_tweets": 2385304, + "total_reach": 5111767 + }, + "start_time": "2015-07-16T00:00:00Z", + "top_hashtags": [], + "top_tweets": [ + 489946528547880960, + 489924339416846336, + 489937811454177280, + 489952508031164416, + 489945130678226944, + 489942703912669185, + 489949518067019776, + 489948210182369281, + 489971869131354112, + 489945880858877952, + 489942025211363329, + 489935608047882240, + 489933840295555072, + 489928528155009024, + 489938618002075648, + 489519752214093824, + 489944547410345984, + 489937878886391808, + 489923860792217600, + 490164231447543808, + 489968528506621952, + 489933312643698689, + 489928360697401344, + 490209511924588545, + 489936864925605888, + 489992305265229825, + 489955444501135360, + 491349443879645184, + 489527535059755008, + 489977832072695808, + 489482142901346305, + 489872769673207808, + 489971382344626177, + 489943543801053184, + 489926543456468993, + 489959488816828416, + 489584634208862208, + 489962838325096448, + 489932682403397632, + 491283969468407808, + 489929879454900224, + 490250128444252160, + 489947476565045248, + 489889245872799744, + 489996502115160064, + 489961477395464192, + 489520442240016384, + 490155311857410050, + 489950070926618625, + 489956878479130624, + 489947232347496448, + 489964396924260352, + 489437701569912832, + 489952280368521216, + 489967993326018562, + 489935121437691904, + 489947643385094145, + 490177096853889024, + 489938236639543296, + 489968517492375552, + 489943675397365760, + 490011911019573248, + 489953535828955136, + 489935166669070336, + 489964316876374016, + 489968562627682304, + 489941248736624640, + 489954336785825792, + 489936846445486080, + 489969178045349888, + 489977518632366081, + 489934213055926272, + 490003625746243584, + 489984921625042944, + 489933974610132993, + 489997418369282048, + 489893714773291008, + 489575247947911170, + 489970547661357056, + 489990804992446464, + 489949679350603776, + 489957654077657088, + 489941209113444352, + 489959018426032128, + 489874889327652865, + 489936644078710784, + 489929289576755201, + 489948822466883585, + 489954914547032064, + 489989270954733568, + 489979510482141185, + 489965110664757249, + 490918231285460992, + 489965268676788224, + 489984306580684803, + 489942129033355264, + 489956902093090817, + 490001533724295168, + 489926307544059905, + 490137328997126144, + 489928928682078208, + 489952325759295489, + 489619536392757248, + 489928692022263809, + 489942459883864064, + 489987642151694337, + 489937110972243968, + 489938786957021185, + 490006540133597185, + 489844250889056256, + 490000372312727552, + 489972897599877120, + 489953051344920577, + 489101327759187968, + 489992062511906818, + 490404070608625664, + 489103026901118977, + 489927388000555008, + 489959383657218049, + 489937922984914944, + 489950541733453824, + 489982555920158720, + 489985391278452736, + 489937448148152321, + 489976941139615744, + 490000131031183360, + 489961552947449856, + 489929747799887873, + 489968667703402496, + 489938195815989248, + 489958662639591424, + 489939307612741632, + 489950842519556097, + 489963377494474752, + 489998811578638337, + 489931940900794368, + 489975151526543361, + 489945869018357760, + 489934582561906688, + 489581062628986880, + 489939822132207616, + 490005340445241344, + 490010566837026816, + 490139990764961793, + 489506746373636096, + 489959451781496833, + 489958024715722752, + 490000424834174978, + 489943067000983553, + 489932823626006528, + 488850281392635905, + 489942000381493248, + 489954551466708992, + 489950098470998016, + 489930286256652288, + 489755055579357186, + 489970124980772864, + 489955074408341505, + 489482115512545280, + 489941682259914752, + 489982719930408960, + 489988191542607873, + 489969132352204801, + 489951272188268545, + 489927335572144129, + 489239886851891200, + 489947418763747328, + 489824480894943233, + 489925760418070529, + 489981059845861376, + 489181576643629056, + 489961160423538688, + 489948642296733696, + 489943234484113409, + 489937453315522560, + 489595444893200385, + 489950387399454721, + 489963893314564096, + 489934830915059712, + 489992167885008896, + 489949143977431040, + 489791575686250497, + 489955195439575041, + 489572373956292609, + 489929785234051072, + 489964543674966016, + 489987791313731584, + 489927148632014848, + 490116592424845312, + 489950234785505280, + 489956177313165312, + 489807224760713216, + 489136756965380096, + 489946586974130176, + 489966220217946112, + 489944766906630144, + 489514815316955137, + 489992460190621696, + 489957137716899840, + 489848281007394818, + 489137011874615296, + 489970204366340096, + 489173040463638528, + 489954182225354752, + 489163298525687808, + 489962139184939009, + 489888160004861952, + 490135581339303936, + 489902759131746304, + 490146567681499136, + 489944382850621442, + 489925114881118208, + 490213914035388416, + 489236792734781441, + 489091569174052864, + 489995247204962304, + 489972478287294464, + 489967818108989440, + 489968088193175552, + 489809637127254017, + 489970101412589569, + 489927389908971520, + 489947620450656256, + 489935313415192576, + 489793018057064448, + 489925564409446400, + 489965955456720898, + 490146410701275136, + 489968410064089088, + 489910558670725120, + 489137117348761600, + 489953652199936000, + 489756180646875137, + 489816342061924354, + 489992970360193027, + 489949622685544448, + 489784093903958017, + 490343644621443072, + 489976599224516608, + 489971184935907328, + 489935943504109568, + 490302557559193600, + 489943194751483905, + 489958865316741121, + 489952504604794880, + 489971288812027906, + 489929932659642368, + 490306475785351168, + 488860222694240256, + 489988127352950784, + 489924054762393600, + 489935896813121538, + 489890559084204033, + 489898743391477760, + 489931756804386817, + 489954356440338432, + 489930296087703553, + 489948403468869632, + 489904657742196737, + 489984350532812800, + 489807056074203136, + 490010022983008256, + 489810325186023425, + 489923127959629824, + 489944602317955072, + 489924633471516672, + 489953615033810945, + 489951515097202688, + 489953434976546816, + 489955892541259776, + 489979151466897408, + 489940660019949568, + 489916157173194752, + 490325661890785280, + 490333206064140289, + 490218453517606912, + 489924304822599683, + 489945993077473280, + 490006583615959040, + 488696767249014784, + 489936327840763904, + 489965297471074304, + 489945491615260672, + 489599092540989440, + 489981098685124608, + 490327922033823744, + 489980532340850688, + 489972000774180864, + 489890434815381505, + 489808465737809920, + 490137193139015680, + 489934195905400832, + 489962089814163456, + 490003353171394560, + 489966377323597824, + 489953588832395264, + 489914196919083008, + 489987950722035712, + 489946977908817920, + 489946450424389632, + 489970149098016768, + 489983219316424704, + 491723134211330050, + 489959544433680384, + 489948950087364608, + 489942927372976128, + 489969871527354368, + 489987000100200448, + 490005022759870465, + 489432691021217792, + 491054748372848640, + 489941827231834112, + 489955401463775232, + 489938065004453888, + 489520261171916800, + 490334718681169920, + 490338245704953858, + 489939609753632768, + 489934777689329664, + 489835558454427648, + 489978912592900096, + 489923753997242369, + 489778125824593920, + 489969094226350080, + 489958041073491969, + 489957635462926336, + 489965245717557249, + 489959617687207939, + 489985303718154240, + 489969030015770627, + 489943975294693376, + 489911226408128512, + 489946079136591872, + 489968770891272192, + 489984350138925056, + 490334893704871937, + 489930816122667008, + 490305051794345984, + 489964842518732800, + 489973370553786368, + 489976670476959745, + 489963784484974592, + 489927188183928832, + 489965786468204544, + 489952368998772736, + 490113769604141057, + 489956179100311552, + 489934386352390144, + 489486288152973312, + 489963539176488960, + 489963465109684225, + 489962171829219328, + 489975323954798592, + 489628601587757057, + 489980967915098112, + 489966520186179586, + 489942751069601792, + 489992490033098752, + 489945413173010432, + 489926682480873473, + 489933210500222977, + 489967490865569792, + 489911403525201920, + 489564895516426240, + 489983219522338816, + 489968735101284352, + 489961912981934080, + 489015746962685952, + 490311537786359808, + 489932009561935873, + 489969855605776384, + 489951089673117696, + 489944528141316096, + 489873099324530689, + 490245718251016192, + 489914278913114112, + 489995943761428480, + 490315157361659905, + 489990363101147137, + 489959700432035840, + 489951369991032832, + 489825032131330049, + 489954921064579072, + 489915330274541568, + 489968458751549441, + 489982919713513472, + 490350166730231808, + 489866995534671872, + 489938092137394176, + 489938126190936064, + 488865540774297600, + 489930549243293696, + 489976751972696064, + 489993078758199296, + 489208416674787328, + 491387894935089153, + 490199632887021570, + 489958829841731586, + 489947614893588481, + 489914740958068737, + 489963862511202305, + 489961381392052224, + 489614683389706240, + 489918664536522752, + 489932716901953537, + 489995332726439936, + 489969593889595393, + 489943878091681793, + 489963888344330241, + 489964634934231040, + 489899488715096064, + 489944157285142529, + 489951712015163393, + 489605488611704832, + 489943058516283392, + 489936058722045952, + 489934433097879552, + 491450096752812032, + 489931402704457728, + 489960599778889728, + 489964849229991936, + 489932075978346496, + 489930730408247296, + 489835711974346753, + 489946001386377216, + 489447330261655552, + 489984393323085824, + 489936884056223744, + 489995085111918593, + 489968212964937728, + 489432448972111872, + 488774128908779520, + 489964702613925888, + 490303790839775232, + 489966322324090880, + 489270005201379328, + 488845277089267712, + 489958185906626560, + 489962994374172672, + 489852845923909633, + 489964349914484736, + 489916784900710400, + 488774921858723840, + 490233790099619840, + 489930145579667457, + 489967334313172994, + 489923459737460736, + 489244364296552448, + 489964642052349953, + 490006904114921472, + 489970147180834817, + 490347840989036544, + 489991767945920513, + 489934684810248192, + 489961688796381184, + 489940879512449024, + 489953101617442816, + 489910737171931136, + 489469362999681024, + 489862702827704320, + 490571824984371200, + 489953172647997440, + 489606122303520770, + 489238434439909376, + 490013617861824512, + 489950849443983360, + 489936621521752064, + 489945897225031681, + 489991199839637504, + 489150324779667456, + 489971180812902400, + 488855650290896897, + 489445496591622144, + 490245824447016960, + 489967328063684608, + 489940769503858688, + 489997345430327298, + 489926424070201344, + 489941988675174404, + 490001004143063040, + 489955113604100096, + 489520137620299778, + 489959985787723776, + 489147940942778368, + 489897153184428034, + 489958755392843776, + 490010480921288704, + 489475416269520896, + 489968854647316480, + 489945890333798401, + 488843998056828928, + 489957591301505024, + 489955348674269184, + 489847065263235072, + 491052456487694336, + 489970217498329088, + 489822634629431296, + 489909250702184449, + 489949270808608768, + 489956817922191360, + 489899423950835714, + 489958633036599296, + 489975325267591169, + 489955846634217472, + 489952992553353217, + 489960354693517313, + 489979213248622593, + 490130224689192960, + 489928128547266562, + 490137078915956736, + 489760330118356992, + 489569634438623232, + 489961814919491584, + 489937431932964865, + 489961639509512192, + 489999282448388096, + 489939623993278464, + 490148087722016768, + 489951156110888960, + 491450036191236096, + 489936394010525698, + 489931532551741441, + 489936863885811712, + 489234890752532480, + 489853768851136512, + 490302526906839040, + 489962224191287296, + 489958423325581312, + 489993864422236160, + 489970187571965954, + 489990319438839808, + 489606939211739137, + 489934677621239809, + 489979156030296064, + 490244899237675009, + 489852973674012672, + 489934322552426496, + 489956944753729536, + 489932205326864384, + 489165152387088384, + 490183160068857856, + 490137639257767937, + 490235836927975424, + 489919723002667008, + 489936455524179968, + 489924685753114624, + 489954145252958208, + 489606670725959680, + 489587818071457792, + 490366689419476992, + 489160475108589569, + 489428492938129408, + 489243139195293696, + 489608973411450880, + 489951219859730434, + 489925850167799808, + 489212827396489217, + 489909178282962945, + 489933294864052224, + 489931007575871488, + 489936240733462529, + 489780779111575553, + 489989159814455297, + 489956088461402112, + 489999799413129216, + 489925367285968896, + 491082651181142016, + 489959103205101568, + 489957833640013824, + 489939515885121536, + 489958946527256576, + 490003243670732800, + 489471464043606017, + 489925408037810176, + 489986840447840257, + 489877237391704065, + 489852520324288513, + 489243027823943680, + 489908908275023872, + 490016034611417088, + 489899154366148610, + 489935024561860608, + 489959492696551425, + 489927848439058432, + 490004760272326656, + 490382582446432257, + 489471148695224320, + 489935173379960832, + 490341692906557440, + 490601979593629697, + 489948622918668289, + 490910828682833920, + 492099835966021633, + 488343717963501568, + 489990405794971648, + 489916060410589185, + 489605409662312448, + 489931609341435904, + 490172363422437376, + 490027246858403841, + 489959741855395840, + 489218219363033088, + 489967807900434432, + 489968887132618752, + 489968932439474176, + 489959764642648065, + 489933906737893376, + 490264976205295616, + 489933509554077696, + 489993586176692224, + 489949878051962880, + 489953433613787136, + 489963451411099648, + 489911353633550336, + 490001066608451584, + 489904224168579072, + 489936459655548929, + 489976405024051201, + 489952389156585472, + 489954013103030273, + 489864990023614464, + 489952012747161600, + 489963310997966849, + 489958007443161088, + 489914243924627456, + 490314474839343104, + 489976828225142785, + 489922676228886528, + 489952743671349248, + 489752963590533120, + 489972911865090049, + 490371737696358400, + 489995331619520512, + 489953399551844352, + 489962731336761346, + 489932917372514304, + 489899032009928705, + 489866964391571457, + 488866669083635712, + 490373232919605248, + 489976066417913857, + 489934509371305984, + 490158889401593857, + 489956556759244801, + 489990229777215488, + 489957942461202432, + 489953999991218177, + 489925195667603456, + 489956882321117186, + 489943478579654656, + 489880781611732993, + 489995243346198528, + 489965762816524288, + 489968199668994048, + 489830067917172736, + 489961703795601408, + 489945948458455040, + 488861840210792449, + 489898951219224576, + 490008321831628800, + 490511404286611456, + 489950586712776704, + 489892300181348353, + 489243914457473024, + 489930649198133248, + 489934180617568256, + 489963389872254976, + 489923002029449216, + 489950981614886912, + 489925588207951873, + 489963952021839872, + 490373971989512192, + 489958305734090752, + 489925469052354560, + 489924279602249729, + 489947232574398464, + 490538967390228480, + 489933758129111040, + 489930647788851201, + 488865775961513984, + 490186740532260865, + 489957498347335682, + 489983225515999232, + 489947325096136704, + 489887772535435265, + 489957164103249921, + 489992442528419840, + 489948890314338304, + 489577756330848256, + 489946050753359872, + 488783663740764160, + 489294385373122560, + 489947333514108928, + 489933636683460608, + 489929292646993920, + 489971657902399488, + 489959333765988353, + 489937826981875712, + 489994410550386688, + 490892336516567040, + 489949495950471168, + 489934064359849984, + 489946757678514178, + 489956823290880000, + 491402250875834369, + 489932450785943552, + 489938994961321984, + 489974640182177793, + 489948533324529664, + 489933204481400832, + 489954532885950465, + 489953455403180032, + 489973954178998273, + 489897739913011202, + 489972786035580928, + 489971800928178177, + 489945964065878016, + 489948342227836928, + 489927389183758336, + 487239534607106048, + 489941852297363456, + 489900728090386433, + 489925718843740160, + 489973475277537281, + 489961295894941697, + 489958863140290560, + 489926051662135296, + 489992541954387968, + 489937294489812992, + 489891937374044160, + 490526491029958656, + 489962553196294145, + 489945532467785728, + 489959766035533825, + 489758094856323072, + 489972220048179200, + 489596030359732224, + 489964021005975552, + 489930005002989568, + 489950262103379969, + 489933847887245312, + 490496293723471872, + 489943947939041280, + 489801038325895169, + 489623036128428033, + 487603106885402624, + 489965344963194880, + 489938381552771072, + 489937299363627008, + 489936498889080832, + 489944412122644480, + 489920533807771648, + 489945360291606528, + 490680025839329281, + 489927548151676930, + 489971295116083202, + 489950546355580929, + 489941621778042880, + 489575446498246657, + 489934453372768256, + 489948369344036865, + 489599003408207873, + 489561675146993664, + 489968479312019456, + 489926373705007105, + 489968437687369728, + 489944668093042688, + 489877204936167424, + 489525642157760513, + 488866112629506048, + 490296258498924544, + 489920270149648385, + 489946617517473792, + 489925379252305920, + 489182361808928768, + 489970120329281536, + 488764274152456193, + 489958771285037057, + 489942461171896320, + 487941632936144896, + 489947745579724801, + 489924823078809600, + 489961272461762560, + 491319203157516289, + 489906786141364224, + 489965618696060929, + 489893010126041088, + 489926387222863872, + 489531175221075969, + 489964876425854976, + 489179747029512192, + 489918327381561344, + 489959099195744256, + 489950935050121217, + 489923329793724416, + 489862107350175745, + 489972558729469954, + 489930488791203841, + 489924087658319872, + 489908820249178113, + 489953486050574337, + 489943241693753344, + 489934654154485760, + 489938771023257601, + 490157408275021825, + 490496373993635840, + 489925102793162752, + 489964396316479488, + 490848914929893376, + 492182816214364160, + 489935898763870208, + 489840076445061120, + 489937034807500800, + 489968498698113025, + 489910548767580160, + 490542562881437696, + 490069767911649281, + 489942925405872128, + 491020528992673792, + 489968235568439296, + 489966023303790592, + 490200024476033024, + 489945166686732288, + 489946438726475776, + 489941806973734912, + 489984328064335872, + 489950515963633665, + 489939991876108288, + 488762489187090432, + 489942691593977856, + 489954780060868608, + 489933151419244545, + 489966047521673220, + 488742713547059200, + 489942793486217216, + 489970168525623297, + 489480298829447168, + 490235242381590528, + 489955764522328064, + 489954516393922560, + 489936520728821761, + 490039515885481984, + 490117012354793472, + 489968301175754753, + 490454897754902528, + 489763968542449664, + 489746212531077121, + 489955661929652224, + 489866766747578368, + 489964849875927040, + 490205009959600128, + 489933026483531776, + 487590093008695296, + 489949204375412738, + 489889906458890240, + 489974516789952512, + 489928691791568896, + 489953283394396161, + 489939156689514497, + 489969523638812673, + 489904149279289345, + 489938374380093440, + 489936072814895104, + 489866537495318528, + 489923875149721600, + 487976612030201857, + 489948033619337217, + 489961836293287937, + 489955713071202304, + 489960105082101760, + 489243572735328256, + 489924583185977344, + 489952630727532544, + 491052098541207552, + 490160658005381120, + 488760596469256192, + 489951513792372738, + 489934756340318208, + 489979245964566530, + 489960035993128960, + 489815862958780416, + 489936381783703552, + 489925816697245697, + 489934322447953920, + 489804257629978625, + 489979357679456257, + 490382538654089216, + 490258032790896640, + 489934034089541632, + 489948618091397120, + 489473429985193985, + 489951418858475520, + 489940978699362304, + 487597178127646720, + 490224488592969728, + 489875017413697537, + 489954497754460160, + 488744741484642304, + 489957126249259008, + 489970982644240384, + 489962090673999872, + 489973406016630785, + 489968589005275136, + 490008612472102913, + 489854551122796544, + 489958982639824896, + 491628753450463232, + 490524920817156098, + 490104402758619136, + 489991952168124416, + 489561511866941440, + 489993093546926080, + 489907662948433920, + 489636217302966274, + 490141545178619904, + 490036672424595458, + 489945402658263040, + 490379826445172736, + 489149034125619201, + 489967933553377280, + 489956401612328960, + 490110568922382336, + 489942999968006144, + 489965641856581632, + 489931031278260224, + 490454728854077440, + 489949102546096129, + 489936644875636737, + 490168624024653826, + 489910677390491648, + 489877282408775681, + 489946280333152256, + 490255553588125696, + 489163433628413952, + 489963984481959937, + 489935400073318401, + 490558473269043201, + 489938533076201473, + 489948779026845696, + 489924163709452288, + 488742644190040065, + 489866134951563265, + 490149187959681025, + 490525065101213697, + 489959108712607745, + 490524840852721664, + 489953974376595457, + 489962566790414337, + 489935066592591872, + 489566540543442944, + 490153744659922944, + 489942914685239296, + 489796877114937344, + 489119490018246656, + 489951784702451712, + 489963543429906432, + 489957005990563840, + 489952561731223552, + 489947413621137408, + 489936845401120769, + 489947876483944449, + 489777738346409984, + 489152659526397952, + 489523224573513728, + 490154898185805825, + 489911511767601152, + 489942220016214016, + 489937727140265984, + 489985126844346368, + 489401569663000576, + 489932066067611648, + 489933519632998400, + 489933344642039808, + 489955636080549888, + 489976135837417473, + 489915800938360832, + 490710215890067456, + 489938217601617921, + 488474661827932160, + 489948222257786880, + 491035142639865856, + 489886830041784320, + 489942443111239680, + 489937892413030400, + 490738682706411520, + 489933150462955520, + 490110568658128897, + 487596778959945728, + 489950089323220993, + 489909784569978880, + 489891097637052416, + 489951071390167040, + 489911763719446528, + 489955920643104768, + 489943260027043843, + 489950218830757888, + 490181113394892801, + 489966223170736128, + 489853429721092096, + 489951905905274880 + ], + "top_users": [ + "19720019", + "180418331", + "196795202", + "31133017", + "40924038", + "188478643", + "46452468", + "26757599", + "78687173", + "102729125", + "128813009", + "31927467", + "124172948", + "57099808", + "65186457", + "128023009", + "1154946600", + "34010442", + "1233537913", + "39797433", + "44409004", + "47736553", + "24516380", + "379288431", + "40908929", + "63779020", + "72047325", + "112597880", + "209867913", + "254274083", + "153433497", + "1213508726", + "77694285", + "65668018", + "277180205", + "30913899", + "77010454", + "1170406879", + "121169579", + "15737175", + "207819013", + "591661900", + "46527223", + "146200269", + "743071651", + "171530998", + "1322632638", + "2207524212", + "595952437", + "117281110", + "153295172", + "372897682", + "2238250958", + "47288005", + "215103276", + "73886981", + "17813487", + "77504008", + "36980853", + "9695312", + "772070826", + "956123270", + "221559108", + "275303288", + "79327591", + "60969521", + "459014526", + "44670915", + "145294614", + "480822169", + "173721593", + "232305292", + "174935275", + "2390439726", + "243764855", + "1491330559", + "68904673", + "80657284", + "288053938", + "71938819", + "95540269", + "119573510", + "249775593", + "36443298", + "87302192", + "135560283", + "1061771467", + "88686689", + "32701605", + "158028837", + "537266119", + "1237557283", + "764835216", + "31118158", + "106538753", + "66190349", + "600319106", + "69413371", + "172037769", + "244272038" + ] + }, + { + "country_breakdown_percentage": {}, + "country_code": "GB", + "device_breakdown_percentage": {}, + "end_time": "2015-07-20T00:00:00Z", + "event_type": "MUSIC_AND_ENTERTAINMENT", + "gender_breakdown_percentage": {}, + "id": "1h", + "is_global": false, + "name": "Latitude Festival", + "reach": { + "total_reach": null + }, + "start_time": "2015-07-16T00:00:00Z", + "top_hashtags": [], + "top_tweets": [], + "top_users": [] + }, + { + "country_breakdown_percentage": { + "AE": 0.2, + "AR": 0.45, + "AT": 0.07, + "AU": 1.42, + "AW": 0.02, + "BE": 0.05, + "BH": 0.02, + "BN": 0.02, + "BR": 0.77, + "CA": 4.07, + "CH": 0.27, + "CL": 0.25, + "CN": 0.07, + "CO": 0.43, + "CR": 0.11, + "CY": 0.07, + "CZ": 0.02, + "DE": 0.43, + "DK": 0.2, + "DO": 0.11, + "EC": 0.07, + "EG": 0.05, + "ES": 2.08, + "FI": 0.23, + "FR": 0.99, + "GB": 22.99, + "GG": 0.05, + "GH": 0.02, + "GN": 0.02, + "GR": 0.25, + "GT": 0.07, + "HN": 0.05, + "HR": 0.09, + "HT": 0.02, + "HU": 0.05, + "ID": 0.23, + "IE": 1.4, + "IM": 0.02, + "IN": 0.34, + "IQ": 0.05, + "IS": 0.02, + "IT": 0.77, + "JE": 0.02, + "JM": 0.05, + "JO": 0.02, + "JP": 1.4, + "KE": 0.02, + "KH": 0.07, + "KR": 0.11, + "KW": 0.2, + "KY": 0.05, + "LB": 0.02, + "LU": 0.02, + "LY": 0.02, + "MA": 0.02, + "ME": 0.02, + "MK": 0.02, + "MQ": 0.02, + "MX": 1.2, + "MY": 0.56, + "NG": 0.23, + "NI": 0.02, + "NL": 0.97, + "NO": 0.41, + "NP": 0.02, + "NZ": 0.09, + "OM": 0.02, + "PA": 0.14, + "PE": 0.05, + "PH": 0.45, + "PK": 0.07, + "PL": 0.05, + "PS": 0.02, + "PT": 0.07, + "PY": 0.02, + "QA": 0.05, + "RO": 0.05, + "RU": 0.11, + "SA": 0.5, + "SE": 1.08, + "SG": 0.34, + "SI": 0.02, + "SV": 0.05, + "TH": 0.38, + "TR": 0.61, + "UG": 0.02, + "US": 50.63, + "UY": 0.05, + "VE": 0.25, + "VI": 0.02, + "ZA": 0.45, + "ZM": 0.02 + }, + "country_code": null, + "device_breakdown_percentage": { + "ANDROID": 9.23, + "BLACKBERRY": 0.02, + "DESKTOP": 36.56, + "IOS": 53.91, + "OTHER_MOBILE": 0.28 + }, + "end_time": "2015-07-20T00:00:00Z", + "event_type": "SPORTS", + "gender_breakdown_percentage": { + "female": 36.51, + "male": 63.49 + }, + "id": "1v", + "is_global": true, + "name": "Golf: The Open Championship (British Open)", + "reach": { + "total_impressions": 330947913, + "total_number_of_tweets": 1155585, + "total_reach": 11243056 + }, + "start_time": "2015-07-16T00:00:00Z", + "top_hashtags": [], + "top_tweets": [ + 490913468217049088, + 490836871090823168, + 490897102911070209, + 490501805458354177, + 490470698482429952, + 490488754717868032, + 490497650295582720, + 489745176475103233, + 489732202876239872, + 490903785901162496, + 489729604811124736, + 490522820561350657, + 489792793783861249, + 490881870377132033, + 490856708450037761, + 490009788516794368, + 490911435296620544, + 490165880773701632, + 490199621516681216, + 490125344675217408, + 488380256089542656, + 490509312130023424, + 487979109205966849, + 490919840677646336, + 490912025183522817, + 490910724076888064, + 489765822140018690, + 490881641024610304, + 490583629241016320, + 490925779875008512, + 490821738813730816, + 490113788801482752, + 490866287929991169, + 490510431677865984, + 490912375902851072, + 490911473611595777, + 490881121962700801, + 489726212332195841, + 490798323570208768, + 490201166572437505, + 487255391064313856, + 490910762702221313, + 489754908652867584, + 490500242065068032, + 493453821793034240, + 489758744444936192, + 489041100460814336, + 489803864364023809, + 490911926596431872, + 490907254817054720, + 490200275404464128, + 489721021596205056, + 490857941629956096, + 491219236065267715, + 490912382743347200, + 490910774974373888, + 490854149198602240, + 489679657646977024, + 490911637696958464, + 489365882737405952, + 490910708583104512, + 490893297830076416, + 490222560572084224, + 490913110950043648, + 490916970423123968, + 491211902413185025, + 490114801730072576, + 490138545110401024, + 489767771090481152, + 489759042072768513, + 488700415132041217, + 490517441437392896, + 489743192275697664, + 490916642621493248, + 489053304929140737, + 490915047439212544, + 489794177996029953, + 489802707889569792, + 490799052611923968, + 490912107916177408, + 490581480532217856, + 490873559842308096, + 490194496219774976, + 489842042630328320, + 490912884965527554, + 490942286856220672, + 490894109012656128, + 490910933842415617, + 490989617240612864, + 489137389755830272, + 489152484816871424, + 490910673732665344, + 490910775054061568, + 490873776020545538, + 490499362578251776, + 490912481611505664, + 490211359544844288, + 490880749642727424, + 489386168640098305, + 490910961629667328, + 490872868943962113, + 490854091854479360, + 491328712693276672, + 491160798132441088, + 489653386342825984, + 490210812494381058, + 490372194120515584, + 489334697982304258, + 490919553627852800, + 490179265862717441, + 490099149594169344, + 490509021557035009, + 490005061356253184, + 490883087803633664, + 490864272638226432, + 490557133423775745, + 491188367346774016, + 490030533079220224, + 490028875024695296, + 490898722708942849, + 490860623266607104, + 490928027787075584, + 490925559749173248, + 490724919689625600, + 491148884505550848, + 490785725693321216, + 490874667381817344, + 490492227874205696, + 488632340479213568, + 490521875483992064, + 490520479326011392, + 490461791101542401, + 490563615666475008, + 490512633024741376, + 490507894191058945, + 490506103848198144, + 490843579431288832, + 490933123602214912, + 491236006394200065, + 490209461471313920, + 490569894950621184, + 490941418987601923, + 490911308389552129, + 490893871011069952, + 489470022041878528, + 490913410755076096, + 490376786774343680, + 490896332119625728, + 487147342924357632, + 489355539781271553, + 490893214707351552, + 490188181254713344, + 490502745536094208, + 490543572463415297, + 493479901929160704, + 489867242344292353, + 490828086465019904, + 491070420335218688, + 490925452111122432, + 490075393714843648, + 490843030975709184, + 490906571535171584, + 490914244456890369, + 490524658241130496, + 489718459111342080, + 490551847422541824, + 488616390664802304, + 489409198115913728, + 489959046993043456, + 490496444764528640, + 490549934912200704, + 489491699341991937, + 490911602993299456, + 490118842400911362, + 489335373416251392, + 490203531522351104, + 490777646595604480, + 490750618144112640, + 490909067423285249, + 490488546562949120, + 489458890099425280, + 491126811972341761, + 489339468131106816, + 490902853834141697, + 489679174869999616, + 490911450366750720, + 489389981702451200, + 490933214475997185, + 490916145789415424, + 490910570796044288, + 490205925740142592, + 490207380345745408, + 490548690898386945, + 490195676291407872, + 490883316997169152, + 490915008021164034, + 490208288194437121, + 489785462752415746, + 489062127458455552, + 491127705128435712, + 490908113181351936, + 490915464768270336, + 489853523145027584, + 490861207692541952, + 490883317852803072, + 490399896852508672, + 491292784402661377, + 490906486718349312, + 490839376877088768, + 490879918948241408, + 490492747644538880, + 490911707183996928, + 490891505142611968, + 490806376843976704, + 491129022378950656, + 489696831950311425, + 490511758713712640, + 489681081491525632, + 490855185141334016, + 490389833484079104, + 489646403384520704, + 489457890470924288, + 490406543058538496, + 488744642226040834, + 490889001117966337, + 490200639738494976, + 490917208177254400, + 490893184659386373, + 489866779062452224, + 490510474962681857, + 489474021063688193, + 490903977954127872, + 490847584890945536, + 490908586302640129, + 490897013735976960, + 490780193980960768, + 490794713889669120, + 490911119146364928, + 490591395124891648, + 489858763965616128, + 490765293967654912, + 490905427614629888, + 490922521395355648, + 490908834484199425, + 490880764612206593, + 489846309650984961, + 489444250145546240, + 490429754559197185, + 489804175371677697, + 489771556969521152, + 490175114366169090, + 490870008126644225, + 490210947471249409, + 490509200515416064, + 490903162103291904, + 489649900150607873, + 490502205342900224, + 490478920207433728, + 490841554417111040, + 490422450505924608, + 490403978300362752, + 490388813962039296, + 489116141869355008, + 490446991508647936, + 490876252031447040, + 490896335470874625, + 490856405256372225, + 490826483292979200, + 489472322496393216, + 490536989671043072, + 490847093742133248, + 489654122803888128, + 490866644160610304, + 490517407786893312, + 490903637624098816, + 490533002632769536, + 491188631910903808, + 489084398240026624, + 490885631871299584, + 489798167400308736, + 490409184538935296, + 491097586548609024, + 490810820335779840, + 489061992859463680, + 490912714383163392, + 489434566349049856, + 490485779748356096, + 490910701415038976, + 490520130724835328, + 490182839154278401, + 490896406602072064, + 490912482978844672, + 490419838607974400, + 490533780797800449, + 489670220567412737, + 490812548099620865, + 490853413576781824, + 489841865592950785, + 489686359087800320, + 490452304102178816, + 490046242396061696, + 490494387118678016, + 490207085251276800, + 489388788553379840, + 490855538175922177, + 489329751287296000, + 490461498234662913, + 490907171098722304, + 490253413801025537, + 489660763947425792, + 490919636213305344, + 490197693873266689, + 490451496648323072, + 489664387771559936, + 489838911049719808, + 489045862489022464, + 490881881554944001, + 490862249960292353, + 490177804336914433, + 490186001206505472, + 490833109274071040, + 490909493656825856, + 490871713643913216, + 492195014911721472, + 488976372715773953, + 490900614457880576, + 490908874065870850, + 489338630113333249, + 490466265832906752, + 489836536725508096, + 490079918383190016, + 489371562181939200, + 490918262566555648, + 490900554089254912, + 490023463646941184, + 490883979349086208, + 490025886994153472, + 489820554325929984, + 490492519000862720, + 490909084267610113, + 490165863392497665, + 489774887326580736, + 490820381184622592, + 490420821580861440, + 489370851272581120, + 490255680230948864, + 490905181283184640, + 490907692861370368, + 490573639222575104, + 489744426441666560, + 491188219527327744, + 490832340688838656, + 489732676933672960, + 489381109332180992, + 490196213019725824, + 489077836330696704, + 490511907380805632, + 489381106257768448, + 490193924355805184, + 490478827257462784, + 488707255865704448, + 490953650487828482, + 489805730313027588, + 490864295149076480, + 490210137140125697, + 490910006552719360, + 490519164537565184, + 490158496487587842, + 487991168181882880, + 490908109615816704, + 490533556415123456, + 490906788922155008, + 490867603343429632, + 490863700816183296, + 489417542575095808, + 490910512213786624, + 490525866846617601, + 490788420944670720, + 490594745618808832, + 490248784279269377, + 488635374814900224, + 489019424108978176, + 490478916742574080, + 490878674636664832, + 490902340971814912, + 490914879776489472, + 489718389565575168, + 490815946026938368, + 491047417769644032, + 490856906786078720, + 490087819856338944, + 490248537348009984, + 490908765278195713, + 489426587189014528, + 490896976717033472, + 490467576615804928, + 489876661689516032, + 489727570091712512, + 489802293404246016, + 489813774707458049, + 488993118684200960, + 490179684748251137, + 490905358140178433, + 489807680396337152, + 490490751822741505, + 491404774253031424, + 490130986454110209, + 490887577637904384, + 490865792192634880, + 490114348783005696, + 489349747950768128, + 490448962751827968, + 490121144092356609, + 490575525686300672, + 490821054542012416, + 490859774582726657, + 490891006305239040, + 489371292010053632, + 490473785519538177, + 490856966332645378, + 490126930092781568, + 488959346911760385, + 490907093336326145, + 490832358581739520, + 489353392008220672, + 490034745506803712, + 487561335648321536, + 490910717126901760, + 490827335587749889, + 490904834015768576, + 489395679337660416, + 489739364592017408, + 490246811681312769, + 490091804487061504, + 490889074656698368, + 490501602277871616, + 489026429372600320, + 489819511294812163, + 490072699663028224, + 489704991066980352, + 490932334490034176, + 490171690492903424, + 490094222348132352, + 490070055951298560, + 490151209781968896, + 489725144722853889, + 490480482111733760, + 490503202706849792, + 490119646407032832, + 490481475016732672, + 489752400412946432, + 490068985216761856, + 489429954103230465, + 488624338627997697, + 490820019983761410, + 488642107243233280, + 490854861559574528, + 490819411935494144, + 489693617267961856, + 490089005040410624, + 490504455448576001, + 490810463173619712, + 490861268002430977, + 490205704700313600, + 490804664510586881, + 489784999953334272, + 489030287738044416, + 488808296934285312, + 490941668296630272, + 490150258316673024, + 489684839650852864, + 490091354455035904, + 489712606438236160, + 490481941737525248, + 490463546665607168, + 490858191874691072, + 490856227518545921, + 489757144158593024, + 489696687993389056, + 489758942806167552, + 490134370070855680, + 490913045250441217, + 492255382060818432, + 490055439997206528, + 487646621904412672, + 489716139938054144, + 490906733582487552, + 490910668489764864, + 490853408199692288, + 490787578006999041, + 489714049257836545, + 490201369446735872, + 490509242290679808, + 490901322028580864, + 490109306113888256, + 490509176461066240, + 490918095075422208, + 490899774720442369, + 490224732336566273, + 490114200333979648, + 490799026095546370, + 491481845679521792, + 490910827961409536, + 491241515252203520, + 490211962329268225, + 489689336523149312, + 488694910313582592, + 490956540732768256, + 489686066463780864, + 490900799200194560, + 490910365363232768, + 490150943561089024, + 490893677435564033, + 490914725253763072, + 490060226348195841, + 489788730014973954, + 489702416720596992, + 489723418074685441, + 490913092428374017, + 489848817081401344, + 489681349746630656, + 491034828817846272, + 490912306948476928, + 490907224660017152, + 489725199236218880, + 490444126937415680, + 489591381401145345, + 490846208869412864, + 490051356112474112, + 489682448146792448, + 490911063664107520, + 489436820762267648, + 490069218357182464, + 489724807475646464, + 491060255707914240, + 492557397194702848, + 490077942601773056, + 490898795677634560, + 488725148628189184, + 490061097127645184, + 490921308931104769, + 490914528440635392, + 490893036759822336, + 490968138763489280, + 489794551461462016, + 490917052572782592, + 488018827746484225, + 490416529746714624, + 491040624523894784, + 489751841144455169, + 487433097416568832, + 489688969542901760, + 490440776959397888, + 490906066322878464, + 490911332787429376, + 490917582833057792, + 490043396753739776, + 490961971022667776, + 490910897238323200, + 491622216161718274, + 491020987992141824, + 489672765298184192, + 489487389522661376, + 489476489952645120, + 490890721927639040, + 490687542447341569, + 488485071494447105, + 490765590941171712, + 489841399094071296, + 490910048499949568, + 489092843785314304, + 489424282511220736, + 490937054050914304, + 490917421977702401, + 489098143460773888, + 489731867462365184, + 490545287006388224, + 490812531418877953, + 490201248646578176, + 488060376354127872, + 490933589690023936, + 489507444704681984, + 490043926079111168, + 488747624913444864, + 489767118213091328, + 487683250522161152, + 490886606770155520, + 489046456117264384, + 491190132473462785, + 489743979546951680, + 490062423433703424, + 490239481275236352, + 490055003714125824, + 490912189747048449, + 490485711339270145, + 489812783744028672, + 487662860391440385, + 490911303427715072, + 490670427828936704, + 490052085288034304, + 490910707563913216, + 487706945194057728, + 490214458271473665, + 489961507305054208, + 490923639693672448, + 489948419201699841, + 489923507375984640, + 487806779888132096, + 489514148829487105, + 488317234494701569, + 489753893564198913, + 489681369199411200, + 490411300216770561, + 489470186794528768, + 487315394324340736, + 488690142178058242, + 489678737328599040, + 490763317594849280, + 490887748384206848, + 490914137913184256, + 490231912787886080, + 490909859777622017, + 490741898450325504, + 489365785584750592, + 490165673557913602, + 488852703599407104, + 488747763224805377, + 490210740834684929, + 490298980312821760, + 490858181493813248, + 490243216181313536, + 490654828960694273, + 490149117172011008, + 490873414555824128, + 489453224001159169, + 490533381491286016, + 490517675223695360, + 490901077378625536, + 490333961957408768, + 490922908714545152, + 490530531520430080, + 490912757340852224, + 490918155733454849, + 490527606371282944, + 490853588147929088, + 490134410889805824, + 490958694201712640, + 491217284762206208, + 490509841908379648, + 489585527390490624, + 488869309473882113, + 490857353827594241, + 492617766869155840, + 489680924192161792, + 491022654825316352, + 490512517701984258, + 489761049001095168, + 490892690775896064, + 491166696670236672, + 490910677553655808, + 493465569849769984, + 489569928216051713, + 489818565743484929, + 491030718647402496, + 490851997604904960, + 490911026901450752, + 490832247851716608, + 490892837501018112, + 487952873435578368, + 490571673532641280, + 490507607396720640, + 490569011235536896, + 491326689238978561, + 490513827679961088, + 488404635280228352, + 488858362055258112, + 489744308657213440, + 489591568563597312, + 489505294968700928, + 490903580279578624, + 489662454104748032, + 490958314034196480, + 490577192129421312, + 490912890204205056, + 493514488478707712, + 489563990302158848, + 490857150600577024, + 490574281508933632, + 490915574357446656, + 490852769348472833, + 489668288881102849, + 490214078145908736, + 493479710186565632, + 493495351706664960, + 493480311771394049, + 489003133004423168, + 490889867145273344, + 487418667450122240, + 490862055298461697, + 493445975965708291, + 490796976431452160, + 490761660970569728, + 491132220066004992, + 490414523711758337, + 489749007573348352, + 490094215788240896, + 490228269187600384, + 490849484092755968, + 490872897452662785, + 490819131101700096, + 488426573214011393, + 490932298087690241, + 490241443219656704, + 490200089106075648, + 490483197801533441, + 493428601766039552, + 490549138459992065, + 489485985072558080, + 490911996607758336, + 490882194651746304, + 489367591497256960, + 488355879394107393, + 493461299108798464, + 490117790901497856, + 490882483571793920, + 493473401705865216, + 490892824423178240, + 490034687356579840, + 493427603064487936, + 488796387568402432, + 489743276820676608, + 490425484543795200, + 493478562503348224, + 490477522879254530, + 490870778863570945, + 490127570277769216, + 493112770788098048, + 490912340695842816, + 490511422946701315, + 490916565714759680, + 489450682252935171, + 493451387091836928, + 490817001582243841, + 489644649087504384, + 491152685937467392, + 493442698809196544, + 490914179197698048, + 493115960568844288, + 493391720823144448, + 488719206389915648, + 489470877075898368, + 490188251031142400, + 490505220007665664, + 489740678243819520, + 490487369951633408, + 490207631769096192, + 489851156483813376, + 490895020397170689, + 493459304780169216, + 490894909399138304, + 489499366143832064, + 490987018369761280, + 489071935528386560, + 490467417655898112, + 490442488738775040, + 490893399223201792, + 489443379768729600, + 490456476000219136, + 490893782594768896, + 493477912063279104, + 490882873034285056, + 490910938393227264, + 490511245251211264, + 493468855600427009, + 490470614562373632, + 490539063540060160, + 493103883632140288, + 488424127951540225, + 490859209232494592, + 490424922892947456, + 487685390342828032, + 490897570609106945, + 491248501469503488, + 490908893074427904, + 490509814074990592, + 487702065360027649, + 493481903618392065, + 488951352131735552, + 493455279678574592, + 490499772210348032, + 490923892652134400, + 488436105466089472, + 490594435260882944, + 490925293436416000, + 488456570314182657, + 490535475149811712, + 489872172463423490, + 490052896848101376, + 490917454575849472, + 489781973758795776, + 490509411627323394, + 490615063175512064, + 490523320606281728, + 490435889412046849, + 488433187199397890, + 488066731462909952, + 490910745161633792, + 488056957279154177, + 490234220825296896, + 490570817873657856, + 490471752938823680, + 490486556021764096, + 490478798245494784, + 488431905109712896, + 489858834643423233, + 490839603952517120, + 490821375993851904, + 489886764442869762, + 488438355995004928, + 487136252303773696, + 490854575810039808, + 490820992269570048, + 490910691281604608, + 490176682129514496, + 488426512002326529, + 489632130214146049, + 490193348809211904, + 488042227542016001, + 490441922251866112, + 489797686460047360, + 490193466232950784, + 492003717781417984, + 489880260721532928, + 490850637899653120, + 488444762069164032, + 493078636543893505, + 490885715983884288, + 489132795261120513, + 490914650653855744, + 490178077935538176, + 490911782957891584, + 490504993813041152, + 489769102995890176, + 488407383740542976, + 490397632247136256, + 490103066604351488, + 488409151039881218, + 490131672491626497, + 490186997894377472, + 489814288542879744, + 490913689172602881, + 490907967248936960, + 490911969625792513, + 493137658517139457, + 490234737731305474, + 490888937863278593, + 490894588610347008, + 493108568447414274, + 488411543793827841, + 490250159713185792, + 490911615165140994, + 490803805642973184, + 490987633779027968, + 490894584558649345, + 490929829781331968, + 490452109117390848, + 489735531216265216, + 489068069197979649, + 488773549013090304, + 490917617449041921, + 490497727001010176, + 489711124867461122, + 490506547878187010, + 490899984016216064, + 489620649652916225, + 488071687905509376, + 490780356476665856, + 490911870745067521, + 487681211863932928, + 490167261253357568, + 489686546376060928, + 490906834690408450, + 490503198701268992, + 487284117940482048, + 489098325950754816, + 490242120989827072, + 490499601582284800, + 490904159143886848, + 490216691109232641, + 490143107418447873, + 490428708470390784, + 490914717201096705, + 489720908744261632, + 488080722289496065, + 488413032012595200, + 493150630329221121, + 490435736710418432, + 489769241852526593, + 489512273262563329, + 489752084762218499, + 487225983792336896, + 490910813989789697, + 488002420556177408, + 489771941004193793, + 489071229673168896, + 490795365839679488, + 488429363461758978, + 488634576592703488, + 490841783639633920, + 490912844674629633, + 490912426473562113, + 490905906058518528, + 490898690463105024, + 492385623064727552, + 490916719637299200, + 490913652506370048, + 490918658529431552, + 490263496329007104, + 490242227713892353, + 490161739292364800, + 490860522926243840, + 491128993174024192, + 488071425732149248, + 490025546441830401, + 489796390944792576, + 491161197342117888, + 489717506584498176, + 490223678094073856, + 490910950976159745, + 488077340703219713, + 489785348286078976, + 493153400025251840, + 489831404851576832, + 490847006647021568, + 490436150856015872, + 490555004571623424, + 490913578070073344, + 490928092282494977, + 489462391147474944, + 490076416500064257, + 490869894368354304, + 491014404931330048, + 490938893970448386, + 490499293099216897, + 489682571882938368, + 490836278477615104, + 490912297229893633, + 490910587850067968, + 489653098047340544, + 490909653975310336, + 490420208373223424, + 489796170684702721, + 488746114720739329, + 489770890478231552, + 490121002610081794, + 490133235939434497, + 489171048253120512, + 490939720500002816, + 490956758446534656, + 490535634042224640, + 490900961460645888, + 490407412273147905, + 489639318307094528, + 490444126329245696, + 490876217860845568, + 489653385915039744, + 490850511185543168, + 490029773339762689, + 490887061659209728, + 492406246730104832, + 492015299647275008, + 490911462207258624, + 490128198034673666, + 490065304165576704, + 490913656742236163, + 490120439252123648, + 488354627327647744, + 490446147342073856, + 490840522450141185, + 490902071642959872, + 490080731277058048, + 490142383129255936, + 489336443660410880, + 490510137719668736, + 490826390624034816, + 490908628250275840, + 490905961029042177, + 489748128019406850, + 491258868451012610, + 489807486270988288, + 492433638651625472, + 490923869466001410, + 489869324942077952, + 490894065819738112, + 490944990508777472, + 490839174820683778, + 490188082453286912, + 490421886388817920, + 490844247273525249, + 490447051084529665 + ], + "top_users": [ + "26257166", + "265902729", + "14063426", + "53120768", + "471287735", + "2557521", + "108568373", + "14387275", + "26981013", + "2327369137", + "890891", + "105119490", + "7589572", + "47945492", + "28534252", + "166767883", + "171117515", + "299201079", + "83689988", + "86230406", + "37360915", + "55809761", + "19230601", + "81856710", + "216299334", + "75014376", + "218349448", + "43641364", + "24277551", + "113712551", + "17386885", + "517657650", + "217536107", + "435225922", + "19292816", + "95465386", + "53639654", + "26829777", + "43139414", + "249154446", + "31447081", + "216264820", + "75772415", + "197418586", + "234521957", + "279321785", + "71022075", + "270949258", + "558797310", + "257013116", + "2447235019", + "19964983", + "5402612", + "32073913", + "91968975", + "72899120", + "243731008", + "28569392", + "37290954", + "352947624", + "144130505", + "155642429", + "55246492", + "188039706", + "437700198", + "32717570", + "212256947", + "22449520", + "326179750", + "46390648", + "103185664", + "331311644", + "1543364688", + "740336334", + "247437542", + "807095", + "488011724", + "2412757700", + "283894108", + "20463402", + "1115127925", + "9570452", + "21771530", + "1667654144", + "493127463", + "2390790188", + "153118706", + "538031518", + "19339713", + "388233363", + "263257931", + "1329138481", + "590316679", + "271106411", + "87416722", + "518090552", + "75974281", + "44588984", + "171404842", + "96966644" + ] + }, + { + "country_breakdown_percentage": {}, + "country_code": null, + "device_breakdown_percentage": {}, + "end_time": "2015-07-19T00:00:00Z", + "event_type": "SPORTS", + "gender_breakdown_percentage": {}, + "id": "2d", + "is_global": true, + "name": "\u65e5\u672c\u30d7\u30ed\u91ce\u7403\uff1a\u30de\u30c5\u30c0\u30aa\u30fc\u30eb\u30b9\u30bf\u30fc\u30b2\u30fc\u30e02015 (Japanese baseball: Mazda all star game)", + "reach": { + "total_reach": null + }, + "start_time": "2015-07-17T00:00:00Z", + "top_hashtags": [], + "top_tweets": [], + "top_users": [] + }, + { + "country_breakdown_percentage": { + "AE": 0.16, + "AL": 0.02, + "AM": 0.02, + "AR": 0.05, + "AT": 0.02, + "AU": 1.21, + "BA": 0.02, + "BB": 0.02, + "BD": 0.05, + "BE": 0.09, + "BN": 0.02, + "BO": 0.02, + "BR": 0.37, + "BS": 0.05, + "BY": 0.02, + "CA": 4.02, + "CH": 0.05, + "CL": 0.27, + "CO": 0.18, + "CR": 0.05, + "CY": 0.02, + "CZ": 0.02, + "DE": 0.48, + "DK": 0.02, + "DO": 0.09, + "EC": 0.11, + "EG": 0.23, + "ES": 0.84, + "FI": 0.02, + "FR": 0.59, + "GB": 16.25, + "GI": 0.02, + "GR": 0.11, + "GT": 0.02, + "GY": 0.02, + "HK": 0.02, + "HN": 0.02, + "HU": 0.02, + "ID": 0.37, + "IE": 1.1, + "IL": 0.07, + "IN": 0.43, + "IQ": 0.05, + "IT": 0.43, + "JE": 0.02, + "JM": 0.09, + "JO": 0.11, + "JP": 0.96, + "KE": 0.07, + "KR": 0.02, + "KW": 0.25, + "KY": 0.02, + "LB": 0.05, + "LC": 0.05, + "LK": 0.05, + "LU": 0.02, + "LV": 0.02, + "LY": 0.05, + "MA": 0.02, + "MX": 1.26, + "MY": 0.41, + "NC": 0.02, + "NG": 0.11, + "NI": 0.07, + "NL": 0.16, + "NO": 0.05, + "NP": 0.09, + "NZ": 0.11, + "OM": 0.02, + "PA": 0.02, + "PE": 0.14, + "PH": 0.78, + "PK": 0.16, + "PS": 0.05, + "PT": 0.02, + "PY": 0.02, + "QA": 0.02, + "RO": 0.02, + "RU": 0.02, + "SA": 1.12, + "SE": 0.07, + "SG": 0.39, + "SK": 0.02, + "SR": 0.02, + "TC": 0.02, + "TH": 0.16, + "TR": 0.18, + "TT": 0.07, + "US": 64.0, + "UY": 0.02, + "VE": 0.16, + "VN": 0.05, + "ZA": 0.23, + "ZW": 0.02 + }, + "country_code": "US", + "device_breakdown_percentage": { + "ANDROID": 10.64, + "BLACKBERRY": 0.05, + "DESKTOP": 36.55, + "IOS": 52.47, + "OTHER_MOBILE": 0.29 + }, + "end_time": "2015-07-20T00:00:00Z", + "event_type": "SPORTS", + "gender_breakdown_percentage": { + "female": 30.2, + "male": 69.8 + }, + "id": "3j", + "is_global": false, + "name": "WWE Battleground 2015", + "reach": { + "total_impressions": 41646974, + "total_number_of_tweets": 516824, + "total_reach": 2497330 + }, + "start_time": "2015-07-19T00:00:00Z", + "top_hashtags": [], + "top_tweets": [ + 490964574678827008, + 491025934128914432, + 491044529798397952, + 491048560046379009, + 490819117100711937, + 491049717388685313, + 491058636613902336, + 491046150917861376, + 491052682090938368, + 491088854284513280, + 491045303051882496, + 490911575428313088, + 490189078810222593, + 491052921631424512, + 490924521025986560, + 491054393312432129, + 491057447109279744, + 491041529440780288, + 490918799638810624, + 491059949385306113, + 491053100799885312, + 491045108205109250, + 491045145656057859, + 491016185811853312, + 491055996370841601, + 490966653543657472, + 491049113207570432, + 491048507327791104, + 491037399502172160, + 491047572090265602, + 490975992966434816, + 491027421567524864, + 491044017061126144, + 491070072543518720, + 491044371694112768, + 491014051640905729, + 489235977089851392, + 491050769672855552, + 491055442504581120, + 490948428080246785, + 491028846846541824, + 491045952321781760, + 490700632043438081, + 491031626185338880, + 491060285974011904, + 491030244514463744, + 489095606283952129, + 491160718918836224, + 491091407696707585, + 491038716379426817, + 491046758320205824, + 491100324997124096, + 491049044324519936, + 491048221649952770, + 491016783714066432, + 491054749735596033, + 491045032690843648, + 490828812478058496, + 491236747008032768, + 490881367941873664, + 491270088096354305, + 491132218299789312, + 491039757795721216, + 490677686268735489, + 491047824969060352, + 491030822615412736, + 491043494862266368, + 490927788493271040, + 490956857838940161, + 491029854251667457, + 491055050358153216, + 491028448991653888, + 491033720338382848, + 491018983735574528, + 491043170122092544, + 491296675345207296, + 490941782042361856, + 490846033141043201, + 490866268564885504, + 492096896576786433, + 488498455417868288, + 490073566608887808, + 491020713651085313, + 491037282833416193, + 490435953295908865, + 491032117296386048, + 491019771761405952, + 491031973125980160, + 491130494898438144, + 490896508032921600, + 491041285189287936, + 491190935360122880, + 491037937841475584, + 490316130398248960, + 490858910937788416, + 490971991839870976, + 491462702309847041, + 488933962056994816, + 491035931223556096, + 491033811900448768, + 490934412163698688, + 491031638298853376, + 490677682917883904, + 491035277612179456, + 490289619536449536, + 490669499738124289, + 491553346369888258, + 491492893673402368, + 491523138027786240, + 490892815707033603, + 489096429659377666, + 491021235766456320, + 490973686933884928, + 491432498690523136, + 490949739676827649, + 490496770095321088, + 491034014183342080, + 489258202891296768, + 491019883933880320, + 490939654213238784, + 491038927672049665, + 491311833257893888, + 490938593188528128, + 490899806617751552, + 491025736900558848, + 491023105679446017, + 490647537393893376, + 490889392999768066, + 490932626656489472, + 491019559269183488, + 491219052266659840, + 491025900356382720, + 491021485171949568, + 490315478749810689, + 488847863158693888, + 490904051115368448, + 488880508739534848, + 488878060742397953, + 491021865549570048, + 491014285573644289, + 491906904562491392, + 490926652877463552, + 490893909300486146, + 491271798793584641, + 490895385611616256, + 490311391807799296, + 489922928163962880, + 491025101886746624, + 490883118254260224, + 491033754610044928, + 489826537332432897, + 491015363619201024, + 489455460802506752, + 491030199098556416, + 490526739551232000, + 490949487137800192, + 490556773875863552, + 490587110458392578, + 490572280678719488, + 490992409048649728, + 491047589593104387, + 491248129690185728, + 491033986169188353, + 491012704224968704, + 490919546467782656, + 490985789669388290, + 491013666234728448, + 491251814361485312, + 490311368394805248, + 490979755739455488, + 490889134232596480, + 491017191362293760, + 491303513415094272, + 488376677257728000, + 491221130645340160, + 490990455182483457, + 490919296168493056, + 491014337037746176, + 491012059694632960, + 491091968424833024, + 491015188972597248, + 490988423147032576, + 490964774721961984, + 491015400746795008, + 489493236436987905, + 490526712456048640, + 491050734658416641, + 491018933307056130, + 489160046102982656, + 490239683147096065, + 491071654274285569, + 490232220138102785, + 490969582182887424, + 491011566603894786, + 490987146611019776, + 491953424033132544, + 491010707102527488, + 490978541375598592, + 489838655351959553, + 489061876895342592, + 491265113291501568, + 491009833223868416, + 489054303035084800, + 489107210786848768, + 490133984618487809, + 489809407165743105, + 490149479874838528, + 491308456775663616, + 491010778154401792, + 489839527239102464, + 488836222232829954, + 490242476393779200, + 491011130534268930, + 492044261140230145, + 492391363367825408, + 491016734485139456, + 491262308455178240, + 489771650037321728, + 490307770852184064, + 490149734964015104, + 491052824122228736, + 490982490220154880, + 491057542341345280, + 490184208015319040, + 488796035607572480, + 490262284531695616, + 491045587588874241, + 491011952890896384, + 491379404174798848, + 491051964310908929, + 491052633465962497, + 490177469169688576, + 491624896401666048, + 489089005250949120, + 491012307590610945, + 491066916002205696, + 490994893678850049, + 489175139180097538, + 491027263895252992, + 490270252513902592, + 490998409399386114, + 490994703287214080, + 491033356419616769, + 491050836387053568, + 491013632176566272, + 491024891110371328, + 491004017288687616, + 491000715985584128, + 491035152269602817, + 491050288065695745, + 491048450771804160, + 491049664553033728, + 491063099294633984, + 491037602330320896, + 491021752563036160, + 491041048458584064, + 491053074077605888, + 491048210408812545, + 491022529130016768, + 491029769312428033, + 491044290961739776, + 491031851423653888, + 491028765397356544, + 491038909782974464, + 491019281367171072, + 491040487571079168, + 490887913035403264, + 491018421354516480, + 491031690072952833, + 491016945450229760, + 490995133966712833, + 491010180029497344, + 488816708543463424, + 491024376834183169, + 490873976517054464, + 491030957059629057, + 491051456187731970, + 491021751187685376, + 490926804266663937, + 491050895183183872, + 490844927618600962, + 490155814506594305, + 491495229384441857, + 490926718811504640, + 491188633219522560, + 491038145912508416, + 491088217408413697, + 490910047040319490, + 492685725502930944, + 491002509779951616, + 491031434535387136, + 491016490171506688, + 491051432142204929, + 490617184721199104, + 491052501664145409, + 490578012031950849, + 491044032512917504, + 490872699401826304, + 488138968668454912, + 491004803875868673, + 491002294465343488, + 491041859796353024, + 488830694458544128, + 490932744931639296, + 490922716770623488, + 491035051765673984, + 491003686986846209, + 491004941503594496, + 491057683638652929, + 489213294645764096, + 491033442591993857, + 491048165508784129, + 491024383499333633, + 491365411485925376, + 491287316791828480, + 491050219195211777, + 490955522372149248, + 489533509610921985, + 491029702111674368, + 491032929603444736, + 491046344086130688, + 491002178874904577, + 491040339168215041, + 491003898069798912, + 491041685900513282, + 491030196515258368, + 491003210543296512, + 491047134167171073, + 491013744701734912, + 490912711278997504, + 491039939010637824, + 491024302456569856, + 491012774466560001, + 491002984143155202, + 491018650552254464, + 491032153476460546, + 490696346316201984, + 490935895554416640, + 491004244120846336, + 491025114335436800, + 491007518899175424, + 491016313611894784, + 491254574204739584, + 491016299560988672, + 491018573541019648, + 491022183062204417, + 491028427785666560, + 491046813126770689, + 491038117185335296, + 491020031845617666, + 491032946703220736, + 491251024468799488, + 490224106231853056, + 491018196414373890, + 491027944785969152, + 491061853901299712, + 491047742571962368, + 491028812046413825, + 491036770377945088, + 491055480358584320, + 491050882113351680, + 491029199549763584, + 491110304126750721, + 491005038081638400, + 491036114623676417, + 490515352036454400, + 490627937373155330, + 491036705236209664, + 491012817705652225, + 491010980613070848, + 491002579548381185, + 488870569904189440, + 491022603952205824, + 491043580283072513, + 491037492502474754, + 491046168466432000, + 491026523399262209, + 491049699319615488, + 491030498840281088, + 491036932508352514, + 491019191554945024, + 491018521606770688, + 491036265244917761, + 491025262390566912, + 491021084557197312, + 491045311297495041, + 491039130910855169, + 491027360301338624, + 491046182488006658, + 491020432254832640, + 491042988504526848, + 491066244406460416, + 490977476873441280, + 491035222415142913, + 490966739203538944, + 491028490574364672, + 491066991529050112, + 491040402988728324, + 491038618736398337, + 490647538723463168, + 491006921042710528, + 491023179842732032, + 491050911045672960, + 491018900461481984, + 491047002277695488, + 491014477291470848, + 488878501282729984, + 491011849559617536, + 491020304576413696, + 491034723481706497, + 491022915463557120, + 491052580899131392, + 491006086229417985, + 491038063850577920, + 491042700116774912, + 491021651664850944, + 491017301576011776, + 491056282292715520, + 490122451813036033, + 491015868055175168, + 491158002058399745, + 491023694198607873, + 491024699162238976, + 491019412116217856, + 491050116862595072, + 491001273484066816, + 491020044936032256, + 491055959096438784, + 491033680744157184, + 488837423678640128, + 491015239576481792, + 491004632039059456, + 491010511966703616, + 491018083478147072, + 490314745547743232, + 491039074384228352, + 490496767109369856, + 491045757324365824, + 491038805344796672, + 490889137327996928, + 491050067537973248, + 491016885224218626, + 491010934828044288, + 491319499472527360, + 491017368135794688, + 491046204814684160, + 488831469960167424, + 490989760907706368, + 491040780694597632, + 491038298400628736, + 491057571650752512, + 490314925282435072, + 490999632189595648, + 491039491734261760, + 491039579365851137, + 490987167494070272, + 491058944014811136, + 491053212300890112, + 490937368506281984, + 491050550679445505, + 491028047093432320, + 491054741288681472, + 491041322313064448, + 491035373372706816, + 489140723359694848, + 491014705302237185, + 490979755630813184, + 491012403870437376, + 489150757263130624, + 491274753546522624, + 489151782036074496, + 491052470504681472, + 489145420627456000, + 491054415663882240, + 491046454442852352, + 490828812247379969, + 491061219915485184, + 489859203222503425, + 491011399275905024, + 491013395592671233, + 491037406452129793, + 489147451048488960, + 489146423628554240, + 491014213049917440, + 491199389042372608, + 491059454948159488, + 491044985593421825, + 491001159042101248, + 491033747098042369, + 491044933701480448, + 490669055485833218, + 491041514257014784, + 492115509320876032, + 490149481032478720, + 491022751478845441, + 491048033463721984, + 491038762428674048, + 489144393019162624, + 491044600073961473, + 491023040613208064, + 491013931247210497, + 491014906456850432, + 490935344322207744, + 491052604009750531, + 491030814054830080, + 491022141014704128, + 491052573076385793, + 491024685543354370, + 490669575449481216, + 491043871262920704, + 491039734278668288, + 491185541711269888, + 491058283323875329, + 491071754845294592, + 490991781429788672, + 491032289980059649, + 491044313984684033, + 491024165814562816, + 491052517464084480, + 491044504535703552, + 492142221013946368, + 491014907845181440, + 491033472643780608, + 491056410218614784, + 491022124061310976, + 491053053169381377, + 491002908893130752, + 490996848421634048, + 491059595704414208, + 490949486324498432, + 491038270093295616, + 490846145133150209, + 491219460754530304, + 491032400806551552, + 490844804201594880, + 491053506028388352, + 488855454445867008, + 491024077092818945, + 491067280210821120, + 491032088317927424, + 491041370895679489, + 491002678772629506, + 492097001157570562, + 493005623827902464, + 491016983589031936, + 491019404009025536, + 491048596368662530, + 491027985873391617, + 491044901359222784, + 491053000623157248, + 491055487874785280, + 491055227278479360, + 491042687051522048, + 491028071236251649, + 491082342044160000, + 491002715347365888, + 491030802281807872, + 491011139044507649, + 491046673905225729, + 491051648891244544, + 491055001544830976, + 491037618768195585, + 491054016626167808, + 491058783968575489, + 490875639927693312, + 491038175251292161, + 491035758103261185, + 491052236311523328, + 491050379183128576, + 491008895520079873, + 491052591246503936, + 491010956776837120, + 491054698372554753, + 491037369391677440, + 491053412407332865, + 491024492483710976, + 491048640547270656, + 488841063004532738, + 491039230827966465, + 491056182363426816, + 491045329790197760, + 491024061255122944, + 490997010128838657, + 491086078539862016, + 491051090008625152, + 491021763887644672, + 488859775443415041, + 491045487878078464, + 491043443075198976, + 491022733246230529, + 491028181529686016, + 490810932168511488, + 491049534748106752, + 490954150239539200, + 491052556001755136, + 490587109561233409, + 490972361076662272, + 491044530909483008, + 491044888067457024, + 491044297509445633, + 491033328951103488, + 491041349987074048, + 489983764001734656, + 493139015978463232, + 491052823443152896, + 491002382537351168, + 491055214745497600, + 491039395252666368, + 491052337763741696, + 491057405024018433, + 491032723205525504, + 491017173154816000, + 490997814600536064, + 491379618704658432, + 491044384977080320, + 491017490168705024, + 491071861053083648, + 491008467269062656, + 491040873732251649, + 490089601919250433, + 490956634378612736, + 491024902430801920, + 491037348956618753, + 491055059762159616, + 491009824709435392, + 491016493308461057, + 491044026456371200, + 491043156461236224, + 491026895052361730, + 491001214281076736, + 490962502965264384, + 491044673658847232, + 491048670775623682, + 490994703333351424, + 491017457474088960, + 490991741437104128, + 491046017618280448, + 491028451592110080, + 491135551815573504, + 490880826834296833, + 491063060116029441, + 491047143718002688, + 490907074239291392, + 491029230260879361, + 491032498122412032, + 491051315703721984, + 491011895780864001, + 491057989923512320, + 491023416003031040, + 490849349887614976, + 488846581769453568, + 491050832377286656, + 491052617813217282, + 491382389302886400, + 489991943057719299, + 491010110899388416, + 488962269657567232, + 491047090370674688, + 491053761784446976, + 491004705519042561, + 491037220439334912, + 491043630275371009, + 490957262543126528, + 491032166956924928, + 491048690098790400, + 491305486231543808, + 491021446487871488, + 491050241504727040, + 491037303515938816, + 491013022169972736, + 491048784613228547, + 491152538142404608, + 491049928555126784, + 490981359109025794, + 491047562002972672, + 488880496878043137, + 491048731895033856, + 491038356327788544, + 491031769991634946, + 488847867281281024, + 491030932162629633, + 491017057505648641, + 490823813756878848, + 491018687541833729, + 491053180151939072, + 491039405436862464, + 491037572483670017, + 490272413016662019, + 491023209232609283, + 491072998342811649, + 491016913443889152, + 491058477079334913, + 491052819739582464, + 491021359971966976, + 491325788814594050, + 491045600402493440, + 491030326844481537, + 491043950233264129, + 491041150837739520, + 491043729374195713, + 491044522806484993, + 491066707071729664, + 491048692041154561, + 491036184727261184, + 491059636150083586, + 491596416863989761, + 491044925702938624, + 491005662684798976, + 491022197449056257, + 491055547156680704, + 491048681379201024, + 491018479261478912, + 491053080423972865, + 489414270107807744, + 491052385805283329, + 491039326344450048, + 491048740187553792, + 491039846287552513, + 491002179772104704, + 491043823259484160, + 491048717089116160, + 491055266775842816, + 491004877523668992, + 491046655974965248, + 490912408609632256, + 489437403044909056, + 491061753468706816, + 491021077045579776, + 491053291137404928, + 491018335166148609, + 491016302681931776, + 489082289121681408, + 491003362507522048, + 491031484049141760, + 491018873068466176, + 491054036603641856, + 491031602651099136, + 491051567953358849, + 491075240173121536, + 491019734528581632, + 490952196922408960, + 491021317937061889, + 491310075844501504, + 491017476873146368, + 491020261492539393, + 491043256416096257, + 491016768442613761, + 491045621605089280, + 491052970331873281, + 490983544463060994, + 491033360056475648, + 491046308711772160, + 491041510453182464, + 490964713556443136, + 491021629632167937, + 491040401001046016, + 491052431678009344, + 490981199087951872, + 490854007808614400, + 491024533064015874, + 489828838919385089, + 491049264865624064, + 491055216318365696, + 491035060796018688, + 491051528049143808, + 490628673939456000, + 491050606694793216, + 491001868080799744, + 491038341886799872, + 491024609358389248, + 491244266455564288, + 491033189788680192, + 491039442963296256, + 491027985353297921, + 491374528585416704, + 491020014653558784, + 491045258424500224, + 491009905235881984, + 491052526108950529, + 490836035128287232, + 491032991830130688, + 491027655978799104, + 491025271706095616, + 491043241559470080, + 490940172792782848, + 491010858131001344, + 491019250308763649, + 491035586229444608, + 491699045958946816, + 491015346493472768, + 491023334235451393, + 491050469721403392, + 491071965549957121, + 491037165028388864, + 491021664285917184, + 492050604316184577, + 491022379498631168, + 491032641005948929, + 488886266952699905, + 491018779506139137, + 491022287920173056, + 491023875334209536, + 491420607234723840, + 491026011916488704, + 491049103955333121, + 491052393426354176, + 491044384721604609, + 491030588447801344, + 491041216956755968, + 492311143013449728, + 491038012198125568, + 491018488950300672, + 491046592993320961, + 489614376803262464, + 491015598457905152, + 491052048398295040, + 491040161099436033, + 491052338358919168, + 491042214190260225, + 491021052601200640, + 491006475049762816, + 491990737509425152, + 491054589525778434, + 491027221772259328, + 490868693665325056, + 491052125443477504, + 491026084486717441, + 491047455199621122, + 491050206222245890, + 489076002341941248, + 491020444385177600, + 491026007647068160, + 491027530292666368, + 491049933714120704, + 491031264887988224, + 490855062495707137, + 491044865065512960, + 490897108191682560, + 490834205543530496, + 491040082716266496, + 491030840688640000, + 491020439444279296, + 491028407640403968, + 491043323918819328, + 488838090686234624, + 491031258579759104, + 491015023528280066, + 491032502568767488, + 491026081529741312, + 489072403528814592, + 491300095808512000, + 489838469473390592, + 491015389737123840, + 491028220909981697, + 491048319935070208, + 491026002349670402, + 491019974643687424, + 491053421886447616, + 491306572162027520, + 491025199484370944, + 491218329064185856, + 490941921985306625, + 490887203015626752, + 491028604772708352, + 491016154664931328, + 490985053183152128, + 491044234690961408, + 491040745642405888, + 491051969231192067, + 491043344634880000, + 491296959295406080, + 491067934651858944, + 491023606156369920, + 491044009276874752, + 491032430770679808, + 491027947625512961, + 489084120530571265, + 491033610347364352, + 491044761122652160, + 491024382513651713, + 490869762574921728, + 491044014029012992, + 491056403956924416, + 491026452008431618, + 491044086728495104, + 490946030570315776, + 491042971609862144, + 490505002646245376, + 491296584563720192, + 491053892973506561, + 491042866269937664, + 491017115940290560, + 490883263552962561, + 490998782159765505, + 491046765345267712, + 491054145789771776, + 491026012725989377, + 491061759076499456, + 491058344988119040, + 491019279479754752, + 491019218632974336, + 491032481626619904, + 491042921576427520, + 491933929965109248, + 491048867639459840, + 491062145237282818, + 491039416052240384, + 491031662130507778, + 491065615314989056, + 491043095685763072, + 491019234915672064, + 490921423733399552, + 491036811960274945, + 491035435624198145, + 491030020337729537, + 491041589016276992, + 491047988714684418, + 491048759216713729, + 491030525742571520, + 489394248387547136, + 491026097144754177, + 491030687534055424, + 491080125149356032, + 491296789790998528, + 491025145180323841, + 491018626481528832, + 491269301647990785, + 491046983457845248, + 491040386307985408, + 491042997430390784, + 488301961859842048, + 490504666388910080, + 491085069667553280, + 491029064707489792, + 491044174058496000, + 491039586957541376, + 491016916845481984, + 491054078781186048, + 491031188673658880, + 491102369938042880, + 491044160984469504, + 491040501437440000, + 490987737932369921, + 491012173791895552, + 491028146641059840, + 491292090987716608, + 491024680304664577, + 491228044431204352, + 491051791480782849, + 491296885551161344, + 491030619476881409, + 491044239938420736, + 491043061250539521, + 491026052907405313, + 491030197257654272, + 491050975298605056, + 491011477621329921, + 491046065744125952, + 491050342554292224, + 491037596089200640, + 491016885442711552, + 491048389241757696, + 491046456799666176, + 491045323364892673, + 491039687570509824, + 491031039838789632, + 491024320110395392, + 491021711115304960, + 491011017615605761, + 491042913905025024, + 492372351246696448, + 491037255449182209, + 491057209694883841, + 491021697827340288, + 491026079486726144, + 491026060692434945, + 491045381841891328, + 491299958210199552, + 491009243773157376, + 491013124804206592, + 490994603760549888, + 491044664741359617, + 489030792321204224, + 491044434188849152, + 491020191137280000, + 491288761196498944, + 491009871089639424, + 491048323588317184, + 491016189075013632, + 491011804638625792, + 488858346103922688, + 491045691771600897, + 491021526993760256, + 491031472313470976, + 491018759591972864, + 492199736435560448, + 491054326425456642, + 491043633584279552, + 491173991156305920, + 491031785871253505 + ], + "top_users": [ + "7517222", + "228698447", + "23827692", + "15290441", + "368703433", + "68577152", + "436888973", + "20632300", + "73571504", + "57213267", + "249249080", + "470865922", + "28301551", + "221573745", + "43971053", + "17290098", + "355708717", + "44527648", + "89014429", + "168767461", + "366937615", + "17733320", + "2614708134", + "28265228", + "17929027", + "70725301", + "349157263", + "59319830", + "29206353", + "1284803784", + "40542150", + "43949085", + "2651708190", + "415953853", + "89556802", + "7376382", + "48623391", + "105251590", + "141664648", + "260294255", + "359099321", + "380482353", + "185384617", + "14387275", + "411936401", + "139188510", + "299926319", + "515722353", + "26568085", + "172887151", + "1241937762", + "27744721", + "104201555", + "54403121", + "1289482598", + "112915037", + "57391600", + "239095089", + "118483749", + "1641246398", + "433804134", + "241964676", + "45675029", + "17936412", + "42984662", + "732948073", + "216766313", + "115700178", + "52135300", + "629097517", + "1850388888", + "246160575", + "2194683961", + "93997039", + "2592634077", + "40082124", + "480577832", + "1681899386", + "298317641", + "115682368", + "16745015", + "29209028", + "257993504", + "26121271", + "43298203", + "339994434", + "14980903", + "739052749", + "168798952", + "131806073", + "34668551", + "36311369", + "307126928", + "1376315006", + "27027641", + "110895343", + "955885435", + "14515589", + "85450511", + "32117870" + ] + }, + { + "country_breakdown_percentage": {}, + "country_code": null, + "device_breakdown_percentage": {}, + "end_time": "2015-07-26T00:00:00Z", + "event_type": "SPORTS", + "gender_breakdown_percentage": {}, + "id": "2g", + "is_global": true, + "name": "\u9234\u9e7f8\u6642\u9593\u8010\u4e45\u30ed\u30fc\u30c9\u30ec\u30fc\u30b9(Suzuka 8 Hours Endurance Road Race)", + "reach": { + "total_reach": null + }, + "start_time": "2015-07-23T00:00:00Z", + "top_hashtags": [], + "top_tweets": [], + "top_users": [] + }, + { + "country_breakdown_percentage": { + "AE": 0.09, + "AR": 5.3, + "AT": 0.05, + "AU": 0.79, + "AW": 0.02, + "BE": 0.54, + "BG": 0.05, + "BN": 0.02, + "BO": 0.02, + "BR": 7.31, + "CA": 2.72, + "CH": 0.19, + "CL": 0.6, + "CO": 2.0, + "CR": 0.14, + "CY": 0.02, + "CZ": 0.02, + "DE": 0.35, + "DK": 0.05, + "DO": 0.12, + "DZ": 0.02, + "EC": 0.47, + "EE": 0.02, + "EG": 0.28, + "ES": 10.56, + "FI": 0.07, + "FR": 2.49, + "GB": 10.1, + "GN": 0.02, + "GR": 0.19, + "GT": 0.67, + "HK": 0.02, + "HN": 0.23, + "HR": 0.14, + "HT": 0.02, + "HU": 0.05, + "ID": 0.35, + "IE": 0.67, + "IL": 0.07, + "IN": 0.4, + "IQ": 0.07, + "IT": 0.54, + "JE": 0.02, + "JM": 0.05, + "JP": 4.98, + "KH": 0.02, + "KR": 0.05, + "KW": 0.12, + "KY": 0.02, + "LB": 0.07, + "LU": 0.02, + "LV": 0.02, + "LY": 0.02, + "MA": 0.02, + "MK": 0.02, + "MQ": 0.02, + "MT": 0.02, + "MX": 5.63, + "MY": 1.3, + "NG": 0.02, + "NI": 0.05, + "NL": 2.12, + "NO": 0.05, + "NP": 0.02, + "NZ": 0.07, + "OM": 0.02, + "PA": 0.16, + "PE": 0.3, + "PH": 0.81, + "PK": 0.09, + "PL": 0.09, + "PS": 0.05, + "PT": 0.4, + "PY": 0.63, + "RO": 0.02, + "RS": 0.02, + "RU": 0.26, + "SA": 0.37, + "SE": 0.72, + "SG": 0.67, + "SI": 0.02, + "SV": 0.16, + "TH": 0.37, + "TR": 1.7, + "TT": 0.02, + "UA": 0.02, + "UG": 0.02, + "US": 27.71, + "UY": 0.35, + "VE": 2.14, + "VI": 0.05, + "ZA": 0.19 + }, + "country_code": null, + "device_breakdown_percentage": { + "ANDROID": 18.89, + "BLACKBERRY": 0.08, + "DESKTOP": 36.8, + "IOS": 43.77, + "OTHER_MOBILE": 0.46 + }, + "end_time": "2015-07-27T00:00:00Z", + "event_type": "MUSIC_AND_ENTERTAINMENT", + "gender_breakdown_percentage": { + "female": 47.17, + "male": 52.83 + }, + "id": "1w", + "is_global": true, + "name": "Tomorrowland", + "reach": { + "total_impressions": 122426138, + "total_number_of_tweets": 4193759, + "total_reach": 11176262 + }, + "start_time": "2015-07-24T00:00:00Z", + "top_hashtags": [], + "top_tweets": [ + 490647488299548672, + 491261434337046529, + 492098498482143232, + 489767149989535744, + 490867432995561474, + 490412600061341696, + 491936005797462017, + 491037116697038849, + 490960426793197569, + 491090032640667648, + 494099324398489600, + 490209832931426304, + 490159038127034368, + 491281605005443072, + 490151000226156544, + 494315900703490050, + 490925007812300801, + 490557352844607488, + 490433219750141952, + 490956431638921217, + 493147571301666816, + 490958849709727745, + 492572672153620480, + 493368267659304960, + 490481474219823104, + 489825556717129728, + 490949082597572609, + 489353492298207232, + 491025533514166272, + 493022588596412416, + 491027771586797568, + 490476386029944832, + 490072553734803456, + 490480378571153409, + 490593193222627330, + 490247850736250881, + 490151848284680193, + 492823826686701568, + 494191452973711360, + 490402843216449536, + 493074867215159296, + 490295123327336449, + 490164614349737984, + 490797081410285568, + 490576453701210112, + 493468348177342465, + 490534020879753216, + 490571639696805888, + 490243592708165632, + 490257896500760576, + 490858928784564224, + 490558811561017344, + 489736137749975042, + 494997613419446272, + 490825797381672961, + 490698519326388224, + 489730986750791680, + 492313870896087040, + 490831442679959552, + 490408773119266816, + 490218985107906560, + 490503495577903105, + 494657868767842304, + 490511409575256065, + 493129911075217408, + 493438496846413824, + 493108502492360704, + 490586458286473216, + 492848175347412992, + 493518813598842880, + 493229384925315073, + 490778026020335616, + 490752365533081600, + 490612326157254656, + 490916155167498241, + 490619610979663872, + 492722507099942912, + 490780884518576129, + 490198693002231809, + 490569662103834625, + 490226633085710336, + 489872923214106624, + 493402096444506112, + 493129438062968832, + 490923028566376448, + 490507982501732353, + 493213502719283201, + 490669515949502464, + 491875160862244864, + 492982968202166272, + 490846234748669952, + 490247550054989824, + 490893343883161600, + 495037059154063360, + 493440416789053440, + 490629572505780224, + 490141800544223232, + 490835013940690944, + 490932651206123521, + 490942548282966016, + 490170708996001792, + 490524564732915712, + 490571964419801088, + 490865048164642816, + 493433597446328321, + 493033076360892418, + 490285522456444928, + 490658209435508736, + 490918835457769472, + 494151933699977218, + 493507057174470656, + 490066151008133120, + 490649220467396608, + 493445700538335232, + 491042092106645507, + 491750058346684416, + 493015254541295616, + 489816765166522368, + 492161471812341760, + 493219084398374912, + 490878426555744256, + 494859063767744513, + 490907769747173377, + 494848636782514177, + 491296589101547520, + 490973919940472833, + 493002445497593859, + 490881962454704128, + 492470623675748352, + 492986037761605632, + 490799637365006336, + 490651132931604480, + 490140477111689216, + 489594311127105536, + 489432503632285696, + 492937763717533696, + 490601859879800832, + 490183183657213953, + 489739745459965952, + 493461194725130240, + 491448483606724608, + 489832013256724481, + 490114913084649472, + 493446149840183296, + 490453181366042624, + 490092880519004160, + 493207210957086720, + 490688918686138368, + 490590830852591617, + 490519674484838401, + 493453964151914496, + 492545086245568513, + 491933288529813506, + 493484771431825410, + 495959681530347520, + 490573032717430784, + 491010976456904704, + 489469095705075713, + 490882610814410753, + 490359174182621184, + 490857590403117056, + 493382707049549824, + 490579809722830848, + 493142519274696704, + 490907332147032065, + 490725846723084288, + 491117194374156288, + 490208813249609728, + 495024565454905346, + 490058029677572096, + 490762028492259330, + 491227037424971776, + 490205649347682304, + 493082979116146688, + 490597728221548545, + 492525810625282048, + 493457426067120128, + 493531624873918464, + 493343627104354304, + 489783455916376066, + 490466973093228544, + 490208196284256256, + 494494745805488128, + 495887326803800065, + 490541255940509696, + 489721292954673152, + 494533765616500736, + 490485480039780352, + 490614755627778048, + 491051357315805184, + 490472911762104320, + 493033832149311488, + 490497791429332992, + 490482917681156096, + 490145646029328384, + 489737253363933184, + 490712417492824064, + 490564195482488832, + 493141615695781888, + 490895011538432000, + 492723331322621952, + 490608055902806017, + 493383007772766208, + 490232269173309440, + 489856000380653568, + 489782576203440129, + 493388085699567616, + 492701662004264962, + 494188685118951425, + 490448470482755585, + 492725607730786304, + 490473365199933440, + 490460609297674240, + 493023608625573889, + 491763490194202625, + 492712623389958144, + 492038812705779712, + 490980847579709440, + 493005843692912641, + 493103878809088000, + 492939617684168704, + 494556682237018112, + 493425122490200064, + 490996623343104002, + 490469505362309120, + 491066661962014721, + 491634439366385664, + 492989767059914752, + 495195024397971457, + 491791124672282625, + 490938411671224321, + 490850485474459650, + 490125608836685824, + 492696025426305024, + 490816996083105792, + 490092058137616384, + 493026122854969344, + 493126465441898496, + 489352658600202240, + 490248652477059072, + 490398771713306624, + 492289116894425088, + 493381209766899715, + 490398911069442048, + 490414863282614272, + 492387545276092416, + 493002669557317632, + 490121185536274432, + 490202516693319680, + 490912404478648322, + 492000348962566144, + 493069271023370242, + 490181140788314112, + 490908868944613376, + 493105101800611840, + 493495829249130497, + 493378434345607169, + 493480999272345600, + 490932510671785986, + 491184621976297473, + 490780428769296385, + 490695937451655168, + 491803015599636481, + 493014214278402048, + 490953616485019648, + 492975155304357889, + 490293025797455872, + 493074154740924417, + 491191757452091392, + 494442191767760896, + 493912741493489664, + 490946451053494272, + 490857519452258305, + 490197047640068097, + 494673114480259072, + 491300325505372160, + 494573895924461570, + 492692499094585344, + 490146541894914048, + 490655690072281088, + 494580206531665921, + 490648629691293696, + 494829925510430720, + 490476263627587585, + 490433937681182720, + 492262678531162113, + 490420262324928512, + 490431284381229056, + 491757846091292672, + 491954245915013120, + 495635611207081984, + 493342555958816768, + 492338534204710913, + 493089053303001089, + 493081820167430145, + 492041538147336192, + 490813521807278080, + 490144620048056322, + 490090904469114880, + 490498194531684353, + 490496318104555520, + 491189452598157312, + 490496287477731328, + 490585476714496000, + 491567378350620675, + 489453624465321986, + 492290643604307968, + 492397110726098944, + 490252408518623232, + 493363875946172416, + 493018869376630784, + 492995328895758336, + 490399356580007936, + 490511635123941377, + 492713377408352257, + 492859949605978112, + 494741795864326144, + 490882856021807104, + 490823430858891264, + 490938244729958400, + 494412912602402816, + 492958775486476288, + 489872019182608384, + 492252880938991616, + 493103379246100482, + 493489778818813954, + 489779640803008513, + 492643904895078400, + 495635185657192448, + 490037395899686912, + 491057514101112833, + 491339107327832064, + 491151797080571904, + 492794702232825857, + 496011025150668800, + 493474278931578880, + 494190824507588608, + 490779472547704832, + 492957830136074240, + 491285526453174272, + 493504198009716736, + 489710767428861952, + 490496982042284032, + 492696539023024128, + 493361444420079617, + 491303440526876672, + 492369462960869377, + 492733442300203008, + 490549406333411329, + 493269212392357888, + 490252415430828034, + 493404144041218050, + 492062957460004864, + 494051285356670978, + 490660141293776896, + 490552817321799682, + 491702588752920576, + 490979672415809536, + 491066158351908864, + 492223455220486145, + 493426044029112320, + 493027356106584064, + 492668051100557312, + 492949631618531329, + 490451057844035586, + 490164457268854784, + 489847568038645761, + 492688989707448320, + 491811311693860864, + 493353163307876352, + 490175091167490048, + 493504541057630208, + 493505834161561600, + 492426708528537601, + 492767919642656769, + 489992159815548928, + 490515047706529792, + 490528208102490112, + 489751913617842176, + 492725450272419840, + 494253340679995392, + 492717451553931264, + 493042429650403328, + 495751345425899520, + 493477596265316352, + 494399531933794304, + 490094370629386240, + 489992152030531584, + 491811326638170112, + 492756674331951104, + 491755868648521730, + 489614904383782912, + 490585128163631104, + 490525272861835264, + 493486565922861057, + 494557374733352960, + 493079151180410880, + 490817381728796672, + 490208111106334722, + 493512212880039937, + 490664957080784896, + 490330431494311936, + 493483926648668160, + 494856115180830721, + 490191821927362560, + 491736512698925056, + 490934208743747584, + 490645253830230016, + 489952148504195073, + 491241861005451264, + 491266555607785472, + 492985816621522944, + 493239070143700992, + 491036934731739137, + 490530915941355520, + 491271326410485760, + 489486490637201408, + 492995442247208960, + 493140666000478208, + 492749954713018368, + 491539268591169536, + 492711182978285569, + 492983908539961344, + 492739885829079040, + 490929182839697408, + 494476667373371393, + 490262326608920576, + 491932234002497536, + 491013585158819842, + 492686762440142848, + 490210969394503680, + 493086798839443456, + 494089914863349760, + 492669082647289856, + 492596945396174848, + 492823708197998593, + 492416262811549696, + 489935247434612736, + 492746151230054400, + 490412448269496321, + 489805335272890368, + 490949459044745216, + 493129654556172288, + 490968186276159488, + 490166321070768128, + 490566136212516864, + 491399747706834944, + 490331936162717696, + 490323496539406336, + 490187448668790784, + 492764157200961536, + 492893273716162560, + 489975557099368448, + 490580343611994112, + 491291092193923072, + 491739572473458688, + 492742801550213120, + 492661716933541889, + 490527805948452864, + 492648565525577728, + 492668333469483009, + 493137758550900736, + 491079353443553280, + 493123753014861824, + 493192069830410240, + 490975482439925760, + 490959046598729728, + 491066976174104576, + 492624216148410368, + 491409411374858240, + 490594501367316480, + 490958710060371968, + 493524909436698624, + 490697509996855296, + 492745771653939200, + 491360361820725249, + 493442333418225664, + 493441563335622656, + 490207852233887744, + 494360750001901568, + 491283028807667713, + 490592092272340992, + 491750888705634304, + 495917121646243840, + 492722100059537409, + 492716678321410051, + 491753976011165697, + 489730886083309568, + 495636658810015745, + 490069119761678336, + 490474966870421504, + 490602478560608257, + 493068743245709312, + 495762432565190656, + 493418251779833856, + 489979083929833472, + 490908245087633410, + 492801266964496384, + 493936609209757696, + 490166813758865409, + 494382422692069376, + 490974865139052544, + 493013417288937472, + 490615450196508673, + 491012874882777088, + 490519627949408256, + 493405505814278145, + 490593976131780608, + 492878341939421185, + 492683819410264064, + 492827325646770177, + 493460699008729088, + 490608516827463681, + 493070963513491456, + 492617276210683904, + 490593313108799488, + 492378732389474305, + 490491059630534656, + 490970194412859392, + 493001057300004864, + 494656989772128258, + 493136858239750144, + 493520009931407362, + 491056623272865793, + 490986088798773248, + 492672887485366274, + 493068361085898752, + 492363398693523456, + 489818145365164033, + 491654825541898240, + 491339275485851648, + 491017313836335104, + 490619201003216897, + 489747747008831488, + 490218484777750529, + 495709238212435968, + 489607224852221953, + 494493389682126848, + 491217536172974081, + 491057761208500224, + 490841067403882496, + 492021345031430144, + 491154764051144705, + 491419274523975680, + 492658536808054785, + 490595502606782464, + 490415478566027264, + 490537500310372354, + 491287102756503552, + 490294746003144704, + 490652116294569984, + 492061475058774016, + 491053804453134336, + 492652803525849088, + 490968087806500864, + 493082666690805762, + 489734217950318592, + 493452064690044928, + 490527117554511873, + 493164175607496705, + 490261577501642752, + 493121110372667393, + 490214168952602624, + 491027205988679681, + 494100353970089984, + 492248944534360065, + 492742712735846400, + 490844072420966400, + 490259175390605312, + 490213359753904128, + 493124935767048192, + 489330878964051968, + 490701482321121280, + 490408598758236160, + 491204338006917120, + 490517159420784640, + 490298250738827264, + 492658507238637568, + 492609494015574018, + 490212652954554368, + 495497939536842752, + 493082981137805312, + 490626183114264576, + 490202117807017984, + 491763270131650560, + 490452606825672704, + 490635076603219968, + 491364907049570304, + 490219824321028096, + 491394149686317056, + 489522448165904385, + 493068141648281601, + 492361196428083200, + 494854471277899776, + 490211009593085952, + 493127422540120064, + 490067696265203712, + 495661621436760064, + 492728731761672193, + 490608330448965632, + 490280166577696769, + 491691201238933505, + 490378437786619904, + 491385973373415426, + 491323117793341440, + 493086346496315392, + 491894252654575617, + 489459480912875520, + 490524129138061313, + 490201857206128640, + 490913649255809024, + 489748954880286721, + 490361515229589504, + 490644134982856704, + 493540232311345152, + 494995972779298816, + 494153341320978432, + 495645760227405825, + 492059424480329729, + 493020794776477696, + 494844813385404416, + 492499491740975105, + 492006508260229120, + 490959049958367232, + 491016229403238400, + 490237590428483584, + 494803888743391232, + 493486158702080000, + 490255774703026177, + 495901339864805376, + 490592266210541569, + 495213007874846720, + 491248772215607296, + 490987516615348224, + 490282475805884416, + 492807855213641728, + 495537584534474752, + 492710332721545216, + 492988219806715904, + 495079002210836480, + 495368327410487296, + 492746911909027840, + 490869440792514561, + 490986053168164864, + 490164447521284096, + 493050148487188480, + 490523352566480896, + 491757809084932096, + 491529526422552577, + 493071770489192450, + 490295012987789312, + 492676851157196802, + 489453861497995264, + 490986977752518656, + 490958239539163137, + 490235310333493248, + 493532778731159552, + 490236172229017600, + 492348668604059649, + 490510614817964032, + 489917231447289856, + 490320364527190016, + 493409453711310848, + 490985753921740801, + 493469626043727873, + 493085755816677376, + 494236201281282049, + 490457157209690112, + 490144079872016384, + 494212611622178818, + 492676512470933504, + 493085877761892353, + 489749595878981634, + 494967621784453122, + 490997481581600769, + 492744248958398464, + 491413792971321344, + 489811493769478144, + 494082636130680832, + 490421144973877248, + 492709667101876224, + 490353983240675328, + 492648433095041024, + 490563119404441601, + 491013328308027393, + 491387350552162305, + 491047256804843520, + 491947144505339904, + 489782650597437440, + 490573689482924032, + 489516080235155457, + 490223894834315264, + 492363371682213888, + 490966883328589824, + 492153088544112640, + 494479273479393280, + 493015028426354689, + 492625131005427712, + 493028403424272385, + 491311313839472641, + 491926990732025857, + 493053739972849664, + 492972850182361088, + 490611155363442689, + 490968196351262720, + 492398981088313344, + 490268661966315520, + 492504694036901888, + 492101714032754688, + 490883016374624257, + 490210515692843008, + 492025186141499392, + 490985609411182593, + 493329614019002369, + 490907460379500544, + 492125562002231296, + 492984768594968576, + 491707799651745792, + 492805387952095232, + 491035795848196097, + 490288556284575744, + 490361102484525057, + 490438726347423745, + 490292067151917056, + 492782085229518848, + 490095270475358208, + 491790543068725249, + 489877569680838656, + 490355778692608001, + 489963708219936768, + 490152135099559936, + 493382044227862529, + 492989521181835264, + 491215722186821633, + 490352714614718464, + 490986638143549442, + 490156390871494656, + 492055375139454976, + 491332118417772544, + 492821831590506496, + 490969972911636480, + 490848761984593921, + 489981593994682368, + 493201124657496064, + 490758751742590976, + 492825111326490625, + 491648810096275456, + 492934759853858816, + 493502203487739906, + 492055335956660224, + 490966266996596736, + 490584470748426240, + 493395745689845760, + 491311359863586816, + 489788961683165184, + 494833749667110912, + 490470988992110595, + 492466986442838016, + 491726145885585408, + 490581889187459072, + 490178255740100608, + 493078790479024128, + 493027725251067909, + 495165468257157120, + 490873805972045824, + 492881535721553920, + 490480428222918657, + 490986180729921536, + 492825708595785728, + 489741446258245632, + 489790119097139201, + 491346091011756032, + 490503899866857472, + 490907828170006528, + 492041071560761344, + 491355995734814720, + 490211671492030464, + 490616478979219456, + 493361427353051137, + 490467489487519744, + 491591764936261632, + 492956798203461632, + 495437269977673728, + 492115996308537344, + 490249999662739456, + 493425287686651904, + 490446439215292416, + 492712384377913344, + 490983546748948480, + 490940702289702912, + 494244315070472193, + 491308465097568256, + 489826157320081408, + 490351712226791424, + 491046092285706240, + 493318656294944768, + 490354871389126656, + 491341075291070464, + 490258755049635840, + 493109062167310336, + 495246566832496643, + 490239759675949059, + 491789200979918848, + 492327094979162112, + 490924682317930499, + 490992506528858113, + 493114876630282240, + 489574010733072384, + 489515218209214465, + 493529494691799040, + 490298589693104128, + 490063007612170240, + 495630116337098752, + 489575211311071232, + 490287186940788736, + 492853316917792768, + 494202096301133824, + 492712510018301952, + 489543002655059968, + 491010074727702528, + 492051551981416448, + 490990042140389377, + 493442174835773440, + 493185115300696064, + 490324710866300929, + 493101248317751296, + 491577286656008193, + 492026767205748736, + 492503008165761026, + 490945272944807937, + 490356801691340800, + 492129753403367424, + 490210951418085377, + 490771650095644672, + 490364195154980864, + 490957874085249024, + 490161627355185152, + 490425678828171264, + 492791514930884608, + 491433901726789632, + 493257684310065152, + 490804601885450240, + 491662697633972224, + 489933216426774528, + 489483983844286464, + 490672322081476608, + 493006659351224320, + 492130724091146242, + 492013985659486208, + 494565068173234176, + 490572029318275072, + 492817839892754432, + 492787622327357440, + 493125136095010816, + 490288942961655809, + 490110624874364928, + 493028863958458368, + 492997071180681216, + 490669394130120704, + 491739757421297664, + 495027969887576064, + 492021914307923968, + 493528718200283136, + 490244304242483200, + 491629757956882432, + 492888740604690432, + 492730210333126656, + 493494350966685696, + 493054997790482432, + 490791782163439616, + 492059462925291520, + 495914443394797568, + 491388025067565056, + 489745048733376513, + 490141562844618752, + 490886638852001792, + 491218966006988800, + 491643037366243328, + 490659657489580034, + 490481567933161472, + 489490743955034112, + 491324339116326913, + 491606214602547202, + 491623337051693057, + 494656273770889216, + 493077232370589696, + 490613432904073216, + 490276303040688129, + 490227212352618496, + 490939747758796800, + 491229941212925952, + 490533889975148544, + 490723615634374656, + 490820232077144064, + 490301496308011009, + 495537745583165440, + 490959140941230081, + 494959913152835584, + 490433026510557184, + 489487300741853185, + 492990785194065920, + 491976312328699905, + 490197075267977216, + 491287812142923777, + 490228254897606656, + 489875767120392195, + 490055247902306304, + 493185027724046336, + 491383321499541504, + 490145165106245632, + 493245639267209216, + 489746946106478593, + 490939705782185985, + 492751539782418432, + 491245436314071041, + 490351367878234114, + 492987884614737920, + 490224325715562496, + 492726894102859777, + 490623755194867712, + 491599304549998593, + 491630674902659072, + 490913814531936257, + 490514238142967809, + 490221998187233280, + 491813982714359808, + 491257383805812736, + 490939958690316289, + 490636359401766912, + 491444785191067648, + 493505756465872899, + 494120438990376960, + 491221321804943361, + 489700003817201664, + 491765103449341952, + 494555500952825856, + 490214805614391297, + 490961714167312384, + 491769639194873856, + 493500820835405825, + 492739904036941824, + 490647723721650176, + 491692630456422400, + 491463302979928065, + 492985610756689920, + 491018548748492801, + 490252298254561280, + 490613432795009024, + 490556223901544449, + 492469300167327744, + 492326143513862145, + 492678237475332097, + 493025940260528128, + 492651453261938688, + 492761216432218112, + 490212172312477696, + 491408712729645056, + 490246362152595456, + 490670447663779841, + 492387788507983873, + 490274603810689025, + 490657920313344000, + 492519677713604608, + 490520007617417216, + 490226269205045248, + 490033117550223361, + 493468138500263937, + 490231103593406464, + 490251629586046976, + 492744505527779328, + 490214349701939200, + 494796538619510784, + 490662736763031553, + 490251341499879424, + 493024685458984960, + 490084717954600960, + 491604526973984768, + 491021942791897089, + 490268292293332994, + 490952127238668288, + 490520300317331456, + 493075814830067712, + 495638378021658624, + 490488587901624320, + 490266651854897153, + 492007144355790848, + 490284928974606336, + 490934187579305984, + 491086551921983488, + 491031377912291328, + 490518744910032897, + 493081904124796928, + 490878976655888385, + 491751168729939968, + 491786141205807105, + 490212389682282496, + 490605802579714048, + 495235234464804864, + 490303527319642112, + 492942459270209536 + ], + "top_users": [ + "69542069", + "21787625", + "40101400", + "2284275066", + "148759764", + "17019152", + "134234000", + "1216258832", + "130151627", + "2402304913", + "28987332", + "18750157", + "1537877701", + "361594753", + "21568477", + "34914032", + "17174309", + "122556667", + "443196382", + "35727881", + "331311644", + "2551472479", + "59399268", + "18776605", + "2208949903", + "23976386", + "22611082", + "398306220", + "2620189999", + "31369541", + "543078828", + "790915958", + "73365668", + "19520983", + "14569981", + "1254582336", + "58576769", + "24693705", + "18980519", + "51086473", + "10228272", + "964212584", + "759251", + "21174888", + "21001379", + "488751763", + "156735736", + "295070534", + "635787453", + "290243668", + "2307425070", + "412536926", + "19388771", + "294636267", + "2222143400", + "9695312", + "701423664", + "2373475078", + "1901426832", + "44150093", + "2214937387", + "7736222", + "582907105", + "23733354", + "400489504", + "2332348778", + "237737133", + "495110565", + "23027648", + "14098533", + "794364504", + "358974434", + "41784974", + "129356981", + "1379083118", + "101477788", + "416500384", + "366452430", + "21086501", + "17865039", + "185702760", + "188478643", + "52270992", + "37718134", + "9317502", + "846523069", + "2658187867", + "754823287", + "225895204", + "592202860", + "1393084334", + "20696985", + "1558141890", + "1869691568", + "126971226", + "990845760", + "135414892", + "28358543", + "1209565878", + "2564148836" + ] + }, + { + "country_breakdown_percentage": {}, + "country_code": null, + "device_breakdown_percentage": {}, + "end_time": "2015-07-27T00:00:00Z", + "event_type": "MUSIC_AND_ENTERTAINMENT", + "gender_breakdown_percentage": {}, + "id": "2c", + "is_global": true, + "name": "Fuji Rock Festival", + "reach": { + "total_reach": null + }, + "start_time": "2015-07-24T00:00:00Z", + "top_hashtags": [], + "top_tweets": [], + "top_users": [] + }, + { + "country_breakdown_percentage": {}, + "country_code": null, + "device_breakdown_percentage": {}, + "end_time": "2015-08-10T00:00:00Z", + "event_type": "SPORTS", + "gender_breakdown_percentage": {}, + "id": "2f", + "is_global": true, + "name": "\u4e16\u754c\u6c34\u6cf32015 (FINA World Championships)", + "reach": { + "total_reach": null + }, + "start_time": "2015-07-25T00:00:00Z", + "top_hashtags": [], + "top_tweets": [], + "top_users": [] + }, + { + "country_breakdown_percentage": {}, + "country_code": "US", + "device_breakdown_percentage": {}, + "end_time": "2015-08-03T00:00:00Z", + "event_type": "SPORTS", + "gender_breakdown_percentage": {}, + "id": "2t", + "is_global": false, + "name": "Special Olympics", + "reach": { + "total_reach": null + }, + "start_time": "2015-07-25T00:00:00Z", + "top_hashtags": [], + "top_tweets": [], + "top_users": [] + }, + { + "country_breakdown_percentage": { + "AE": 0.14, + "AR": 0.97, + "AT": 0.05, + "AU": 1.0, + "AW": 0.05, + "BE": 0.18, + "BG": 0.02, + "BH": 0.02, + "BN": 0.05, + "BR": 1.84, + "CA": 4.49, + "CH": 0.2, + "CL": 1.38, + "CM": 0.02, + "CN": 0.05, + "CO": 0.61, + "CR": 0.14, + "CY": 0.07, + "CZ": 0.02, + "DE": 0.48, + "DK": 0.11, + "DM": 0.02, + "DO": 0.14, + "EC": 0.11, + "EG": 0.09, + "ES": 1.7, + "FI": 0.07, + "FJ": 0.02, + "FR": 1.2, + "GB": 11.08, + "GG": 0.02, + "GR": 0.27, + "GT": 0.09, + "HK": 0.05, + "HN": 0.07, + "HR": 0.14, + "HU": 0.05, + "ID": 0.43, + "IE": 0.84, + "IN": 0.2, + "IT": 0.82, + "JP": 2.97, + "KE": 0.02, + "KR": 0.05, + "KW": 0.14, + "KY": 0.05, + "KZ": 0.05, + "LB": 0.05, + "LK": 0.02, + "LU": 0.02, + "LV": 0.02, + "MA": 0.02, + "MW": 0.02, + "MX": 3.31, + "MY": 0.63, + "NG": 0.07, + "NI": 0.02, + "NL": 0.66, + "NO": 0.23, + "NP": 0.02, + "NZ": 0.2, + "OM": 0.05, + "PA": 0.07, + "PE": 0.16, + "PH": 0.61, + "PK": 0.11, + "PL": 0.07, + "PS": 0.02, + "PY": 0.11, + "QA": 0.07, + "RS": 0.02, + "RU": 0.2, + "SA": 0.41, + "SE": 0.34, + "SG": 0.36, + "SV": 0.02, + "TH": 0.27, + "TR": 0.75, + "UA": 0.02, + "UG": 0.02, + "US": 57.63, + "UY": 0.07, + "VE": 0.39, + "VI": 0.05, + "XK": 0.02, + "ZA": 0.32 + }, + "country_code": "US", + "device_breakdown_percentage": { + "ANDROID": 8.9, + "BLACKBERRY": 0.02, + "DESKTOP": 36.13, + "IOS": 54.61, + "OTHER_MOBILE": 0.33 + }, + "end_time": "2015-08-03T00:00:00Z", + "event_type": "MUSIC_AND_ENTERTAINMENT", + "gender_breakdown_percentage": { + "female": 48.8, + "male": 51.2 + }, + "id": "11", + "is_global": false, + "name": "Lollapalooza", + "reach": { + "total_impressions": 97330331, + "total_number_of_tweets": 562139, + "total_reach": 10005018 + }, + "start_time": "2015-07-31T00:00:00Z", + "top_hashtags": [], + "top_tweets": [ + 495434362813685760, + 495607542895345665, + 495382580687290368, + 494303588689408001, + 496458087906033664, + 495758556646219776, + 495634056923467776, + 495192801395875840, + 495947963139895296, + 496642062238769153, + 495299021989097472, + 494535449629958145, + 495995772635480066, + 495256505617502209, + 498227231919849472, + 495783151504220160, + 496131609687769088, + 495733156134547456, + 496152265548636162, + 495945543953432576, + 495681605370122240, + 496022956330348544, + 496320567688331265, + 496753835898310657, + 496471915687862272, + 497786834949128192, + 496017844325187584, + 496448010142765057, + 496030212799201280, + 494843763819180032, + 495603391985627136, + 495766655822077952, + 496131123068801025, + 498152265174507520, + 495287617374928897, + 496714480500637696, + 496131806509682689, + 494739712779640833, + 495241905165189121, + 494738129538912258, + 497762937738903552, + 496368774828662784, + 495666158436380674, + 496005347018948608, + 495686553189220352, + 495628080434929664, + 495656542440816640, + 495014874532306944, + 494595525598281729, + 494514419720679424, + 496093101271048194, + 495401682353020929, + 495991750843179008, + 495689464782786560, + 494573245182787585, + 496133038192214016, + 497836481600159744, + 496321187816161282, + 496116938792112129, + 494142989959049217, + 496014628481015809, + 494729974499520512, + 498182879470710784, + 496145137907798016, + 494618852542513153, + 495016944937234432, + 495816382291136512, + 495693750295740416, + 496144981283704832, + 496018727616651264, + 495337187442192385, + 494167575333335041, + 495803687650877440, + 495947291375591425, + 496166434951536640, + 496053901108731904, + 495830395699478528, + 495056507550302209, + 495599978572550146, + 496133932703047680, + 495800342484090880, + 496018535043588096, + 495597669289451522, + 495760259022344192, + 495304838515662848, + 495395875855007744, + 495372290486697984, + 495570170929479681, + 495051173523886080, + 497513836107530240, + 496018752623112193, + 495650064879333376, + 495390892661174273, + 496090644083777536, + 495243191944499201, + 495766311629512704, + 496463175316168704, + 494523051724124161, + 497815864461524992, + 495606009562292224, + 495380957307088896, + 495577299832807425, + 495389714464374785, + 495223476899565568, + 496099864363950081, + 497568313887969280, + 496007651634188288, + 494680115583152128, + 495627604872151040, + 495415770923679744, + 497561626221223936, + 496107809936007168, + 494739834389676032, + 495770214017937408, + 497101293220270080, + 495742364728963072, + 495207510845177856, + 494163982039523328, + 495267606790934528, + 496604765078695936, + 495245201560965120, + 496362069369688065, + 496094673564229632, + 496404501486911488, + 497192983151009792, + 495590597571665920, + 497765959000535042, + 494137730109304834, + 495678415954255873, + 495965548728320000, + 495947746126221312, + 495771394752270336, + 495736985068126209, + 496406075097481216, + 495978655383027712, + 495413646340915200, + 495642741087682560, + 496445771383066624, + 495238291541995520, + 496456279100231680, + 495607960220217345, + 495965206015913984, + 496705487434694656, + 494966402499870720, + 495208584427208704, + 494230812708306945, + 496083120408363008, + 495583597810941952, + 496171463272300544, + 498049846901997568, + 495787356671049728, + 495741426110828546, + 496453045694115840, + 496046806128939008, + 496145941628747777, + 495172109518528513, + 495361400529620992, + 497079111853293569, + 495380103032225792, + 495390875762315264, + 496111547534823426, + 496113790673768448, + 496414807676186625, + 495381921124605952, + 496134418999037953, + 494134202812473344, + 494896586158510080, + 495232520368451585, + 495969869536301056, + 495672646378745856, + 495620165955256321, + 495606293840007169, + 495201706255605760, + 495730787996549120, + 496148846146093056, + 496844958159368192, + 495736575121432576, + 495556385560887296, + 496292455751221249, + 495799482106511361, + 495978040447361024, + 495266338760581120, + 495799258059395072, + 496016620138278912, + 496330657585328128, + 495498353590169600, + 497421187954126848, + 495977402405638144, + 495749092455501824, + 495239853114527745, + 495281783681089536, + 494928093035761665, + 495586814594260992, + 495635181555187712, + 495728121392668672, + 494172014291472384, + 495599975078690816, + 494999707857715201, + 494384777890635776, + 496279684230164480, + 495390057633943552, + 496114870006583296, + 495649050247454721, + 497695013590302720, + 495285108409368576, + 496427467939520513, + 495270766058172416, + 497934505777594368, + 495634386134781952, + 496364196779802624, + 495758990065020929, + 495923160676851712, + 495375551235117056, + 495099496435433472, + 495752263072092160, + 496104932354064385, + 494534684286914561, + 496003881395318785, + 495624328143450112, + 495756700289597440, + 495002294552133632, + 494542992036753408, + 495747889440645121, + 497825885626843137, + 496037821376102400, + 495907917523333121, + 494129478415974401, + 496365710382485505, + 495359470114181120, + 495972522400419840, + 494752061175894016, + 495753408763002880, + 496107518868082688, + 495366504666652672, + 495502701862875136, + 496108809879044096, + 495660327598452736, + 496117332440539138, + 495378696677498880, + 495673897337884673, + 496366280236990464, + 495727903271694336, + 495969068965724160, + 495361743229845504, + 496596529290149889, + 495754436611158016, + 496094907166367745, + 495595366558236672, + 494191129785794560, + 495920360161026048, + 495322025146449920, + 495983939752706048, + 494167981770166272, + 495361387523502080, + 495958380662759424, + 496015173074046977, + 496002497673428992, + 495693955884126208, + 496298047308320768, + 495635022913994753, + 496007676984561665, + 496167677816487936, + 497050029627305984, + 495721769743818753, + 496568045725564928, + 495755661184364544, + 496101730002931712, + 495740866288680960, + 495382512483721216, + 495926330618175488, + 496138845315141632, + 496393838827954176, + 496644343374290944, + 497540095361429504, + 496083119251161089, + 496098217336266752, + 495963136256929793, + 495345274387443712, + 497433283995910144, + 495369235494080512, + 496385273828487168, + 496027246906601472, + 494906604832448513, + 495250110100434945, + 496704163330260992, + 495958988400656384, + 496295540460879872, + 494933015282589696, + 495679963484286977, + 495398820167946240, + 494271169189928960, + 495977294100303872, + 496662022827032576, + 496032741809725440, + 495665604628869120, + 496471973631770625, + 495368217703895040, + 496022599621935104, + 495648990071762945, + 495649069344514048, + 496039079759597569, + 495404142664626176, + 496036360265158656, + 494948691266908160, + 495697420534435841, + 496035046286192640, + 495292892173598723, + 495377001847742464, + 496138415226630144, + 495708784853925888, + 496008225687617536, + 494924018718605312, + 495677296289013760, + 494949313835847680, + 495825247019761664, + 495692181580308480, + 496003822553432065, + 495652795903508480, + 496034825628037121, + 494861310036021249, + 494153014672769024, + 495670732223811584, + 494830849615855616, + 494962849697902592, + 495385134405656576, + 496346370589351936, + 495374650718035968, + 495032212551925760, + 496126089555894275, + 496040967896858624, + 496004786438021120, + 496045785549918209, + 495599800759640065, + 496051667016880131, + 495663104341327872, + 495655243657797632, + 496288618647142400, + 496046603883806721, + 494588248636018688, + 498495320402444289, + 495666365446242305, + 495754706082615297, + 495605042234540032, + 495650283448696833, + 496388081034207233, + 495656629120282625, + 496034375717650432, + 496025853008953344, + 495652891647299586, + 497614790542753792, + 496048894292541441, + 495995289359380480, + 495754718917181440, + 497098815485132800, + 496307186554114048, + 496513835176833025, + 495287864868212736, + 495648710735699969, + 496010434412290048, + 496057540661501954, + 497079183982739457, + 495314011333074945, + 496325978021314560, + 496069088603803649, + 496062728541573120, + 497495810787930113, + 495306724845572096, + 498336740638490624, + 495242113102381057, + 495268981683781632, + 496011278117519361, + 496302399087448065, + 496761497180450816, + 495688852129214468, + 495658721083551744, + 495297961971417088, + 495421251994013696, + 495246354764283904, + 495770255072178176, + 496107026997850114, + 495330212000038913, + 495990051634180096, + 495281594559922176, + 495331362573131778, + 495685831848255488, + 495990283935678464, + 494921243590545410, + 495330183260696576, + 498298997841612800, + 495382616519213056, + 495635677787475968, + 495629090934648832, + 495951111157989376, + 496675081053954048, + 495389060647882752, + 496380857561542656, + 496302270112616448, + 497094823686729730, + 496034262651789312, + 497063769865203712, + 495694760992976896, + 495422930520920064, + 495552318801457152, + 495821243162324992, + 495320075512336386, + 495797151470190592, + 496705558301655040, + 495751856371793921, + 495391426474426368, + 495281565187198976, + 496118297000431616, + 494388476054605824, + 497837006131847168, + 495318157159301120, + 495341969711706113, + 495686732797714434, + 495665592972894208, + 494899468924231680, + 495764308458868736, + 495759812194729984, + 495391563951128578, + 496555118918393856, + 494409013980041217, + 496139288602755072, + 495279047451377664, + 496147135805800448, + 495363099130859520, + 495949945959370755, + 495646129896579072, + 495769418832822272, + 496086900214861826, + 495218453138399234, + 495922286994927616, + 496097551880577024, + 497867571438583811, + 498152141643476993, + 495743168101752832, + 496479589514747904, + 496106183342956545, + 495415890738159616, + 496120000357613568, + 496154083980767232, + 497122892950544384, + 495401019925626880, + 494148088752111616, + 495562907380629505, + 498139243768987648, + 495335686212689921, + 495400745651675136, + 495431050647326720, + 495754815163858944, + 495730347037179904, + 495739290690015232, + 494978311702183936, + 496490919877951488, + 495456754294349824, + 496114134942232577, + 494909184232935424, + 496120528122310656, + 495598485774020609, + 496814217732042752, + 495655079098478592, + 495283656538456064, + 495744582760812545, + 495703693464207361, + 496091140488458241, + 495373432641822720, + 496473843234791425, + 495951390876114946, + 495831478719115264, + 495932879336394752, + 496100324055068673, + 495940220014297088, + 494614720733642753, + 496116237924331520, + 495750244471410688, + 496088073684660224, + 495411779628199936, + 495993558122651648, + 496469599148576768, + 495395142099283970, + 495912167758376961, + 496366857914294272, + 496862509199269888, + 494510539913977856, + 498295170623094784, + 494998548854108160, + 494479272942112768, + 497094551949938689, + 495768237419024384, + 497862397894623234, + 495389699310387201, + 495473728143499264, + 495393432891052032, + 495567138929664000, + 495957995088379906, + 495283291096768512, + 495403183616061440, + 495958033735098368, + 495283452044791808, + 496766095013867520, + 495758189284302848, + 495418486316085248, + 495987456684990464, + 495437599172198402, + 495002982266986496, + 495646468473372672, + 495728550704848897, + 495388219689926656, + 496482446721167360, + 495477411190812672, + 495722341197156352, + 498098878257041409, + 496478050687938560, + 496486824668590080, + 495737583746695168, + 495359612175278081, + 495741837802749952, + 495538674105585664, + 494887202174693382, + 495300270541512704, + 496332907666243585, + 496305878803685376, + 496493353966796800, + 495878467993755649, + 496075552420536320, + 496514437495652352, + 496618207378440192, + 495702490797858816, + 496087333046079488, + 495697906650054657, + 496264799110828032, + 495469784944087040, + 495705966688870400, + 496314652117057537, + 495481709396492288, + 496322068779380737, + 498558183016001537, + 496465195028729856, + 496069252030660608, + 495727475096182784, + 495421872196952065, + 497404549355667456, + 496325454551588864, + 496089735233032192, + 496330990319849474, + 495327745917059072, + 495213719727931392, + 496456091950399489, + 496403762483699713, + 495730452666535936, + 495939683265040385, + 497034722477109248, + 496283815850307584, + 495276242468601856, + 497064624936607746, + 496490788839104512, + 498076579122397185, + 496280765110685696, + 495243853255823360, + 497932914412519424, + 496197831842340864, + 495767804256473088, + 495577291586809856, + 495341794415370240, + 495690692388458497, + 497406546817454080, + 495720917172236289, + 495727248302157825, + 495703094358204416, + 495638764484456449, + 496107297920532480, + 497501081178361857, + 496011725054181378, + 496018753558417408, + 495984370532904960, + 495695099494678528, + 496283369584750592, + 496904540617469952, + 495430497431220224, + 495369554441535488, + 495609742640041984, + 495594938759794688, + 497653011641290753, + 495947285403271168, + 495379949835264001, + 497119120929062914, + 495645685853995008, + 495969911337152512, + 496048239196401664, + 495369308244283393, + 497727787156135936, + 495942820528529408, + 497268699183984641, + 496073033342533632, + 495201403485159425, + 495986688284319745, + 494860413574864896, + 495757710365704193, + 494695792179826690, + 496622495634845696, + 495965276455047168, + 495584844358119424, + 495965599143841792, + 496425617169330176, + 495691632126087168, + 496046884629540866, + 496009312347885568, + 495982729985802240, + 496699260646080512, + 495650204159582209, + 495363320548179969, + 494980911264325633, + 496147567726456833, + 497762962782711809, + 495226263536431107, + 496046866216153088, + 494449682136190976, + 496111953471741952, + 496378817452474368, + 496460663150379008, + 494935897083625472, + 494877800206442496, + 495347589383204864, + 496321723357487105, + 496427132122181632, + 496610076002889729, + 496004112576937985, + 496047657467805696, + 495113402277453824, + 496348682259034113, + 495722059381489664, + 496478267978055680, + 495230358829686785, + 495968839193362433, + 496115676990300160, + 495011048861077504, + 495642568521428992, + 496030896936738817, + 495267209128579072, + 495998827258998785, + 495998694496673792, + 495598565692305408, + 495984680668131328, + 495344776376766464, + 494481924081987585, + 495328127430983680, + 495656024033206272, + 494105420102119424, + 497041551336677376, + 495949109250256896, + 496978881354948608, + 494467797137620996, + 495646655858081792, + 496146636050292736, + 496039040492515328, + 495705621724143617, + 494841816231866368, + 495315479062671360, + 496018186945716224, + 495629599653761024, + 495607505335377922, + 496063525975252992, + 496035090615398400, + 498199603758768128, + 495235554049789952, + 496336056971960321, + 496006396560031744, + 496017683717292034, + 494843842022354944, + 495345490624794624, + 495626466357686272, + 495623240379678720, + 496385403516387328, + 495344461346779136, + 495290428120236032, + 496043541463064576, + 496056504718729218, + 494840908240539650, + 495312936748216320, + 496116507647434752, + 496353890556973056, + 495620759705092096, + 494730799808532481, + 496075211117445120, + 495372546158505986, + 496399865283641344, + 495003459368665088, + 495602871912902656, + 495710617588998145, + 496106612486979584, + 495687713262403584, + 495637124046389248, + 496042608536199168, + 496065929349197824, + 496374077309734912, + 497661300043186176, + 494925744124858368, + 495659096419622912, + 497237237931966464, + 496065742996275201, + 495238932301611008, + 495660083691671553, + 495280461330264065, + 496813130979475458, + 496347674501992449, + 495711963134296066, + 495965091905273856, + 494624788581580800, + 495693902167703552, + 495697255052378113, + 496080890108608512, + 496397200990408704, + 495654046079148032, + 495058481339449346, + 495700104075313152, + 495646349761974272, + 495657960916680704, + 495381888748761088, + 498257475066662912, + 495261040012439552, + 495342041459478531, + 495340705779548160, + 496349508717277184, + 495326226735984640, + 495654740634918912, + 496056730569027584, + 497030894972968960, + 494511838173085696, + 496416653723590656, + 496135150796042241, + 496008945849597953, + 495333669868154882, + 495320862275686401, + 495247608336879616, + 494953280087547904, + 494184901709553664, + 496979297161052160, + 495291239932366848, + 497067870153887744, + 494829098943119360, + 494578698310258688, + 494589471757578240, + 495316528666279937, + 496118118809223169, + 494930557780779008, + 496515972610949120, + 494983414768885761, + 495693725063200769, + 496385131515748353, + 496366846065770497, + 495514635861516288, + 494134138924826625, + 495678010956070912, + 496425298368675840, + 495646072929533952, + 495206686190092288, + 496068329137004545, + 496709507800498176, + 495622596483088384, + 495313880545890305, + 496113794104324096, + 495669323889774592, + 496687903637254144, + 494195711681265666, + 496016451099430912, + 495401070563061760, + 496345879444742146, + 495269488976486400, + 496460691675811840, + 495277330919878656, + 496809035392622593, + 495286672947695616, + 496753914897649664, + 494570232195727360, + 497142241370984448, + 496079589350051842, + 494806766157586432, + 494223409622953985, + 495338790656176129, + 496055295253417984, + 495379767932497920, + 496063574478176258, + 496751293609017344, + 496332264524251138, + 497057226109227009, + 497509808908410881, + 496264421594112002, + 496513441826607104, + 495687994817671169, + 495337733670567938, + 494235461791936512, + 497096078605287426, + 495292967947874305, + 497729428940914688, + 496021037268877313, + 494577746081619969, + 497940370509279232, + 495276962743865345, + 495259200352944128, + 494224193680969728, + 494221779423232002, + 495312095056252928, + 494915687199305728, + 495258091030454273, + 494907658604781568, + 494906109992267778, + 494923675636756480, + 495982701556420608, + 496124553232281601, + 496378715878617088, + 495699346449764352, + 495713163694718977, + 494610966341222400, + 495261987249864704, + 494105650491039745, + 496124807331983360, + 495767580494139392, + 496023825503363072, + 495969973320568832, + 497051196319088640, + 496035480858025985, + 496711387549552640, + 496460789180403713, + 496076251824922625, + 495715403885445120, + 496071224460853249, + 495332605386973184, + 494894735534727169, + 494513110989144064, + 497217105662443520, + 494903143465881600, + 495301492421574656, + 495830928493924352, + 496351386326417408, + 495275415288938496, + 495271262256889856, + 496723143466422272, + 494542982700609536, + 495303264230195200, + 495253050252988420, + 495693244798627840, + 495709850429849600, + 496274826722824192, + 495562155685855232, + 495570526027657216, + 496086790902915072, + 495252702700781568, + 494506600334229504, + 495883120189923328, + 497459763006160896, + 495239288930316289, + 494539347203727361, + 495417890418733056, + 496023334547881984, + 495062610891792384, + 495988318719332352, + 495041447213953026, + 496301655542206464, + 495648437921394688, + 495969869754793987, + 496061684264366080, + 496282922887176193, + 496105773601021952, + 495306813005627392, + 494890310992818177, + 495722897508683776, + 497986650060771328, + 494879480742424576, + 496345395145224192, + 495733030778990592, + 495231339944501248, + 495299285471485952, + 495330452719538176, + 495317269627797504, + 496004037062713345, + 496653100120145922, + 495282867891478529, + 495709344319938561, + 494316192195444736, + 495285334931161089, + 495596494024900608, + 496040461078110209, + 495701899354836992, + 495364676059144194, + 495734433866317824, + 496110792463613952, + 495620501667340288, + 496269262118735872, + 495391905363288064, + 495629761738448896, + 495721582435000320, + 496419072737685506, + 495732188873523200, + 494811119995731969, + 495092218806697985, + 495395202874736641, + 494815161383792640, + 495979846632501248, + 495706249649205248, + 495305097438822400, + 495710026850660352, + 495314300832321536, + 495361633502629888, + 497108304863449089, + 495364998349062145, + 495392730810703873, + 495713573499592705, + 496500878308679682, + 495636973265358848, + 494185353809371136, + 496742312140353536, + 495327825562701824, + 495775211305054208, + 497770514274738177, + 497155356314075138, + 495695085171126272, + 496439194311753728, + 496022810389934081, + 497023813704757248, + 498331491462426624, + 495980145715736577, + 496101015020920833, + 496127053486624768, + 495756494559019008, + 495436797761949698, + 497215907786010624, + 495326454042091521, + 495773145438371840, + 495569772772220928, + 495303353782763520, + 496355893995638784, + 494935742804918273, + 496375582176067584, + 495319863083425792, + 495779353008275456, + 496419058838171649, + 495563645753888768, + 495740316453208064, + 495765089677352960, + 495646026880270336, + 496316912180400130, + 496739871822970881, + 495739808137109505, + 495638378021658624, + 495327684730585088, + 496645176841211904, + 495380482784509954, + 498092049825288192, + 495241811267289088, + 495349874133831680, + 495873219594039296, + 495406660140007424, + 495267859741032448, + 495393045274447872, + 495016204722270208, + 495775042039738368, + 498260759592587264, + 495270247151050752, + 495414179168542720, + 496148740512948225, + 495326291366006784, + 496086075241009152, + 496589414156759040, + 495608028620918784, + 496058390691713024, + 495193770963386370, + 495417549396254720, + 495117130124513280, + 495301900107931648, + 496977785773387776, + 494228503311970305, + 496600507973398528, + 495278011315683330, + 495187864054161409, + 495304236432125952, + 495681544707907584, + 495992900866830336, + 495389078347874305, + 495276962622230528, + 496742243945160705, + 494894022063046657, + 495154551767719936, + 496093225082716160, + 495774397676806145, + 496459016982499329, + 495683417586290690, + 495243866506027008, + 495234145748914178, + 496430864088461312, + 495180898753445888, + 496661530210226176, + 495919044080308224, + 495914675000053762, + 496082163243421697, + 494638695434027008, + 494858502003621888, + 496367490226999297, + 496055430683316224, + 496063868515680256 + ], + "top_users": [ + "15429316", + "17540485", + "9695312", + "181572333", + "79293791", + "14089195", + "30495613", + "14117843", + "16331010", + "14511951", + "355307031", + "22940219", + "14780915", + "101858534", + "21506437", + "1689178531", + "40076725", + "545443555", + "39600564", + "972651", + "155705264", + "180505807", + "134234000", + "104249727", + "23482952", + "98199951", + "21086501", + "19063323", + "116710152", + "13049362", + "1925157330", + "70350936", + "5695632", + "352145373", + "1577662069", + "14098533", + "97082147", + "29330030", + "522473594", + "21701757", + "251433567", + "136361303", + "26578749", + "18825961", + "19341413", + "431921733", + "19329393", + "182127941", + "144130505", + "2367911", + "265605041", + "49636886", + "18625669", + "69491538", + "1068612073", + "7976822", + "21174888", + "417457593", + "227324947", + "757829184", + "438897828", + "597777590", + "22515643", + "20177423", + "292359364", + "386814545", + "566755174", + "23818581", + "71679123", + "47700997", + "558371361", + "262749118", + "519708002", + "144380789", + "24343698", + "2360403715", + "238002889", + "15178186", + "14293310", + "7563792", + "14419089", + "16212685", + "1537877701", + "373471064", + "355743494", + "19102343", + "34935679", + "136505371", + "297882651", + "16352599", + "283673240", + "21114159", + "23832022", + "15764415", + "129701195", + "44441179", + "16870853", + "383044849", + "25142830", + "20493439" + ] + }, + { + "country_breakdown_percentage": { + "AE": 0.02, + "AU": 0.07, + "CA": 0.23, + "DE": 0.02, + "ES": 0.02, + "FR": 0.05, + "GB": 0.05, + "HK": 0.05, + "ID": 0.05, + "JP": 98.7, + "KR": 0.05, + "MX": 0.02, + "NG": 0.07, + "NO": 0.02, + "NZ": 0.02, + "PH": 0.02, + "SG": 0.02, + "TH": 0.05, + "TW": 0.05, + "US": 0.43 + }, + "country_code": "JP", + "device_breakdown_percentage": { + "ANDROID": 5.42, + "DESKTOP": 25.99, + "IOS": 68.46, + "OTHER_MOBILE": 0.12 + }, + "end_time": "2015-08-10T00:00:00Z", + "event_type": "MUSIC_AND_ENTERTAINMENT", + "gender_breakdown_percentage": { + "female": 58.92, + "male": 41.08 + }, + "id": "36", + "is_global": false, + "name": "Rock in Japan Festival", + "reach": { + "total_impressions": 7204543, + "total_number_of_tweets": 82940, + "total_reach": 997437 + }, + "start_time": "2015-08-01T00:00:00Z", + "top_hashtags": [], + "top_tweets": [ + 494467033111613442, + 494894507050016769, + 494382410285322242, + 494494634605699072, + 494378356947681280, + 494493527414288384, + 494431218159464448, + 494467456992165894, + 493229300229758976, + 494829867888701441, + 494105069013311488, + 494684146996744192, + 494384362507350016, + 494075983511552000, + 494452356281401345, + 493979049060884480, + 494010694358925312, + 494864404391809026, + 494029572170469376, + 493289478929145856, + 494678848932302848, + 494789474388152321, + 494316461494513664, + 493954075923214338, + 494426589564633088, + 494871407038173185, + 494454860587102208, + 494394445148610560, + 494395026168758273, + 494344893641543681, + 494903878039506944, + 494754587828834304, + 494799348224368643, + 492866909885317121, + 494759530484363264, + 494452436476497922, + 494698284712095744, + 494455422858690561, + 494836794299383808, + 494735065226563584, + 494376266456264705, + 494370389921763329, + 494746661298528257, + 494420576132276225, + 494372197146697728, + 494824657195765761, + 494399532596076544, + 494696219654881280, + 494407259292594178, + 494717355243487233, + 494744327428395008, + 494452353508982784, + 494494636841238528, + 494830939550134272, + 494823290028834816, + 493024424652587009, + 494452358638620672, + 494426016777895936, + 494683559462854658, + 494732876865228800, + 494788733548232704, + 494439409953955841, + 493321891302481920, + 493415776208961536, + 494684149819514880, + 493290890983514112, + 494749097383841792, + 494467459324190720, + 494855683431337985, + 494105071265660928, + 494412523508989953, + 494438484631764992, + 494010696502243328, + 493229302414995456, + 493928273361907713, + 494029574368268289, + 493955338597445632, + 494829870493364224, + 494807815110668289, + 494737706161676290, + 494407316804866048, + 493954078376853504, + 494087222740533248, + 493385094573211649, + 494581168709173248, + 494316463784591360, + 494452490692083713, + 494732583268544513, + 494425091296358400, + 494678851230781442, + 494676466878001152, + 494401010039664640, + 494331626508136448, + 494678847141318656, + 494843335660404738, + 494087060668436481, + 493956981145600001, + 494079554059636737, + 494087163378552832, + 494332149747576833, + 494435510173986817, + 494780704538910721, + 494087118784708608, + 494449081792471040, + 494476257862492160, + 494421339516575745, + 494081914483912705, + 494439652309204992, + 494889099585536000, + 493048107202916352, + 494443749359902722, + 493401193847066626, + 493019479081631745, + 494777015971483650, + 494039008163266560, + 492855385640820736, + 494449331869478913, + 494121998889414657, + 493263074820775938, + 494611354448166912, + 494443611002388481, + 494840716409860098, + 494818283409784832, + 494139364482355203, + 494439974469525504, + 494699969782112260, + 494029584946311168, + 494410226016083968, + 493972785849319424, + 494138601307770880, + 493053809380163586, + 494460281607565313, + 494786895860080641, + 493912335195463680, + 494450623685734400, + 494395661916192768, + 494420415507206144, + 494487566117138432, + 494418458986041347, + 494425214730502144, + 494450401953845251, + 493287709113192448, + 494452790367125504, + 494422421093371905, + 494459573533544448, + 492866912032804866, + 494828349508702208, + 494482925119762432, + 494448194806235138, + 494678875759075330, + 494448148568219648, + 494844293576523778, + 494124367916171264, + 494443085321871360, + 494784758627708928, + 494784549075685377, + 494131636359815168, + 494454696514301952, + 494446697750069248, + 494707326406778881, + 494161099319541761, + 494487521837871105, + 493025215723487233, + 493378850051485697, + 494703363049541633, + 494444435468333057, + 493226885879312385, + 494438702060302337, + 494032275474874368, + 494712635212853248, + 494531743035039744, + 493226221635768320, + 494359806396755968, + 493409227268841472, + 493333717285208064, + 493367740820779008, + 494771978780147712, + 494391972908380160, + 494184034964996097, + 494394829405577216, + 494495356646731777, + 493950206040231937, + 494860502590181378, + 493005437130653697, + 494281321888239616, + 493927120653910017, + 494858960197779458, + 494690599371423745, + 492902865820606464, + 494391975303323648, + 493976184544186368, + 494847699305263104, + 493259649982791680, + 494449741564870656, + 494443332961988609, + 494763067729670144, + 494427503759343616, + 494458624366739457, + 493351623842729984, + 494450966486200323, + 494422196333195264, + 494668298873614337, + 494459274454499328, + 492897389091377153, + 494075963961921536, + 494422384511029249, + 494422647485112320, + 494748343394779136, + 494420215862525952, + 494363832450445312, + 494720413239238656, + 493005792182673409, + 493227695191257088, + 494434868277690369, + 493054152423915520, + 494376918955724800, + 494050059416121344, + 494693959646449664, + 493937212392632320, + 494403658541305856, + 493209067725144065, + 493021646081388545, + 492878430090715136, + 494763727325892608, + 494333504725852160, + 494392126164058113, + 494864638236831745, + 494731491083956226, + 494608435062005760, + 494455040283660290, + 494368486412410880, + 494044670846980096, + 494427670617153536, + 494067178233024514, + 494419895740682240, + 494668569783713792, + 494089976926072833, + 494761732808531968, + 494448709380218881, + 494077583298801664, + 494417136794619904, + 493946232146915331, + 494450807555637250, + 494443601837821953, + 494437470000676865, + 494421336194707457, + 493534921722314752, + 494376869177741312, + 493049737247866881, + 494441202075172864, + 493238555452264448, + 494427934673743872, + 494498402856484866, + 494057448055902211, + 494992267673747457, + 494826533299556352, + 494444176021282818, + 494663760334704642, + 494419082561589248, + 494429069245566977, + 494074884222238725, + 494327533182414848, + 493973181640617984, + 493029147971555330, + 493397817218437120, + 494971153962635265, + 494420872170455041, + 494808733629681664, + 493921869276270594, + 494032269577707522, + 492987722911338497, + 494868996936986624, + 494418400819421184, + 494797556593856512, + 494419479271456768, + 494437879293022210, + 494834606395256833, + 492997557266575360, + 494825389663862784, + 493319911087693826, + 494859859783737344, + 494849117797875712, + 494457672570130433, + 494310105785962497, + 494431191135571969, + 494633891207319552, + 494438978053873666, + 494468159961706496, + 494305153084698625, + 494857764212969473, + 494443723220975617, + 494448923100995584, + 494451704939556865, + 492897264483172352, + 494472121884475395, + 493000529190981632, + 494438039741947904, + 494032968889823233, + 493969342867177472, + 493908796842848257, + 493383002794110978, + 494815061886521346, + 494422019509714944, + 494449963334516737, + 494437453504057344, + 494867700691116032, + 492894500092538880, + 494028284674322432, + 493419092712251392, + 494440953927569408, + 494702684247953408, + 494316479555186690, + 494769464194244609, + 493018098778116097, + 494833277694271490, + 494422162607202304, + 493048656698687488, + 494286270843998211, + 494769721628033025, + 494834836175986689, + 494448446409953281, + 493366937594777600, + 494744448815742976, + 492861347839758336, + 493953320113811459, + 494705450948890624, + 493031661068500992, + 494796008556343297, + 494449524639686656, + 493995120258064385, + 494304426006298624, + 494403623283998721, + 492900083885547521, + 493230593102991360, + 493367084735143936, + 494450190498025472, + 494277478513262593, + 494116763626258434, + 493304977566466048, + 494428866413219840, + 494000041346875394, + 494694151762366465, + 494471861950889985, + 492851825343614976, + 494844757764366338, + 494418937967165440, + 494477553714102272, + 493302665699282948, + 493237976210481152, + 494636434943275008, + 494819652212494336, + 493361112708939776, + 493404052424630272, + 494082623103176704, + 494317748953296896, + 494741861274107906, + 494460772810911744, + 494690703100768257, + 494519139630080000, + 494033200587362305, + 494086736264171520, + 493212943551455234, + 494668822998036482, + 494475648648228864, + 494868894004166656, + 493029862366392321, + 494362005910740992, + 494787707936059394, + 494319759127609344, + 492866933289533441, + 494360585400627200, + 494483782942990336, + 494128970657329152, + 493234938896871425, + 494474920189890562, + 494837566672101376, + 494042951454978048, + 494833560306450434, + 494033445710868480, + 494734032903471105, + 494492137002520577, + 492923491172089857, + 494421822041907200, + 494720838847848448, + 494761686885089280, + 494855282778832898, + 494719109603414016, + 494805120509440000, + 494824760438566912, + 494330172661702656, + 494039597479759872, + 494695765948628993, + 494779761592266753, + 493935497220067328, + 494793504057348096, + 494446979485671424, + 494400754166136833, + 494422049926807552, + 494862457022578690, + 493241692208627713, + 494481527569276930, + 494347610614812672, + 494798437016039426, + 494447518961266689, + 494696816860884993, + 493936583309918208, + 494393689607655424, + 493951461391212544, + 493964715689648129, + 493284484909776897, + 494667446947545090, + 493987437840855040, + 494771623514238976, + 494862646118596610, + 494798823454019585, + 494786414324625408, + 494085347509149696, + 494817774342905856, + 494454675916066816, + 494868345225633793, + 494708785080836099, + 494447438699458561, + 494084369598799873, + 494704672288960515, + 494863312006291456, + 494981489126162432, + 494795863361724420, + 494868590936354816, + 494879280677933057, + 494012897001893888, + 494864841740271618, + 494836495962746881, + 494736744705572865, + 494453521266143233, + 494104255498706944, + 493947343297716224, + 494800393541410816, + 493041779768164352, + 492994567033978882, + 494702168100704257, + 493391083632484352, + 494863879193628676, + 493190846926168067, + 494863034913796096, + 494098458702139393, + 494867396323069953, + 494981049496403969, + 494446501892853761, + 494763712658423809, + 493913018527252480, + 494764871821426688, + 494462577204682752, + 493276425336532994, + 493276093814542336, + 494435604868767744, + 493409942347345923, + 494473996419596290, + 494867139547762688, + 494498865551130624, + 493404569544585216, + 494496856097832960, + 494864610277593091, + 494140442552700928, + 494862271588204545, + 494760657967796225, + 493437753049096192, + 494862420574105603, + 494868009811333123, + 494106547933310976, + 494403671291985921, + 492937318760603650, + 494375631409278977, + 494781890771972096, + 494478362509733888, + 494406754436780032, + 494718531632521216, + 494447534224322561, + 493394061445701632, + 494439526975025152, + 494732630609252354, + 493024866660921344, + 494734253851041796, + 493060483570597888, + 494861821690396673, + 494653824515063809, + 494872069205528576, + 494007012531785728, + 493418573461594115, + 494124452049727491, + 494864254994874368, + 494319469242486785, + 494848502564798466, + 494795451162308608, + 494050297996513280, + 493923650106433538, + 493271695159873536, + 494862112582160386, + 493329036102213632, + 494819788921651202, + 493923150208327682, + 493394347912478721, + 494854103369920512, + 494279715314618368, + 494812422893355009, + 493189170991362048, + 493013349521559553, + 494113500134780928, + 494017863926050819, + 493948188609376256, + 494407265546297345, + 494703087127236608, + 494862619044368384, + 493949829060370432, + 494653357730971648, + 494428561084649472, + 494686975413080064, + 494098015104139265, + 494120748668039169, + 493341814779158529, + 494344894367145984, + 493244198473052161, + 494786426353876992, + 493260454794248192, + 494772778461970434, + 494841261786796032, + 494861943253893120, + 494381378796929024, + 494823428797386752, + 492867668345511936, + 494125625058140161, + 494103231883014144, + 494477556465532928, + 494087220878274561, + 494675310395133953, + 493221268980629504, + 493292822682796033, + 494700940495028226, + 494844651912720384, + 494071627525545985, + 493531302864252928, + 494857130348789761, + 494462650252685312, + 493317715960922113, + 494359898117771265, + 492941577858191360, + 494478377307238401, + 494421832775106560, + 494878104225996802, + 493016001823264770, + 494644543707308032, + 494091913478148096, + 494501021972824067, + 494294953342681088, + 492959437837971456, + 494129295095123968, + 494865587038715906, + 494481682699808768, + 494784610568388608, + 493518163888177153, + 494860641379688448, + 494760914160058370, + 494031121596678144, + 494897747816751105, + 494113858970071040, + 493407424674398210, + 493219881504866304, + 494437086934470656, + 494407219996131328, + 494086537227694081, + 494821667458125827, + 493071690297909248, + 494006811138072576, + 494472966130782209, + 494552774890110976, + 494428259933638656, + 493237731548352512, + 494707892029640705, + 494340803901145088, + 494825088328298496, + 493221297556430848, + 494086920960352258, + 493010891374219266, + 492949149185085440, + 494033809700958208, + 494477556377456640, + 494453393574739968, + 494407287633481730, + 493320336868265985, + 494091243903655936, + 494300245598031872, + 494614095421636608, + 494486505260187649, + 494605076204232704, + 494587058388606976, + 493281454558703616, + 494968035094970370, + 493231898936631296, + 494475715434135553, + 494131720346533888, + 494760204416712704, + 493010840191127553, + 494139407838875648, + 493365603189530624, + 493403852352135168, + 494477556666888192, + 494780668266557440, + 493394016709267456, + 494393006443597824, + 494134953492226048, + 493380328078069761, + 493033966673215489, + 493352090790416384, + 494336999621283842, + 494812488840409088, + 493277229955026945, + 493305090191536129, + 493270637159264257, + 494114389302079488, + 493342878903439360, + 494859125126209539, + 494481077847592960, + 493002945147834368, + 494047000078192640, + 493201734441783296, + 494756153058795520, + 493213919977021441, + 494728637808001024, + 493036316553007104, + 494423267684265985, + 494512061171236865, + 494386227710156800, + 494116036258439168, + 494764035049418752, + 494069421011251200, + 493380998780813313, + 492937272891678720, + 493009427490816000, + 494857316802375681, + 493040422881861632, + 492827348547674113, + 494872150075899904, + 494103156859490304, + 492999571945951232, + 494053476498808835, + 494442588930199553, + 494043899640287233, + 494111522407215106, + 493948865792315394, + 493259303583629314, + 493944611258126337, + 494440062809931776, + 494761298177974275, + 493216189758181377, + 494698157033263105, + 494796055578304512, + 494030302927261696, + 493408435958870017, + 493393916733816833, + 493281031718309888, + 494401027185975299, + 494082100446756865, + 492919758535159809, + 493412427975782400, + 492974258423754752, + 494687808112451584, + 494680937515347969, + 493008158877429760, + 493447222051483648, + 494856033177571328, + 494802993200377856, + 494673926996238336, + 494019154052005890, + 494876318698201088, + 492854712182390785, + 494860296318496769, + 492840317729509377, + 493210539351236608, + 494493988372480000, + 494474369825906688, + 492936600490229761, + 494966767869890561, + 494758739195346946, + 494457935343271936, + 493951516403724289, + 492932294567411712, + 493342043893006337, + 494459946675630081, + 493370892164943872, + 493253797477486594, + 494482873886318594, + 493018764904894464, + 494446836296331265, + 494361239896608768, + 494248556752928768, + 494125878683508737, + 494111197591924736, + 493915758124998657, + 494870659739054081, + 493028719024291840, + 493023860518711296, + 494754519256162304, + 494449860720873473, + 492837503485759488, + 494513537205555201, + 494878840569614336, + 494429759716065281, + 493931008488534017, + 493054214474436608, + 493959979154411522, + 494444154382872577, + 493913609097850881, + 493283186508431362, + 492925569747525632, + 494662868499832832, + 493398587158458368, + 493028097852067840, + 494974661763940353, + 493967822595182592, + 494810407836475392, + 494689578012262400, + 494638765927723008, + 494713773840560129, + 494003730283384832, + 494077123967979520, + 494103348941840385, + 493241382425751552, + 493946272005378049, + 493391964792819713, + 492874160951934977, + 494754576201830400, + 492947521497346048, + 494156865123536898, + 493978135877009408, + 493310874510057472, + 494382039710187520, + 494379743148380162, + 494850408121004033, + 493974246033342464, + 494477047448621058, + 494434463623835648, + 494824136208687104, + 494848588032139264, + 494798624937623553, + 492862957479419906, + 494280725621772288, + 493295192699465729, + 493303573912903682, + 494836016130187267, + 494497859467636737, + 494456779476987905, + 494462827743043585, + 493018351463981056, + 492875682616057857, + 493346916055252992, + 493214645952327680, + 493028386709577729, + 494876873113890817, + 494606473331105792, + 494486188120477697, + 494768744128708608, + 494853195810603010, + 494875469796220928, + 493360286066151424, + 492827382022017024, + 494970262534627329, + 494663672464015361, + 494132166448513024, + 494080978608869376, + 493402703200931840, + 493962020404723714, + 494141182184656896, + 493370488148606977, + 494839726038216704, + 494061815161044993, + 494039771673403393, + 494299141728526337, + 493348686194147328, + 493035878223060992, + 494465322900922369, + 494785761053388800, + 493377691773456384, + 493535409431773187, + 493352449055264769, + 493921342928875520, + 494454830425837568, + 494439962041802753, + 493390489257644032, + 493235318145835008, + 494802961717932034, + 494420441927135233, + 494321156774567937, + 494038362731196417, + 493358395580112897, + 492848043809456128, + 494498426889850881, + 493017111661273088, + 494086978762076162, + 493028995064012800, + 493938834485157889, + 494787921665196032, + 494489425569542146, + 494356799764443139, + 494099887797981186, + 494493371696558080, + 494824740683399168, + 494714035334443008, + 493034484455841792, + 492882748051189760, + 494081390997032960, + 494048957274673154, + 494330910892752896, + 493536046018093056, + 493534593052463105, + 492972720158568449, + 492915736457662465, + 494480733830791168, + 493053150295638017, + 494694118262439937, + 492947367696429056, + 493379900670099456, + 493205679121784833, + 494093844518928384, + 493248726614278144, + 494475515164516352, + 494474092607586304, + 493529634516910080, + 494104076380950528, + 493933210842050563, + 494058213336047619, + 493507288704225280, + 493021851157667841, + 494701636242010112, + 493262839868428288, + 492878817954762753, + 493251582675271680, + 493985567843971072, + 494501293235265536, + 494398960123928576, + 494679464584830976, + 493381689968582657, + 494666039024553986, + 493044939819712512, + 493028127832961025, + 494750145808834560, + 493406322432286720, + 494864913446105088, + 493030939363012608, + 493231441736527872, + 493297986743443456, + 494829641060741120, + 494611804467646464, + 494150696371904513, + 494150139003428864, + 493061120563769346, + 494869129526906880, + 494143082586075137, + 492887928771584001, + 494007911203360768, + 492915909917298688, + 494782262353743872, + 494962527596331008, + 493431210501107712, + 494859429263601664, + 494860484609191936, + 494528471901536256, + 494707201689137152, + 494694752818704385, + 494460122966417408, + 494333229541777409, + 493954014761848833, + 494776461526462464, + 494634609410203648, + 494698506762735616, + 493963482211954690, + 493350493154848769, + 493325220644532224, + 494431116967673857, + 494838884769869824, + 494285297438302208, + 494076505241042944, + 494790896437559298, + 494863639967309827, + 494285011617464322, + 493965741104713728, + 493410111042224129, + 493109278362714112, + 494799639518793728, + 494455973075906560, + 494112552419201024, + 493385628080279552, + 492836100407173120, + 494850308426579968, + 493018938163208192, + 494483080325783555, + 494377420607086592, + 492826868983136256, + 494130389552599040, + 493403241825042432, + 494315475674087424, + 494645502894305281, + 493315752598831105, + 494877876848570369, + 494483886806548480, + 494797595483447297, + 494357659999404033, + 494810212771983361, + 494799262601863170, + 492975867849490432, + 494825245950214144, + 494679852016861184, + 493008296731619328, + 494853501571178496, + 494462451451043840, + 493303277908262912, + 494280832601690112, + 493201140796768256, + 494969742214438912, + 494702890745729024, + 493026033805717506, + 494384719706849280, + 494515846257987585, + 494196835993391106, + 493328458571739136, + 494025918445142017, + 492913813973237760, + 494725247438835712, + 494346653671759872, + 492903554202353664, + 494373105159004160, + 492853909291941889, + 494400461407932417, + 493069130207989761, + 494498375270547456, + 493053240364134400, + 493249548291039232, + 494837627925700608, + 494861072340242433, + 494488728820133889, + 494031575059689474, + 493957028713213953, + 493257849103855617, + 494750140268154880, + 494694281886457857, + 494819795850625024, + 494788186095091712, + 493340610296680448, + 493223608093663232, + 492838648409112576, + 494640671718776832, + 493310575477145601, + 493207379576516608, + 492982182411911168, + 493399870804217857, + 494369930469326848, + 494115133648408577, + 493929849317101569, + 494548865186410496, + 493991881970155520, + 493414243203416064, + 493051173511766016, + 494788835268509697, + 494606817272397824, + 494408605873868801, + 494337442883715072, + 494437852608876546, + 493272857518931968, + 494132931858677762, + 494418378329571328, + 494481598218113025, + 492842459089473538, + 494955266350141441, + 493972211938504704, + 493003644292173824, + 493391044839354368, + 492841108351635456, + 493927261993590786, + 493279925890072578, + 494500906050658305, + 494369378838659072, + 494677893344018434, + 494437016558239746, + 494334932257222658, + 494774459941658624, + 493251989019455489, + 494830955714990080, + 494414183987814400, + 493206301728468992, + 494494768764686338, + 494278617526853632, + 494385259543154689, + 494006299529465856, + 492915610322341890, + 493359439508824064, + 493370464882814977, + 493311804232040448, + 493281712730681344, + 494076570571505666, + 493233995493036032, + 494488847724457984, + 494355179878088704 + ], + "top_users": [ + "92686837", + "166503496", + "540650366", + "1360896643", + "1706043704", + "265768361", + "2376777744", + "1324073262", + "159016009", + "124052932", + "469280874", + "1447935552", + "418591980", + "228696597", + "106659486", + "253980946", + "239312339", + "806016300", + "161992316", + "97679405", + "281954373", + "276240792", + "112651040", + "270879074", + "68037244", + "2219295830", + "862693758", + "150197637", + "257942585", + "136914199", + "136514533", + "452032334", + "1643377730", + "139370904", + "42549961", + "385713036", + "595763350", + "112608103", + "171150195", + "132427897", + "1657118941", + "1649539508", + "332699761", + "277181672", + "2368979952", + "200534692", + "63952674", + "333530956", + "84372072", + "372126633", + "121315885", + "202535910", + "70702735", + "1428509941", + "116852010", + "1425116126", + "50738137", + "372892175", + "126536518", + "359301926", + "195448063", + "137929495", + "422447260", + "362978780", + "259566850", + "1471703268", + "60855116", + "419172620", + "1727606522", + "215692419", + "228243801", + "193592253", + "613590982", + "372454635", + "159080479", + "200031529", + "927695323", + "836633245", + "710385902", + "1307732928", + "162852980", + "1227710852", + "1478683058", + "606267330", + "253431899", + "142083637", + "122346386", + "1979131842", + "2192278603", + "1842561576", + "148566695", + "1039412442", + "595492688", + "2414317748", + "247120995", + "47543698", + "367268825", + "615719058", + "1024094546", + "136649007" + ] + }, + { + "country_breakdown_percentage": { + "AE": 0.29, + "AR": 0.64, + "AT": 0.09, + "AU": 1.13, + "BA": 0.02, + "BE": 0.27, + "BG": 0.04, + "BH": 0.09, + "BN": 0.04, + "BR": 1.47, + "BY": 0.02, + "CA": 1.93, + "CG": 0.02, + "CH": 0.2, + "CL": 0.71, + "CM": 0.02, + "CO": 1.16, + "CR": 0.09, + "CY": 0.07, + "CZ": 0.04, + "DE": 0.4, + "DK": 0.09, + "DM": 0.02, + "DO": 0.07, + "DZ": 0.02, + "EC": 0.13, + "EE": 0.02, + "EG": 0.11, + "ES": 4.64, + "FI": 0.07, + "FR": 2.87, + "GB": 32.19, + "GG": 0.02, + "GH": 0.11, + "GR": 0.27, + "GT": 0.27, + "HK": 0.02, + "HN": 0.09, + "HR": 0.09, + "ID": 3.09, + "IE": 1.73, + "IL": 0.04, + "IM": 0.11, + "IN": 0.36, + "IQ": 0.02, + "IS": 0.04, + "IT": 0.69, + "JE": 0.02, + "JM": 0.02, + "JO": 0.07, + "JP": 2.02, + "KE": 0.13, + "KH": 0.07, + "KR": 0.07, + "KW": 0.31, + "KY": 0.02, + "LB": 0.04, + "LU": 0.02, + "LY": 0.02, + "MG": 0.02, + "MQ": 0.02, + "MT": 0.04, + "MV": 0.02, + "MW": 0.04, + "MX": 2.33, + "MY": 1.82, + "NA": 0.02, + "NG": 0.69, + "NI": 0.04, + "NL": 1.6, + "NO": 0.73, + "NP": 0.04, + "NZ": 0.02, + "OM": 0.04, + "PA": 0.02, + "PE": 0.13, + "PH": 0.51, + "PK": 0.13, + "PS": 0.02, + "PT": 0.13, + "PY": 0.09, + "QA": 0.16, + "RE": 0.02, + "RO": 0.02, + "RU": 0.09, + "RW": 0.02, + "SA": 1.53, + "SE": 1.44, + "SG": 1.49, + "SN": 0.02, + "SR": 0.02, + "SV": 0.11, + "TH": 0.62, + "TR": 3.0, + "TT": 0.04, + "TZ": 0.04, + "UA": 0.02, + "US": 22.64, + "UY": 0.11, + "VC": 0.02, + "VE": 0.53, + "VI": 0.02, + "VN": 0.02, + "XK": 0.04, + "ZA": 0.6, + "ZM": 0.02 + }, + "country_code": "GB", + "device_breakdown_percentage": { + "ANDROID": 11.16, + "BLACKBERRY": 0.25, + "DESKTOP": 35.64, + "IOS": 52.41, + "OTHER_MOBILE": 0.54 + }, + "end_time": "2015-08-03T00:00:00Z", + "event_type": "SPORTS", + "gender_breakdown_percentage": { + "female": 32.54, + "male": 67.46 + }, + "id": "2u", + "is_global": false, + "name": "Community Shield Football", + "reach": { + "total_impressions": 94212071, + "total_number_of_tweets": 1094914, + "total_reach": 5105727 + }, + "start_time": "2015-08-02T00:00:00Z", + "top_hashtags": [], + "top_tweets": [ + 498497161311817728, + 498504531471511554, + 498502748183478273, + 498493295308206082, + 498453284777381888, + 498504827434201088, + 498497839665016832, + 498497080143667200, + 498501080901517312, + 498497043833585665, + 498488977142591488, + 498489265777807360, + 498469685542019072, + 498454394359517185, + 498453609915633664, + 498454187756515329, + 498474885375877122, + 498521101979623424, + 498474538116857857, + 498480246627512320, + 498471409258356736, + 498489002136444928, + 498479788240408579, + 498470959368896514, + 498480620096741376, + 498473981654364160, + 498480689990627328, + 498504696836141056, + 498500142874755072, + 498492185160187906, + 498452645255069696, + 498493659659386880, + 498474419548073985, + 498479776135663616, + 498488638695833600, + 498494847419187200, + 498492981616607232, + 498496132960755712, + 498480439909441536, + 498491565858238464, + 498451378797559808, + 498479473990582273, + 498474589203480577, + 498490466565120000, + 498491083077459968, + 498484953404170240, + 498485579945082880, + 498502265687519232, + 498505085153206274, + 498455515002060801, + 498480345566949377, + 498486702655438848, + 498475199894151168, + 498476248512098304, + 498505913318535168, + 498487511715676161, + 498486990678290433, + 498502367332294657, + 498506093489037312, + 498505416192847872, + 498488501143633920, + 498506292550696960, + 498477785640222721, + 498533213032042496, + 498484791961214976, + 498466961731629056, + 498505681788731392, + 498777500986920960, + 498478469735809024, + 498504427222106115, + 498492559421751297, + 498504813324546048, + 498744968065085440, + 498469457841631234, + 498497215749697536, + 498471015610351616, + 498465431670513664, + 498504694109835265, + 498504547510542338, + 498473763638607873, + 498496866485821440, + 498508469079904256, + 498473412801859584, + 498472452566310912, + 498474105491193857, + 498468820001251328, + 498468984388616192, + 498454306446909441, + 498454091262341121, + 498475666032320513, + 498495014436339712, + 498599295889600512, + 498492168722710528, + 498490653890715650, + 498507690600325120, + 498506524785127425, + 498489721577025536, + 498481823828430848, + 498778307458912256, + 498597605312851968, + 498489998313000960, + 498497247571881985, + 498475336850755586, + 498507827443683328, + 498488760623845376, + 498459874460958721, + 498492649268338689, + 498490077782507521, + 498496593054953472, + 498525770185461760, + 498497953880109058, + 498479501568114689, + 498492855589941249, + 498480361434005504, + 498529239914672128, + 498735777044373504, + 498457514812669952, + 498518049046421504, + 498505621117755392, + 498479391089770496, + 498485776221736960, + 498479059009941504, + 498489698378338304, + 498509947253305345, + 498457133349101569, + 498488591602159617, + 498480767782354944, + 498496689632993281, + 498487306240950273, + 498504596852338688, + 498465415266574336, + 498505543376715777, + 498474732711583744, + 498475114753953792, + 498486619117486080, + 498515876740857856, + 498496564860841984, + 498497514543521793, + 498475179828596736, + 498479731374039040, + 498455943479578624, + 498485352764805121, + 498453808075530240, + 498474637844824064, + 498497048401170432, + 498499004125417472, + 498454724358963200, + 498484390360793089, + 498501174644191232, + 498463521987117057, + 498470055563509760, + 498497196527222784, + 498479556198957056, + 498473074195709952, + 498480308875169792, + 498497218115305472, + 498454394934140928, + 498474428297396225, + 498488954560479233, + 498480534071562241, + 498499983956774912, + 498463318710177792, + 498453406617702400, + 498479361667133441, + 498474285971693570, + 498463528454742016, + 498466351565246465, + 498480481089126400, + 498479696552923136, + 498490354279403520, + 498481509372678145, + 498497033507205120, + 498467766169780224, + 498474152626778112, + 498453729923072000, + 498458904444293120, + 498468137013354496, + 498479589048733696, + 498500302296064000, + 498467843936374785, + 498491068233809920, + 498479713267228672, + 498492921604481024, + 498479645952860160, + 498489169178796032, + 498497806160908288, + 498460832251273216, + 498468098182496256, + 498492454329675776, + 498497136313769985, + 498488923275165696, + 498489515141771264, + 498474751489490945, + 498494531919433728, + 498488892157599744, + 498487516761436161, + 498486696594653184, + 498501536834936832, + 498495903993720832, + 498488623273373698, + 498522939541577728, + 498447589977882625, + 498480627206090752, + 498479499391295488, + 498479604609581056, + 498754717171077120, + 498479327512907776, + 498494971159535616, + 498486282251952129, + 498476195332112386, + 498490691002335232, + 498453763146141696, + 498507837392551936, + 498491859384418304, + 498484733165469696, + 498494841245171713, + 498484514126303233, + 498474753674711041, + 498472468202684416, + 498474413478912001, + 498488490972426242, + 498478232094924800, + 498497299820314625, + 498474401202192384, + 498491186068619264, + 498491623266066432, + 498490442351403008, + 498480297068204032, + 498476523083800576, + 498486715401916416, + 498489568799498241, + 498487545194627072, + 498488942141140995, + 498506147838820352, + 498485514467815424, + 498447104772419585, + 498495832040407040, + 498480370430791680, + 498470885700169728, + 498493159480238080, + 498474359598878720, + 498454075839897600, + 498468362595614720, + 498492648240730113, + 498758312641298432, + 498472065562079233, + 498501952054251520, + 498470467549024256, + 498465379212333057, + 498486555116584960, + 498524216246145025, + 498486242343153664, + 498467387931643904, + 498473377628450816, + 498498488196694016, + 498485272062205953, + 498497067980169216, + 498499367037583362, + 498470078514741248, + 498483995307675648, + 498498798252204032, + 498482661329879043, + 498465367241785344, + 498481827649449984, + 498478075450253312, + 498483029565014016, + 498479461273452544, + 498471644709781504, + 498488486518075393, + 498473756239855617, + 498476576766697473, + 498484842850713600, + 498461943725064194, + 498501267153776640, + 498474963809349632, + 498466081611452416, + 498478650850041857, + 498464158850228224, + 498476463587221505, + 498482913139105792, + 498467069235437568, + 498482817299279874, + 498472595071971329, + 498480847172157440, + 498477976154279937, + 498485124384555008, + 498467402800443393, + 498472910592696321, + 498477394093948929, + 498498669101207553, + 498460725300719617, + 498461446859395072, + 498460673085804544, + 498488868673699841, + 498455138986897408, + 498484913323380736, + 498484092506476544, + 498452783495147521, + 498468925609623552, + 498468653504139264, + 498497666004054017, + 498484626802102272, + 498506510998446080, + 498488674200612865, + 498491712554426368, + 498479732393263104, + 498488785500635136, + 498481343719030785, + 498489054330384384, + 498611672945557504, + 498505668249542657, + 498478112297209856, + 498497172850352131, + 498489170449694720, + 498495799928840193, + 498460603619770368, + 498450633981444096, + 498496599174443008, + 498470382245269505, + 498509175983706112, + 498508519466102785, + 498448643314450432, + 498497253829775360, + 498449803886755840, + 498479516516618240, + 498480004691664897, + 498497511020314624, + 498446814375575553, + 498496290247163904, + 498490761462444032, + 498503078572998656, + 498459917381279744, + 498483730705838080, + 498456880176721920, + 498480655903109121, + 498476771130769409, + 498499807833759744, + 498501463945932800, + 498479374283575296, + 498455148298244096, + 498455896457240578, + 498496024617705472, + 498469419073683457, + 498474416872103937, + 498475687636762624, + 498479455825068032, + 498488952450740224, + 498486172776423425, + 498496634742112256, + 498488625018187776, + 498474363126284288, + 498479397163110400, + 498474331404767233, + 498494230789357568, + 498480442556035072, + 498474303101624320, + 498493254829350912, + 498736416646778881, + 498489067039129600, + 498480539704504321, + 498474218225672192, + 498455700780384257, + 498484949327302656, + 498491912651669504, + 498488790466301952, + 498488672652902400, + 498475911000637440, + 498480175432990720, + 498468978768224256, + 498457706639147009, + 498497059272810499, + 498475428928307201, + 498478355575238656, + 498497763756494849, + 498499342844850176, + 498479350095020032, + 498490373535432704, + 498464431874265088, + 498479618962509824, + 498479802891108352, + 498498450917691392, + 498479317408841728, + 498518121691766784, + 498457677509697537, + 498490980145057793, + 498480459701948416, + 498497199039213568, + 498459351376723969, + 498484699975942145, + 498453851729821696, + 498488585612718080, + 498474432185532416, + 498466852860076032, + 498606862351482881, + 498479883908317184, + 498479706057216000, + 498512965306691584, + 498465532317007872, + 498465959678861312, + 498496820520443904, + 498470427602087937, + 498499181213143041, + 498497193603391490, + 498479841046724608, + 498498698213855233, + 498480557886828544, + 498499443361337344, + 498479379861622784, + 498494199181111296, + 498511709855055872, + 498453463542796288, + 498466886745866240, + 498489339824066560, + 498757101481496576, + 498488604151517184, + 498450854312419328, + 498464461788024832, + 498497070924582912, + 498488940278841344, + 498465007852863488, + 498495011953332224, + 498474218892185602, + 498497344066039808, + 498497433932791808, + 498453468118806528, + 498453484648148993, + 498462294368845824, + 498783653292675072, + 498453887699795968, + 498462864215404544, + 498458226917396480, + 498603763478065152, + 498518461883379712, + 498511619341950976, + 498458251629821952, + 498488744865841152, + 498483125270614018, + 498456321277313025, + 498469486622945280, + 498474161749385216, + 498474616080576513, + 498521271018463232, + 498474451856818176, + 498498145270394880, + 498495303084167170, + 498459628649611264, + 498502215880171520, + 498507012901437440, + 498497649746907136, + 498483562887532544, + 498475019279011840, + 498466506251198464, + 498490446239531008, + 498497357814972416, + 498519562221260800, + 498495156711337988, + 498474322043084800, + 498474600083509249, + 498494587338756096, + 498536131894714368, + 498489294504620032, + 498493049044234240, + 498497388970254336, + 498489919153930241, + 498481613656064001, + 498480787176448000, + 498610259347267584, + 498498814706479104, + 498474284021334017, + 498525488059801600, + 498474489047711745, + 498458073476771841, + 498485105745481728, + 498477394018451457, + 498534513434447873, + 498505687220383744, + 498535740914270208, + 498496208638607360, + 498491511344885761, + 498480114347556864, + 498461713604554753, + 498488836478230528, + 498474240098975745, + 498535340987416577, + 498453571642593280, + 498488660359389186, + 498480542908956672, + 498489077290008577, + 498458016564248577, + 498453561085530112, + 498497966920196096, + 498523032429015040, + 498535087575928832, + 498488241860120577, + 498498449105747968, + 498498899154595840, + 498479627476930560, + 498480703865364481, + 498492558704918528, + 498468730142461952, + 498459926080270336, + 498488833013735425, + 498453051767001088, + 498499809050124289, + 498497661172195329, + 498468652220682240, + 498505115360583680, + 498472031089094657, + 498736263017791489, + 498455339524960256, + 498449034688745472, + 498535123009437699, + 498479446236884992, + 498479760633516032, + 498497196988588032, + 498494160375406593, + 498497491067994112, + 498523630687776768, + 498471654990020608, + 498487942722383872, + 498485035620925440, + 498479844913467392, + 498460107618123776, + 498473676946546689, + 498457334210113536, + 498454225823993856, + 498497461045170176, + 498593092786999296, + 498474321749499904, + 498741030888677376, + 498463740837498880, + 498483260503363584, + 498454012887597057, + 498483239145971712, + 498478710086176770, + 498497176730083330, + 498488715279626240, + 498479498426609665, + 498481174487248897, + 498595378791743488, + 498475320295833600, + 498494653680066560, + 498481006836727809, + 498482573820301312, + 498484799070543873, + 498499924942938112, + 498480561284194306, + 498496722415661057, + 498480570079641601, + 498479579074678784, + 498485605664583681, + 498509882690404352, + 498480308644478976, + 498499431294324737, + 498488876844212224, + 498469235212165123, + 498474286685122560, + 498493559428108288, + 498488854744403968, + 498474191491178497, + 498489934760923136, + 498529344722325504, + 498492013185343488, + 498498647739596800, + 498475368765194240, + 498480638962696192, + 498479618899607552, + 498490387221467136, + 498452411846258688, + 498491349969420288, + 498498887683149824, + 498482596905762816, + 498497551042347009, + 498497323396530176, + 498490828088958976, + 498463361735344128, + 498512907299487744, + 498457289117171712, + 498498284009553922, + 498480618599374848, + 498497457396121600, + 498504074069692416, + 498479416071421952, + 498466351271669760, + 498497016381841408, + 498497465977700352, + 498491105504407552, + 498485482469490690, + 498469596312391680, + 498484631814299648, + 498478392036306945, + 498479816874921986, + 498497534088970240, + 498495627379347456, + 498454733829718016, + 498505928040513537, + 498463204784480256, + 498479381929791489, + 498454465947906048, + 498511897055227905, + 498488658933321728, + 498492790276653056, + 498499074350649344, + 498505015393546240, + 498479837238272000, + 498473176574488576, + 498468875542216704, + 498489269040996352, + 498511021741719552, + 498488927565914112, + 498783258684194816, + 498482090229657600, + 498480577054793729, + 498497674652299265, + 498480800674107392, + 498474415651577857, + 498498649622859776, + 498479959825219585, + 498495625336717312, + 498497581178445824, + 498506188632653824, + 498489189990948864, + 498497323387744257, + 498492295654944768, + 498526849820295169, + 498486402087415809, + 498491388859019264, + 498474251297759232, + 498523430250356736, + 498485300822540288, + 498474694891556864, + 498488748183941120, + 498470891098230784, + 498499725264711680, + 498479528613019648, + 498480097956216832, + 498480728804720640, + 498491126694031361, + 498480655098195968, + 498499232865607681, + 498497016293371904, + 498488803963969536, + 498483295559376896, + 498475114795905024, + 498486171283234816, + 498460879470727168, + 498481072079126528, + 498484909317451777, + 498497279834456064, + 498492558872686592, + 498477478198120449, + 498456474872725505, + 498503176627437568, + 498455081772408832, + 498497105976373248, + 498490213828952064, + 498474523365478400, + 498495248562393088, + 498488737852948480, + 498498134524592128, + 498743575946231808, + 498458270043234304, + 498497004138266625, + 498479543674744832, + 498499288134344705, + 498484822017208321, + 498518084609916928, + 498496671404142592, + 498498227055124480, + 498497803199320064, + 498490630482714624, + 498463211910615040, + 498472552235548672, + 498501720658677760, + 498486456730804227, + 498488794841370624, + 498475180453552129, + 498480484540620800, + 498446987084443648, + 498509488073474048, + 498469776449359872, + 498489304453488640, + 498476541115117568, + 498476800679227393, + 498488608932642816, + 498478137295265792, + 498489190225813504, + 498472011728175104, + 498497079573221377, + 498497275761803264, + 498486200848887809, + 498481252564230144, + 498491897372233729, + 498495572471713792, + 498497421190504448, + 498488870409752576, + 498497030298140672, + 498490051605843968, + 498453023895855105, + 498494620469559296, + 498477437383364608, + 498496987449536512, + 498479460329746432, + 498496857333825536, + 498497957311025152, + 498487618934673409, + 498508067403608064, + 498488625290809346, + 498491615665598464, + 498501316931780609, + 498488625961910272, + 498486587794001920, + 498479701065994240, + 498490224800825345, + 498508687246655488, + 498488678801747969, + 498453743701327873, + 498479473332076544, + 498498726294716416, + 498462109714612224, + 498472483616751616, + 498489520653086720, + 498466919088160768, + 498478676485611520, + 498488823970803712, + 498488649282248704, + 498497821344288768, + 498738552528990208, + 498479445280165890, + 498531719382061056, + 498483044530262017, + 498476166995406850, + 498494913177485312, + 498470480316485632, + 498536301361364992, + 498474487302848512, + 498475076769951745, + 498488927553339392, + 498510053604081664, + 498480855120363520, + 498484964045123584, + 498507135827718144, + 498501033052872704, + 498480582490611713, + 498472967555149824, + 498492977032228864, + 498484877390393344, + 498463836526370817, + 498480449489227776, + 498497250268823553, + 498477212312829952, + 498474781986263040, + 498461595387695106, + 498479736767512577, + 498468680804859904, + 498493066458980352, + 498475371919335425, + 498466675629776896, + 498486149262761984, + 498493408114393088, + 498496941366317057, + 498485923341164545, + 498489920923901953, + 498479322127011840, + 498467855411998721, + 498479645663428608, + 498466854177083392, + 498479737514524672, + 498511697922248704, + 498489054657523712, + 498480921352224770, + 498479990510743553, + 498480019803754496, + 498474218065891330, + 498478600199606272, + 498503311046508544, + 498489401237049344, + 498485348524359680, + 498474373788213250, + 498479373880938496, + 498457476837412864, + 498510483381833729, + 498514430955900928, + 498474211267313664, + 498489187101052928, + 498454010354208768, + 498496915580133376, + 498454264940089344, + 498488821227716608, + 498464498953752576, + 498465990242349057, + 498522054476693504, + 498479821031489538, + 498495097106071553, + 498483316035960833, + 498497333299253249, + 498492049734520832, + 498471829682388993, + 498490424559169536, + 498466267930824706, + 498452869159608320, + 498462518097219584, + 498474577794977795, + 498469304325931008, + 498483039660675072, + 498527402449190913, + 498471234997583872, + 498496329736519681, + 498483987451764737, + 498467757055152129, + 498454097394421761, + 498475265128136705, + 498465433205211136, + 498507891281002497, + 498474579526840320, + 498489049464987648, + 498465859338530818, + 498484716463747072, + 498489870290288641, + 498480442086277120, + 498487000656531456, + 498461249194442752, + 498480456476934144, + 498490713735430144, + 498453639145738240, + 498473693656256513, + 498468368408932352, + 498479784121610240, + 498519510899757056, + 498507946238951424, + 498474460966817792, + 498490474731433984, + 498487471697850368, + 498465933669580800, + 498465646376927232, + 498484686596087809, + 498488710443581440, + 498467804933550080, + 498453346852683776, + 498454996522778626, + 498515596326481920, + 498497128809779201, + 498500151171104770, + 498488724641300480, + 498479826886729728, + 498488964320624640, + 498589698550665216, + 498496175189032960, + 498495548400631808, + 498520261545959424, + 498466326458167297, + 498489399689363457, + 498474241793478656, + 498493943890604032, + 498488759693103105, + 498494478010032130, + 498474201393954816, + 498479731336282112, + 498471546277879808, + 498454045150154752, + 498497097923313664, + 498482264125489152, + 498480028003631104, + 498467973913669633, + 498526687987261440, + 498468884270166017, + 498472567012069376, + 498522628928602112, + 498479740396007424, + 498504259260796928, + 498488693363978240, + 498470075205435392, + 498498804203921408, + 498517969878913024, + 498477524611911680, + 498496160328601601, + 498481804236820480, + 498474828425596928, + 498496302637129728, + 498465561362595840, + 498479592060239872, + 498453034746527745, + 498480296153862144, + 498515546229710848, + 498497724594278401, + 498497648480247808, + 498454828217929728, + 498488946884870144, + 498468858059952129, + 498497915695165441, + 498517275755175936, + 498457418129752064, + 498484782557564928, + 498497600085970944, + 498496342348808192, + 498508306349322240, + 498479496207798272, + 498498911615877120, + 498455087619276803, + 498792282607591424, + 498468917166477312, + 498526398718689280, + 498481420353159168, + 498479762353164290, + 498455812067831809, + 498494418509627392, + 498742493395943424, + 498468897767428096, + 498497172498042881, + 498498101095960576, + 498480097385787392, + 498480600731648000, + 498481146716758017, + 498481101162430464, + 498515551438663681, + 498473213132029952, + 498476433585741824, + 498499566468354048, + 498476074922414082, + 498470763545251840, + 498479601606471681, + 498476516804919296, + 498464200168325121, + 498497973739741184, + 498479800361951233, + 498452497372282881, + 498479656656728064, + 498488642311294976, + 498512293073022976, + 498480326768082944, + 498477503812759553, + 498499500496154624, + 498497511657832449, + 498493501127262208, + 498500386299584513, + 498480675679649792, + 498490574182580224, + 498493447754747904, + 498479467975946241, + 498457586963087360, + 498479902723948544, + 498481576297394178, + 498474797660381186, + 498472141806129154, + 498500091276447744, + 498497833734246400, + 498471614691147776, + 498457100037939202, + 498498317576204289, + 498480741471506433, + 498454441331556352, + 498490278786138113, + 498497479005200384, + 498518280345493504, + 498506925311807488, + 498491616060243970, + 498505288061030401, + 498496690757046273, + 498751041102684160, + 498488831319240704, + 498500495598968832, + 498519013501452288, + 498510261226328064, + 498489229614542848, + 498480332518486016, + 498506388989943811, + 498762962027302914, + 498511193070637056, + 498535288441143296, + 498474308411617280, + 498485041702641664, + 498455026671820800, + 498469097924222976, + 498470515443785728, + 498497827660914688, + 498482497160609792, + 498459778331734016, + 498471608764608512, + 498497710614650880, + 498489691809648641, + 498498157865865216, + 498468282194993152, + 498490498395693056, + 498486640831373312, + 498474616302870530, + 498499038237306880, + 498488675735322625, + 498497081536163841, + 498481728064090112, + 498459090998530048, + 498457594756075520, + 498589632179621889, + 498459423418118145, + 498595475675963392, + 498495110704021504, + 498475375446724609, + 498453421553643520, + 498532044952305664, + 498454180491976704, + 498492607895728128 + ], + "top_users": [ + "34613288", + "216299334", + "14387275", + "14573900", + "39360648", + "37896651", + "266135518", + "533085085", + "108568373", + "44606764", + "471287735", + "435225922", + "26003792", + "69962890", + "1573649600", + "166767883", + "20689749", + "118739566", + "443103982", + "263257931", + "18091004", + "2255036665", + "985172054", + "71108476", + "13087382", + "1372726615", + "119593082", + "19339713", + "580967619", + "1030711922", + "713993413", + "221769011", + "140070953", + "587841789", + "454430831", + "436702610", + "155642429", + "71303860", + "99806132", + "47659350", + "576241232", + "385473825", + "347909288", + "1830525626", + "418380713", + "64252165", + "281199878", + "1131407466", + "265902729", + "552803420", + "21754872", + "199354750", + "15356900", + "571964518", + "229178711", + "22503279", + "2402010382", + "1499266621", + "221850321", + "50853348", + "283894108", + "1627736996", + "64673319", + "268383434", + "489705506", + "354241843", + "220011213", + "317138367", + "298839575", + "365952417", + "1885004688", + "785361792", + "253544925", + "15016249", + "38742405", + "1631928242", + "40837929", + "370536393", + "38839266", + "282182210", + "533386792", + "16099375", + "307827749", + "1966554482", + "471436748", + "212560938", + "436141986", + "637318580", + "557108010", + "129475770", + "2546507294", + "1358062944", + "78021630", + "247239087", + "18286505", + "51293759", + "243867090", + "1023128869", + "240337795", + "1617422839" + ] + }, + { + "country_breakdown_percentage": {}, + "country_code": "JP", + "device_breakdown_percentage": {}, + "end_time": "2015-08-10T00:00:00Z", + "event_type": "SPORTS", + "gender_breakdown_percentage": {}, + "id": "3k", + "is_global": false, + "name": "\u6771\u30a2\u30b8\u30a2\u30ab\u30c3\u30d72015\u6c7a\u52dd\u5927\u4f1a (East Asian Cup 2015)", + "reach": { + "total_reach": null + }, + "start_time": "2015-08-02T00:00:00Z", + "top_hashtags": [], + "top_tweets": [], + "top_users": [] + }, + { + "country_breakdown_percentage": {}, + "country_code": null, + "device_breakdown_percentage": {}, + "end_time": "2015-08-10T00:00:00Z", + "event_type": "OTHER", + "gender_breakdown_percentage": {}, + "id": "3i", + "is_global": true, + "name": "GamesCom", + "reach": { + "total_reach": null + }, + "start_time": "2015-08-05T00:00:00Z", + "top_hashtags": [], + "top_tweets": [], + "top_users": [] + }, + { + "country_breakdown_percentage": {}, + "country_code": "JP", + "device_breakdown_percentage": {}, + "end_time": "2015-08-23T00:00:00Z", + "event_type": "SPORTS", + "gender_breakdown_percentage": {}, + "id": "37", + "is_global": false, + "name": "\u5168\u56fd\u9ad8\u6821\u91ce\u7403\u9078\u624b\u6a29\u5927\u4f1a", + "reach": { + "total_reach": null + }, + "start_time": "2015-08-06T00:00:00Z", + "top_hashtags": [], + "top_tweets": [], + "top_users": [] + }, + { + "country_breakdown_percentage": {}, + "country_code": "FR", + "device_breakdown_percentage": {}, + "end_time": "2015-08-08T00:00:00Z", + "event_type": "SPORTS", + "gender_breakdown_percentage": {}, + "id": "32", + "is_global": false, + "name": "Reprise Ligue 1 (Ligue 1 Opening Day) ", + "reach": { + "total_reach": null + }, + "start_time": "2015-08-07T00:00:00Z", + "top_hashtags": [], + "top_tweets": [], + "top_users": [] + }, + { + "country_breakdown_percentage": { + "AE": 0.13, + "AM": 0.02, + "AR": 0.49, + "AT": 0.07, + "AU": 1.25, + "AW": 0.02, + "BA": 0.02, + "BE": 0.16, + "BG": 0.02, + "BH": 0.02, + "BO": 0.02, + "BR": 0.65, + "CA": 4.45, + "CH": 0.18, + "CL": 0.34, + "CN": 0.02, + "CO": 0.47, + "CR": 0.07, + "CV": 0.02, + "CZ": 0.07, + "DE": 0.56, + "DK": 0.09, + "DO": 0.2, + "EC": 0.11, + "ES": 1.09, + "FI": 0.11, + "FK": 0.02, + "FR": 1.21, + "GB": 14.1, + "GH": 0.07, + "GR": 0.16, + "GT": 0.07, + "GU": 0.02, + "HK": 0.02, + "HN": 0.07, + "HR": 0.09, + "HU": 0.07, + "ID": 0.34, + "IE": 0.8, + "IL": 0.13, + "IM": 0.02, + "IN": 0.16, + "IQ": 0.02, + "IT": 0.67, + "JE": 0.02, + "JM": 0.04, + "JO": 0.02, + "JP": 1.03, + "KR": 0.09, + "KW": 0.07, + "KY": 0.02, + "LB": 0.02, + "LU": 0.02, + "LV": 0.02, + "MA": 0.04, + "MT": 0.02, + "MX": 3.78, + "MY": 0.25, + "NG": 0.04, + "NI": 0.07, + "NL": 0.42, + "NO": 0.11, + "NZ": 0.16, + "PA": 0.07, + "PE": 0.07, + "PH": 0.45, + "PL": 0.09, + "PT": 0.13, + "PY": 0.13, + "QA": 0.04, + "RS": 0.02, + "RU": 0.13, + "SA": 0.13, + "SE": 0.58, + "SG": 0.16, + "SI": 0.04, + "SV": 0.11, + "TH": 0.11, + "TR": 0.65, + "TT": 0.02, + "TW": 0.02, + "UA": 0.04, + "US": 61.34, + "UY": 0.07, + "VC": 0.02, + "VE": 0.34, + "VI": 0.02, + "VN": 0.02, + "ZA": 0.22 + }, + "country_code": "US", + "device_breakdown_percentage": { + "ANDROID": 7.28, + "BLACKBERRY": 0.03, + "DESKTOP": 36.25, + "IOS": 56.17, + "OTHER_MOBILE": 0.26 + }, + "end_time": "2015-08-10T00:00:00Z", + "event_type": "MUSIC_AND_ENTERTAINMENT", + "gender_breakdown_percentage": { + "female": 52.96, + "male": 47.04 + }, + "id": "3g", + "is_global": false, + "name": "Outside Lands", + "reach": { + "total_impressions": 12231057, + "total_number_of_tweets": 74596, + "total_reach": 2824429 + }, + "start_time": "2015-08-07T00:00:00Z", + "top_hashtags": [], + "top_tweets": [ + 497960925186367488, + 498500727442927617, + 498545086179733504, + 499251451026489344, + 498307102650408960, + 498589583509311488, + 497918814541987841, + 497923498975559681, + 497473088939098112, + 498325406131306496, + 499382399990759424, + 498984474105765888, + 497938309252136961, + 498647034447265793, + 498426418058240000, + 497633157005709312, + 497958501428514816, + 497584401815855104, + 499269161835442178, + 498952012155731968, + 498889418695278594, + 499676888248229888, + 497936809188265985, + 500028087518515200, + 499015324281622528, + 498157935537577984, + 497472255191187456, + 497449650950270976, + 498481379555180545, + 499021039431864320, + 497902097581350912, + 497967010362298368, + 497982148994154497, + 497745182042128384, + 498274599922982913, + 498474242493915136, + 497960767996436481, + 498558170831134720, + 499008631049035776, + 498259486050512897, + 498533372025917440, + 499024916784893953, + 499673295818477568, + 498692452547457024, + 498576194154270720, + 498349873205243905, + 498128016183422976, + 498556561846198272, + 497521841356148737, + 498840067801362432, + 497622555126018048, + 498564572304146432, + 499354139751485440, + 498297126250872832, + 499606108944994305, + 498513558808694785, + 497466414266318848, + 497973133291560960, + 497583054383501313, + 498337349760061440, + 497839956673314817, + 498274835668025345, + 498647777472032768, + 498668269495386112, + 497959203664068608, + 498265998764433408, + 498664140786114562, + 497790636096249857, + 497771040575987712, + 498534666811367426, + 497931061158887425, + 497952633681100800, + 498174744064036864, + 498423493961474048, + 498657718325243904, + 498144058502426624, + 497855504161329153, + 498192043320299521, + 498470438591156224, + 497778344176676864, + 498152476529266688, + 498626514989371394, + 498304565146439681, + 497908326273789952, + 497903511913631744, + 498282462011994112, + 498258633956659200, + 498249882550165504, + 498678949203820545, + 498620534150955009, + 498482341397151744, + 498184411699875840, + 498478516816850945, + 498169010018471936, + 497464370310307840, + 498281051849236480, + 498213212689793024, + 497782650279456768, + 498875596253167617, + 498885223027720192, + 498875745700421633, + 497910401439637504, + 498149363760517122, + 498050780331769856, + 498103000360316928, + 497933459398987776, + 500310612069871616, + 498886574722260992, + 499359793002201088, + 498553064899760128, + 498674167282032640, + 498003359065210881, + 498494684067414017, + 498493307652030465, + 497468277157658624, + 498567981878611969, + 498214782831718400, + 497752998160773121, + 499035054224334848, + 497950637137485825, + 497929545367166976, + 498099067277574144, + 498336148565934080, + 497817550856941568, + 497913370499358721, + 497595206720421888, + 498371375053033472, + 498230789650542592, + 497578854454931456, + 497600987633168386, + 498151796741648384, + 499019951920128001, + 497563523489087488, + 497778111971196928, + 497908639198240768, + 498923089351024640, + 497579352583057409, + 498138306639458304, + 498661063668539394, + 497933177533771776, + 498160532437073920, + 498544346464280576, + 498703955711778816, + 497811831042211840, + 499965952570585088, + 497943558725197824, + 498565548989353985, + 498589005773307906, + 498278297227108352, + 497838511119400961, + 498556369977769984, + 499352177681244161, + 497835978648600576, + 498138345894326272, + 498328836388683776, + 498098983274024960, + 498563109041471489, + 498886734021533696, + 497980549584011264, + 498346900429348864, + 498213537794113536, + 497482263521923072, + 498098922892836865, + 499232277256503300, + 499350476488335360, + 498177990426386433, + 499209803047383040, + 497874181086646274, + 499230309255507968, + 498345273391738880, + 497497344682627072, + 497792774402760705, + 498585102260396032, + 498472817319751681, + 498850172160712706, + 498134537914699776, + 499553435998756864, + 498933499114450946, + 499135180301275137, + 499280143379357697, + 497853383349243905, + 499024084177412096, + 498325896320000000, + 497983275676495872, + 498499241614925824, + 498965876990046208, + 498677510176276480, + 497911290170327040, + 498176221981573120, + 497852298778144768, + 498686291983077378, + 498783758267334657, + 497970359077859328, + 497920251749609472, + 498232825607647232, + 498329465168994304, + 497941062753996800, + 497943403166855168, + 500346842023223296, + 497939474202902528, + 498662521835118593, + 497812031534137344, + 498342499451416577, + 498552580793184256, + 498579365777514496, + 499388975019483136, + 498167132455456769, + 497869015058903040, + 498899584278491136, + 498939789802885120, + 500468157786497024, + 497972731011678208, + 498237367795613696, + 497913877909504001, + 497764248554967040, + 498260485351804928, + 499621941766942720, + 498271732050833409, + 497754719146631171, + 498203266266972161, + 498368230319075328, + 498613763470135297, + 497470917434671104, + 498117954496507904, + 498281408477925376, + 497617842301190147, + 497728699223912448, + 498282081693081600, + 497814900844920832, + 497402567941718016, + 498300238726057986, + 499286532730011648, + 499257276729806848, + 498628931814453250, + 498295169620664320, + 497805711770796032, + 498403443824799747, + 498318255912517634, + 498749398185435136, + 498129331970125826, + 498566131045502976, + 499730329192923136, + 497978645609074688, + 497903880194121728, + 497359030327603203, + 497745648171892736, + 498247594947399680, + 498941052154179584, + 498216753919307777, + 498318337823477760, + 498533578213298179, + 499757386232758272, + 497907889772580864, + 497549012309131264, + 498876551719436291, + 498857182939844608, + 498145154763476992, + 498638319857590272, + 497915208644300800, + 498484288200126464, + 498520298858090496, + 499573049306664960, + 497966724545654785, + 498371809222205440, + 497901380540313600, + 498234024750354432, + 498173366537162752, + 498996558113697793, + 498426810246643712, + 498501926862876675, + 501114285050068992, + 498993521450172416, + 498503393514504192, + 498847437034127360, + 497945937335943168, + 497949870460641281, + 498633006148775936, + 497933518782337025, + 498608265555902465, + 498153291197325312, + 499360952555290624, + 500006796539752449, + 497798707203416064, + 498230712147800065, + 498504847759388672, + 498502796484681728, + 498133872974909441, + 498557001329164288, + 499071535424888832, + 498190229434818561, + 498969919611215872, + 498877680184328192, + 498945576105693184, + 498584737330380800, + 497907109397135360, + 498329057088372737, + 497905135821942784, + 498177778668158977, + 497764612851240960, + 497953040247570433, + 498151245819822080, + 498137802911924225, + 498196781772320769, + 498193837173788672, + 498132804706643968, + 498145492224991232, + 497959940569714688, + 498223294961565696, + 498184219781128192, + 498533503102111745, + 498865684253007872, + 498501107782393856, + 497959209409851392, + 498570395004731392, + 498235280365588480, + 497457403206455296, + 498614908628766722, + 497798906256715776, + 498659818396057600, + 498082302090416129, + 498584456337584128, + 498908128805548032, + 497540754118836225, + 499330522225455104, + 498915282908241920, + 498328738602291201, + 498242342227558401, + 497408194629865472, + 497552096409829376, + 500095533927895040, + 497900362762694656, + 497645701896339456, + 498553607591976961, + 498934982513934337, + 497781245212774400, + 497834699025162240, + 498571259006156800, + 497898294576955392, + 498935060394180609, + 497874886254030849, + 498153787903574017, + 498312450291138560, + 499026264528015360, + 498310190291103745, + 498645733554536449, + 499329978119380993, + 498540741702852608, + 497807707790114816, + 497551921172197377, + 498368621932859392, + 498429657734074368, + 498274051077316608, + 497833619050594304, + 497555361063124993, + 499235780423081984, + 497981393507323904, + 498204825990234112, + 498332514277027842, + 498288975652466688, + 497926492005748737, + 498958803170516992, + 498288452291809280, + 498501962619711489, + 497852769538412544, + 498279866421506048, + 497950145158189056, + 497767014941720576, + 499989950696153088, + 499619553841012737, + 498269118219685888, + 498258828581171200, + 497845953865334784, + 497857519889297409, + 497469181814906881, + 499258871110959105, + 498513961445498881, + 497836477007405056, + 498663852847136768, + 499688508877848577, + 498200325270933504, + 498178789566709760, + 498323580858683392, + 498078942989787136, + 498932209760600065, + 498313299394453504, + 498266477720776704, + 497444185491140612, + 497936851395559426, + 498518222917103618, + 497887683029778432, + 498292440818647040, + 498352596705218560, + 498838583168364545, + 497966531263733760, + 498899641589841920, + 498361156793536512, + 497804843143032832, + 497547153514852352, + 497789415041679360, + 498298633620828160, + 498212139727740928, + 497904188933025792, + 497369837728194560, + 497899651203612672, + 498186107792945153, + 498259056042450944, + 498906295945011200, + 497907201714167808, + 499048418505797634, + 498846420019867648, + 497819064820318210, + 497970169130782721, + 498559512320946177, + 498223720696016896, + 497491189340184576, + 500414105040465920, + 498215234180370432, + 497956466582503426, + 497805332949639169, + 498468868528934912, + 498817638198673410, + 497959661870788608, + 498551981678399489, + 497493047874031616, + 498294696339177472, + 499046389523836930, + 497830553224503297, + 498519097018044418, + 498870393957281794, + 497841079102611458, + 499278914179842050, + 497846701365805056, + 498507275351638017, + 497429340619960320, + 499632629260754944, + 498647641946083328, + 497498864765505536, + 498301482542702592, + 498256174576574465, + 498198581883334656, + 498867692036583424, + 499337067076550657, + 500392640995532800, + 497896990080892929, + 497834670722396160, + 498354282157330432, + 498944453369815042, + 498589914469265408, + 498963005091352576, + 497906157340475392, + 498245400986669057, + 498204638433120256, + 498591562671345664, + 498273876208795648, + 497802279064326145, + 498489801138376704, + 500332661252964353, + 498319999014948864, + 499066439630737409, + 498557423439724544, + 499389939713187841, + 497830324156776448, + 498333095213670400, + 498529631356862464, + 498663671514791936, + 498168832276848640, + 497736818511462400, + 498874759837659136, + 497856527106318336, + 498914258302672896, + 499245017592889344, + 497840350866575361, + 497571479920209921, + 497372781265580032, + 498207301342601217, + 497542628045766656, + 497914946617765890, + 498793603364184064, + 497505870100451328, + 497863866030624769, + 497902664403795968, + 498182003083059200, + 498606173306634240, + 499056453823791104, + 499003141740711937, + 498869044812869632, + 498666216269950976, + 498271544645148672, + 497545012641804288, + 497845628651577344, + 497966454449266688, + 498367834670366720, + 497412718497120257, + 499680433643466752, + 499217003895214080, + 499313193404362752, + 497863125966651392, + 498203749618176001, + 497963575097712640, + 498151850017693698, + 498348238034829312, + 498355875053330432, + 498963069410631680, + 499674523214831616, + 499333260267098113, + 498180626319941632, + 498163066962710528, + 497853260816871424, + 498959595574792193, + 499395717085929472, + 498531324999630848, + 498162831548624897, + 498686467741597696, + 497449596277096448, + 497577467264401408, + 499404440894316544, + 498219005543342082, + 499664541991858176, + 497834695158013952, + 498852134667161600, + 497417139117367296, + 497768206778372096, + 498995561887199236, + 498540309261733888, + 497843601569636352, + 497980064546713601, + 497769558237642752, + 497872742654296064, + 497638431841742848, + 499942336710049792, + 498553857459634177, + 498499048593043456, + 498530703899123712, + 498424414116270080, + 499660266880380928, + 498670200154501120, + 498248749333118976, + 498367210495041536, + 498936963873779714, + 497817068440678400, + 498670868911120388, + 499782666523537409, + 498231302848774144, + 498636128493117440, + 497926041319788544, + 497490148162936833, + 498171591558451201, + 497972557325139968, + 498227592433254401, + 498246277814292482, + 497576188672761856, + 498870349874733057, + 498258682661326848, + 498683201741930496, + 498957832663076864, + 498270207954006016, + 497831437668610048, + 498301043432624128, + 497510275382136833, + 498505021009297409, + 499329094237298688, + 497991090407243777, + 498236111928303616, + 497599192240377856, + 499022481173520385, + 498422952052805633, + 497829913551196161, + 497482586814312448, + 497849529593778178, + 498553153923448833, + 499584139343851520, + 497591272098758656, + 498119769992986624, + 498868424559177728, + 498512866475929600, + 498626424698175489, + 498197179664568320, + 498244347683299328, + 500066301767737344, + 498084325435273218, + 498597118568042497, + 498418445126754304, + 497928039733673984, + 497937864303194112, + 497936778393694208, + 497786918034083840, + 497784348850937856, + 498250015156879360, + 498243267645800448, + 498885844074123264, + 497602674263875584, + 497968761375166464, + 498243207465926656, + 498286365667524609, + 499059840304820225, + 498693109967245314, + 498528676435472386, + 498238478535389184, + 498608737070772226, + 497552820610924547, + 497573249799041024, + 498158428913950720, + 497577552324853760, + 497502082220306432, + 498589718016036865, + 497952323939749889, + 498556408460509184, + 498501510460760064, + 497545565647818752, + 497680917553758208, + 498529474796064768, + 498184259887042560, + 497807856318423041, + 497777332879245312, + 499936450746810368, + 497819144499515392, + 497962533844971521, + 498894296826007553, + 498997032036495362, + 497830928933085185, + 499004611723022336, + 499372541996449792, + 497447420465512448, + 497917115903381504, + 498177238643527680, + 497571945114652672, + 498867072533659648, + 498318852158009344, + 498517291990921218, + 499425557256232960, + 498377771098185728, + 497958451633344512, + 497573475930755072, + 499253057545183232, + 497957409084555264, + 499340294895456256, + 497892403752083456, + 497423472512233472, + 498134441051426816, + 498143169666498561, + 497634601011916800, + 497971419259478016, + 498716732165738496, + 497500132896538624, + 498893575179227136, + 497517642500960257, + 498645083260866560, + 498329661718278144, + 497970190827532288, + 498173546297032704, + 500445356505968640, + 497969572969189376, + 499106701031645186, + 497941305306017794, + 498273782466105345, + 498894295873908736, + 497756397380325377, + 497990950526783488, + 498246156120752128, + 497545649869426688, + 497801847743463424, + 498505343321010176, + 497622592313118720, + 498268541091471360, + 498160475998138368, + 498257744009637888, + 498258682690666496, + 497923900269809664, + 498514011843878912, + 497935432194478080, + 497958111593132032, + 497955016854867968, + 497606955129520128, + 497944380569702401, + 498628762469416961, + 498352485061632000, + 497857810944638976, + 499042746079137792, + 498844439193063424, + 500370874894008320, + 498897182750015488, + 497924240679899139, + 498887721721397248, + 498666998734151681, + 497882268367851522, + 497962493005029377, + 498354345826865152, + 497424428859285504, + 498704659851124737, + 497933057035214848, + 498571605203632128, + 498286760200536064, + 497981205783281665, + 498540934397579264, + 498271857590546432, + 498589874313003008, + 498636379010904064, + 498349792784048128, + 497823407031873536, + 500371125210468352, + 497611895973498880, + 498328478995857409, + 497883703838654465, + 498327899049443330, + 498267625693011970, + 498924900074020864, + 497923590113615873, + 498273782357041153, + 497944889892827139, + 497925775685730304, + 498887720962252800, + 498531485407010816, + 497876408069550080, + 497828171320807424, + 498011167277608961, + 498121926704107520, + 497919522649944065, + 498170223313186816, + 498175497805651968, + 498149260656123905, + 497946205020647424, + 497582718327070720, + 498504083649875968, + 497536085614804992, + 497957656443633664, + 497929138821267457, + 500047225657909249, + 499258608790827010, + 497943376017113089, + 498648399894568960, + 498430667546722304, + 498713284535545857, + 498883256767774720, + 499861999220555776, + 497960095662092291, + 498622489275027456, + 498501683019005952, + 498628465768538114, + 497906072233836544, + 498729808030072832, + 498615155111247872, + 498286978291359744, + 497578019268354048, + 497591740074065921, + 498337164350857216, + 498361819455426562, + 498353740261228545, + 498680264537538560, + 497591364927107072, + 497513828750348288, + 498869282877743104, + 498311045447155713, + 498272732183015425, + 498325434828742656, + 498642037277614080, + 497425746520846336, + 499036584604626944, + 498534416243650560, + 498526379743252480, + 498321107930198017, + 498699640066162689, + 498733734535766016, + 499013239871897600, + 498619844984864770, + 499581575248769025, + 497757905823608835, + 498559143951618049, + 497417377550991360, + 497854885505687553, + 498308938627301376, + 497988078808481792, + 498304136845074433, + 498323751381905408, + 498163315902648320, + 497965872619597825, + 497807549992042496, + 497774272719638528, + 498007530401173504, + 498353647177056256, + 498219324251713536, + 498879621111480320, + 498148770505568258, + 498004269266522112, + 498340081921314817, + 498934001760219136, + 499752446433198080, + 498140458338746370, + 498527569424416768, + 499981099104485376, + 497921867748220928, + 498167683410427904, + 497821549542387712, + 498409702167154688, + 498524653493559296, + 498180667751276546, + 497517115465666561, + 498247708503588864, + 498960669669330944, + 498258222516412416, + 498333087328378880, + 498543143675895808, + 499037528067158017, + 498491937649725442, + 498281580977471488, + 500011786331238401, + 498101023081504768, + 497960876197294081, + 497915239363395584, + 498654827937673218, + 498225205278294016, + 499490605312266241, + 497737098108370944, + 498511502735708160, + 498224554653675520, + 498214387283292160, + 497936029085868033, + 499695639911874562, + 498704115640180736, + 498281843779960833, + 497968863477526529, + 497590025941299200, + 498634339929042944, + 499988299889790976, + 498717394383024128, + 500492383319236608, + 498136627303448576, + 499983187653570560, + 497782516359520256, + 498488614733365248, + 498529259242397697, + 497958851690254336, + 500814347376263168, + 500771523171340290, + 497864313579651072, + 497887770874880000, + 498004268469596161, + 498704023059324930, + 497757804602482689, + 498894141829693441, + 498669517468205056, + 498334966959583232, + 498027321606307840, + 497936776581763073, + 500568229774110720, + 498601660814745600, + 498670978436567040, + 498643411327401984, + 497384746121297921, + 497863666952593409, + 499684524956348416, + 498621074716635136, + 497911380008501248, + 498247426357338112, + 497785717796245504, + 498273125709402112, + 498152009124827137, + 498192648805830657, + 498342491414724609, + 497676128665223169, + 499131776795561984, + 498686465329483777, + 498677287194087425, + 498296695101198337, + 498181223223545856, + 497892411201159168, + 497806455291269120, + 498303917617602561, + 497939080194555905, + 498852820419084289, + 498719896235040768, + 498924952486019072, + 498355152147857408, + 498537176976478208, + 498166869728051200, + 497987923401134080, + 498635543173808129, + 498263567251275776, + 498557356226011136, + 498629645827584000, + 497460656120266752, + 497996514052939776, + 497849450615046144, + 498306580417224705, + 497902667478212608, + 498552642260307969, + 497465926959112192, + 498153345056784384, + 498199794163400704, + 498668710794887168, + 498166965916008448, + 497757625627312130, + 498281313183756288, + 498711877246263296, + 498641060793708544, + 498284698192207872, + 498259737109340160, + 498530396733444096, + 498509167460888577, + 497580780529266688, + 497939639735689216, + 498688292444205056, + 497769821342142464, + 498320672318558208, + 498646721119793153, + 498092618052423681, + 497944783789125633, + 497898204050890752, + 498578949090185216, + 497582638623096832, + 497494843606585344, + 499001912918700032, + 498642195533279233, + 497947247645294592, + 497960650279100416, + 498497811915497472, + 498326620244283392, + 498232948479778816, + 497774841731104768, + 497937951536324608, + 497407631003115521, + 498225826127564800, + 498194868259536897, + 500371912653275137, + 498167269848268800, + 498725812506755072, + 498309481768288256, + 497966018334302208, + 498526972058681344, + 498293198280998913, + 498931191840387072, + 497955416119472128, + 498858043551936513, + 497954285196300288, + 498240952444526592, + 498560094951321600, + 498004267047714816, + 498325416654819328, + 498154040111271936, + 497887509368430593, + 498254817513709568, + 498192273453379585, + 498327875523592192, + 498195521744695296, + 497865574249422849, + 498290107758415873, + 498211155198754816, + 498714482860752897, + 499620875554279424, + 498536235241975808, + 498184323892125696, + 498570256852336640, + 497457461800869888, + 498260645788135425, + 498167682672234497, + 498521536064536576, + 498137225490874368, + 497959315542515714, + 500358876911656962, + 498677543621623809, + 498004267723010048, + 498670177962049536, + 498261541272432640, + 498166020058939393, + 498635115153874944, + 498326254865506304, + 498193004394336257, + 498233557824049152, + 498944460567609345, + 497760049830191104, + 498488560832753664, + 498283740179623936, + 497900836270661632, + 497810619161407489, + 497442168479698944, + 498673502090571776, + 498299272073576449, + 498547869419200512, + 498208036930854912, + 498172009407193088, + 498535489574813696, + 498283470037458944, + 498172359145046016, + 498511129123885057, + 498704456167342080, + 498640974642675712, + 497997802010472448, + 498713590472654848, + 499710763284439043, + 499026553343201280, + 497901690264092672, + 499730904538177536, + 498187334505213953, + 497853864100380672, + 498563435316391936, + 497971279253995521, + 498290457278181376, + 498851171306463232, + 497438067578646528, + 498627268902547456, + 497890463341617152 + ], + "top_users": [ + "25365536", + "26601342", + "18159470", + "40101400", + "431921733", + "17936793", + "39600564", + "9695312", + "38502678", + "602317143", + "181589093", + "373471064", + "169962549", + "103467620", + "19329393", + "14992840", + "19063323", + "24190981", + "274002139", + "18993395", + "18949610", + "126000232", + "378041590", + "16870853", + "18937428", + "326889905", + "17486893", + "109702390", + "35554723", + "445659911", + "15652540", + "15515919", + "136505371", + "18125335", + "36511031", + "14511951", + "37572591", + "22679419", + "246515294", + "49608424", + "30925378", + "145835700", + "376502929", + "30018058", + "29891110", + "262921126", + "438897828", + "1393084052", + "288574927", + "172933437", + "161966800", + "58742042", + "31271020", + "5135521", + "40076725", + "20035593", + "14740219", + "20097362", + "47786489", + "1496971", + "17222678", + "18583294", + "18132494", + "15553222", + "15066760", + "18220767", + "69671781", + "8962732", + "14093707", + "52810109", + "189470083", + "6273552", + "21362105", + "28074588", + "17244030", + "261945610", + "168960199", + "175091719", + "30278532", + "3362741", + "74580436", + "1931324696", + "66515223", + "73402597", + "30347257", + "551348611", + "16306235", + "21249332", + "33588206", + "111556701", + "22811432", + "46509384", + "59837460", + "237414634", + "1433866286", + "1709164238", + "20012399", + "183075111", + "154175423", + "64654475" + ] + }, + { + "country_breakdown_percentage": {}, + "country_code": "BR", + "device_breakdown_percentage": {}, + "end_time": "2015-08-10T00:00:00Z", + "event_type": "HOLIDAY", + "gender_breakdown_percentage": {}, + "id": "35", + "is_global": false, + "name": "Dia dos Pais (Father's Day)", + "reach": { + "total_reach": null + }, + "start_time": "2015-08-09T00:00:00Z", + "top_hashtags": [], + "top_tweets": [], + "top_users": [] + }, + { + "country_breakdown_percentage": { + "AE": 0.13, + "AR": 0.49, + "AT": 0.07, + "AU": 1.52, + "BD": 0.02, + "BE": 0.04, + "BH": 0.02, + "BN": 0.02, + "BO": 0.02, + "BR": 0.66, + "CA": 4.95, + "CG": 0.02, + "CH": 0.15, + "CL": 0.18, + "CO": 0.53, + "CR": 0.07, + "CY": 0.02, + "CZ": 0.07, + "DE": 0.38, + "DK": 0.2, + "DO": 0.02, + "EC": 0.07, + "EG": 0.02, + "ES": 1.97, + "FI": 0.22, + "FR": 0.68, + "GB": 16.85, + "GG": 0.02, + "GH": 0.02, + "GR": 0.15, + "GT": 0.11, + "HK": 0.04, + "HN": 0.04, + "HR": 0.09, + "HU": 0.04, + "ID": 0.15, + "IE": 1.33, + "IM": 0.02, + "IN": 0.13, + "IS": 0.07, + "IT": 0.8, + "JE": 0.02, + "JM": 0.04, + "JP": 0.97, + "KH": 0.02, + "KR": 0.07, + "KW": 0.09, + "KY": 0.02, + "LB": 0.02, + "LU": 0.02, + "MK": 0.02, + "MT": 0.02, + "MW": 0.02, + "MX": 1.08, + "MY": 0.18, + "NG": 0.15, + "NI": 0.02, + "NL": 0.75, + "NO": 0.44, + "NP": 0.04, + "NZ": 0.11, + "PA": 0.07, + "PE": 0.11, + "PH": 0.24, + "PK": 0.04, + "PL": 0.04, + "PS": 0.02, + "PT": 0.2, + "PY": 0.04, + "QA": 0.02, + "RU": 0.02, + "SA": 0.42, + "SE": 1.44, + "SG": 0.2, + "SI": 0.02, + "SK": 0.02, + "SV": 0.02, + "TH": 0.29, + "TR": 0.55, + "US": 59.11, + "UY": 0.09, + "VE": 0.15, + "VI": 0.02, + "ZA": 0.29 + }, + "country_code": "US", + "device_breakdown_percentage": { + "ANDROID": 8.6, + "BLACKBERRY": 0.05, + "DESKTOP": 35.87, + "IOS": 55.17, + "OTHER_MOBILE": 0.32 + }, + "end_time": "2015-08-17T00:00:00Z", + "event_type": "SPORTS", + "gender_breakdown_percentage": { + "female": 37.1, + "male": 62.9 + }, + "id": "2i", + "is_global": false, + "name": "Golf: The PGA Championship", + "reach": { + "total_impressions": 268804611, + "total_number_of_tweets": 1501084, + "total_reach": 8874231 + }, + "start_time": "2015-08-13T00:00:00Z", + "top_hashtags": [], + "top_tweets": [ + 498520375928848384, + 498626103926620160, + 498629637556432896, + 498574451852992512, + 497487526719127552, + 495993053333954560, + 498631849582030849, + 497414791708024832, + 498578773324099584, + 498590298751369216, + 498612875758690304, + 498597628163416064, + 498578634337034240, + 496071597070237696, + 498630878528942082, + 498560399021981696, + 498604677236551680, + 498632440274251776, + 498630797914828801, + 495273368858685440, + 498187048214605824, + 498587281650114560, + 498533498945552384, + 498631925100449792, + 498563829882945537, + 498575418761703424, + 499986022420066305, + 498621645482131456, + 498195027143569408, + 498586475270004736, + 498181747746816001, + 495333075770150912, + 498551402407657473, + 498603772839751681, + 498599355071623168, + 498632885159473152, + 498510441166176256, + 498634021686222848, + 498622526449541120, + 498631217173250048, + 498605862270013441, + 498632087550066688, + 498630830344794113, + 498631029800710145, + 498608631269838848, + 497505483616288769, + 497531185434996736, + 498246197845704704, + 498630953125044224, + 498487820252901377, + 498519360177467393, + 497778113234100225, + 498506822563954688, + 498578843670552576, + 498583805121531904, + 498628377503596544, + 498630496549879808, + 495280568418856960, + 498264262188740609, + 498620431151431681, + 498631720963682304, + 497513695925133312, + 498570872110600192, + 498630790016958464, + 498620413056806912, + 498626862332276737, + 498611644738834432, + 498220787393105920, + 498633510580936704, + 498624298551345152, + 498526897505312768, + 498225402373218304, + 498630866726584322, + 494960703430995968, + 498611435363377154, + 498631144636968960, + 498631966384992256, + 497818832107765760, + 498621570433421312, + 498519081046515712, + 498630863736029185, + 498242855916560384, + 498613673855033346, + 497456160669462528, + 498237547873853440, + 498537766947672066, + 498233619413209089, + 498531353009197058, + 498625240000626688, + 498634383533019136, + 498238583460073472, + 498613141610438657, + 498579454793633792, + 497830380935061504, + 498631793126694913, + 498579967153045504, + 495653419978600448, + 496025702643556352, + 498265508790415360, + 498623359228211200, + 498565560452808705, + 498633634149330944, + 498529992087994368, + 498549106256936961, + 498520013121548288, + 498598052622794752, + 498264908690358272, + 498541171388739584, + 498593390238646272, + 498610609366499328, + 498631603732492290, + 498518945423699969, + 498554816348844033, + 498197039663284225, + 498248637391327232, + 497537908136738816, + 498633432948539392, + 497780863124652033, + 498564503651745792, + 497889498924335104, + 496007567664230400, + 498574817386565632, + 498624562360094720, + 498604398680219648, + 498622288955473920, + 498186068551020545, + 498602291029889024, + 498605427912114176, + 498511349111336960, + 498585493396017155, + 498246022507003904, + 498127121416740864, + 498517730333818881, + 498630788188229632, + 497428737689124864, + 498624980905521153, + 498532286342909952, + 497431417824239616, + 498627377581146112, + 498210465479393280, + 498199410460078080, + 498194511819206656, + 498168992545382402, + 498607479782404096, + 501140200605896704, + 497440934641303553, + 496072628214702080, + 498590353495441408, + 498581550314061824, + 496069114566553600, + 498622547424858112, + 498631843739353088, + 497487727022342145, + 498612003712544768, + 498570962498228226, + 497815758357819393, + 498631477987663872, + 498574553258663936, + 497826735858393088, + 497490494960988160, + 498571010099412992, + 497491098340581376, + 497437063096963072, + 498599628334694401, + 498631896273027072, + 498484008003829762, + 498189116933414912, + 498627042070781953, + 498581205592580096, + 498599447560220672, + 497788437576306689, + 498615158810640384, + 497483919693209600, + 498540905897684993, + 498601422691123200, + 497442225761316864, + 498632748161302528, + 498629843400269824, + 498566543668961280, + 498584604295827459, + 497450966409834497, + 498158129876860929, + 498483930220466176, + 498613088187596801, + 497890321033097216, + 498512745768050688, + 498539062815625216, + 498224839904485376, + 498612115461386240, + 498619966841974784, + 498605210793938944, + 498630846770085888, + 501102629188276225, + 498153951834165249, + 498540981252550656, + 498531844648747008, + 496043464489177088, + 498633288467378176, + 498236825341673472, + 498580945222762496, + 498228229233467392, + 498631351227015168, + 498229702872805376, + 498577774152781824, + 500715630535118848, + 498515960098074624, + 497889280434634752, + 498512869743263744, + 497875780685561856, + 498608522146643968, + 498628379609165824, + 496026221038551040, + 498478289262895104, + 498631302061772800, + 501079766934749184, + 501110218638761984, + 495662180038348800, + 497497068282212353, + 500013131335475201, + 498578904811331584, + 498601773087883265, + 495646484961173505, + 498630079618899970, + 498602750385860609, + 501121573047521280, + 498631703284310016, + 498631598263119873, + 498612830837698560, + 498594415427211264, + 498584912535228416, + 500016681863770113, + 498213801423286272, + 498057189320581120, + 498632494707933184, + 500752469044248576, + 500743049098833920, + 498605446132146176, + 498226585645096960, + 498633537596030976, + 498587812053397506, + 498617036197859328, + 498631287411068929, + 495666602650509313, + 496062176776695808, + 498527139306950656, + 501118988848734209, + 498633473738170369, + 498264704197074944, + 500356290045292544, + 498633533976350721, + 498217287259017217, + 496065853008674819, + 498575589507624960, + 498628825740480512, + 501120032605483008, + 498594438713573376, + 495675438224920577, + 498227510396858368, + 498604048774610945, + 498628746895949825, + 498634051188953088, + 498551979749425152, + 498163884411600896, + 500760665385357314, + 500761896119975936, + 498622519679934464, + 498190537493471232, + 498604623767547904, + 498476821655330816, + 498145821901484032, + 498632327862685698, + 498630933210099714, + 498630912398344192, + 498615954038083584, + 498478676258742272, + 498525644523700224, + 498625224817278976, + 497417026668097536, + 498630990978244608, + 498602801749303296, + 498628013668704258, + 498627893552218112, + 500715014765154304, + 495359244016058369, + 498608038430134272, + 496065356294008832, + 498632931452399616, + 498607853708771328, + 498579493347262464, + 498632077177151488, + 498626299272122368, + 497436673425555456, + 498542223982886912, + 498631518370414592, + 498629306709323776, + 498626586120568832, + 498613610869174272, + 498633159857410050, + 498568493462478848, + 498631348706631681, + 498271693430079488, + 498628541223690241, + 498513199826604032, + 498575620851634176, + 498536879734530051, + 498609260469948416, + 498541434698760193, + 498629570367877120, + 498630773214552064, + 498633789422051328, + 498609045184729089, + 498551185163714560, + 500691669348794370, + 498631368243679232, + 494905501667172352, + 497458840846491650, + 498631791172136960, + 498621514124902400, + 496068044318605312, + 498215872670875648, + 498605003360448512, + 498618078801199104, + 498623195105472512, + 498609592080019457, + 498631851704352770, + 498188929372127232, + 497847934034403328, + 498178330009403392, + 498204184425271297, + 498606889975173121, + 498613659900583936, + 498631637681582081, + 498514971261935616, + 498625562047688704, + 498631374312452096, + 498193311664852992, + 495289544192045056, + 498187846436405248, + 498188490610196480, + 498625748635484160, + 498603791579906051, + 498633748200816640, + 498620334841409536, + 498532713372983297, + 498624613203849216, + 498633697235836928, + 498200017795317761, + 498152047448182784, + 498243579278794752, + 498603436300972032, + 498511045175312386, + 497821408102068224, + 500345469793341441, + 498576639622909952, + 498520157917282304, + 498547994003013633, + 498261712991444992, + 498625149990866945, + 497485497380261888, + 498177897988112384, + 498261407297568770, + 498632666393346048, + 498143875215933440, + 498622325517205505, + 498170021609472002, + 498553999503929346, + 498624361386225664, + 498620510667018240, + 498575006671319041, + 498540994644570112, + 498631017649827841, + 498625850372550656, + 498540673893941248, + 498626960978108416, + 501120644231483392, + 495990807649067008, + 498623879104192513, + 500690812708327425, + 498632767429967873, + 498517352649342976, + 498630813533995008, + 497832700376408064, + 498625729790500864, + 498632170013872128, + 498541028618797056, + 498602425964830720, + 498544349928759296, + 498545035835887616, + 498213506005884928, + 495991940018864128, + 498632404202823681, + 497536571470798848, + 498131932946128896, + 498227680701980672, + 497426220989317120, + 498541061661532160, + 498108631607685120, + 498516271667744768, + 498504803241447425, + 497846825261363200, + 498131120169689088, + 497880518227423232, + 498634276028432384, + 498533535074906112, + 498523629605244928, + 497901449339486208, + 497482897952342017, + 497884705799557120, + 500001502136901632, + 498630083318648832, + 497831052535025664, + 498628604868448256, + 498629796067176449, + 497861127259570178, + 498239142774325250, + 498597486450069504, + 498533209882505217, + 498541138434080768, + 498608728057577472, + 498541065322786817, + 498627990864281600, + 497856473968291840, + 498541115772239872, + 498156894029348865, + 498630449288466432, + 498592589491081216, + 498625375677988864, + 497459810691211264, + 500412914004934656, + 498603533340377089, + 498491467858706432, + 497904389160701952, + 495998981055709185, + 498607430951911424, + 495948647948111872, + 498601335072096256, + 501053220043902977, + 497827173710184448, + 498605516743245826, + 497826439224238080, + 495301974716600322, + 498634399135830016, + 498604679270383616, + 501087820841504769, + 501112504601550848, + 498605856330899457, + 498633148486262784, + 497475398910099456, + 498188407156539392, + 497846848212963328, + 498139248793776128, + 498627451766198273, + 498605548460593152, + 498613581706178560, + 498631336052404226, + 497860731287506945, + 498630769620037632, + 498195879228997633, + 495605681928806400, + 498629457624563712, + 498539897439780864, + 497493553614815233, + 498261445067669505, + 498620660994670592, + 501098391515181056, + 498607913976741888, + 498634101927059457, + 498622258722897920, + 498608568002949120, + 498513321570865152, + 497796796769660928, + 494934931874021376, + 498603463891505152, + 498629552705634304, + 498621594332192768, + 497803795108081664, + 497456608310345728, + 501078424174465025, + 498578642750799872, + 498526558127390721, + 497796168026685440, + 500007962669514752, + 499991606947512320, + 494943644034818048, + 496000062192123904, + 497458810311950336, + 500009794565341184, + 498541080724635648, + 498609031296999424, + 501076997356150784, + 497845593125822464, + 498111830171344896, + 496070065583030272, + 501093105744236544, + 498140407600263168, + 495992125977157632, + 498543935052980225, + 497454394762211329, + 500699182253236226, + 495593873109159937, + 497814603909185536, + 498483951636586496, + 497436373570162688, + 501062515779186688, + 501071816577024000, + 498631741792608256, + 498593399222444032, + 500358868724355072, + 498569448496717824, + 498561928328151040, + 498563550814937089, + 495585185711542272, + 500716836020043776, + 498630443483553792, + 498120802328674304, + 496041586716065793, + 498578791518576640, + 498604114738438146, + 498612258109673472, + 498619828232798208, + 498253285824798721, + 500705782837837824, + 498625998616027136, + 495314925070610432, + 498540920770658304, + 498507302941376512, + 498205039190872064, + 495598401355268096, + 501069316402712576, + 498622523224121345, + 498631008292732929, + 495987106469408769, + 500020791359315968, + 498586844473622528, + 498626145815126017, + 500710422744666113, + 497888217258295297, + 498215398719123456, + 495612227987472384, + 501080627081646081, + 498627429607276544, + 500708582435074048, + 498630923882336257, + 495987515816697856, + 497859830162653184, + 498182553346801664, + 500697621967949825, + 498541175796928512, + 496055077661323264, + 498162229108559872, + 498632564547280897, + 498229207546085377, + 498516126200897536, + 498629549681160193, + 498554632801890304, + 498631199603318784, + 498630837483892736, + 495613381572063232, + 495280644822695936, + 498629410623205377, + 500674679154421761, + 498124983093460992, + 500376633875103745, + 498630046874365953, + 495641866478833665, + 498627062065033216, + 498626105591341056, + 498190867233271808, + 498175843181809665, + 495592215507648512, + 498630765887123456, + 500731220620480512, + 501111865502887936, + 500725422787932160, + 500357666808803328, + 498597635927064576, + 495977573693005825, + 498571462559539201, + 501094587612807168, + 498531946691969024, + 501096109390172160, + 498601218089156609, + 498211324800024576, + 500723800070451201, + 498129086829821952, + 494966499900010496, + 500675290935590913, + 495253890892570624, + 498124045276446721, + 498535331030130688, + 500739525581496320, + 498597381399527424, + 500687301899350016, + 498534423466213378, + 500721476124016640, + 498617889029894145, + 498623156245262338, + 498193391893889024, + 500016815607914496, + 498620537921617920, + 495988044932317185, + 498580518875963392, + 498235946027208704, + 494968638873821184, + 498613052162736128, + 498630520100900864, + 498513812350599169, + 498515296336875520, + 498228069803773952, + 500004184914427904, + 498594884581081088, + 497810409718427648, + 494935161218551808, + 498626033210646528, + 498518274096001024, + 498125433435856896, + 497855094780481536, + 498631197736861699, + 496052150649520128, + 500730719199838208, + 500362544343965697, + 498606539096473600, + 498628208938721281, + 498626311980871681, + 498522107559415808, + 498238459556151296, + 500705630018351104, + 498571103477178368, + 498634330311098370, + 498587395940679680, + 495990897214234624, + 498602715715756034, + 500737515503222784, + 500344170826174465, + 498573928332529664, + 500764944477212673, + 501120464551698432, + 498630935362170880, + 498630864423510016, + 498142447848157184, + 498167834040889346, + 498604209244491776, + 498607938496237568, + 498631962161344513, + 498601156302868480, + 498632075281330176, + 498576381056651264, + 500029578652704768, + 494917027950526464, + 500011945454751745, + 498599874896883712, + 497833539702759424, + 498620223810207744, + 498512395107446784, + 498540703559872512, + 497820032907218944, + 494929853100335104, + 495324482459148288, + 498632237207023616, + 497459376404561920, + 495329628685631489, + 498516806806798337, + 498566021926486016, + 498233470628265984, + 494965750163992577, + 497804953713659904, + 498530371781529600, + 498561253514567681, + 498578789455396865, + 499988329342177280, + 496072135589515264, + 501063991297204224, + 497543513022930945, + 498622349525413890, + 498588688645771264, + 498579777859502080, + 498631173632180224, + 498523672135892992, + 500406836156444672, + 495326735874138113, + 498121573728280576, + 498232762013212672, + 498222649604968448, + 495329767894568960, + 498230653822177281, + 498578475905581057, + 497819935540654080, + 498633044484296704, + 498630483341611008, + 497488550691352576, + 495986447229652994, + 498621432524308480, + 500040168406282241, + 498213795026575360, + 496040087751499776, + 498610770863603712, + 498586118284005376, + 498606334817107968, + 498518190704836609, + 498630912364789760, + 498587043619151872, + 498609831469928448, + 498270556870160384, + 497881060827353088, + 500398370931085314, + 498631515585404929, + 498631163653939202, + 497419642064076800, + 498198954291769344, + 498631623735533568, + 498193584810491904, + 498598741327495169, + 498605040576507905, + 500737414487629824, + 497873540667162624, + 498590281202036736, + 498565458874757120, + 498513225785565184, + 497775124532051968, + 498586767990456321, + 498630817271525378, + 498592320082944000, + 501089808995729408, + 498541170784763906, + 498605477538717696, + 498605973398093825, + 498631072893374464, + 498608923193397248, + 498628899451187200, + 498632332157669376, + 501125874536947714, + 498236401444339712, + 498630810287624193, + 498630434872651776, + 498624778404909056, + 498606025717846016, + 498600092551507969, + 498218203215319040, + 498600302245728256, + 498541079084679168, + 501136698806652930, + 497815334816997376, + 495306586936463361, + 498573154525409282, + 498594019237462016, + 497436302921707520, + 498592614246252544, + 498221502115115010, + 498540459623723008, + 497775297258090498, + 498482826237317121, + 498480434381324288, + 501107936769626112, + 498617030841360384, + 498585155456749568, + 498601572549406720, + 498579618711224320, + 498631328188084224, + 495988573775360001, + 498480461854035969, + 498537326470246400, + 498623866999025664, + 498628440178700288, + 498609273782693888, + 498627492001751040, + 497512629620178945, + 495989478335721472, + 498603855530459138, + 498574868531527681, + 498190611783360512, + 498591377010475008, + 498627405654016001, + 497809850567782400, + 497843105681252352, + 498571142517751808, + 498181701152284673, + 497896857310609408, + 498633998466170880, + 498608701197254656, + 498632500508635137, + 498541219937808384, + 498629382647607297, + 498545648732741633, + 498570858034892800, + 498630846078013441, + 498474751052890112, + 498190841509187584, + 497821477170077696, + 498631615887978496, + 498588302707281920, + 495248241571950592, + 495365140393758720, + 498573381273284608, + 498603027608387585, + 498631500393635842, + 498608338394185728, + 497829091954130946, + 498174743510794240, + 498633061861687296, + 498612945220567040, + 497789155011993601, + 498167081242599424, + 498626058217062400, + 498203201523691521, + 498551881766273024, + 498531855906267136, + 497841233734422528, + 498631486544039936, + 498630913056456704, + 496022141704605697, + 497500301721473024, + 498611729769971714, + 500752648371707904, + 498626908322820096, + 498628529928421376, + 498590389373521920, + 498605310081499136, + 498613770424680448, + 497854837988417536, + 498176178352816128, + 498226678490226688, + 498633098876026880, + 498603498481926146, + 498240378294632448, + 498268600760016896, + 501104939461246976, + 498611117670031360, + 495304621951561728, + 498490523167248384, + 498592386503548928, + 498611248003837952, + 498522452277075970, + 498517628806520832, + 498162102289580032, + 497814743504392193, + 498187656660938752, + 498561434851483650, + 498597595103506432, + 498626341361561600, + 498623267687911424, + 498189962982866945, + 498607224315727872, + 498602261518770176, + 495340740516777984, + 498528146224726016, + 501121170574684160, + 498224252873494528, + 498605189084233728, + 500766746362802177, + 498541441749364737, + 496055309996404736, + 498612039179173888, + 498214705388064768, + 498613818332020737, + 497832940441985024, + 498630852717207552, + 496012590909513729, + 498627610101170178, + 495277061544898560, + 498496946135638016, + 497491553989193728, + 498551910073266177, + 497434656719925248, + 497442280182403072, + 497841227518459904, + 500052483012829184, + 497841244312457217, + 495268839878189057, + 498248613622185984, + 498177397108510720, + 498578698707419137, + 498620714920837120, + 497534189651361794, + 498623151266226177, + 498622710470410240, + 495332650174144512, + 495270694834683904, + 498501255992332289, + 498541223783989248, + 498188800372113408, + 498483529324703744, + 497487764502618114, + 497809752399691776, + 498630699398610944, + 497808927741194241, + 495647638331883520, + 498608803655716864, + 498511150997188608, + 494999223373672448, + 498535414010241025, + 496052681853919233, + 497860981016387584, + 498537791538860032, + 498598839667130368, + 495990048048046081, + 500685428706795520, + 498629702484250624, + 498604677236539394, + 498629664823197696, + 498223838006870016, + 497501152124993536, + 497789540846014464, + 495991357178392576, + 494951560045031424, + 496061986913148928, + 498533109684764672, + 495648261781606400, + 498226704087646208, + 500023470454218752, + 497860574965805056, + 501090037606662145, + 498602088654704641, + 498189263406522368, + 498633196205248512, + 497901134888316929, + 497886920903368704, + 498574953932156930, + 498191398710300672, + 498612350921228289, + 501125089702993920, + 498191696652275712, + 498626303839715328, + 498627446694895616, + 498623925513768960, + 495329958475345920, + 498630001441660928, + 495301940021309440, + 498542795041148928, + 497840497403392000, + 498121901433434112, + 498265618769281024, + 498550372324376576, + 498117623868309505, + 498193959370240000, + 498505863242711040, + 498474015535546368, + 500416295134060545, + 498630904085250049, + 498469104798294016, + 498564597939331072, + 498523071813124097, + 498630846279344128, + 496021259889967104, + 496053655762894848, + 498204834324291585, + 498630656923295744, + 497887895341252608, + 498627713570459648, + 498618866692796416, + 496049839084670977, + 498499233788723201, + 495989564679655425, + 498268225214627840, + 498625211172810753, + 498632132932407296, + 497873931240742913, + 498562181055528960, + 498581111795380224, + 498591250074058752, + 495303341933875200, + 498628757302050816, + 500054297057714178, + 498584330374230016, + 498584074286821377, + 498239596741025792, + 498631382512697344, + 495279510250856448, + 498633721155960833, + 496013090396184578, + 498631254968127491, + 498227956020682752, + 498630827291729921, + 500402894571847681, + 498620079031214082, + 497874313681182721, + 497814256302444544, + 495989591837773824, + 498235968760328192, + 498609282816802817, + 498568870333284352, + 496022940941426688, + 498631562993631232, + 497849595016527872, + 498615824488611844, + 498600776147939329, + 498623085285617668, + 496023133124837376, + 495999271062503425, + 498627883922124802, + 499981932872998912, + 498541348602265600, + 497456224556703744, + 498186879246684160, + 498630813496664064, + 498608498100682752, + 501121227965341696, + 498628762020237313, + 498545646522359808, + 498574586544672769, + 498236019896885248 + ], + "top_users": [ + "26257166", + "14063426", + "53120768", + "105119490", + "2557521", + "20463402", + "265902729", + "166767883", + "24277551", + "33395719", + "21014439", + "22146985", + "28534252", + "204074545", + "43139414", + "31447081", + "44588984", + "48298347", + "275217630", + "249154446", + "127724517", + "43641364", + "1543364688", + "24224425", + "86230406", + "437700198", + "517657650", + "28349128", + "890891", + "7589572", + "255657736", + "26578816", + "34930912", + "32073913", + "26020351", + "37360915", + "279321785", + "183502719", + "33314461", + "153118706", + "267274202", + "64736207", + "454430831", + "87118217", + "14063612", + "44706253", + "55809761", + "72235760", + "22292529", + "807095", + "32717570", + "512723328", + "16788222", + "47945492", + "17890396", + "216299334", + "26829777", + "493127463", + "17087270", + "183675164", + "108568373", + "204832963", + "137862496", + "21129105", + "70728069", + "435225922", + "43775786", + "222736897", + "19230601", + "41509142", + "109399420", + "17540485", + "1428219750", + "105410287", + "40891771", + "52791522", + "447609745", + "325070854", + "1115127925", + "306420012", + "39288259", + "219243547", + "28785486", + "425989199", + "289459291", + "714591458", + "308981378", + "1138785571", + "46403451", + "14387275", + "613542402", + "13213122", + "160912170", + "14364779", + "256409561", + "155642429", + "6017542", + "28147403", + "9570452", + "82756359" + ] + }, + { + "country_breakdown_percentage": {}, + "country_code": "JP", + "device_breakdown_percentage": {}, + "end_time": "2015-08-17T00:00:00Z", + "event_type": "OTHER", + "gender_breakdown_percentage": {}, + "id": "39", + "is_global": false, + "name": "\u30b3\u30df\u30c3\u30af\u30de\u30fc\u30b1\u30c3\u30c888", + "reach": { + "total_reach": null + }, + "start_time": "2015-08-14T00:00:00Z", + "top_hashtags": [], + "top_tweets": [], + "top_users": [] + }, + { + "country_breakdown_percentage": {}, + "country_code": "US", + "device_breakdown_percentage": {}, + "end_time": "2015-09-13T00:00:00Z", + "event_type": "OTHER", + "gender_breakdown_percentage": {}, + "id": "2k", + "is_global": false, + "name": "Back to School", + "reach": { + "total_reach": null + }, + "start_time": "2015-08-15T00:00:00Z", + "top_hashtags": [], + "top_tweets": [], + "top_users": [] + }, + { + "country_breakdown_percentage": {}, + "country_code": "FR", + "device_breakdown_percentage": {}, + "end_time": "2015-08-16T00:00:00Z", + "event_type": "SPORTS", + "gender_breakdown_percentage": {}, + "id": "33", + "is_global": false, + "name": "Rugby : Angleterre - France match amical", + "reach": { + "total_reach": null + }, + "start_time": "2015-08-15T00:00:00Z", + "top_hashtags": [], + "top_tweets": [], + "top_users": [] + }, + { + "country_breakdown_percentage": {}, + "country_code": "JP", + "device_breakdown_percentage": {}, + "end_time": "2015-08-17T00:00:00Z", + "event_type": "MUSIC_AND_ENTERTAINMENT", + "gender_breakdown_percentage": {}, + "id": "38", + "is_global": false, + "name": "Summer Sonic 2015", + "reach": { + "total_reach": null + }, + "start_time": "2015-08-15T00:00:00Z", + "top_hashtags": [], + "top_tweets": [], + "top_users": [] + }, + { + "country_breakdown_percentage": { + "AE": 0.09, + "AM": 0.02, + "AR": 1.48, + "AU": 1.43, + "AW": 0.05, + "BE": 0.16, + "BG": 0.02, + "BH": 0.02, + "BN": 0.05, + "BR": 3.09, + "BS": 0.02, + "CA": 4.47, + "CH": 0.16, + "CL": 0.37, + "CN": 0.07, + "CO": 0.59, + "CR": 0.12, + "CW": 0.02, + "CY": 0.05, + "DE": 0.47, + "DK": 0.09, + "DM": 0.02, + "DO": 0.21, + "DZ": 0.02, + "EC": 0.19, + "EG": 0.14, + "ES": 2.76, + "FI": 0.09, + "FR": 1.59, + "GB": 10.1, + "GG": 0.02, + "GR": 0.16, + "GT": 0.23, + "HK": 0.07, + "HN": 0.09, + "HR": 0.12, + "HU": 0.05, + "ID": 0.4, + "IE": 0.68, + "IL": 0.07, + "IN": 0.19, + "IQ": 0.05, + "IT": 0.68, + "JE": 0.02, + "JM": 0.05, + "JP": 5.36, + "KR": 0.02, + "KW": 0.23, + "KY": 0.02, + "LT": 0.02, + "LV": 0.05, + "MA": 0.02, + "ME": 0.02, + "MK": 0.05, + "MT": 0.02, + "MX": 2.86, + "MY": 0.84, + "NG": 0.12, + "NI": 0.02, + "NL": 0.91, + "NO": 0.19, + "NP": 0.02, + "NZ": 0.26, + "OM": 0.05, + "PA": 0.16, + "PE": 0.09, + "PH": 0.87, + "PK": 0.07, + "PL": 0.07, + "PS": 0.02, + "PT": 0.07, + "PY": 0.09, + "QA": 0.05, + "RS": 0.05, + "RU": 0.42, + "SA": 0.63, + "SE": 0.59, + "SG": 0.68, + "SK": 0.02, + "SN": 0.02, + "SV": 0.07, + "TH": 0.66, + "TN": 0.02, + "TR": 1.52, + "TT": 0.05, + "TW": 0.02, + "UG": 0.02, + "US": 50.25, + "UY": 0.07, + "VE": 1.12, + "VI": 0.02, + "XK": 0.02, + "ZA": 0.26 + }, + "country_code": "US", + "device_breakdown_percentage": { + "ANDROID": 11.67, + "BLACKBERRY": 0.02, + "DESKTOP": 36.63, + "IOS": 51.38, + "OTHER_MOBILE": 0.31 + }, + "end_time": "2015-08-17T00:00:00Z", + "event_type": "OTHER", + "gender_breakdown_percentage": { + "female": 59.38, + "male": 40.62 + }, + "id": "2l", + "is_global": false, + "name": "Teen Choice", + "reach": { + "total_impressions": 481790670, + "total_number_of_tweets": 11189000, + "total_reach": 17970904 + }, + "start_time": "2015-08-16T00:00:00Z", + "top_hashtags": [], + "top_tweets": [ + 498698698348855296, + 498576354309206019, + 498655641615876096, + 498662493200195584, + 498653295657766914, + 498626843059425280, + 498622989827866624, + 495926329058279424, + 498641786286669824, + 498635594306953216, + 498646074194931712, + 498676203784773632, + 498683417991458816, + 498652790978121729, + 498642973434068992, + 498646861612584962, + 498656417130090498, + 498780061299113984, + 498668229074911233, + 498677238033039360, + 498635846242025472, + 498639928340008960, + 498666596601434113, + 498684263790039040, + 498655872055517184, + 498655570506035200, + 498637106747420672, + 498635049068032000, + 498576247317086211, + 498661462156406784, + 498629040656633858, + 498651553205870593, + 498655502340194304, + 498653783409188866, + 498657297980469248, + 498635935408717825, + 498655960731496448, + 498640166207356928, + 498648224798760960, + 498642655459704832, + 498643795844800512, + 498634889559027712, + 498636041067450369, + 498632087881400320, + 498659981999079425, + 498671863254753280, + 498624936005861377, + 498649899680796672, + 498645215612526592, + 498627343246557185, + 498640876131090433, + 498640574392848385, + 498627626911956994, + 498646579796926466, + 498649751407964161, + 498592017518440448, + 498609982506401792, + 498606200733581313, + 498646024534388738, + 498621569028333568, + 498639049696223232, + 498607503643774977, + 498628170523095043, + 498661718219051009, + 498651712928751617, + 498757635135385601, + 498645253310918656, + 498632587951104000, + 498672864833187841, + 498660489325318145, + 498649138087485440, + 498623807876120578, + 498630458780168192, + 498866093654425600, + 498634179001581569, + 498655680514232320, + 498670745925349376, + 498580782609215488, + 498627307658301440, + 498723139330015232, + 498645692521656321, + 498651192394665984, + 498658248258760705, + 498643694795632642, + 498635736392818690, + 498651900905275392, + 498985697261281280, + 498628247630790656, + 496488326556180480, + 498777540736339968, + 498650724423983105, + 498670821909753856, + 498651965904416769, + 498643166061666304, + 498720115576545280, + 498685747184934912, + 498643920348139520, + 498649700115808256, + 498649465335459840, + 498723632818843649, + 498619893726842880, + 498624515450994689, + 498672339694129153, + 498687907058561025, + 498645287364067328, + 498668960435273728, + 498657187435388928, + 498527184835731457, + 498673771960877056, + 498332427237216257, + 498576519896121345, + 498654292971360256, + 498684609337376769, + 498642709339709440, + 498612451165102080, + 498632817488580609, + 498641956642500608, + 498699875261747202, + 498663002695278594, + 498655264862912512, + 498584896848162816, + 498652502489694209, + 498638052349079552, + 498584131765170176, + 498651895142301696, + 498656488131284992, + 498640842874437632, + 498654358733856768, + 496094518861516800, + 498659231940104193, + 498663062434742274, + 497183710622781440, + 498576215905955841, + 498672130763268096, + 501072740145582080, + 498631647554965504, + 498672369368440832, + 498653387328483328, + 498669893537898496, + 498666453365571586, + 498564931780759553, + 498650448765530112, + 498656430920982528, + 498658529931063296, + 496727466057433088, + 498641083635478528, + 498641507835211776, + 498637375061229569, + 498631568298999810, + 498666384453533697, + 498624004639715328, + 498623889673838592, + 498696403883794433, + 498659451633557504, + 498645661987131392, + 498721292032679936, + 498658161122099200, + 498492071662321664, + 498662762734571521, + 498637148497920000, + 498643400803897345, + 498623719766384641, + 498653680577806336, + 498583193659146240, + 495961260828016641, + 498654748451405825, + 499489124819427328, + 498689185487003649, + 498922270363246594, + 498647877439455232, + 498721549982367744, + 498647899719208960, + 498660564047253504, + 498649375988400128, + 498647838641762304, + 498625115752759296, + 498621136411049985, + 498645753699373057, + 498682743652237313, + 498639212086697985, + 497600074294509568, + 498672707203248128, + 498680536575913984, + 498645352602669056, + 498631235842097152, + 498651301446975488, + 498584894717427713, + 498259953082433536, + 498512536044462081, + 498583189955162114, + 498772707098783745, + 499043287273971713, + 498582232043622402, + 498127396101292034, + 498599907612053505, + 498537989924864000, + 498655731730886657, + 498668148187336706, + 498676752604856320, + 498864115272933376, + 498318949147095042, + 498629692245540864, + 498670388847443968, + 498575257838428162, + 498632366449905665, + 498648022008356864, + 498593359469232128, + 498292504840925184, + 498640494352556033, + 498591067667587072, + 498638650104496129, + 498656567588171776, + 498622669319704576, + 498651751890055169, + 498621955038121984, + 498632605345271808, + 498638287720833024, + 498664118040006656, + 498848788341985280, + 497099573613977600, + 498681946026033153, + 498595238966218753, + 498537184647847936, + 498833265906954241, + 498676140387475456, + 498662679859318784, + 499379362924621824, + 498628756400246784, + 498540601613496320, + 498628504867438592, + 498626587802476544, + 498636435428093952, + 498672174761127936, + 498661304207687680, + 498650654512934912, + 498652569112039424, + 498628126243819520, + 498653336325722113, + 498637989304496128, + 498641664291127296, + 498592682927607810, + 498690501361811456, + 498582618221182977, + 496698284690653184, + 498645922885423104, + 498668984753852417, + 498581123551617024, + 497901400060198912, + 498683234679402498, + 498659384147189761, + 498607671864741888, + 498639483328151554, + 498625753265606656, + 498881853898895360, + 498631123506057216, + 498622375022186497, + 495840829521395712, + 497092520950906880, + 498653494912745473, + 495973480056500224, + 498261872328839168, + 498632789961355266, + 498631618672988160, + 498643476859604993, + 498652977142304768, + 498680116201811968, + 498687288021635072, + 498646739944243200, + 498597068395778048, + 498587394304507904, + 498649367369117700, + 498631992947142657, + 498343180903800833, + 498626441081135104, + 496976283147194368, + 498364898137473024, + 498637533245620225, + 496755036311941120, + 498635141032333312, + 498680116109529088, + 498641033434263552, + 498624219098664960, + 498757423621234688, + 498626245098102785, + 498648022142955523, + 498614223174242308, + 498680303586926592, + 498627293389283328, + 498559099898834944, + 498631003833786368, + 496468275241304065, + 498646381700337664, + 498671030240813059, + 498637436638203904, + 498575806906368000, + 498575447949856768, + 498911737702146049, + 498629187909857280, + 498652955953082368, + 498730761822797824, + 498674048000217090, + 498671492486283264, + 498678019847094272, + 498660608401620992, + 498540220954865665, + 498693695990812672, + 498632346737070084, + 498620004066410496, + 498646197490311169, + 498686745160851457, + 498642552036134912, + 498590623486586880, + 498623733431803904, + 498678349095387137, + 498622888296349696, + 498577479301201920, + 498585330183069696, + 498579663707713536, + 498630682856263681, + 498643077855444992, + 497173241560301568, + 498644433613901827, + 498614975242313728, + 498643516680306688, + 498642562211934209, + 495932374220169216, + 498640534420717570, + 496888261369815040, + 498650037120147457, + 498932875350134784, + 498689907607367680, + 498626436412882944, + 498676304657391618, + 498639724957822976, + 498686422199836672, + 498590372994371584, + 498875493806927872, + 497062630607958016, + 498650476813234177, + 498649832622272513, + 498672190435643393, + 498656814469480449, + 498634847301017600, + 498635056177348609, + 498681541728284672, + 498553884659683328, + 496418419617435648, + 498658754599333888, + 498627790477221888, + 498657511617359873, + 498304556196200448, + 497475140880715776, + 498631006518517761, + 498649252785303552, + 498637216168820736, + 498542028599226368, + 498266277233033217, + 498484188535095296, + 498565041625776128, + 498852324312219648, + 498629765067440128, + 498882454829404160, + 496819326255915008, + 498636652206493696, + 497437785654312962, + 497440848402190338, + 498608900611256321, + 498620204583493632, + 498653758377984000, + 498641200614621185, + 498589714094776320, + 498577570204745729, + 498637477847248896, + 498643682384674818, + 498635041413824514, + 498650820351520768, + 498620666409529345, + 498653195447840770, + 498581262747987969, + 498646965673287681, + 498619832288681985, + 497223246786605056, + 498851883662839809, + 498178597815730176, + 498736916465188864, + 497805432870936577, + 498622776950149120, + 498615400092151810, + 498628964873949185, + 498566222779543552, + 498648978561716224, + 498639437048594433, + 498581666508455936, + 498890352720617472, + 498674938383851520, + 498558724584509440, + 499616626904285184, + 496510950695243776, + 497208062282047488, + 498628643179229184, + 498889344283713536, + 498645752168448000, + 498538260092567553, + 499314057669656577, + 497896334356385792, + 498694195381829632, + 497061468538286080, + 498635353595838464, + 498653433319022592, + 498673756781699074, + 497222862915514369, + 498321564425650176, + 498576031000035328, + 498638789950988289, + 498637013600718849, + 498623282405720066, + 498687762980040704, + 499008677228335105, + 498686183329656832, + 497119988751544320, + 498909375075844096, + 498635054210646017, + 498735469367001088, + 498951493500674048, + 498622976892620800, + 498647726427348993, + 498625623020281858, + 498681486804271104, + 498649817997148160, + 498672860496265217, + 498127852718813185, + 497215853071708160, + 498657117985718274, + 498666712834011136, + 498670277543206913, + 498672696797200384, + 498667533893771264, + 498633099530760193, + 498662356478857217, + 498626672548016128, + 498107751642701824, + 498639208903237632, + 498647516469264384, + 497204214364639233, + 498973428440121345, + 498623810376314881, + 499652881105301504, + 498673243994488832, + 498908054205632512, + 495822551051165696, + 498674632233590785, + 498546697849827328, + 498652384747601921, + 498620081480671232, + 497193090218995712, + 498643461063454720, + 498646297578962944, + 498650131714281473, + 498659719578681347, + 498893880130289664, + 498639703310991360, + 498648740769853440, + 498673974235377664, + 498669699824373760, + 498536250882547712, + 498567171640160256, + 495765673994227712, + 498805080326668290, + 498668127400775680, + 496809265906999296, + 498643699090214912, + 498395514623123456, + 498652768501252097, + 498633001153343488, + 495728399734669312, + 498650521167618049, + 498743112878272512, + 498529968523988992, + 498641984962052097, + 498557567929679872, + 498935676591964160, + 498660408157569024, + 498620522339368960, + 498616572441681920, + 498537120232128512, + 498641431263592449, + 498938725292703744, + 498604364424949760, + 498949207944736769, + 498649998138302465, + 497178053618200576, + 497200793511284736, + 497123669546909697, + 498153107352997890, + 499298029728317440, + 498544372271841280, + 498622020490625025, + 498861033503866880, + 496493048834973696, + 498645308117909504, + 498660630837342208, + 498849611704852480, + 498632643953446912, + 498630824271437825, + 498601483227893760, + 498806952814989312, + 498649111164649473, + 497185778100109312, + 498644036509773826, + 498672450670825472, + 498644026103697409, + 497170692291719170, + 496829588052643842, + 498623140747292673, + 498584646117240832, + 497029522857164801, + 495726398095380480, + 498538607205154816, + 498144424531361792, + 498632557433323524, + 498646438495412225, + 499148734442536961, + 498609372705325058, + 498713857301307392, + 498669230556856320, + 497029960482451457, + 498578869243215872, + 498597053652815872, + 498639646759206913, + 497860154520776705, + 498670202994053120, + 498659687693578241, + 498622415623045120, + 498664303281836033, + 498638038868971520, + 497913512769769472, + 498638701308944385, + 498642730588069888, + 498703136307965952, + 498683834368417792, + 498626984885616642, + 498633413310808064, + 498661441038086144, + 498640865846235136, + 498637011113086976, + 498204683950125056, + 498671152416296960, + 498643345187815424, + 498696937772548096, + 498640606236000256, + 498758499766398976, + 498651551909806080, + 498645355379302400, + 496370719731613696, + 498678292048658434, + 498631477551063040, + 498517596858503168, + 498907427484741632, + 498648450117173248, + 498536848340176896, + 498680319571021824, + 498795052894674944, + 496493945103613952, + 498679557273448448, + 497132660330741760, + 498579943002243072, + 498654374705770496, + 498648594283765760, + 498651138003308545, + 498651980383154176, + 498636804820860928, + 498600471276560384, + 498636291152420864, + 498842784661794816, + 498613356782428160, + 498644710190510080, + 498674538956488705, + 498127368590864385, + 498633558135951360, + 498642740717322240, + 498675890151112705, + 498294755696971776, + 496885690500517888, + 498174534290530306, + 498189619062898689, + 498636895463964672, + 497488672217128960, + 498641502005121026, + 498612579548528640, + 498639554874990592, + 498645446869680128, + 498643877403041792, + 498633845156352000, + 498629910181974016, + 498629657344753664, + 498656512697323521, + 498690160909766657, + 498630470809452545, + 498680222859132928, + 498683479165779968, + 498608023082774528, + 498650452280758272, + 498642738967871488, + 498582158848827393, + 498644229737164801, + 498641016870961153, + 498580852419227648, + 499045530584879105, + 496387414618042370, + 498643636830363649, + 498625154180997120, + 498683805839159299, + 498406603419156480, + 498635241465348096, + 498522553661419520, + 498601721732825088, + 498609885618376706, + 498912907191525376, + 498674815113256960, + 498629225252134912, + 498659504901591040, + 498604984637063168, + 498684123108876288, + 498626834200674306, + 498331995244478464, + 498639860207722498, + 498635647197143040, + 498869341430222848, + 498649706592227330, + 498764100436901888, + 498642048749404161, + 498629299273224192, + 498651224292737024, + 498582208475828224, + 498649354987913218, + 498624945426284544, + 498499514060115968, + 498202437660848128, + 498382224589205504, + 498653095749226498, + 498854879503216642, + 498642272683294720, + 498219838591209472, + 498628145348898818, + 498691375747964928, + 498625329746153472, + 498598420995899392, + 498630997450440704, + 498748850937397252, + 498648580945879040, + 498692542909939713, + 498635202504437760, + 498548066954125312, + 498627688241037312, + 498628568596115456, + 498638558337724416, + 498598316813602816, + 498636019663921152, + 498587647221067778, + 498649320334585856, + 497926450033356800, + 498626534006341632, + 498629963507965952, + 498633176496222208, + 498640174884995072, + 498635636275159043, + 498632106885799936, + 498652930141356033, + 496701861903478784, + 498610521084420096, + 498301908537589760, + 498625252965240833, + 498637033213280258, + 498892336244731905, + 498667552428793856, + 498219819628765186, + 498629250162118657, + 498854008539602944, + 498497727462797312, + 498637380770099200, + 498589904331620354, + 498628920317849600, + 498685108837052416, + 498758736786489344, + 498660580182339585, + 498579743546306562, + 498653501116125184, + 498509893775937536, + 498234869403889664, + 498644153404649472, + 498628501306888192, + 498630518817435648, + 498559659671044096, + 498576055897432064, + 498603452726255616, + 498658394916782081, + 498558613955170304, + 498666266039554050, + 498639008046784513, + 498640477135327233, + 498660286555910145, + 496674120361594881, + 498872546020712448, + 498631575526195201, + 498650007948787712, + 498628307823247360, + 498624556119367680, + 498630899450535936, + 498676311028928513, + 498684053663412224, + 498577098286858240, + 497859372308238336, + 498628269001154560, + 498635873848918016, + 498593415336964096, + 496773910734864384, + 498634971548893184, + 498589684789161984, + 498622543004446721, + 498675952633671680, + 498647505547321344, + 498631818896502784, + 498634495541915649, + 498623050611707904, + 498624093819002882, + 498625362033926144, + 498649061063262211, + 498634192847380481, + 498693485587755009, + 498582831459999745, + 498641801926811648, + 498646361840320512, + 498596874539237377, + 498665221771493377, + 498793711967674369, + 497959902653214721, + 498626686733123584, + 498835001648369664, + 498857792930054144, + 498635467731243008, + 498636692463837184, + 498628122150182912, + 498673558717861888, + 498638473713029120, + 498626037975367680, + 496809714098114561, + 498635167083532288, + 498621612380676097, + 498637715307757568, + 498597325875740673, + 497980628013309952, + 498662025250095104, + 498626582794473473, + 498290950591246336, + 498648561563607041, + 498623358293258240, + 498665003432431616, + 498636508153511936, + 498632534725763072, + 498656893317816320, + 498622082964795392, + 498676434643070977, + 498627720440717312, + 498761629668896769, + 498575065773268992, + 498626525701619712, + 498572728757420032, + 497398526952091648, + 498865228588015617, + 498648110520729600, + 498857586406346752, + 498622090111905793, + 498627230567006209, + 498641912773869569, + 498674938522243073, + 497031911441956864, + 498194896751054848, + 498632865643368450, + 496072610657349632, + 498689162979991553, + 498535727576006657, + 498649740225949696, + 498632998942932992, + 498665682410549250, + 498621386316079104, + 498612817495609345, + 498643244364730368, + 498889717975240706, + 498643461722349568, + 496461591190466560, + 498651836279455746, + 498578682727116801, + 498637412122128384, + 498637458251468800, + 498670515733942272, + 498847259337822208, + 498640848951988224, + 498643246726127617, + 497140221151309825, + 498635034404732928, + 498872834010394625, + 498675179820560387, + 498966523059261441, + 498914255194693632, + 498633307400052736, + 498939468167254016, + 498621039392608256, + 498601222501572608, + 498387552651337728, + 498587925798723584, + 498203840412258306, + 498664032883453952, + 498626507255070720, + 498653776497360896, + 499020538527117312, + 498598313630126081, + 498589651276288002, + 498643140728074240, + 498606089726730240, + 498877030381801472, + 498658760055746560, + 498636926476636160, + 498643280565772289, + 498691946572165120, + 498646790652973056, + 498643519007752192, + 498677401652822016, + 496447115086688258, + 498620041555116034, + 498578577135534081, + 498645450551881728, + 498619816048340994, + 498509119473471488, + 498584961406881793, + 498622108574826496, + 498625444967890944, + 498646280755609600, + 498635015811776512, + 498656868450172928, + 497155695821983744, + 498642480095830016, + 498643183249915904, + 498647514971529216, + 498683897899933696, + 498627961176981504, + 498689555843653633, + 498633822540279808, + 498592624845262848, + 497800462796460033, + 498686717214605312, + 498655775481675776, + 498605013577785344, + 498583186515824641, + 498636468403707904, + 498635858115702784, + 497920796266725376, + 498555098134749184, + 498661702196801537, + 499219016431308800, + 498648975780503553, + 498646070872641536, + 498636601443221504, + 498655951088799744, + 498668953854824448, + 498658971931402240, + 498689868730736641, + 498574608379834368, + 498585306799808512, + 498635074666254337, + 498186456989310976, + 498330435462901762, + 498581107537752064, + 498677080658558976, + 498682482943074304, + 498653916025081856, + 498652803653701635, + 498838762974371841, + 496753953791438848, + 498653404248682498, + 498629364276547584, + 498670191669026818, + 498627059418030081, + 498319776381276160, + 498576059663536128, + 498337136710803456, + 497105681518833664, + 498635565521465344, + 498630053777788928, + 498635005476630528, + 498597167250952194, + 498826812685025280, + 498579658322214912, + 498698548167573504, + 498620869527502848, + 498691735208595457, + 498633868245626881, + 498622870827053056, + 498653066049368065, + 498672917488869376, + 498670764527452161, + 498626817805524993, + 498690257865687040, + 498520524100616193, + 498606254320017408, + 498975695448457216, + 498642396889243649, + 498594413502025729, + 498684074400440320, + 498644751554715648, + 498231991943176192, + 498616523209338880, + 498615485303242752, + 498963129858928640, + 498630092981944321, + 497955295184699392, + 498653977748447233, + 498573285940924417, + 498680120211963905, + 498632689348403200, + 498642863324798976, + 499023810868543488, + 498686795249623040, + 498688186412204033, + 498694186510475264, + 498611006537728000, + 498654701034819585, + 498657565996503041, + 498635510345367552, + 498828648729038848, + 498700729528631297, + 498841267980480512, + 498150483270193152, + 497514927846723585, + 498271823235387395, + 498898887449804800, + 498678322021142528, + 498616219214557184, + 498685030361608192, + 498659497679028224, + 498688604571701249, + 498653602714746881, + 495989725518659584, + 498630588933230592, + 498648266364690432, + 498628239024087040, + 498943284086312961, + 498603971263860736, + 497100632986116097, + 498639710386786306, + 498626754119217152, + 498591268059234306, + 498589874845663232, + 498662558090293248, + 498583308163641344, + 498658118713495552, + 498660090887802880, + 498576952564146177, + 498561020890447872, + 498629042132639744, + 498651145372729344, + 498623098187706368, + 498645636682878976, + 496773737522294784, + 498635735755264000, + 498688541850103808, + 498678420705124354, + 498611883570905089, + 498672672369176578, + 498676077091622912, + 498639541109293057, + 498686211641581568, + 498652825870557185, + 498620000610308097, + 499037084024590337, + 498622606430699520, + 498644905183297536, + 498627106813640704, + 498633589748031488, + 498637544955719681, + 499080209375576064, + 498629839574679552, + 498811189036843008, + 498869814879068160, + 498592489876762624, + 498691316470280192, + 498635461368479744, + 498555325642178560, + 498614826009382914, + 498728119805968384, + 498440315913912320, + 498662857668845568, + 498649278743855107, + 498955454714638336, + 496113414717308928, + 498578941729595392, + 498676465454809088, + 498647967788564480, + 498662295955054593, + 498644348956065792, + 498659210939621376 + ], + "top_users": [ + "19329393", + "549664610", + "109303622", + "73171449", + "14222536", + "2883841", + "45609049", + "363961928", + "18055737", + "43289545", + "268414482", + "25365536", + "989473208", + "25589776", + "46832898", + "216201838", + "50515656", + "22179997", + "34507480", + "586671909", + "23151437", + "32959253", + "21111883", + "393488321", + "1705991035", + "310072711", + "1906234147", + "180949358", + "20012204", + "405728790", + "29756339", + "39596022", + "27260086", + "308297673", + "523723448", + "278328390", + "1396698397", + "169740780", + "2223998131", + "219049532", + "726309991", + "114035804", + "308759071", + "23613479", + "105296218", + "18378446", + "19426551", + "68172010", + "2367911", + "85452649", + "66699013", + "24613756", + "144083497", + "39538010", + "200913899", + "403255314", + "87070315", + "872374136", + "1901273544", + "252709160", + "264107729", + "98199951", + "618336955", + "1526563316", + "379408088", + "56773228", + "30495613", + "304185486", + "163730859", + "2585809427", + "58233603", + "18588279", + "45494617", + "405357311", + "132774626", + "14920785", + "389238190", + "139539038", + "209994211", + "10228272", + "27776098", + "739784130", + "173319092", + "216430965", + "16679529", + "105715305", + "57385263", + "267359197", + "199999865", + "35880417", + "16794568", + "19383317", + "1436659309", + "19748674", + "1543693110", + "598232195", + "134954857", + "403245020", + "14511951", + "154280902" + ] + }, + { + "country_breakdown_percentage": { + "AE": 0.09, + "AR": 0.2, + "AT": 0.05, + "AU": 1.04, + "AW": 0.02, + "BE": 0.09, + "BG": 0.02, + "BH": 0.02, + "BR": 0.5, + "BY": 0.02, + "CA": 4.95, + "CH": 0.2, + "CL": 0.16, + "CN": 0.02, + "CO": 0.23, + "CR": 0.11, + "CY": 0.02, + "CZ": 0.02, + "DE": 0.18, + "DK": 0.11, + "DM": 0.02, + "DO": 0.18, + "EC": 0.09, + "EG": 0.02, + "ES": 0.45, + "FI": 0.07, + "FR": 0.47, + "GB": 4.97, + "GH": 0.02, + "GR": 0.18, + "GT": 0.11, + "HK": 0.02, + "HN": 0.02, + "HR": 0.05, + "HT": 0.02, + "HU": 0.02, + "ID": 0.07, + "IE": 0.59, + "IL": 0.02, + "IN": 0.18, + "IS": 0.05, + "IT": 0.41, + "JP": 0.95, + "KH": 0.02, + "KR": 0.09, + "KW": 0.18, + "KY": 0.02, + "LV": 0.02, + "MX": 1.6, + "MY": 0.29, + "NG": 0.05, + "NI": 0.02, + "NL": 0.32, + "NO": 0.16, + "NP": 0.05, + "NZ": 0.05, + "PA": 0.09, + "PE": 0.02, + "PH": 0.41, + "PK": 0.05, + "PL": 0.02, + "PS": 0.02, + "QA": 0.05, + "RO": 0.02, + "RU": 0.07, + "SA": 0.41, + "SE": 0.25, + "SG": 0.2, + "SK": 0.02, + "SV": 0.02, + "TH": 0.18, + "TR": 0.54, + "US": 76.4, + "UY": 0.09, + "VE": 1.06, + "VI": 0.05, + "ZA": 0.16 + }, + "country_code": "US", + "device_breakdown_percentage": { + "ANDROID": 8.79, + "BLACKBERRY": 0.03, + "DESKTOP": 36.37, + "IOS": 54.57, + "OTHER_MOBILE": 0.23 + }, + "end_time": "2015-08-31T00:00:00Z", + "event_type": "SPORTS", + "gender_breakdown_percentage": { + "female": 41.43, + "male": 58.57 + }, + "id": "2m", + "is_global": false, + "name": "Little League World Series", + "reach": { + "total_impressions": 152916599, + "total_number_of_tweets": 857103, + "total_reach": 11327581 + }, + "start_time": "2015-08-20T00:00:00Z", + "top_hashtags": [], + "top_tweets": [ + 500375215499915266, + 501589008330522624, + 501723005014528000, + 500367281361547264, + 500479985816444928, + 500104006933696514, + 500013407710756865, + 500379014062964737, + 498687014326517760, + 500130568575918080, + 502638830110126082, + 500656346283655168, + 503301995244310528, + 501062771711434752, + 504789895089762304, + 501366463908036608, + 503610572760698881, + 502637635350069249, + 498809185656909825, + 502275620772917249, + 502128371548299265, + 500362984548728833, + 503656146084048896, + 502298104964841472, + 502253563704532992, + 502255483131297792, + 502248914821844992, + 502258728511741952, + 502246655396040706, + 500379060099633152, + 503276187087810560, + 503736793695391744, + 500290205140934656, + 503274111620358145, + 503655240047271936, + 503299032387575808, + 503643777547120640, + 500393847252582401, + 503675621231583232, + 503654146332184577, + 502100276623712256, + 503292606185766913, + 499922156696768513, + 502181272584986624, + 500421830814228482, + 501740537271943168, + 502233145937502208, + 501718756624973824, + 498847269618462720, + 502229732105388033, + 503731211140104195, + 501372849245147136, + 503653964693655553, + 502650416455512064, + 500282568273829889, + 501452422456541185, + 503654394789785600, + 502237812708896768, + 502866558251589633, + 502288065004453888, + 503662960792043522, + 501874699568435200, + 502667503773155328, + 504008903231668224, + 502568725821030400, + 500367892358381568, + 500503332184928256, + 500386931973173248, + 503278818292158465, + 501849112023539712, + 501163071419584512, + 503586599544684544, + 502207921699037185, + 502236422644826113, + 503318683885006848, + 500377472169684992, + 502275104923848704, + 504794267663888385, + 503654336430219264, + 502654375961956352, + 503221797295124480, + 500385287819001858, + 502271135312904192, + 500102162022535168, + 504806865545740289, + 498894757414723584, + 502267403200249856, + 500453610564902912, + 506141400963219457, + 500365898835066880, + 502561142926225409, + 500368033555439616, + 502260858010214400, + 503636569710817280, + 503601280187518976, + 503654368449531906, + 498609114701111296, + 505870463759691776, + 502260683560349696, + 500329846325526528, + 502637849628663809, + 502242182028611584, + 502700363632607232, + 500413639640092674, + 502648212835287040, + 504680107139932160, + 503659944483098624, + 500374588736667648, + 501445300176052225, + 504651331261313025, + 498898256261562368, + 504638827777232897, + 504844143554613248, + 501184241942953984, + 500385438360944640, + 500106998500048896, + 503939537568268288, + 502523103902064640, + 503616843152912384, + 500273270722428928, + 504639243445358592, + 500619359782731776, + 503628369557483520, + 500329972775809025, + 500966886637838336, + 501884113306288128, + 502024199691833345, + 498649917095952385, + 503292068241104896, + 502641223417737216, + 503715397900967936, + 503619206244737024, + 499552727446585344, + 502275498702307328, + 498878456231231488, + 501142143206166528, + 502283293291601920, + 503267629394833408, + 504764063763546112, + 501847739940872192, + 503658174889857027, + 500394722301444096, + 500402250846834688, + 501789503653044224, + 502290765393821696, + 499038932076863488, + 503642704543494146, + 502351700733480960, + 503542863838601216, + 500045079780683776, + 502254615006830592, + 504682655234158593, + 500086190016843777, + 500082442380660736, + 501181581458145280, + 503315467776180224, + 498831661862510592, + 500316665117036544, + 501701266511503360, + 501383378294550528, + 502249901276004352, + 501080092618280963, + 502244733431709697, + 502857600409821185, + 501435746902114304, + 503305011708055552, + 500323057488363520, + 503304799199449088, + 500680941572878337, + 503332293537456129, + 503664496356106240, + 503598734861942785, + 498989768286695425, + 501097951100674049, + 500708447420440576, + 503303532930682880, + 502276673065476096, + 503654557293891584, + 503609846613426176, + 501523982584016897, + 503278380369059840, + 503261056865955840, + 503654579314372608, + 503228417115164673, + 502862538426830849, + 501099630483218432, + 498608044826431488, + 501078489546911744, + 500037180098904064, + 497540261405536256, + 500415756425629698, + 503209342058135552, + 502312446384562176, + 500104368088449024, + 503656318700630016, + 503309853579034624, + 502263122561105921, + 498847945723478016, + 498997478445047808, + 503322019958906881, + 500349775540416512, + 502275927347191809, + 498886607307808769, + 500663341564833792, + 500379304220717057, + 501368129352904704, + 498855381737930753, + 503617649226809345, + 501919315134656512, + 500390919817162752, + 499951650921250817, + 500303501734727682, + 502190414095724544, + 502854466610417664, + 500696227831627776, + 500408041414864899, + 501734664089128960, + 503301353230585856, + 502651884205641729, + 502269156704927744, + 498098301112422401, + 500400309941043201, + 500421277669011456, + 498950340927307778, + 500374378794586112, + 499363140933386241, + 500280929311797248, + 499996585649242112, + 501774525940240384, + 501874325536776192, + 498944925086789632, + 502250262527242240, + 502479012602867713, + 502270049819062272, + 502225556189220864, + 502641938533994496, + 502563701585903617, + 501488603932147712, + 500400320116031488, + 502637811204628481, + 503300883615334401, + 505090619120058368, + 503651707163656192, + 498200463897272320, + 500038467083337728, + 502234896254111744, + 498940465216258048, + 504094727176589312, + 503135573511766016, + 502494863502618624, + 502260040364199936, + 500107020096512000, + 500251837014884352, + 503540998040215552, + 502587266771197954, + 503179978876264448, + 503619421370200064, + 502651413848424449, + 502168375645454336, + 502638387468447745, + 502293027516186624, + 499035313260355584, + 500353960633724929, + 500293175119183873, + 499921054060400641, + 499959014369669121, + 501788722766299136, + 500412910901141504, + 502230268833701888, + 500086817077886976, + 501142759798218752, + 503662572621795328, + 502638337350701056, + 503654466344984578, + 503309486338371584, + 498631676936085504, + 500445270878851076, + 500018323116265472, + 498832015584538625, + 503280488484986881, + 503576032893349888, + 502255896094052352, + 500479577039597568, + 503582550812819456, + 500477992468893696, + 503562921960812544, + 501181176095465472, + 501152015318540289, + 498923969303830528, + 500692614304505858, + 502961050619490305, + 503619822895116288, + 500395553881346049, + 503300845627510784, + 500369238910308352, + 500473771997020161, + 503303144848523264, + 503301761973485568, + 501092953688141824, + 500387307388936192, + 500334266228936704, + 503654234563551232, + 502261675295129600, + 500362757599133697, + 502637668988379137, + 506053049094135810, + 503302024654749696, + 501790174972739584, + 503625269513846784, + 502642445814099968, + 502260239182200832, + 502851156457316355, + 503595188770852864, + 503202563865714688, + 503942849394917376, + 503645278667546626, + 501054108774957057, + 502237456843157505, + 498311600407711744, + 500604011645386752, + 502843390719840258, + 500119252616368128, + 498797611420098560, + 502808308060020736, + 503215058210799616, + 503240291000676352, + 501468679867875328, + 498950613410263040, + 500385743659753473, + 498202935038193664, + 501823471048196096, + 502275601416609792, + 500072079027224579, + 500668837772398592, + 500417681971892225, + 500108307650985984, + 501355615621746689, + 502249336408141824, + 500387121187020800, + 503310737205649408, + 503306246926393348, + 502983811404406784, + 501721427645825024, + 502287199216631808, + 502490585253806082, + 500077195214086145, + 501111976140210176, + 503494875711414272, + 503995177347076096, + 502661315911888896, + 501709544876437505, + 501093861754929153, + 501757523335335937, + 503275512283029504, + 501905664310915072, + 502576424503762944, + 503598879330156544, + 503318622916587521, + 501393172023738368, + 502455208027234304, + 503356568436744195, + 503628951269302272, + 500109517997494272, + 498627369817489408, + 503595979787235328, + 502825060235636736, + 504073797444440064, + 503976658404392960, + 498210307987083264, + 502225692466372608, + 503695614853394432, + 501592516924559360, + 500024720838758400, + 503664353405861890, + 500401308906844161, + 500122711017148416, + 499959993337413633, + 503301211563782144, + 503006218881757184, + 500824354393829377, + 501509934853263360, + 504076319605280768, + 498223219510214656, + 503301223823331328, + 501181065797840896, + 503568196146692096, + 502847902784716800, + 499260165049573377, + 503260938666250240, + 501457728716689408, + 503296591164235776, + 503284114242666497, + 500462336982142977, + 500437633202278400, + 500384319979159552, + 500409524415516674, + 498600392243286016, + 503627767771320320, + 502747265862086656, + 502637996211183617, + 502475350518300673, + 503648106681225216, + 503633766401966080, + 500017750992228353, + 502277469672837121, + 502455165878689792, + 499912159896150016, + 502571138812489728, + 502635899046621185, + 500374421501411328, + 501180958117089281, + 500692431797764096, + 500462096845258753, + 502233635857367042, + 500463227978141697, + 502275434743345152, + 504791611272753152, + 500367740130316289, + 503293764312793088, + 503260356836589568, + 503615823454674944, + 503284076757782528, + 503538735544164352, + 502234292207243265, + 503654470883246080, + 502852912755003393, + 501515377042812928, + 502291504623149056, + 503653245219524611, + 502781198196678656, + 505452621163814912, + 502474458721189888, + 500692081292378112, + 501736310814814208, + 500385934287048704, + 503619732616912896, + 503580052982738945, + 503652002837327872, + 500363365256941568, + 503734690306473984, + 502512677219213312, + 503680269036310528, + 500038632305328128, + 502473721098285056, + 501561568073891840, + 497172592441430016, + 503301503767945216, + 500383809343586304, + 501167597719928833, + 502192219080900608, + 499968145063694336, + 501186786954334208, + 499979801776885760, + 503304108452110336, + 501167816381562882, + 500436331064205312, + 500367050431553536, + 501181885721366528, + 502324142210043906, + 502593241037156352, + 501783517819596800, + 501555128386977792, + 503662619879014400, + 503951542039232512, + 498899728420315137, + 499034589692977154, + 502653517060796416, + 498168483080052736, + 498616935069007873, + 498864640248397824, + 503654480718864385, + 503642131454763008, + 500370347234164736, + 503303209990246402, + 502185045302730752, + 503333002483892224, + 497218732133855232, + 500426842697129984, + 500099714759811073, + 502618293619142657, + 498854353084903424, + 502619537855238144, + 502242067368927232, + 503297682371125248, + 503263966651764738, + 503660525109411840, + 500406574150864896, + 497849161807826945, + 502477359803424768, + 500469665031008256, + 500664327012372480, + 503302511931846656, + 503655486122893312, + 503654224253972480, + 503303544053956609, + 502253871964880896, + 498880505920897025, + 502248017001328640, + 500311021752311809, + 499686737874923520, + 504700113890316288, + 500108215153995779, + 501607009188188160, + 500017678749151234, + 501891177751146497, + 503661353102753794, + 501040634631712768, + 500019733152808960, + 501080797437124609, + 502607955553177600, + 497779306018271232, + 502283374799884289, + 500361748160200706, + 503629569229090817, + 502473897326170112, + 502310392308449280, + 501905833153015808, + 503889526885199872, + 503311314890936320, + 502535658565828609, + 500386545979760640, + 502251684941148160, + 503262607105478656, + 502198460259373057, + 500441572253908994, + 501738897291112448, + 500009893240524800, + 500727530765418496, + 497548505016442882, + 500142668023087104, + 500439843403759616, + 497854203210268672, + 500115470998327297, + 503278908859363328, + 500589454802034690, + 498790603338293248, + 500485617177096193, + 500502139085815809, + 503640186493079553, + 503304450602061825, + 503317371130753024, + 504777552800411648, + 502222081850081280, + 502643991670964225, + 502261958494535680, + 503606519389515777, + 500673410482339841, + 503576380849004545, + 503650220576489473, + 497187357532377088, + 503624079669469184, + 502638814670901248, + 503301767761649664, + 503656440746106880, + 500460395942125568, + 500384398433210368, + 501890666989752320, + 503341287421255680, + 503597361751269376, + 503259180716023809, + 499056902882742273, + 500385685090476033, + 503641521279623168, + 502596593754054656, + 500065511040745473, + 502177836241653760, + 499944830664200194, + 503621615251623938, + 503302444768841728, + 503278590273024002, + 501555508533133312, + 502639900307779584, + 500316657265684480, + 500456965793804288, + 500368838685257728, + 501554358660526080, + 503621514022096896, + 503232849202647040, + 500398357953904640, + 502290777414713344, + 499990782552862720, + 502535502038597633, + 502451879386025984, + 503654896311091200, + 499962229505409024, + 503655667937181696, + 501720049984352256, + 500484557427445760, + 501070611548884992, + 503654750634508289, + 501898496929050625, + 502536284913410048, + 502817663077601280, + 502248940218372096, + 502608796288819200, + 503301766155599872, + 502786549382410241, + 502653477299167232, + 502686631715827712, + 501427084011782144, + 502428451136368640, + 500397322665091073, + 505774859876446208, + 503292575051415552, + 502616757874720768, + 498941747507245057, + 502278475743387648, + 501569184447614976, + 501008674576670720, + 501016860562030592, + 502641414086610945, + 501736561617416193, + 503298674970353664, + 502620413525250049, + 506137918541680640, + 500416644657999873, + 500642151756087296, + 500384456096481282, + 499597365074878465, + 502242078986752001, + 502649147837923329, + 502539179302346753, + 503274278037757952, + 497537064028893184, + 501554835611992065, + 497575274108575744, + 502948792719515648, + 500384875153985536, + 501223215126290433, + 502273364502007808, + 503296440417148928, + 500039668030009345, + 501181848777539584, + 502635910954229760, + 500375490692399104, + 503747374024376320, + 503299716059525120, + 502502464260939776, + 503301369474719744, + 500384448647802880, + 503624072534970370, + 502255579235352576, + 501183780988944384, + 501183296391225344, + 498844603928576001, + 500394146939432962, + 501810603837882368, + 502538471819739136, + 499986657186430977, + 501532479959085058, + 501903927454228480, + 503300940141973504, + 503260805983260672, + 500138167811727361, + 500480801373708291, + 502243722663579648, + 500241780139249665, + 502884430013542401, + 501365432972890113, + 503271776588414977, + 500384966518521857, + 502204651706789888, + 501181951215026177, + 502618536238665729, + 503619799797497856, + 500367214294597633, + 502275765636190208, + 503662666716807169, + 499352293071155201, + 503288086860558337, + 502496718957850624, + 499225790689849344, + 502850209576402944, + 503296637960069120, + 503595292361768960, + 502262045954568192, + 504660310226378753, + 501779434563993600, + 503620746850369536, + 497827105347231745, + 502273661471326208, + 500480841764839424, + 500442421398732800, + 497859967610007553, + 503301398508105728, + 500107316910252034, + 503292805788479489, + 501523268419846144, + 500385295796146176, + 505913342280482816, + 500695960469925889, + 502638985853009920, + 500444344491716611, + 503283802882334720, + 502227605622255616, + 500362121683939330, + 501828538723737600, + 502661916620488704, + 501038869538541569, + 498835744853852160, + 500832068704956416, + 500316672277086209, + 498201160957046784, + 501394264409243648, + 501523101306605568, + 500030041758375936, + 503636166512766977, + 498941741219995649, + 502171913003622400, + 501851853639139328, + 502487402112245762, + 503295715830136832, + 502645953611190273, + 503299796589760512, + 503557701176393728, + 500021590374232064, + 503584543895736320, + 500500475179847682, + 501480945216532480, + 502246961957711874, + 498293166059954177, + 500372829502971904, + 498568142721785856, + 502862615815917569, + 502291031761879040, + 503633351945646080, + 500412489591312385, + 500310861747998720, + 502489238588248064, + 499999629086171136, + 503302415924211712, + 500813294651703296, + 503329091194335232, + 503342028273774592, + 503563454876499968, + 501556253093806080, + 501790072375484416, + 502268176139567105, + 500486533913526273, + 502196705744678912, + 502273089237839873, + 501905412309131264, + 499240008319246336, + 502251539705389056, + 502515661437149185, + 501905765402038273, + 503625742757134336, + 503656275587371008, + 502638113622355968, + 502852364601401345, + 502619492514811904, + 500387103730323456, + 501745943679864832, + 501718713922777088, + 503300922525904896, + 500715341165907968, + 499296048561414145, + 502578148052307968, + 503297652331921408, + 502638006415933440, + 501189231524720640, + 501896173255290880, + 500408404758638594, + 502258297148555264, + 500814085462556673, + 501184494037389315, + 501924558723891200, + 498281061798125568, + 501496367370764288, + 498848131392352257, + 505774525196566528, + 502462779543257088, + 502635696310738944, + 502262128129363968, + 503303798086197248, + 501972203161022464, + 503441282442604544, + 503652329888182273, + 500001218983636994, + 499211722214088704, + 503301561603588096, + 502656715087962113, + 503659322745036801, + 497946942639718401, + 502224916016414720, + 501032897269088257, + 503290868410097664, + 500384904547676160, + 499920903674015744, + 504627776092385281, + 502258852533108738, + 503287369660129280, + 502248095451987969, + 503267967061479425, + 500395073734180864, + 500388943154937856, + 500403875183333376, + 501545760622931968, + 499010444833460225, + 502267222510022656, + 500362354904010752, + 497520518715940864, + 500624282934714370, + 500394846402924544, + 500286897735106561, + 503623893127811072, + 503619288281153537, + 498837412752003072, + 500375639523082241, + 502246002938871809, + 502228628978302976, + 502273598577737728, + 500027674845126657, + 503597594044805121, + 503709249416216576, + 497718026746081280, + 501704712404873217, + 499999069901959168, + 500384868685991936, + 501180868153864192, + 500375645814554624, + 502236161587568640, + 500384943386918913, + 502273634342539265, + 503641483090886657, + 500808446065639425, + 503309347330727936, + 500383367272333312, + 501093729437241344, + 500466575154356224, + 501860224316092416, + 503630361826693121, + 498673700737409024, + 500470602155581440, + 499579294226452480, + 500630694352412672, + 501182023063842816, + 497519715468996608, + 503334660445700097, + 500845202354208769, + 502238197565652992, + 503621571479871489, + 503302996739235840, + 501095144276627456, + 501484064873119744, + 498939363544563714, + 502294666729910272, + 501923345928323072, + 497927510123114497, + 503628153643094016, + 501099537575215104, + 499304236535283712, + 498617745039437824, + 504647762420711425, + 503644608958836738, + 503915405992529920, + 500459705815142400, + 503185929591590913, + 503302531335077888, + 500120791648710660, + 500463263734198274, + 500731316288385024, + 500384449000112128, + 503375855309946880, + 502293141546758144, + 503312088803311616, + 503656604206919680, + 503307723455225858, + 502988619494092801, + 501450258245636096, + 502276528630005760, + 503621485299527680, + 500411033148592129, + 502635347508232192, + 502233560875819008, + 502641330955509760, + 501898791197618177, + 503381677276532736, + 501910516277592065, + 502264319912841216, + 497934776448606208, + 503628056788238337, + 503286661321871360, + 502699187754921986, + 499545561830551552, + 503300681395367936, + 503276460040142848, + 499995981233278977, + 503271113326354432, + 501450478232686592, + 502915731122839552, + 501551874110398467, + 500467456809660418, + 502279807124525056, + 498656305725575168, + 500342089763131394, + 500348773743468545, + 503290284915306497, + 503930724429201408, + 497176241251045378, + 500412412000886784, + 502587535567388673, + 501555564397486080, + 498904611776782338, + 500450109902315520, + 501553366645080064, + 503654033807400961, + 503288978154729472, + 499988650843987968, + 503301935391178752, + 500809121969762304, + 501480179760250880, + 502623955287805952, + 501799460847230976, + 500404760366051328, + 503604560968318976, + 502245848357810177, + 499304237458001920, + 503899417754095617, + 502639233774141440, + 500397270366318595, + 502250506669268992, + 500809023583952896, + 500860402423857152, + 503654577887928320, + 500373746533040128, + 502607316009877504, + 500349614487531520, + 498896305515925504, + 504813177612533760, + 501084384653766656, + 501180874193633280, + 501704856222978049, + 503280071390793728, + 502513404444033024, + 500703308433338369, + 500329461829885952, + 503624966378893312, + 499991149365694465, + 498167442041233408, + 502252102761332736, + 501590868500152320, + 502641656928415744, + 503301309697916929, + 500375678714671105, + 499916542868738050, + 501831083504467968, + 501793655183912960, + 501173892702932992, + 501178115859550210, + 501167748915818496, + 497385516086472704, + 504623305601871872, + 501167354470866944, + 502253612446547969, + 503299203775619072, + 503304071944499200, + 503652716187754498, + 503638720642564097, + 502616262242209792, + 504093284244127744, + 501103370577645568, + 500372263057649664, + 502243996794912768, + 503623633122918400, + 497182757530128384, + 501143624449798145, + 503302488393404416, + 501991005185638400, + 500396783802286080, + 504025187332141056, + 497180273604558849, + 502272942151987201, + 497772846593359873, + 501161132023762944, + 503638868231720960, + 502275545280049152, + 503640806079873024, + 501181268776591361, + 503710417873432576, + 499963977322221568, + 503645056470106113, + 500332783492145153, + 499218582593486849, + 502260299559628800, + 499766273190805504, + 503653936956731392, + 501735642511192065, + 499653588126560256, + 501162719425208320, + 503660979356717056, + 500296143230623744, + 503559360572694528, + 500409039701151744, + 503619966684241921, + 502266776072503296, + 500375759501148161, + 502276350292422656, + 503321377001472000, + 504639529811066880 + ], + "top_users": [ + "26257166", + "2557521", + "53120768", + "18479513", + "890891", + "241544156", + "807095", + "15846407", + "299800115", + "53197137", + "428333", + "145107843", + "194714715", + "28785486", + "13213122", + "41144996", + "7313362", + "1367531", + "544620720", + "813286", + "776049583", + "122261841", + "28370738", + "2369602650", + "51241574", + "16745015", + "21254264", + "590316679", + "504930127", + "116362700", + "248900032", + "250831586", + "24277551", + "14075928", + "362189733", + "759251", + "499311662", + "7302282", + "301251379", + "6017542", + "159894847", + "255657736", + "52529896", + "23501022", + "43139414", + "53178109", + "15754281", + "972651", + "22650211", + "17159397", + "14511951", + "17169320", + "144130505", + "1199195173", + "43024351", + "57333521", + "20632796", + "16212685", + "104063679", + "60704215", + "1001227081", + "14173315", + "262749118", + "14885860", + "1406346067", + "2740287490", + "14293310", + "775264357", + "22637974", + "237590404", + "181572333", + "41384610", + "15256225", + "43641364", + "68881642", + "26588937", + "2600937812", + "16409285", + "35586563", + "23482952", + "16812787", + "805793407", + "78183672", + "447410369", + "26053643", + "30313925", + "872185597", + "1274492916", + "492675987", + "15755669", + "21454322", + "1403820548", + "11856342", + "1209997460", + "600398381", + "186320027", + "500301582", + "17134268", + "1093090866", + "19329393" + ] + }, + { + "country_breakdown_percentage": { + "AD": 0.02, + "AE": 0.05, + "AR": 3.28, + "AT": 0.02, + "AU": 0.33, + "AW": 0.05, + "BE": 0.02, + "BH": 0.02, + "BO": 0.05, + "BR": 1.51, + "BS": 0.02, + "CA": 1.14, + "CH": 0.05, + "CL": 1.33, + "CO": 4.14, + "CR": 0.21, + "CW": 0.02, + "CZ": 0.02, + "DE": 0.14, + "DM": 0.02, + "DO": 0.81, + "EC": 1.3, + "EG": 0.05, + "ES": 3.89, + "FR": 0.35, + "GB": 0.91, + "GR": 0.05, + "GT": 1.12, + "HN": 0.49, + "HR": 0.02, + "HT": 0.05, + "HU": 0.05, + "ID": 0.07, + "IE": 0.14, + "IL": 0.02, + "IT": 0.3, + "JO": 0.02, + "JP": 0.6, + "KE": 0.05, + "KW": 0.09, + "LB": 0.02, + "LC": 0.02, + "MA": 0.05, + "MT": 0.02, + "MX": 13.22, + "MY": 0.05, + "NG": 0.07, + "NI": 0.09, + "NL": 0.05, + "NZ": 0.02, + "PA": 0.49, + "PE": 0.86, + "PH": 0.16, + "PL": 0.02, + "PS": 0.02, + "PT": 0.05, + "PY": 0.3, + "QA": 0.02, + "SA": 0.19, + "SE": 0.05, + "SG": 0.07, + "SI": 0.02, + "SK": 0.02, + "SN": 0.02, + "SV": 0.3, + "TH": 0.02, + "TR": 0.05, + "TT": 0.02, + "US": 50.4, + "UY": 0.4, + "VE": 9.93, + "VI": 0.05, + "VN": 0.02, + "ZA": 0.07 + }, + "country_code": "US", + "device_breakdown_percentage": { + "ANDROID": 15.18, + "BLACKBERRY": 0.35, + "DESKTOP": 37.07, + "IOS": 46.97, + "OTHER_MOBILE": 0.43 + }, + "end_time": "2015-08-21T00:00:00Z", + "event_type": "OTHER", + "gender_breakdown_percentage": { + "female": 51.99, + "male": 48.01 + }, + "id": "2q", + "is_global": false, + "name": "Premios Tu Mundo", + "reach": { + "total_impressions": 32780833, + "total_number_of_tweets": 1954810, + "total_reach": 2408280 + }, + "start_time": "2015-08-20T00:00:00Z", + "top_hashtags": [], + "top_tweets": [ + 502260484696182785, + 502274186531069952, + 502077344111017984, + 502457243653386240, + 501353079862607874, + 502827166623465472, + 502580938392731648, + 502794604794507265, + 502631239090962434, + 502616743018500097, + 501715477245071360, + 503336947821993984, + 502628766992977920, + 502302365622755328, + 503043979928039427, + 502661431104634880, + 502641581732941824, + 502607913412993024, + 502664657979842560, + 502576142315159552, + 502548098066153472, + 502548355747434496, + 502622047642869760, + 502613023312601088, + 502576610558881793, + 502637628551102466, + 503210733937909761, + 502615471120998400, + 502652455583506432, + 502560907277639680, + 502615797257478145, + 502561030380482560, + 502522036183633920, + 502263987942473729, + 502640403922059265, + 502657950843162624, + 504099734639116290, + 502248379561553920, + 502682372341379073, + 502660062218035200, + 500343167221497856, + 502639815545073664, + 502602989358837761, + 502624465612967937, + 502619236628692992, + 502682243643355136, + 502608656450342912, + 502658752089432064, + 502271516428730369, + 502627957073281024, + 502658899611500544, + 502657299375079424, + 502624734081994752, + 502645073570701312, + 502617234775494656, + 502651893781237760, + 502625500117094401, + 503717335606517761, + 502658159279095812, + 502591535594995712, + 502668999058923521, + 502615329714233344, + 502655657418706944, + 502609518745108480, + 502655242979540992, + 502642053772505088, + 502272224976715776, + 502606116476293120, + 502624157113540608, + 502648428061417472, + 502614455046643713, + 502865813544525824, + 502613726215032833, + 502641865749823488, + 502623640618541056, + 502648668521238529, + 502626390370680832, + 502624789400666112, + 502252217907179520, + 502613709731414016, + 502638064393789440, + 502614786149212161, + 502630409822560257, + 502130046463901696, + 502630698248077312, + 502627810222297088, + 502634832296701956, + 502643021608124417, + 502639156259192832, + 503746551697903616, + 502273198806036480, + 502646554013204480, + 502523898772983808, + 502540371617124352, + 502649817752150016, + 502637824429268992, + 502649650156175360, + 500077914344685568, + 502635504215789571, + 502635601137778689, + 502639334403891200, + 502642735829229568, + 502641784292651009, + 502627909262405632, + 502649829827543040, + 502543972582297600, + 502670297821347841, + 502650419475386368, + 502650465289797632, + 502629875497598977, + 502616785758478336, + 502622283685699586, + 502558552654098435, + 502629278752964608, + 502638299333545986, + 502639508345860096, + 502629756870090752, + 502618893996011520, + 502650334163263488, + 502646184125952000, + 502653381253812224, + 502649863205433344, + 502635583748206592, + 502449218536357890, + 502638653735436288, + 502578825939943424, + 502558420588060672, + 502638927212445697, + 502632595969294336, + 502623917425844225, + 502629540951511041, + 502556454831013888, + 502616999105933312, + 502622752072032256, + 504431873980788736, + 502668084722040832, + 503000169458434048, + 502638744567300096, + 502614889446506496, + 502638985458778112, + 502614958883221506, + 502652003206848513, + 502649531042111488, + 502582973372583937, + 502625592601481217, + 502571588580286466, + 502677898890076160, + 502629785605251073, + 502574667669196803, + 502570289591779332, + 502628501053517825, + 502570962781736961, + 502624589722451968, + 502980071800725504, + 502997170912776194, + 502582858209583104, + 502665959090708481, + 502616520007352321, + 502539017637101569, + 502570293467308032, + 503347206200754176, + 502607212360265729, + 502833486764720128, + 502633026313269248, + 502697664283414528, + 502621177102479360, + 502610132849942530, + 502645660660015104, + 502651514591391744, + 502619153757667330, + 500034923768463360, + 502606518337171457, + 502515792370737152, + 502656308836048898, + 502616402537508866, + 502629847764828162, + 502630210551185409, + 502673303979708417, + 503362276955791360, + 502577172985683970, + 502643468544790528, + 502640589226004480, + 504068336557502464, + 502646429941522432, + 502684344318562304, + 502623366155862016, + 502647272166133762, + 503046489548292096, + 502610740260655105, + 502783402693894144, + 502541427671588864, + 502613580945317888, + 502631510273699840, + 502630630363258881, + 502651737560600576, + 502630698273222657, + 503368067876130817, + 502625020498440192, + 502622775170060288, + 502547347390607360, + 502607338600030209, + 502629407673307136, + 502089642397958144, + 502982304856559616, + 502647434166956033, + 502617198289252353, + 503639502611820544, + 503345958818951169, + 502589986022383617, + 502656419477602304, + 502639164610084864, + 502661358362845184, + 503348478119264257, + 502615359128883200, + 502631778923085825, + 502636653480275968, + 502646179663183872, + 502494347536130048, + 502645108484087808, + 502635370866282496, + 502645987115298816, + 502644078530793472, + 502667132484599808, + 502642155098501120, + 503168550774009857, + 502629290081783810, + 502981056375816192, + 502627017700151296, + 502636270041202688, + 502621250871902210, + 502867280066531328, + 502632513903550464, + 502642586377805824, + 502631612098822145, + 502813145489211392, + 502653899916840961, + 502618727293386752, + 502625759945834497, + 502635739000344576, + 502635203089948674, + 501910269204115456, + 502946594711683073, + 502593850574376960, + 502636537805537280, + 503160596091920384, + 502641683142819842, + 502648306917728257, + 502646425142829056, + 503159961791528960, + 502638357680521216, + 502317621094912001, + 502630698403246081, + 502656439047835648, + 502942861105840129, + 502623704829161472, + 502644229919604736, + 502580672113180672, + 502614186720231424, + 502637710172241922, + 502615505010966529, + 502657549670166528, + 502642547056193537, + 502613526893318144, + 503057582312136705, + 503058312611782656, + 502100869807357953, + 502630348006899712, + 502622799996129281, + 502611624096956416, + 502651569859731456, + 502624269390852096, + 502655024024281089, + 502629513948577792, + 502636579324964864, + 502624012233871360, + 502201641035370496, + 502636715425939457, + 502615039011205122, + 502618189214519296, + 502816602782711808, + 502638285920174082, + 502146181804199936, + 502635509320273920, + 502611198303797248, + 502645449153859585, + 502652731819970560, + 502630923754815488, + 502662712363470848, + 502629121441427456, + 502634266539622402, + 502592021249675265, + 502796275264528384, + 502646539421253632, + 502579651072761857, + 503627588993306626, + 502648629501251584, + 503038359888224256, + 502622193206177793, + 502623326888792065, + 502653446496194560, + 502616366420336643, + 503368648338440192, + 504062290128556032, + 502659520762740736, + 502652568909414402, + 503132899890450432, + 502697675348004864, + 502049780789694465, + 502169492332752896, + 502652799227006976, + 502626116323262465, + 502236067315978242, + 502627396391305216, + 503413959513624576, + 502636780697710594, + 502607780025741312, + 502200814115753984, + 503173587654946817, + 502929055147380738, + 502551422853218304, + 502617700167090177, + 502621551586705412, + 502622636942585856, + 502612520830787585, + 503162261272547329, + 502610611571032064, + 502937853488558080, + 502667985140473856, + 502639693914439680, + 502615570274336769, + 502622852261367809, + 502639372102270976, + 502925075881164800, + 502621429524103168, + 502179257117057025, + 502261085379239937, + 502572462950084608, + 502138605905522688, + 502615643016167426, + 502650197491474433, + 503172414818516994, + 502641905734533120, + 502658769630007296, + 502628687955918850, + 502591962235809793, + 502632512557187073, + 502618146185183232, + 502611260022980609, + 503345998094036993, + 502675034842730496, + 502634858334945280, + 502617117154627584, + 502235953969115137, + 502684351989968896, + 502932376717369344, + 502177543207026689, + 503270755686432769, + 502631998415196160, + 503346001109737473, + 503071951519481856, + 502625204569653248, + 499913899488342016, + 502649678458933248, + 502636940370665472, + 502893683729911809, + 502630565775151105, + 502617662594510849, + 502646480784855040, + 503290018564431873, + 502614242672263168, + 502958502839861248, + 502612927946711040, + 502642584339369985, + 502657417348268032, + 503240575865593856, + 502777301856428032, + 503217137616703488, + 502406017494581248, + 502625275252080640, + 502669780852015104, + 502665216765612032, + 502672522362384384, + 502631243549523968, + 502655929549352960, + 502626253401518080, + 502613131722772481, + 502632894565982212, + 502610159093706752, + 502178744862117889, + 502625759639638017, + 502657629932359680, + 502618083593584642, + 503127595958161409, + 503072651062312960, + 502606947422834689, + 502632026512830464, + 502610790508425218, + 502649872890073088, + 502890606981414914, + 502666008075575296, + 503616329522630656, + 503286658675277824, + 502646179096973312, + 504396026870906880, + 502886904769961984, + 502593039215656960, + 502619336477913088, + 502644249985568768, + 502625162450440196, + 502795551080214530, + 502877637824368640, + 503239577143087104, + 504016095897219073, + 502640686622330880, + 502650884292345856, + 502656422379663362, + 502647686336905216, + 502826872837656576, + 502631065908154369, + 502626481710047233, + 502630062391582720, + 502618594635960322, + 502795274075766784, + 502889873578000384, + 502127235051298816, + 502644087808606208, + 502591943130759168, + 502874386677108737, + 502902288781152256, + 502886844963385344, + 503708368188354560, + 502877131236737024, + 502650893104578561, + 502474369415647234, + 502628827798192128, + 503007585201848322, + 502658935107514368, + 502600696274108416, + 502608648812916736, + 502888507790987265, + 503189617102053378, + 502624068714373121, + 502795456590938112, + 502894291362906112, + 502645757607170048, + 502616916796932098, + 502902089853698049, + 502625212081643521, + 502618771295850496, + 502677296101081088, + 503255395549192192, + 502827778333368320, + 502606239659200512, + 502677839989047296, + 502606693965254657, + 502609506917154817, + 502624723373944833, + 502627452171354113, + 503345996147851264, + 502642492563410944, + 502249991919116289, + 502663317522239489, + 502606249973014528, + 503485474946965505, + 502827703947378688, + 502877560901206016, + 502633548457975808, + 502958094855733249, + 502687110495621121, + 502580607869009920, + 502641211950108673, + 502874372215173120, + 502630976909225985, + 502690457445351424, + 502553725408657408, + 502637559215058944, + 502179040720338944, + 502902038746136577, + 502612234133323776, + 502638010169839616, + 502630966851272704, + 502889293795164160, + 502628236237754368, + 502635101466157059, + 502651393384001536, + 503345995355127808, + 502868624567459840, + 502660579572862977, + 502814991935094784, + 502645141421981697, + 502640939492732929, + 504019194720309252, + 502681081095524352, + 503149663500128256, + 502610195420577792, + 502803058251010048, + 503109181696929793, + 502631243054596096, + 503330874385891328, + 504526519994437633, + 502685657534189570, + 502533230923644928, + 502671514937090049, + 502611873695801344, + 502632009190363136, + 502616768142405632, + 502831182354997248, + 502831288521224192, + 502868144655204353, + 502875728430776320, + 502627989478449152, + 502884021140221952, + 502554128892325890, + 503213379654533120, + 502963041303269377, + 502650759432130561, + 502627022947246083, + 502680068825423872, + 502851837137911808, + 502886362169626625, + 504395651749117952, + 502639610141626371, + 502628020239495168, + 501710489790214148, + 505092924489883648, + 502835598357319682, + 502608691989065728, + 502878010543202304, + 502883892546633728, + 502589456520871938, + 502667675584446464, + 503008745958678528, + 502622023299125250, + 502682840979353603, + 502823334656999424, + 503244985073168384, + 502202915898294272, + 502831401863888896, + 503033943151902720, + 502875971498672129, + 503213310951829504, + 502865509470453762, + 502823009699512320, + 502628484653789185, + 502632389877960704, + 502823479855431680, + 502795152046718976, + 502860315206619138, + 503003177764278273, + 502628337819611137, + 502623266369179648, + 502621292542308352, + 502838990928478208, + 502853677103595520, + 503109900164403200, + 503111441604698112, + 502690390672023552, + 502826696626536448, + 502823202633289728, + 502629743175675904, + 502607136728567808, + 502881598803415040, + 502613874622070784, + 502623102833295360, + 502611303371116546, + 502697680573722624, + 503134904415424512, + 502905967575846912, + 502636303037792257, + 502837506681745408, + 502853810503442432, + 502546424433999872, + 502802897693081601, + 502633421106331648, + 502911985357709312, + 501897631254478848, + 502823317733400576, + 503112676940460032, + 503617761965133825, + 502881685474529280, + 502882631399538688, + 502685382861811712, + 502608238408630273, + 503693252516532224, + 502628743484297218, + 502640564391915520, + 502697177513091073, + 502663511441674240, + 502823544498053120, + 502684099618680832, + 502614991946940416, + 502690417473634304, + 502622192031768576, + 502470134439874560, + 502646179197616129, + 503207060423467008, + 502901801851838465, + 502644046964482048, + 502627233547419650, + 502611151436660736, + 502823615344033793, + 502532228522733568, + 502637195464019969, + 502163713533562881, + 502244981592293376, + 502643337837690880, + 502983581048639488, + 502693594680291329, + 503587559537012736, + 503384988117905408, + 502620581490356225, + 503132067006529536, + 502991585848852480, + 502826685574955009, + 502210924284235776, + 502623888195715072, + 503006352592355328, + 502630482585329666, + 502629489835536384, + 502853552843149314, + 501766273240690688, + 503572471086202880, + 502631597422960640, + 502591992527073280, + 502489394930921474, + 502609062417432576, + 502607931612073985, + 502628848492892160, + 502654545936535552, + 502607387090771969, + 502817486870310914, + 502418759563612160, + 502907717502402560, + 502983653786271744, + 503013813952602112, + 502817944007876608, + 502611790564700161, + 502630010864553988, + 503021346490576896, + 502607841442926595, + 502637138765443073, + 502915173120999424, + 502991163800821761, + 502636298184966146, + 502613888605913089, + 502556883589541890, + 502540869803573248, + 502645252189351936, + 502631410742886401, + 502607182559338496, + 503144656281272320, + 502652300448788480, + 502596834846842880, + 502653217977946112, + 502642412523905025, + 503028918836666368, + 502194233307299840, + 502996454655668224, + 503177384791932929, + 502658260634468353, + 502693653739868160, + 502644093215047681, + 502629411599175680, + 502894325949149184, + 502554887365079040, + 502640397873844225, + 502608087040409600, + 502998792988528640, + 502681593954451457, + 502665985690980352, + 502489534165426176, + 502621551993577472, + 502631965108232193, + 502653333082234880, + 502818028959305728, + 502114071861555200, + 502607598345273346, + 502483855962820608, + 502968527586742272, + 503647975403294720, + 502652665294520321, + 503693250319089664, + 502907458898366464, + 502695164314263552, + 503595545819373568, + 502646391169355778, + 503046993657069568, + 504303692536111105, + 502880385723011072, + 502612136766734336, + 502607691332988928, + 502553040780808192, + 502680197985230848, + 502647633459281922, + 503044039323967488, + 502625780820885504, + 502424515323129857, + 502813162572627968, + 502631103392661506, + 502649118154842112, + 503006251941236737, + 503285572496932864, + 502702852792270848, + 503037680478076928, + 502646271245815809, + 502243727448875009, + 502628988653961216, + 502545722483703808, + 502619174716571648, + 502650272943202305, + 502628485207457793, + 501765326577491968, + 502660951435669507, + 502610897282801665, + 503632859962167297, + 502624159693021184, + 503042720529907712, + 502616944840036352, + 502625389907570688, + 502952153573769216, + 502616303619014656, + 502623683828285440, + 502678475220992001, + 503142183588069377, + 502632793474859008, + 502621440479608832, + 502622222037843969, + 502626188700176386, + 502637541213106176, + 502636022896001024, + 504247164626010113, + 502642735862779905, + 504303645228539906, + 502455297995075584, + 503602654312812545, + 502968553067134976, + 502439962131050496, + 502548549197111297, + 502642352247566340, + 502641293689094146, + 503046484741586944, + 503767501772431360, + 503240327952478209, + 502647466156883968, + 502215950297751552, + 502652665063804929, + 502648348382613506, + 502990653580914688, + 502998738206351360, + 502551092526608384, + 502176297771360256, + 502535948119592961, + 502626750183264257, + 502548542758854656, + 502991158490853376, + 503693248963964928, + 503225215388631041, + 502639565241589762, + 502653586741145600, + 503022592715157504, + 503525678189670400, + 502629595741691905, + 503663056581185538, + 502644873561112576, + 502625630929059840, + 502626561259220992, + 502637948417089538, + 502669714741399553, + 502808426171613184, + 502636371266506752, + 502643232342560768, + 502123960411385856, + 502639042069291008, + 502586006538031106, + 502626577814134784, + 502618028425883649, + 503693249693753345, + 502654881615060994, + 502274350440259584, + 502623230688260096, + 503280150994100224, + 502628194194055169, + 502496414807912448, + 502608452242644994, + 502691737153048576, + 503047744655990784, + 502674353923043328, + 502641775778213888, + 502988540582825985, + 501852797193973760, + 502681154508832768, + 502640555067981824, + 502197877197012993, + 502454401462579202, + 502632948001427458, + 502974515555893249, + 502688915577659392, + 502648716445360128, + 502628532749873152, + 501083546107125760, + 500690957767938048, + 502976291571007489, + 502644492537958403, + 502633714300751873, + 503195311784079360, + 502483073226006529, + 502787287264923649, + 502506394168590336, + 502690323324092416, + 502623804976553984, + 502692157405163520, + 502651864438296577, + 502619909281820673, + 502628128016326657, + 502832740723482625, + 502982666338459648, + 502855433200361472, + 502528087687712768, + 503179659698528256, + 502580701339086849, + 502934969770315776, + 502635871947198465, + 502477732320923648, + 502612390329204737, + 502653964752785409, + 502651124298821633, + 502630138392358913, + 502425247514370048, + 502048673640222720, + 502426749045837824, + 502646020686495746, + 503044026413510656, + 502839632460255232, + 502630992247783424, + 502135723588198400, + 502938296641540096, + 502694941727158272, + 502802387413647361, + 502619323052359680, + 504384298359586816, + 502976052138737664, + 502614773964742656, + 502906865756672002, + 502639976321130496, + 502847784207151104, + 502549660930961408, + 502118560466878464, + 502593308921974784, + 503570020581257217, + 502591937367801858, + 502616205367451649, + 502630314217570305, + 502552625502773248, + 503914988625354752, + 503397681431973888, + 503300665636962304, + 503056595589537794, + 502616562516643841, + 502657374399004672, + 502877884067749889, + 503327616632635392, + 502410209806274560, + 502655361267286018, + 502052220813451264, + 502649141139607552, + 502676862703636480, + 502644091956781057, + 502580994470580224, + 503270466258075648, + 502047758506016768, + 502626372674920449, + 502213571481051136, + 502636526988443650, + 502212497324388352, + 502652211587842049, + 502650202160107520, + 502530626718023681, + 502696925498310656, + 502628474654584832, + 502660337733480448, + 502181034340143106, + 502183437508169728, + 502692508615577600, + 502940899794776064, + 502659287018377216, + 502493008059965440, + 502923216608698369, + 502630327962304513, + 502546826877501440, + 499904346713112577, + 502478761976004608, + 502149378174222336, + 502643449360023553, + 502617890496204800, + 502984832797143040, + 502227641454166016, + 502969068077727745, + 503327343969312768, + 502637290033016834, + 502665520081289216, + 502697231091126272, + 502097476447256576, + 502623877726732289, + 501410709087854592, + 502984878095626244, + 502823560985837568, + 502635683635556353, + 502955965873127424, + 502893791536513024, + 502648588707438592, + 502636834477080577, + 502671582662524928, + 502643873207025665, + 502642202561228801, + 502655160565645312, + 502611451811725312, + 502648087572385793, + 502618386141306880, + 502627455757471747, + 502608296361345025, + 502670765381009409, + 503018829711425536, + 502656886798176257, + 502815211007782912, + 502661811834220546, + 503023861919907840, + 502618754543779840, + 502593832413052930, + 502632400300826625, + 503678151386361856, + 502819081180151808, + 502627055948029952, + 502636094828331008, + 502680281477054464, + 502638514870427650, + 502787527070453760, + 502216272679940096, + 502211338081677312, + 502613997674590209, + 502206001022398466, + 502635684218560512, + 502653265503199232, + 502635737603637249, + 502628485798846466, + 502640523283533824, + 501446158510981120, + 503995270019817472, + 503184014912794624, + 502655961677713408, + 502160779315920896, + 502862782513946624, + 502632885820870656, + 502625841973850113, + 502697690250379264, + 502668429099548673, + 502908085074010112, + 502606401693569024, + 502665577756753921, + 502821537175859200, + 502577475285954560, + 502588518712242177, + 502507982807003136, + 499932332221284353, + 502778261576093696, + 502682313902522368, + 502620168523354112, + 502118432884547586, + 502560857398980610, + 502633963736039425, + 502437779893411840, + 502953440280993792, + 502531301141127168, + 502634769885429760, + 502609043404644356, + 502506661358354432, + 502467910846410752, + 502424714426720256, + 502643790814150656, + 502622061580550144, + 502587029566529537, + 502628365837533186, + 502646176710402048, + 502692674659700737, + 502184871964311552, + 502190878568370176, + 502983647964590081, + 503919785483051008, + 502611866414493697, + 502632863490400256, + 502642294093516801, + 502887232471322624, + 502644031558795264, + 502597561761669121, + 502640444392488960, + 502877182382063619, + 502837789483073537, + 502636529022668802, + 502632326724337665, + 503942434657554433, + 502669189598167040 + ], + "top_users": [ + "600402341", + "124172948", + "22952132", + "128813009", + "26757599", + "92670884", + "251538489", + "222159267", + "15007299", + "151514912", + "94900238", + "872374136", + "47288005", + "16676396", + "25382962", + "468030842", + "372897682", + "91957553", + "108740292", + "44399838", + "71448442", + "207976895", + "41820310", + "57099808", + "63263205", + "390394018", + "14071538", + "8544002", + "65466544", + "6015212", + "150003563", + "73886981", + "2308726255", + "109019058", + "174298035", + "223272482", + "95139587", + "15726324", + "348023985", + "171530998", + "1177035210", + "15737175", + "174496334", + "107017154", + "243339782", + "312315209", + "25482356", + "23986837", + "70390438", + "2367385932", + "127895424", + "65491558", + "64297333", + "135697779", + "37323507", + "268361752", + "59169087", + "76931020", + "292007127", + "68208970", + "155598890", + "1109861918", + "876113210", + "212105265", + "155745396", + "299335572", + "69413371", + "34700266", + "48812582", + "1589450359", + "120835612", + "196463183", + "129112971", + "1090975256", + "2191176823", + "243260587", + "465978180", + "376939390", + "181300983", + "22578516", + "47719006", + "153433497", + "129348511", + "160437291", + "2663800255", + "77010454", + "1170219228", + "169989918", + "167460294", + "2749841038", + "1692092802", + "19084628", + "250862815", + "2288589416", + "60739159", + "106929904", + "102872017", + "383639026", + "1675827620", + "1512111259" + ] + }, + { + "country_breakdown_percentage": {}, + "country_code": "BR", + "device_breakdown_percentage": {}, + "end_time": "2015-08-31T00:00:00Z", + "event_type": "OTHER", + "gender_breakdown_percentage": {}, + "id": "3h", + "is_global": false, + "name": "Festa do Pe\u00e3o de Barretos", + "reach": { + "total_reach": null + }, + "start_time": "2015-08-20T00:00:00Z", + "top_hashtags": [], + "top_tweets": [], + "top_users": [] + }, + { + "country_breakdown_percentage": {}, + "country_code": "US", + "device_breakdown_percentage": {}, + "end_time": "2015-08-22T00:00:00Z", + "event_type": "OTHER", + "gender_breakdown_percentage": {}, + "id": "2n", + "is_global": false, + "name": "We Day 2015", + "reach": { + "total_reach": null + }, + "start_time": "2015-08-21T00:00:00Z", + "top_hashtags": [], + "top_tweets": [], + "top_users": [] + }, + { + "country_breakdown_percentage": {}, + "country_code": "GB", + "device_breakdown_percentage": {}, + "end_time": "2015-08-24T00:00:00Z", + "event_type": "OTHER", + "gender_breakdown_percentage": {}, + "id": "2v", + "is_global": false, + "name": "V Festival", + "reach": { + "total_reach": null + }, + "start_time": "2015-08-22T00:00:00Z", + "top_hashtags": [], + "top_tweets": [], + "top_users": [] + }, + { + "country_breakdown_percentage": {}, + "country_code": "FR", + "device_breakdown_percentage": {}, + "end_time": "2015-08-23T00:00:00Z", + "event_type": "SPORTS", + "gender_breakdown_percentage": {}, + "id": "34", + "is_global": false, + "name": "Rugby : France-Angleterre", + "reach": { + "total_reach": null + }, + "start_time": "2015-08-22T00:00:00Z", + "top_hashtags": [], + "top_tweets": [], + "top_users": [] + }, + { + "country_breakdown_percentage": {}, + "country_code": "JP", + "device_breakdown_percentage": {}, + "end_time": "2015-09-24T00:00:00Z", + "event_type": "SPORTS", + "gender_breakdown_percentage": {}, + "id": "3a", + "is_global": false, + "name": "FIVB\u30d0\u30ec\u30fc\u30dc\u30fc\u30eb\u30ef\u30fc\u30eb\u30c9\u30ab\u30c3\u30d7", + "reach": { + "total_reach": null + }, + "start_time": "2015-08-22T00:00:00Z", + "top_hashtags": [], + "top_tweets": [], + "top_users": [] + }, + { + "country_breakdown_percentage": {}, + "country_code": "JP", + "device_breakdown_percentage": {}, + "end_time": "2015-09-01T00:00:00Z", + "event_type": "SPORTS", + "gender_breakdown_percentage": {}, + "id": "3d", + "is_global": false, + "name": "\u4e16\u754c\u9678\u4e0a2015", + "reach": { + "total_reach": null + }, + "start_time": "2015-08-22T00:00:00Z", + "top_hashtags": [], + "top_tweets": [], + "top_users": [] + }, + { + "country_breakdown_percentage": { + "AE": 0.09, + "AR": 0.22, + "AT": 0.07, + "AU": 1.21, + "BA": 0.02, + "BE": 0.11, + "BG": 0.02, + "BH": 0.04, + "BO": 0.02, + "BR": 0.49, + "BS": 0.02, + "BW": 0.02, + "BY": 0.02, + "CA": 4.22, + "CG": 0.02, + "CH": 0.04, + "CL": 0.36, + "CO": 0.18, + "CR": 0.04, + "CY": 0.02, + "CZ": 0.04, + "DE": 0.47, + "DK": 0.02, + "DM": 0.02, + "DO": 0.07, + "EC": 0.07, + "EG": 0.11, + "ES": 0.97, + "FI": 0.02, + "FR": 0.76, + "GB": 16.53, + "GG": 0.02, + "GR": 0.22, + "GT": 0.04, + "HK": 0.07, + "HN": 0.02, + "HR": 0.09, + "ID": 0.38, + "IE": 1.44, + "IL": 0.07, + "IN": 0.27, + "IQ": 0.07, + "IT": 0.34, + "JM": 0.04, + "JO": 0.04, + "JP": 1.01, + "KE": 0.04, + "KH": 0.02, + "KR": 0.09, + "KW": 0.13, + "KY": 0.02, + "LU": 0.07, + "LY": 0.02, + "MA": 0.02, + "MK": 0.02, + "MQ": 0.02, + "MT": 0.04, + "MW": 0.02, + "MX": 2.29, + "MY": 0.47, + "NG": 0.11, + "NL": 0.29, + "NO": 0.11, + "NZ": 0.18, + "OM": 0.02, + "PA": 0.09, + "PE": 0.27, + "PH": 0.79, + "PK": 0.04, + "PL": 0.02, + "PS": 0.04, + "PT": 0.16, + "QA": 0.04, + "RU": 0.09, + "SA": 0.88, + "SE": 0.31, + "SG": 0.38, + "SK": 0.02, + "TC": 0.02, + "TH": 0.13, + "TR": 0.18, + "TT": 0.07, + "US": 61.39, + "VE": 0.18, + "VI": 0.02, + "XK": 0.04, + "ZA": 0.29 + }, + "country_code": "US", + "device_breakdown_percentage": { + "ANDROID": 10.38, + "BLACKBERRY": 0.03, + "DESKTOP": 36.44, + "IOS": 52.76, + "OTHER_MOBILE": 0.39 + }, + "end_time": "2015-08-24T00:00:00Z", + "event_type": "SPORTS", + "gender_breakdown_percentage": { + "female": 36.39, + "male": 63.61 + }, + "id": "2o", + "is_global": false, + "name": "WWE SummerSlam 2015", + "reach": { + "total_impressions": 88385980, + "total_number_of_tweets": 1078660, + "total_reach": 5793218 + }, + "start_time": "2015-08-23T00:00:00Z", + "top_hashtags": [], + "top_tweets": [ + 501218019780333568, + 501025326479069184, + 501171664051113984, + 501202827360739329, + 501191906773061632, + 501204356251652096, + 501201067418607616, + 501934197138026497, + 501126390595321856, + 501181066506297344, + 501162361798279168, + 501222248632438784, + 501199986231877634, + 501173037106876416, + 501052381010751489, + 501200150300073985, + 501022839063859201, + 500661681039503360, + 500705242363604994, + 500709594872557569, + 499646728476569601, + 499641317140746241, + 501159874697240576, + 500267085356732417, + 501227001513246720, + 501202766186815488, + 501268018396012545, + 501200933007544321, + 501156534529691649, + 501181000198545408, + 500487282340544514, + 501796747350654977, + 501206095080484867, + 501199561990635521, + 501166316405796864, + 501202418496180225, + 501211360328310785, + 501211933370904578, + 501201313783640064, + 501162047246458880, + 502227597892542464, + 501138613024067586, + 501413264425644033, + 500916829934469121, + 500006612107411456, + 501241474021744644, + 501182213816598528, + 500672372475588609, + 501234096769880066, + 501384134082973696, + 501203291553161217, + 501205631450501120, + 501200533076459520, + 501058147235004416, + 501946599657193472, + 501194318317510657, + 501200460834144256, + 501234493147971584, + 499014302997553153, + 501198218563436544, + 501185403484127233, + 501167336142151680, + 501217961953468417, + 501196077421576193, + 500421180965150720, + 501200784655413248, + 501195185947017218, + 501042822045134850, + 501059219752116224, + 501193179342057473, + 500816485392973824, + 500145249810141184, + 501122423589457921, + 501337776907124736, + 500817150211543040, + 503685877227614208, + 501042117037129731, + 501183066178867200, + 501189393131249664, + 501162584037683200, + 501186234522550273, + 501185441907761153, + 501055438587043841, + 500569384696709120, + 499532569017593856, + 498822891266273283, + 501122957427875841, + 501188321021030402, + 499351635886219265, + 501186219498541056, + 501194883302846465, + 501186073314476032, + 501170895650840577, + 501073554449129473, + 500924813851230208, + 501169788874670080, + 500841692879003650, + 501015600026906624, + 500853876031905792, + 501198361517903872, + 499653577388744705, + 501361528327901184, + 501054603572432896, + 501158221810511872, + 501473660356800514, + 501166322290802688, + 499205029816201217, + 501169110408253441, + 500298607006732288, + 501200867266396161, + 501179330807230464, + 500917452201418754, + 501193144177029120, + 501056063290880000, + 500764213288382464, + 501201902219304960, + 501816393143418880, + 499075468226994176, + 500975670764527616, + 501193506430668800, + 501038476268421120, + 501143941152919552, + 501035912961486849, + 501194708790804480, + 501188822735286272, + 499866679825162240, + 501181464315461633, + 501186132886163456, + 501136860262187008, + 501162773116903424, + 501118813858193408, + 501085780832694272, + 501160898556624896, + 501579383900237825, + 501133150383525888, + 501177102436036609, + 501193001457451008, + 501188206033784833, + 501443492800131072, + 501058702636761088, + 501126254037565440, + 500869640747499521, + 501177056596856832, + 501169081991852034, + 498499851949068289, + 501199733625729024, + 502245417623764993, + 501180857928146944, + 501186947189321728, + 499942361066377216, + 499945250262351872, + 499888535244402688, + 501177400323878912, + 501235424824942592, + 501176765167828992, + 500688464572985344, + 501199932687417345, + 500294112894267392, + 501172535736537088, + 503248021170450433, + 500631215414988801, + 501199261581996032, + 501365946809073664, + 501172404123873280, + 498952132016734209, + 499865951362629632, + 501162206247923713, + 501005780020363264, + 501182830911561729, + 501639774768484352, + 500104342221774848, + 501065401363468288, + 501609570570362880, + 501211478956191744, + 501175597767589889, + 501103689936158720, + 501171399713906688, + 500824783047888896, + 500831450464518144, + 501036107287777280, + 498674748835258369, + 501165179925958656, + 501028719201619968, + 499995522329894913, + 500694571035406336, + 501950353672507392, + 501670014395904000, + 501178010934849536, + 501088648247259136, + 501198928919138305, + 502002155415699458, + 499435248229564416, + 498982256581820417, + 501181062413045761, + 501373660611899394, + 501124583315865600, + 498983965638656000, + 502493149064069120, + 499966935996833792, + 501199659826573312, + 499034676905123840, + 501700159705997312, + 501194404074622976, + 500386514602569728, + 501171360329379840, + 501178977248358400, + 500643458177302528, + 501372957835284480, + 501111301218000896, + 501188408824193028, + 501163193599668225, + 501075466271600640, + 501158578502500352, + 501013268643979264, + 500319212045221888, + 499735288286281729, + 500716527143120896, + 500390230214455296, + 501409676341153792, + 501109265051164673, + 501367958208544769, + 501166098285592576, + 498991439003389952, + 500748708053811200, + 501066357790998529, + 500631923463843841, + 500794400730284033, + 501165685289279489, + 499827824447205376, + 501181044725665792, + 499007341380272128, + 501044527395000320, + 501096328978763776, + 501103796341460992, + 501197665343131648, + 501043931228827650, + 500250647158325248, + 501166618740019200, + 501162847444160514, + 501024466621976576, + 503240291084955648, + 502364555604152320, + 501390612319715328, + 501187041288548352, + 501167156747599872, + 503203899281797120, + 501198218068500481, + 501160921671421952, + 498894015627276288, + 501197367769833472, + 501405760736464896, + 501184298343731200, + 501085329403564032, + 500814689761525760, + 501201870270902274, + 501375543900925953, + 501443576178307072, + 501050862513688576, + 498936971981758466, + 501082053744787456, + 500809941423116288, + 501195931631747072, + 500293460805419009, + 501198644662796288, + 501481206442385409, + 501181607278309378, + 501127525355905024, + 501428366097256448, + 500734091466407936, + 501154101150093312, + 501128321737183232, + 500798334693806081, + 501157080703983617, + 501451020095217664, + 500736552788430849, + 501201469043777538, + 501195898068541443, + 501194553890971648, + 500824499189993472, + 499012149000163328, + 500796381070905344, + 501168028499730432, + 501112156897959936, + 500801166822080512, + 501163970158657536, + 502195457691357184, + 501458588972638208, + 502461376179470337, + 501398442682613760, + 501193672000421889, + 501159264140795906, + 501126613430697984, + 501237857269207040, + 501409614823321601, + 501420836298182656, + 501175955684331520, + 501166154954838016, + 499983345032261635, + 498997682133024768, + 501208399032233984, + 499619795940044800, + 501195486037311488, + 501563668505432064, + 500667116261892096, + 500462041946398720, + 500669288022155265, + 500670026694004736, + 501157463748403200, + 501199336479662081, + 500711219259781121, + 500673577675685889, + 501136714031562752, + 502828634776694785, + 501466162975477760, + 499556447660044288, + 499956161219919873, + 501768139559174144, + 501180777590042624, + 501157374938578944, + 501031058960560128, + 501435951634481153, + 500443009931288576, + 500024118398701568, + 500456440860254210, + 501191037243883521, + 500447790448013312, + 502153579638300672, + 501187655745675266, + 502976742651621376, + 499616420247138304, + 501202030984458240, + 501195092477366272, + 501730388533051392, + 501194628541206529, + 501165146925203456, + 501145935972679680, + 502515550246174720, + 498942540351930368, + 501170933777051648, + 499930985278894081, + 501156850554122240, + 500069417993404416, + 501158788733616128, + 501194024754352128, + 501413258725949440, + 499991873029550080, + 501208896669630464, + 500891343338496001, + 501167118805528577, + 501163687173189632, + 501184542104104960, + 500800073752903681, + 501167665176911872, + 501192986114670593, + 501206584467283969, + 501177960431648768, + 501174736484044801, + 500438467298353153, + 500281108081442816, + 502877935188312064, + 498989417374437376, + 501157618224599041, + 501790953125187584, + 501193950225764352, + 501158918316630016, + 501765651837755392, + 501185324547325952, + 501192305391726592, + 501760891491467264, + 501199814642892800, + 501168274626056192, + 501538313329967104, + 501167902519619584, + 502187098414526464, + 501172187928485888, + 501190124840177666, + 500929503154040832, + 501194485280550913, + 502183315806621696, + 500313956486246400, + 501190381510619136, + 501200416311623680, + 501162521462853632, + 501171407003582464, + 502455373555859456, + 501185666164981761, + 501208891150331904, + 501186016242200576, + 501177335216082944, + 501189938059427840, + 499971570551758848, + 501191990693085184, + 501158604209405954, + 501169900153733120, + 501166668782268416, + 501191361883045888, + 501182118102573056, + 501496322495897600, + 501180498417565696, + 499944628335169537, + 501166918859247617, + 501188740552085504, + 501175190714593280, + 501162402604646400, + 501163101098881024, + 501201410055479296, + 501160033024221184, + 501162816435658753, + 499572570229051393, + 500673608331825152, + 501195867916075008, + 501162225978343425, + 501180114970091520, + 501189230115434496, + 501175815489748992, + 501137032035696640, + 501134841208143872, + 501185139268132864, + 500015213467664384, + 500296312349548544, + 499624012247732224, + 501182375502831616, + 501806082956984321, + 501187147613745153, + 501161499927543809, + 499949090894282752, + 498853410956136448, + 501185029939400704, + 501164810609106944, + 501192097635258368, + 499961785987129344, + 502915640475516929, + 500332364887633920, + 501519191091212289, + 500039212755070977, + 500796039407095809, + 501160990667702272, + 501201245324189696, + 501166365311782912, + 499601307226103810, + 499933828010758144, + 501183347843145728, + 501206308658225156, + 500341219151843328, + 500829038139936768, + 499299713108418560, + 500795659440902144, + 501191915497590784, + 501176473425035264, + 501179107414401024, + 500282185082241024, + 500930052645601281, + 501180125090959360, + 501162328180936704, + 501195847103946756, + 501174210036002816, + 501178454361264128, + 501187897048186881, + 501159134159712256, + 502168532239790081, + 502298279900491776, + 500379049232199680, + 501162217178292224, + 501529259320823809, + 502575957048573953, + 501179882651803649, + 500091635481739264, + 501185602268971008, + 502936186873458689, + 501181740682338304, + 501177770987503616, + 501198482322255872, + 501185881949343744, + 501182114982006785, + 500685389901074432, + 501209998186131456, + 501165757167075328, + 501193375681630208, + 500496152878276609, + 501190431603195904, + 502824142266052608, + 501179142126055424, + 501184708802531328, + 498489621249277952, + 500477040966246401, + 498876849939054593, + 501121875825926145, + 500401499239772161, + 501174896236695552, + 501182853292752897, + 501192834264092672, + 501141548365795329, + 500326903748632577, + 501181564186005504, + 501173576868065280, + 501169553091858433, + 501181988644999168, + 501198302239399937, + 501167194840252416, + 501503865502838784, + 501131626731278336, + 501190524272115712, + 502470216979611649, + 501169322870722560, + 499932115539345409, + 501194923895701504, + 499933508773883904, + 500360173937254400, + 501165562387783680, + 499060683297005568, + 500401625094434816, + 501162836157267968, + 501168950227386368, + 499608859787685888, + 501176946899038208, + 499945364854943746, + 500370252757483520, + 498601328797818880, + 501177826327146496, + 501202285851328513, + 500898243656421376, + 501173859404349440, + 500402188397867008, + 499013784821067776, + 498640772535963649, + 501024407889125376, + 501173243089145857, + 500329595770765312, + 500796010294435840, + 501159051766792192, + 501170705204256768, + 501169888233537536, + 501149847110819841, + 501182468704448512, + 501205928579182594, + 499024793140613120, + 501172286041235456, + 501175246763065344, + 501176380974186496, + 499951273521975296, + 501221509177040896, + 501201227158269952, + 501141619693744129, + 501151807377506306, + 501157254897618945, + 501170833990385664, + 501199798914277376, + 502073706144100352, + 499731123597881346, + 501174549023850496, + 501186411870306305, + 500805256251703296, + 500691211515351041, + 501171738362015744, + 501175042479501312, + 501148993385398272, + 501431934619484160, + 498889638384107520, + 501185289302204416, + 501199267197775872, + 500688910117130240, + 500258996146544640, + 498309417616805888, + 501199684200054784, + 501303960716976128, + 500416924363546624, + 501165830521245697, + 501185774134767616, + 501191381311037440, + 501101246309076992, + 500332138466521089, + 501192340313489408, + 501170366346457088, + 501428790695043072, + 502036884160540672, + 501198642930126848, + 501200755194228736, + 499079362961227777, + 501169450742460416, + 501182187493146624, + 501208591085232128, + 500596576499544064, + 501197194704084992, + 501198803777900544, + 501168290350125057, + 501223469410172928, + 501176767529631744, + 501197678580359168, + 501176897498529792, + 501561655134658560, + 499026563946790912, + 500906516149727232, + 501170596525658112, + 501184802456731649, + 500268687983935488, + 501089625080082432, + 501547533403828224, + 501226247616077824, + 498669005583155201, + 501189478715637760, + 501792357931835393, + 501199702025842688, + 501188364813340672, + 501167532263632896, + 500349983410126849, + 500342231660634115, + 501166278644871170, + 501192181059575810, + 501168353747034112, + 501092695805558786, + 501171394055770112, + 501201539995033600, + 501166964174516224, + 501197856846266368, + 501163406427451394, + 500278133082181633, + 501182699563130880, + 501908249084715010, + 501566566656638976, + 501536161794625536, + 502683300021149696, + 501190045298982912, + 501162340839333888, + 501241589696839680, + 501194444448595971, + 501150666413596672, + 499232747068854272, + 498652576804782080, + 501152716782309376, + 501195357712154625, + 501167503968444416, + 501144598765244416, + 501193609777922049, + 501201726943137792, + 501202955815878659, + 501176446120116224, + 501180146074664960, + 498320427882917888, + 501185595826139136, + 501152774462386176, + 500849561532108800, + 500784446724145152, + 501188480517427200, + 501194781595537408, + 501172012132622337, + 501205126003314688, + 501151347845398528, + 501179822123405313, + 499659834455650306, + 500777132998410240, + 500712656052162561, + 501149646828630016, + 501181263391510529, + 501165320443543553, + 501158756818747392, + 501174716082561024, + 501210286008070144, + 501177643509641216, + 499607528817586176, + 501052459524321280, + 501180063304257536, + 501168062876635136, + 501195468949712898, + 501180942065876992, + 501165547632197633, + 501228482513207296, + 501174136056872961, + 501199054001274881, + 501185819131277312, + 501191795833708544, + 501170321345359874, + 501056266626932737, + 501073057230757888, + 501174248279248896, + 501062914745569282, + 501187933827645441, + 501376096978227201, + 501409277215776769, + 500417307298914306, + 501166242573471744, + 501685687121608704, + 500490683275550720, + 501176240439820288, + 501190551035604992, + 501194108627456000, + 499023773304365058, + 501197622087286784, + 499285695609856000, + 501102252422344704, + 499399050622287872, + 501183833891299328, + 500595527768375296, + 501498475213643776, + 501235342494552064, + 501148799017164800, + 502669463532351488, + 500429701316243456, + 501296891460857856, + 500134697142591488, + 500201985157922816, + 498980175972163585, + 502945260968738817, + 501169022755278848, + 501186897104744450, + 501162752724201472, + 501225894103351296, + 501196570352549888, + 501013529512919041, + 500056512765493248, + 501098725843152896, + 501173565149175808, + 500711070861115392, + 501176956927213570, + 500729321313820673, + 498984648634949632, + 501901926880251904, + 501097259493494785, + 501164940334346240, + 501038072247504896, + 501187283429511169, + 501152101083660288, + 500696240536170496, + 500527284965879808, + 500460441634865152, + 499976725833322496, + 501204179785113600, + 499985370210394112, + 499287592622628864, + 500387124944728064, + 501206686477344768, + 500975721356210176, + 501178493946712064, + 501197743994732545, + 500776969165103104, + 501150478529732608, + 500132549268496386, + 501414865261432832, + 501179553952174080, + 501183370450452480, + 501201073227304962, + 498540373916934144, + 501196022995890177, + 500692255792168960, + 500675535740362754, + 500696697081970689, + 500849391193042944, + 501197463705755649, + 498641236551811072, + 498939751286976515, + 499042588964298753, + 501203553072185345, + 501190476633223170, + 501194325217533952, + 501299938249408512, + 499440849479274498, + 501199605804318720, + 501166474489122816, + 500826898856161281, + 501097588725391361, + 500850996336422912, + 500015254735441920, + 501161475936112640, + 501185285246681088, + 501201058052325380, + 501168242124021761, + 501210174426976256, + 501183553908899840, + 499300053019025408, + 501164457557782528, + 501158068542275585, + 501181080662470657, + 501175476732174336, + 501157290658238464, + 501175902080733184, + 501188601997447168, + 498897642546819072, + 501210798585151488, + 501181494581149696, + 501396977587093504, + 501210421131763712, + 501158091707416576, + 501191206181691393, + 500406487345147904, + 501182452480503808, + 501199751845773312, + 501173838634164224, + 503618149313294336, + 501170407920394240, + 500991125360893952, + 501177236993495040, + 501222852797140993, + 501180478871699456, + 501158937820160000, + 501221475097903104, + 501133898873442304, + 501083921699061761, + 501183838698373120, + 501133834688421888, + 499205286717300736, + 501166940526624768, + 501458677652393986, + 501026453102678017, + 501208804563091456, + 501167189974872064, + 501151183235731458, + 500503164957630464, + 500097845241073665, + 501185418646540288, + 501261344906420224, + 500706548998369280, + 501195842087579648, + 501157083770007552, + 500704885294510080, + 502074013448142848, + 501079858496430080, + 500326481663627264, + 501204625178238976, + 499642952365666305, + 501199944212959232, + 501176625501716482, + 501200852309127170, + 501164500188286977, + 500372850340278272, + 501159171782606848, + 501168961460129792, + 500686724360835072, + 501011247740256256, + 501556108952363009, + 501169895464124416, + 501199678474829824, + 501199669696147458, + 501116605690937344, + 501179644511412224, + 501199168665583616, + 501215836913532928, + 501069359109144576, + 501086397382791168, + 498265519037108225, + 501524795008110593, + 501398667421437952, + 501177492473122817, + 501160664816427008, + 501252165575270402, + 501184408603226113, + 501182455215562752, + 501168229575053312, + 500704545245515776, + 500287589149335552, + 499253758216241152, + 501178704676913152, + 501198574525612033, + 501171047643619329, + 501152040316182529, + 500726447175380993, + 499614289842294784, + 500244478339190785, + 501169358563844097, + 501384914613567489, + 501521439456251904, + 501186110559911936, + 501193969930629121, + 501206969160445952, + 501393736970944512, + 501162543725805568, + 501199499801661440, + 501165561959555072, + 501285144125517826, + 501200801260654592, + 501190208369733633, + 501886134151299072, + 501151208867135488, + 501168688494440448, + 501088046813810688, + 501201062314139648, + 500395483022360576, + 501184115375616000, + 500428071145861121, + 501192453454852097, + 499904926462795777, + 500878449448194049, + 501159428172050433, + 501174565205458944, + 500172756009639936, + 500145332232388608, + 499903610243665920, + 501204703557214209, + 501058734005972992, + 500055839089381376, + 501200935260266496, + 501194550212583424, + 501197302355488769, + 501171577174515712, + 501185599299387392, + 501065151676575745, + 501161943688675328, + 499606220756746240, + 501156974936219648, + 501185240074051584, + 501158955650138112, + 502477775715192833, + 501193899101413376, + 498520980226981888, + 501167063713722368, + 501163901497524226, + 500991316420202497, + 501164662629879808, + 501105818209906688, + 501182465373782016, + 500699664946331649, + 501520963528179713, + 501193317405577216, + 501178997883949056, + 501161073605898240, + 501185307405213696, + 501195392810487808, + 501196933164462080, + 501172711838601216, + 501365256807919622, + 501187213770903552, + 500459651440193536, + 501166964166123520, + 501199406759440385, + 501198848464015360, + 501202212237099009, + 501214810563182592, + 501084738539372544, + 501157747178868737, + 501199936047046656, + 501166096364216321, + 501167308333916160, + 501187467702435842, + 500824499248713728, + 501193114342932480, + 501259353660620800, + 501096922354950144, + 500363823539564545, + 501185073321111553, + 501159824772841472, + 500960305812627456, + 500778025567682560, + 500336508155727872, + 501160571736059904, + 501185531343306752, + 501158873664077824, + 501171987671052288, + 501156988488015872, + 501381803861495809, + 501410409526480896, + 501206616105287680, + 499662411906166785, + 501171868183703555, + 501199778127286273, + 501198801303257088, + 501228023627014146, + 500690313670045696, + 501277948046217216, + 500566851752321024, + 501161458219376640, + 501196236549287936, + 501200881187307520, + 501195842469265408, + 501170855359942656, + 501200640119693313, + 501167850829012992, + 501186431834791936, + 501163524245032962, + 501190941118824448, + 500023744627490816, + 501192393345863682, + 501173391529750530, + 501176760403509248, + 501109264543649793, + 501219006234103808, + 501198846236848128, + 501467310968676352, + 499910000446537728, + 501345693387460608, + 501195543620911104, + 501113820887416835, + 500371317246267392, + 501199690579578880, + 501022147784212481, + 500686650062946304, + 501167625284907009, + 501196672844984320, + 501192976832688130, + 501161399142211584, + 501056978580701185, + 501168545116721152, + 501201969273647104, + 501158393495961600, + 501517424227663875, + 500354225348440065, + 501213277796323328, + 500011324207017984, + 501175007142502400, + 501199797354000384, + 500306159136681984, + 501199430385537026, + 500428820558913536 + ], + "top_users": [ + "7517222", + "14387275", + "2883841", + "776112300", + "228698447", + "89556802", + "15290441", + "368703433", + "23827692", + "436888973", + "921093588", + "52529345", + "22179997", + "112915037", + "68577152", + "17733320", + "21254264", + "32765534", + "14075928", + "105251590", + "23089228", + "18927441", + "1195370804", + "59319830", + "355708717", + "44527648", + "26568085", + "17929027", + "29555251", + "17290098", + "89014429", + "92367751", + "24560836", + "221573745", + "249249080", + "172887151", + "310463188", + "39860984", + "31353077", + "119511875", + "1357803824", + "195728807", + "43585581", + "241964676", + "139848744", + "43989162", + "179932936", + "139242827", + "102325442", + "764829997", + "20221159", + "28265228", + "17936412", + "37106040", + "23405151", + "24277551", + "1264564686", + "28165335", + "14390187", + "45972667", + "54403121", + "57213267", + "195508960", + "955885435", + "238265021", + "13049362", + "28245852", + "17471459", + "29206353", + "262310943", + "1241937762", + "24529777", + "2194683961", + "66716999", + "20632300", + "122555803", + "27825390", + "168767461", + "516771605", + "70725301", + "17230894", + "91478624", + "267425142", + "14780915", + "359099321", + "16745015", + "115700178", + "65120103", + "43949085", + "43971053", + "1598631030", + "6351572", + "23780831", + "19416579", + "361329018", + "17308994", + "15729027", + "15687962", + "45675029", + "2720929469" + ] + }, + { + "country_breakdown_percentage": { + "AE": 0.15, + "AR": 0.68, + "AT": 0.02, + "AU": 1.33, + "AW": 0.02, + "BE": 0.11, + "BG": 0.02, + "BH": 0.02, + "BR": 0.59, + "BS": 0.02, + "BY": 0.02, + "CA": 4.61, + "CH": 0.11, + "CL": 0.17, + "CO": 0.83, + "CR": 0.07, + "CY": 0.04, + "CZ": 0.07, + "DE": 0.28, + "DK": 0.13, + "DO": 0.13, + "EC": 0.04, + "EG": 0.02, + "ES": 1.22, + "FI": 0.11, + "FK": 0.02, + "FR": 0.7, + "GB": 19.18, + "GI": 0.02, + "GR": 0.17, + "HN": 0.04, + "HR": 0.11, + "HU": 0.04, + "ID": 0.15, + "IE": 1.77, + "IL": 0.07, + "IM": 0.02, + "IN": 0.13, + "IQ": 0.02, + "IS": 0.04, + "IT": 0.68, + "JM": 0.02, + "JP": 0.92, + "KE": 0.07, + "KR": 0.04, + "KW": 0.04, + "KY": 0.02, + "LB": 0.04, + "LY": 0.02, + "MK": 0.02, + "MT": 0.02, + "MW": 0.02, + "MX": 1.14, + "MY": 0.22, + "NG": 0.07, + "NI": 0.07, + "NL": 0.85, + "NO": 0.59, + "NP": 0.02, + "NZ": 0.07, + "PA": 0.09, + "PE": 0.04, + "PH": 0.39, + "PK": 0.09, + "PL": 0.02, + "PS": 0.02, + "PT": 0.17, + "QA": 0.09, + "RS": 0.02, + "RU": 0.04, + "SA": 0.26, + "SE": 2.23, + "SG": 0.28, + "SI": 0.02, + "SV": 0.07, + "TH": 0.09, + "TR": 0.37, + "UG": 0.02, + "US": 56.83, + "UY": 0.02, + "VE": 0.17, + "VI": 0.04, + "ZA": 0.33 + }, + "country_code": "US", + "device_breakdown_percentage": { + "ANDROID": 7.82, + "BLACKBERRY": 0.03, + "DESKTOP": 35.25, + "IOS": 56.66, + "OTHER_MOBILE": 0.23 + }, + "end_time": "2015-08-31T00:00:00Z", + "event_type": "SPORTS", + "gender_breakdown_percentage": { + "female": 33.02, + "male": 66.98 + }, + "id": "2p", + "is_global": false, + "name": "Golf: The Barclays Tournament", + "reach": { + "total_impressions": 58451806, + "total_number_of_tweets": 182817, + "total_reach": 4746493 + }, + "start_time": "2015-08-27T00:00:00Z", + "top_hashtags": [], + "top_tweets": [ + 503605473363628033, + 503673644120551428, + 503671336636796928, + 503641924038053888, + 499986022420066305, + 503638695334133760, + 503656992859500546, + 503665739854020608, + 503664307406897154, + 503614441640820736, + 503577162411433984, + 506202940865253377, + 503583984472055808, + 503297392515743744, + 502505437707505664, + 506113501065396224, + 501140200605896704, + 503624061965316096, + 503658039048945664, + 506113320819388416, + 503248210991669248, + 503267208639033345, + 501102629188276225, + 503598257449496579, + 503243599731912704, + 503592944893718529, + 500715630535118848, + 503674444737687552, + 503246100875472896, + 502515496093499392, + 503626898531184640, + 503245402431565824, + 503254605841858561, + 502877897234075651, + 503632432202264577, + 503632833043501056, + 503259127234441216, + 503608680412368896, + 501079766934749184, + 503622287493705729, + 501110218638761984, + 503657969633222656, + 503652469357182977, + 500013131335475201, + 503274537417736192, + 503627451549765632, + 503609939634696192, + 503666729747501057, + 501121573047521280, + 503640364410884098, + 503251483937472512, + 503649957606600705, + 503623499106504704, + 503646157340672000, + 503618199775346689, + 500016681863770113, + 500752469044248576, + 503269324920856576, + 503641077497462784, + 500743049098833920, + 503625901306052611, + 503245397801041920, + 503645897172189184, + 503254730630762497, + 503659964968488961, + 503634969731031041, + 503284622038679553, + 501118988848734209, + 503291844030377984, + 500356290045292544, + 503558322474455040, + 503303411342012417, + 503632590876995584, + 501120032605483008, + 503285263322611712, + 503638348729442304, + 500760665385357314, + 500761896119975936, + 503217711472967680, + 503242126071980032, + 502924426493825024, + 503648194010836992, + 503657761004322819, + 503663213092024321, + 503673350540255232, + 503662157155028992, + 503299711760334848, + 500715014765154304, + 503657627663237120, + 503672978916511744, + 505824034110455810, + 503675518961868800, + 503302810432438272, + 500691669348794370, + 503733004414763008, + 503650796102094848, + 503311329097441280, + 503646074515771392, + 502511955676893184, + 502922994218704896, + 503271191361363968, + 500345469793341441, + 503572482419605504, + 503213835411787776, + 501120644231483392, + 500690812708327425, + 503597635207692289, + 506155724335218688, + 503560473791709185, + 503617860456181760, + 503632938245050369, + 505509132485820416, + 503679697184886784, + 500001502136901632, + 503262900086374401, + 503237321429221376, + 506160861225181185, + 503657762723614721, + 503614528274575360, + 505801493145198593, + 502918139001470976, + 503585084868657152, + 500412914004934656, + 503239773910499329, + 503325916064677888, + 503237049726803968, + 501053220043902977, + 503574456615600128, + 503620476644909056, + 501087820841504769, + 501112504601550848, + 506184911594979329, + 506161875705675776, + 506175343750021121, + 501098391515181056, + 503685293619568641, + 502580420828225539, + 503568685416845313, + 506120351450140673, + 503231598687698945, + 506150180635574273, + 506167793897975808, + 506119261577035777, + 506136085186236416, + 506172702932361217, + 501078424174465025, + 502872723350384640, + 506111542799392769, + 500007962669514752, + 499991606947512320, + 503667168584925184, + 502935138528141313, + 500009794565341184, + 501076997356150784, + 503595634755387392, + 506169932745543680, + 501093105744236544, + 506111799801184256, + 500699182253236226, + 502911736278945792, + 506202527873134592, + 501062515779186688, + 501071816577024000, + 503652234102853632, + 503665205382242306, + 502899541600124928, + 503232750736781312, + 500358868724355072, + 502906055886921728, + 506139444186185729, + 503623537647947776, + 500716836020043776, + 506186922298200065, + 505407695948873729, + 500705782837837824, + 506143172872110080, + 506134453354512384, + 506124305680580608, + 505435852412305408, + 505784122875609090, + 502894904331472896, + 501069316402712576, + 502520158968352768, + 500020791359315968, + 502506174001213440, + 500710422744666113, + 505432954194391040, + 501080627081646081, + 500708582435074048, + 500697621967949825, + 505812706784718848, + 505778982131073025, + 505818350635982848, + 500674679154421761, + 500376633875103745, + 506197206052139008, + 505441384531505153, + 500731220620480512, + 505825797069094912, + 506143436404441089, + 506143651777773568, + 505795712580591616, + 505413969977573377, + 501111865502887936, + 500725422787932160, + 500357666808803328, + 505817635595235328, + 506192355058540544, + 506139237377671168, + 501094587612807168, + 505428028617654273, + 501096109390172160, + 506198629754081280, + 500723800070451201, + 500675290935590913, + 502535473232105472, + 500739525581496320, + 505842519150964736, + 500687301899350016, + 500721476124016640, + 502883955092488192, + 500016815607914496, + 505424052090331137, + 506200026834800640, + 500004184914427904, + 502524541022007296, + 502875325962145792, + 503263069511090177, + 505439503692357632, + 506139000990863362, + 502889950782959616, + 503613744648572928, + 500730719199838208, + 503620428653678592, + 500362544343965697, + 502558917948624897, + 502563798931492864, + 502868211801804801, + 500705630018351104, + 505411179997839360, + 502900390778925057, + 502571601557471232, + 505807192122216449, + 503592671462830080, + 503284763499982849, + 505466678986432513, + 502932256764469248, + 500737515503222784, + 500344170826174465, + 500764944477212673, + 501120464551698432, + 505470606666891264, + 506195987174789120, + 500029578652704768, + 503623598679289856, + 502517510898716672, + 500011945454751745, + 505814603058917376, + 505831703324409856, + 503275572882309122, + 503265268681162753, + 505457870490828800, + 505832204375973888, + 503594207307915266, + 503622849341689856, + 502866059314364417, + 503605371983114243, + 502567829577949185, + 503663526825955328, + 499988329342177280, + 501063991297204224, + 505473113799524352, + 502500892797861888, + 505833051520512000, + 503639607184195584, + 500406836156444672, + 502576241896357888, + 505444529445822464, + 505841896250687488, + 506197551604068353, + 506196318961037312, + 503253865488457729, + 503668151713009664, + 500040168406282241, + 503289603881963520, + 505846653266694144, + 503284322414395393, + 500398370931085314, + 503643012036300800, + 505478504285491200, + 505476995900530689, + 503665233270165505, + 503633619429363712, + 500737414487629824, + 503292880635846656, + 503632863292837889, + 502575627049107458, + 501089808995729408, + 505482690674835457, + 503680385029799936, + 505850451955556353, + 505484039072272385, + 501125874536947714, + 502946321444384769, + 503301046828285952, + 502583788883693568, + 501136698806652930, + 505451252357267457, + 501107936769626112, + 502567342577287169, + 503642771371356160, + 503622274566860801, + 502583059053830144, + 505487303390003201, + 505855237371224064, + 503303250314264578, + 503678290226581504, + 502893588318265345, + 503644643620560896, + 503664970509189120, + 500752648371707904, + 503664214725382145, + 506214562044317697, + 501104939461246976, + 503603316803137536, + 501121170574684160, + 500766746362802177, + 502910466218524672, + 505857754628907008, + 500052483012829184, + 505497633654579200, + 502568647177801729, + 502894628161720321, + 500685428706795520, + 506164463096324098, + 506125459076427777, + 500023470454218752, + 501090037606662145, + 501125089702993920, + 506219885677252608, + 506156107862376448, + 502954620747280384, + 500416295134060545, + 503685211616727041, + 506154510923079680, + 503315775630082048, + 503651833903333379, + 500054297057714178, + 505492973543772161, + 503613458852900864, + 500402894571847681, + 502948774382415872, + 499981932872998912, + 503617559758114817, + 503606886160019457, + 503282206660251648, + 506140230920208385, + 501121227965341696, + 503652700928892929, + 503608839095074816, + 503628686885920769, + 503273327721324544, + 502910141218697216, + 503274363094052864, + 503636129426710528, + 505510241468178433, + 506175678698770432, + 502928128197816320, + 503665440464580608, + 505439547476701184, + 503654398581432321, + 500766843792269316, + 503562458557349888, + 503649692031266817, + 503581073046249472, + 503643969205837824, + 503272218756153344, + 501091154717593600, + 503606602789027842, + 503653760422268928, + 503649251864219648, + 503634788419657728, + 505803801140686848, + 506114280069283841, + 502964524304310272, + 501060960506085376, + 503246999911952384, + 503652041135124480, + 506160304321855489, + 506169751333527553, + 503656748591247361, + 506124592310919168, + 503255394391556096, + 501113036976177153, + 503294420993998848, + 502937424327368704, + 500722984467050496, + 501051279213613056, + 503665987934519297, + 503298063872446464, + 500686931911782401, + 503601394251595776, + 506145543798915072, + 506147116910391296, + 503663014655315968, + 503650506263494657, + 505812218416758784, + 505832066131701760, + 503616480265912321, + 502510487922540544, + 505779525612220416, + 503263468460703744, + 503622799605657600, + 503298805375451136, + 503320803166158849, + 500061819982348288, + 506184693726056449, + 503301430543781889, + 500743251813736449, + 503657846769463297, + 506208249079926784, + 506190667346087937, + 503278205642735616, + 505797212144959488, + 506174670497132544, + 500683513633730560, + 501120471274758144, + 502599533902438400, + 503319031164588032, + 506134406701285377, + 505822557317390337, + 503572663613554688, + 501141189073321984, + 503664113181290496, + 503627842509238272, + 502522676481896448, + 503643938268655616, + 503230104051658752, + 500703780661628929, + 503673086403547136, + 506204851983106049, + 503688248833888256, + 502565246813618178, + 503685757228580865, + 506144875109421056, + 502960924362567680, + 500755556140060672, + 506196269585694720, + 501112169870934016, + 502933409740890112, + 500367668189618176, + 503564976536055808, + 505799548879392768, + 503631257151242241, + 501050952313749504, + 503663890606350336, + 505449873064591360, + 506192105522622464, + 502523687166550016, + 503225704520376320, + 500675922157391872, + 506121891489521665, + 503589623776706560, + 502934972798607361, + 500043322774528000, + 501120992966868993, + 503674229200785410, + 501136057149452289, + 505778343430881280, + 501111270230482944, + 505792280327114753, + 500346271652397056, + 505460718385528832, + 502908302519726080, + 506135083968102400, + 502924642345312256, + 499995101217964032, + 503645706734010369, + 506127336740114432, + 500396549399379970, + 506215314863165441, + 505840612877533184, + 502886201058394112, + 501121107513315329, + 503652383713673217, + 503598736337936384, + 502900104383455232, + 506131795226554368, + 502535721492959233, + 500694968500252672, + 505863792413384704, + 503668453736452097, + 500004033160294401, + 505439940424261634, + 501039396808704000, + 500374213480701952, + 500711299790024705, + 500014035983953920, + 503632389575561216, + 505443472737046528, + 505818779558088704, + 505438970457489408, + 505842410078089217, + 502527124054761474, + 506171465730129921, + 503663285322153984, + 500764822880133120, + 505422527100108801, + 502567114012897281, + 499985097043771392, + 500376501561606144, + 502515975544373248, + 505412493804847104, + 505416195856945153, + 505470004192903168, + 502903098038571009, + 505472219255156736, + 503665283685294080, + 501078762327646208, + 501116042362777600, + 503647599467831296, + 500763653671755776, + 502515842731753472, + 503667889430605824, + 502513276383936513, + 503280871869124608, + 500690718013550592, + 500030315805417472, + 501128211796066304, + 501051526186795008, + 503247823513874433, + 499994713144180736, + 501113876751347712, + 502878026406055936, + 502868085398077440, + 505480053892063232, + 503273492268072960, + 501040262072631296, + 506170591355731968, + 503246015210586112, + 500691136676384769, + 503251707317727232, + 501122029257760769, + 503664792066744320, + 500746265127567360, + 503668055306547200, + 502576134488608768, + 502943313239212032, + 500356745899024384, + 503671849218105345, + 499999424324845568, + 503622361070186496, + 505454468230832128, + 501046772173897728, + 501141449724157952, + 503374576932634624, + 503666322086309889, + 503592369954897920, + 503668847841669120, + 500406663057514496, + 502567262797451264, + 506152470930665472, + 506160832896458752, + 506115252552208385, + 502873709901012992, + 503671868252246016, + 503267878146015232, + 503583033346117633, + 505796227162980352, + 506178890843164672, + 503258674039894016, + 503317099620892674, + 506164497762254849, + 501094271844630528, + 501140481657417728, + 501099654826565632, + 502586058928693248, + 500684288254570496, + 506127184302706689, + 503288532782551040, + 503611343183048704, + 499983845148884992, + 501125684732121088, + 501054027086712832, + 505843816771764224, + 500751402667220993, + 506121746517618688, + 503663236680392704, + 500383433282314241, + 506189953684893696, + 500044227372666880, + 501092597172289536, + 503636489809326080, + 502863942520430592, + 506191035752407040, + 502872777167486976, + 503670999184056320, + 500755350732406784, + 503678354965659648, + 503667455387238400, + 502918497975160832, + 501051529617747969, + 503666449072660480, + 501106969680572416, + 500701782050209792, + 502510032974790656, + 503211006303420418, + 501112828837650432, + 503240671646720001, + 503666959150759936, + 501135443745054720, + 503272366512680962, + 503639371128791040, + 503601638548848640, + 505830279793999872, + 505817615768379393, + 502922072776265729, + 505474402105167872, + 500693481929457665, + 503570651408388096, + 505795338595491840, + 503663044036009984, + 505508061814202368, + 503276630417354752, + 503602892969103361, + 503563478859534336, + 501134010924679170, + 503690276247175168, + 503607678166646784, + 503276762688937984, + 503247014528679936, + 503299297207533568, + 502953827814105088, + 502936825380737024, + 499997250115108864, + 503576719111241729, + 503223459762434048, + 501120176688234496, + 500761578703429632, + 503615951322218497, + 506177365517426688, + 506196739817103360, + 503558099886931968, + 503239094885838848, + 506191960751607808, + 503276211900911616, + 506170014039150592, + 501050400817315840, + 501143664916451328, + 500387471524245504, + 500716826796773378, + 503261111760596992, + 502928417294409728, + 503302366532489218, + 505840518635352064, + 502890490828980224, + 506167176022073344, + 501127303079149569, + 505833236917129216, + 502874607364218884, + 502514793522425856, + 503304725974880256, + 502883357462892544, + 505777795923189760, + 503246579588141056, + 500766856341622784, + 501086145531625472, + 501122147969138688, + 502573800836579328, + 505422838623662080, + 505814702778482688, + 505417366868471808, + 500764647948292096, + 500720873251553280, + 503661248366395393, + 503643674841206784, + 502515619020177408, + 501110710563532800, + 506183071364681728, + 505412983619469312, + 503561643448881152, + 503564995595358208, + 501128335032741888, + 503214922915143680, + 506209643262386176, + 503689008677810176, + 503668799057309697, + 499993649128931328, + 503622629367222273, + 502940256451035136, + 499998411639103489, + 500362795318534144, + 502935713546248193, + 503225206421200896, + 500009044829282304, + 503251944564326400, + 505420796698054656, + 503679007574224897, + 506146931064582145, + 503639045202018305, + 503587623672094720, + 502934559554433024, + 506190687570624512, + 503573829823000578, + 503674411308703744, + 503663846905880578, + 503563469829189632, + 500416703197888514, + 502588000560103424, + 502596028739362816, + 503618997443895297, + 503558295358275584, + 503229675431530497, + 500674560887627776, + 502907211572461568, + 505871128049352704, + 503663622891909120, + 501113664347594752, + 503306410734538752, + 501124113323532288, + 505414564377145344, + 506190621196189696, + 506179190925037568, + 503247615169802240, + 500673497967128577, + 503611652605222912, + 503665573121638401, + 500772859254669312, + 500064412305469441, + 500344977495699458, + 500347450515677184, + 502876096950697984, + 503646585222598656, + 500416788149305345, + 501136748760825856, + 502592632372334592, + 500016602629570560, + 503605160200126464, + 503672471581884416, + 503663765641232384, + 503322661871570946, + 503213310045847552, + 503595796672315393, + 501101086477127680, + 505485232800137216, + 503678500491235330, + 500005481549955072, + 503660543467454464, + 505430945848365056, + 501131863088726017, + 502865282004951041, + 505862545509728256, + 500726422114029570, + 502909481123328000, + 500714394121437184, + 505845998317363200, + 503665605976014848, + 503676390408216576, + 502510369349599232, + 500703947842404353, + 501111304455999488, + 500741252187684864, + 502539927058649089, + 503671790674403329, + 506112501743091713, + 503688385337507840, + 505429728522543105, + 503667580184571904, + 502908378524696576, + 502947579219292160, + 506159222456070144, + 503643947026370560, + 500788821945229312, + 500386973161648128, + 506196907023032320, + 501069597618221056, + 502903399625805824, + 499997256343236608, + 503573054438404098, + 505855835017580544, + 502924037480517632, + 505442280216723456, + 502881374949634049, + 501121416524496896, + 503590933074821123, + 503573710976999424, + 500716063005634560, + 503263791644409856, + 503671127843954688, + 503566674721660928, + 500689594040713216, + 505478138873516033, + 502530604915625984, + 500690320070545408, + 505430276617822208, + 506156751045926913, + 502582144943030273, + 503233948940763138, + 505782677069651968, + 503619422456926208, + 503674400596832256, + 503690828783828992, + 503604790723874816, + 503573297813291009, + 502907894162268160, + 503572507668918274, + 503219509898272768, + 503564832407556096, + 506132466659524608, + 500688002553638912, + 505475188931461121, + 502937958211911680, + 505500192494616576, + 503630074852442112, + 502555842718490624, + 503653785861115904, + 501123015254736896, + 503671501506109440, + 500768155145601024, + 503636719418490880, + 505414056942268416, + 503640988037156865, + 505414559436656640, + 505808296033271808, + 503626441733713920, + 501053792893145090, + 505481741948452865, + 503649368646615040, + 502560866760278016, + 506220286442618880, + 501068768550727680, + 500378858231582722, + 503602105756975105, + 501129313983672320, + 503294387603132416, + 506137785791967232, + 505844636535894016, + 501148041387462656, + 502909307172978688, + 505824911764357120, + 503687660037505024, + 500058595216474113, + 505460086722936832, + 503297811387936768, + 502936659294683138, + 502504071061061632, + 506185036572655616, + 503245252489383936, + 506167120695402496, + 503600166168170496, + 503647331787739136, + 505447635579174913, + 506137168180695040, + 503304502943158272, + 506133396050149376, + 506136158704005121, + 502896304024862720, + 503247823467724800, + 503650103739961344, + 501121276732506113, + 503627753430974464, + 503666864019759104, + 502512983017521152, + 505444640125112320, + 500767116627173377, + 499979054049542145, + 500736128484274176, + 503665291063463936, + 506195082874486784, + 503254791624331265, + 501130741687021569, + 503656022485893120, + 506137476101320704, + 505465808093708288, + 503684466163068928, + 503234366953115649, + 503586481630642176, + 505507272991453184, + 503265035687575552, + 503627618709938176, + 503635904947175424, + 502934567603683329, + 503670290862600192, + 503259618232242176, + 502931212415954944, + 505869597627936768, + 500020808048472065, + 500768019354640386, + 502864554653913088, + 505510605235572738, + 503627893508153345, + 503625355194679297, + 506198263339290625, + 505832410412752896, + 501053572168298496, + 506134955270103042, + 500058428090634240, + 506185858064474112, + 503645122765258752, + 503222863848280064, + 502914081909923840, + 501128485415297024, + 501086551200522240, + 503294392720183296, + 502891191776468992, + 503620542633873408, + 502548084292087809, + 501128458106179584, + 503261686607134721, + 503274863113809921, + 503282543664574464, + 503298411609608192, + 506130363916103680, + 503247865024499712, + 506208230955950080, + 500741299624878082, + 502891578176724992, + 503308907557974016, + 503273180128358400, + 503594699756929024, + 500709079401377792, + 500759230610034688, + 503611129642614784, + 503281839034101760, + 502524618507173888, + 503664480061243392, + 503297384039059456, + 502533845380767744, + 503640537526992896, + 501121090718941187, + 503663348890607616, + 503606614377897984, + 502526985416220672, + 501128358194069504, + 500776683029676033, + 503270905850916864, + 503606605473005568, + 502531052079157249, + 500690771134406658, + 502893948621561856, + 506117771512774656, + 503665593229127680, + 505845111134375937, + 502936630341419008, + 503669425619603456, + 500383755417030656, + 503268500535001088, + 503669365473300480, + 505847446442754048, + 502549094687318016, + 506148711811272704, + 506225987885875200, + 503610660690079744, + 505868536938762240, + 500776102348861440, + 503645344241291266, + 503229360396984322, + 503280438626889728, + 500394137393586176, + 501128508173979648, + 503311869705064448, + 502515820212547585, + 501126573924552704, + 505424790531096577, + 503287031276240896, + 502939026475601920, + 500708955786469376, + 503249037056016384, + 503594271086493697, + 506174014537338880, + 501129373689602048, + 502519027546488833, + 502904008512507904, + 503287578070880256, + 503663163985125377, + 501128487206662145, + 506203014131380224, + 502869302718906369, + 506114235194408961, + 503606578952810496, + 502514475174342656, + 501129304030588929, + 503653007155007488, + 503630482824003584, + 500693083168989184, + 506129940396646400, + 503251692197265408, + 502587028928987136, + 500680927568494592, + 503616321003995136, + 503648244925476864, + 503328679590887424, + 503637520165666817, + 503660558588342272, + 506213853248913408, + 502930553835110404, + 506202196044959744, + 503606724235128832, + 503614784840163328, + 503662739433484288 + ], + "top_users": [ + "14063426", + "28349128", + "26257166", + "22146985", + "20463402", + "188039706", + "265902729", + "28534252", + "105119490", + "55809761", + "437700198", + "39753512", + "19230601", + "219243547", + "14063612", + "34737134", + "24277551", + "75014376", + "33314461", + "13213122", + "32073913", + "53120768", + "19777398", + "14364779", + "26578816", + "160926944", + "28147403", + "16788222", + "46403451", + "1543364688", + "212256947", + "71022075", + "16331010", + "153118706", + "50945242", + "51079493", + "31524560", + "44706253", + "55246492", + "256204673", + "32717570", + "890891", + "2485131707", + "27651972", + "588730194", + "15764001", + "26829777", + "249154446", + "23642374", + "32078122", + "87118217", + "28406157", + "287407881", + "28370738", + "11176532", + "35924938", + "549197445", + "21660529", + "171117515", + "86230406", + "331283041", + "279321785", + "700393309", + "295202106", + "105272955", + "167103505", + "17212050", + "249113159", + "306420012", + "17866834", + "289888727", + "28171178", + "78183672", + "17070013", + "262218224", + "22903166", + "531657801", + "261895404", + "14885860", + "274184658", + "34395888", + "24531730", + "127621803", + "2283706789", + "394471665", + "872185597", + "20012204", + "29606454", + "16826656", + "494885999", + "111556576", + "36940175", + "26315586", + "390860562", + "17469289", + "46318078", + "1694483425", + "204976949", + "126716505", + "130594732" + ] + }, + { + "country_breakdown_percentage": {}, + "country_code": "GB", + "device_breakdown_percentage": {}, + "end_time": "2015-08-31T00:00:00Z", + "event_type": "OTHER", + "gender_breakdown_percentage": {}, + "id": "2w", + "is_global": false, + "name": "Creamfields", + "reach": { + "total_reach": null + }, + "start_time": "2015-08-28T00:00:00Z", + "top_hashtags": [], + "top_tweets": [], + "top_users": [] + }, + { + "country_breakdown_percentage": { + "AE": 0.2, + "AF": 0.02, + "AM": 0.02, + "AR": 0.73, + "AT": 0.16, + "AU": 1.57, + "AW": 0.02, + "BE": 0.16, + "BH": 0.02, + "BN": 0.02, + "BR": 1.26, + "CA": 2.64, + "CG": 0.02, + "CH": 0.16, + "CL": 0.22, + "CN": 0.02, + "CO": 0.24, + "CY": 0.07, + "CZ": 0.07, + "DE": 0.58, + "DK": 0.07, + "DO": 0.07, + "DZ": 0.04, + "EC": 0.16, + "EE": 0.02, + "EG": 0.07, + "ES": 2.04, + "FI": 0.11, + "FR": 1.31, + "GB": 48.54, + "GG": 0.09, + "GI": 0.02, + "GR": 0.31, + "GT": 0.02, + "GY": 0.02, + "HK": 0.09, + "HN": 0.02, + "HR": 0.2, + "HU": 0.04, + "ID": 0.58, + "IE": 1.31, + "IL": 0.04, + "IM": 0.09, + "IN": 0.2, + "IS": 0.02, + "IT": 0.66, + "JE": 0.02, + "JM": 0.04, + "JP": 3.14, + "KE": 0.02, + "KH": 0.02, + "KR": 0.11, + "KW": 0.11, + "KY": 0.04, + "LB": 0.07, + "LY": 0.02, + "MA": 0.02, + "MT": 0.02, + "MX": 1.55, + "MY": 0.73, + "NG": 0.04, + "NL": 0.42, + "NO": 0.2, + "NZ": 0.09, + "OM": 0.02, + "PA": 0.02, + "PE": 0.07, + "PH": 0.84, + "PK": 0.04, + "PL": 0.04, + "PS": 0.02, + "PT": 0.11, + "PY": 0.13, + "QA": 0.07, + "RU": 0.29, + "SA": 0.18, + "SE": 0.29, + "SG": 0.49, + "SI": 0.04, + "SV": 0.02, + "TH": 0.22, + "TR": 0.51, + "UA": 0.02, + "UG": 0.04, + "US": 24.96, + "UY": 0.07, + "VE": 0.27, + "VI": 0.02, + "VN": 0.02, + "ZA": 0.18 + }, + "country_code": "GB", + "device_breakdown_percentage": { + "ANDROID": 9.47, + "BLACKBERRY": 0.03, + "DESKTOP": 36.71, + "IOS": 53.22, + "OTHER_MOBILE": 0.56 + }, + "end_time": "2015-08-31T00:00:00Z", + "event_type": "OTHER", + "gender_breakdown_percentage": { + "female": 50.48, + "male": 49.52 + }, + "id": "2x", + "is_global": false, + "name": "Reading and Leeds Festival", + "reach": { + "total_impressions": 65216822, + "total_number_of_tweets": 341257, + "total_reach": 4490019 + }, + "start_time": "2015-08-28T00:00:00Z", + "top_hashtags": [], + "top_tweets": [ + 503876983613587457, + 503863709329285120, + 502852262642057216, + 502757079245803520, + 504375460953096193, + 503937637451694080, + 502719907185045504, + 502809382199898112, + 504217398954975234, + 503643384524054528, + 503839799598657536, + 503120833569886208, + 502797621648695296, + 503459932663197697, + 503280448639102977, + 503982174874636288, + 503278188903288832, + 503529049256624128, + 503848015187030016, + 503223293684776961, + 503975313307865089, + 503932883795738624, + 503994039533043712, + 503601770074218497, + 502918016922054657, + 503446896980275200, + 503220146023178243, + 503989447562895361, + 503481913684664320, + 503882015519670273, + 503971791719890945, + 504194757002686464, + 503986774289690624, + 503242142668845056, + 502925343611969536, + 502776421157445632, + 503484417915240448, + 503885607492648961, + 503334296963534848, + 502831360004747265, + 504733199797596160, + 502850560648036353, + 503291130713092098, + 504742364297302016, + 506070186831917056, + 503559389697941504, + 504565396046098432, + 502780830792835072, + 503844864875057152, + 503187674711465984, + 503495701679325184, + 502816089068171264, + 503966408225468417, + 503902660744196097, + 504632026914631680, + 504789107080695809, + 504727302060900352, + 503698383866200064, + 503240380184551424, + 502926762536615936, + 505928856063459328, + 505823565711958016, + 504325567697920000, + 503446621682929664, + 503345463782047746, + 503931472865001473, + 503870348212068352, + 502912329542295552, + 502807457870389248, + 503893445698535424, + 503937984467857410, + 503856881103011840, + 503866848325038080, + 504258780105027585, + 503994004963590144, + 506187187109781504, + 503256660245487616, + 506096643876605952, + 505701543782260738, + 503229475233206272, + 503650579252797440, + 504594399255609345, + 504889924580294656, + 505692794204467200, + 503629156140482560, + 503150842976157696, + 502916676653187072, + 504297771684605952, + 503939720796442624, + 503617915183435776, + 503960371414454272, + 503628886392197120, + 503858443376427008, + 502867433892634624, + 502950596832690176, + 503430274831896576, + 505347858166718464, + 502932829404418048, + 503900996956086273, + 503001061259350016, + 502927587048701952, + 503207337805758464, + 503921673893322752, + 504938974620573696, + 503725497269100544, + 505291620645093377, + 503539819293990912, + 503849122181677057, + 503076742064390144, + 504293660981084160, + 503869098724704256, + 503812832455315457, + 504257822625116160, + 503927783534624769, + 502842775780753408, + 506168015885717505, + 502749497286746112, + 504725122323066881, + 504569456547594240, + 503550996422066176, + 502994258459377665, + 505329082289360897, + 504163923768385536, + 503940534613057538, + 502810266820956160, + 503153242780741632, + 503860024876474368, + 503569736069038080, + 503290318536835072, + 505364436270723075, + 502811963140096002, + 506096637018906624, + 505646143091793921, + 504012884922605568, + 503646566167900160, + 503919411783553024, + 503723691927019520, + 502828890868699138, + 504647581851324416, + 503914783796891648, + 503879515534536704, + 503865661316415488, + 504527559594639360, + 504307897850159104, + 504016685729591296, + 504001568115806209, + 505323259483922433, + 505467644389388288, + 503449155587801088, + 505285587633709057, + 503464285058891776, + 503299183944929280, + 506183494796869632, + 503484420792524800, + 504204266693996544, + 503560636639739906, + 503136572318175232, + 505487446008942592, + 503456747148034048, + 503885917686624256, + 503822219999719424, + 503479409056415744, + 503815326224900096, + 503826665685143552, + 505461675471175680, + 504152552234307584, + 503440372165787648, + 504647286186848256, + 505375933633953793, + 506128073419669504, + 503141514844053504, + 503843010665529344, + 503244103577243648, + 503851874924388352, + 503140881139236864, + 504706253286027264, + 503483505658302464, + 502896802535055361, + 504258889010126849, + 503955069721935872, + 503824184813027330, + 503460468917534720, + 503878342006030336, + 503517527218343936, + 503967698729336832, + 504341928172085248, + 503889729759498240, + 504195415873708032, + 504664637422714880, + 504964892428759040, + 503837963001016320, + 503569876683071489, + 503185001119506432, + 503454188513554433, + 504975621404258304, + 503791472437911552, + 505446167183110144, + 505477470179827712, + 503415190231470080, + 503441624626917377, + 503832983523311616, + 504975206096859136, + 503891844309458944, + 503471831844945920, + 502946935528226817, + 503875730095493121, + 505068617101484032, + 503089529818193920, + 504299555488542720, + 503620647181119488, + 503987948975837184, + 503936228820283392, + 503966333114261504, + 504586748270497792, + 504222993317650432, + 503064137359187968, + 503640090867142656, + 503210689310494720, + 503917755775877120, + 503219126974689280, + 503469910161653760, + 504914792583528448, + 503069168670081024, + 502944750740467713, + 503085524392108032, + 503081872302567424, + 502737956340518912, + 503332385786974208, + 503978219138469888, + 503070442899656704, + 503805264307687424, + 505778251391049728, + 503467372121190400, + 503598388068515842, + 503922322785701888, + 503536841535270912, + 503879897547571200, + 503474400625455105, + 503074398753271808, + 504701307127889920, + 503524650983649280, + 503540711036563456, + 504263416648040448, + 504172773452029952, + 503291857745743874, + 503096944462680064, + 504035996737232896, + 503620744799338496, + 505079958906372097, + 503223475784667137, + 503500701914628096, + 503242891758944257, + 503647778418216960, + 503649217714585600, + 503620742328901632, + 503811576135438336, + 503337283911966720, + 503426539560927233, + 503948706522337280, + 503781348973510656, + 505396570880483329, + 504909933528481792, + 503052796607102979, + 503099360646008832, + 503060340264144897, + 503880749033226240, + 504951596103778305, + 504537088365056000, + 502968612685365249, + 503665592583610369, + 504315790049681409, + 504320509501521920, + 503310285361676288, + 503490792342958080, + 503452932394979328, + 505509056724099072, + 503245838794391553, + 503655779896139776, + 504657134462967809, + 504254645859258368, + 503100661576499201, + 503331335206080513, + 504972534325182464, + 503810319098322944, + 504647169178341376, + 503466397692092416, + 505506757838655488, + 503059283098226688, + 503115724488179712, + 504287203615580160, + 504673074470719488, + 503533143081877504, + 505008215676174336, + 504029359322447872, + 503553917759029248, + 503521679771844609, + 502942458851102722, + 502792035322306560, + 504265417649836035, + 503276748986138624, + 505479222958510080, + 503627864055742464, + 503904757933936640, + 505405871279833088, + 503532271115448321, + 503104483120136192, + 503635373159755776, + 503335817876893696, + 504339757691056128, + 502930032445390848, + 505480762125459456, + 505441166482210816, + 503550415557132288, + 503301258376384512, + 503561178720002049, + 503723037154623488, + 502731960566169601, + 503154881214304256, + 503197137799487490, + 503112076018319360, + 504752834303500288, + 503169732770811904, + 503332891032842240, + 504606714600390656, + 503558952677048321, + 503555729694130177, + 503724578712342531, + 502874592747470848, + 502855377302851585, + 502978553173254144, + 503557312515411969, + 503231506543030274, + 505366569841479680, + 502850488677986304, + 505062350412845056, + 503659321742589952, + 503234297839759360, + 503154742026313729, + 504322128674824192, + 503221749681782784, + 503190221304131585, + 502721541608845312, + 502800564313681920, + 503558418507243520, + 502925704078848000, + 503555374184534016, + 503674418254462976, + 503192533636509697, + 504365387585449984, + 503201289636155393, + 503554430030348289, + 505485056564285440, + 502796097774161920, + 505482897361739776, + 502836391131496448, + 503613378367991808, + 503306027073548288, + 503183250471518208, + 502784592727007232, + 503114599311622144, + 503561704043999232, + 504563568482594817, + 503173147643113472, + 503233816404967424, + 502780359642476544, + 502860930321891328, + 505485268414394369, + 502877642597883904, + 502924152131829760, + 505478773127385088, + 502950752151953408, + 503186765172461569, + 505488456559382528, + 504211622349791232, + 503819566024114176, + 502880465632886785, + 502930438193565696, + 505486472561311744, + 503499141906198528, + 502821106735407104, + 503705260704411648, + 503122277341609984, + 502843907504603136, + 503847026250231808, + 502945272347897857, + 504207903184920576, + 503096725675200512, + 503491592104448000, + 503224560863698944, + 505480168409169920, + 503124503665573888, + 505483658372055040, + 502813737527803906, + 503413695201148928, + 502768449291292672, + 503105384207634432, + 503163044974047232, + 503953062818750466, + 503526534473203712, + 503834776546312192, + 503486170106716160, + 503192522781650944, + 504927362728067072, + 503472650749235201, + 503527205540880384, + 502826257185521664, + 503520861681639425, + 504035471664877568, + 502789858507898880, + 505480631888117760, + 502795882308575233, + 504688475765882880, + 502753675576897536, + 504751504214200321, + 502861264851591168, + 503598330472304640, + 502942111843745793, + 503200208004849664, + 502749723334569984, + 503107846817742848, + 503494615342006272, + 503140374551199744, + 503256913321418752, + 503113882240835586, + 504376210617802754, + 503234876997636097, + 503864413032820736, + 503478996147769344, + 503314956797108224, + 504661742312763393, + 503566601116217344, + 503116165007540224, + 502952824695967744, + 503163887764918272, + 502918428395446275, + 503193865848094721, + 503214375935967234, + 502945588980510720, + 503311739866591233, + 503484712493776896, + 503486212913790977, + 502808931312218112, + 502797882630488065, + 503533111708495872, + 503296012245811200, + 504564980172455937, + 502872459264413697, + 503142133130211329, + 502786952652156929, + 503859401317314560, + 503185986927742977, + 503469634931404800, + 505494590200492032, + 502887949110116352, + 503478108234604544, + 503150334228045824, + 503142360809996288, + 503501992413888512, + 502943315470581760, + 502835471035408384, + 502855932641300480, + 503117860215222272, + 503198722638241792, + 504372041060196353, + 504351343092719616, + 503720683755814912, + 502754911734755328, + 503495062203138048, + 502949624236482561, + 502937266403426304, + 503677851867299840, + 503134580149190658, + 503492295984164865, + 505313337518088192, + 502742275584045056, + 503496976848023552, + 503653110892744704, + 503592276153880577, + 503097789346492416, + 503608376841224192, + 503259134557704192, + 502797554501689345, + 502779135132188672, + 503309617817210880, + 502768711971770369, + 503511809127907329, + 503587585998868480, + 503567439674630144, + 503543292714569728, + 503213360432041984, + 502797589138661377, + 502719985530470400, + 503579797189308416, + 503639561273368577, + 503316864483983362, + 503236039583223809, + 503664876120981507, + 502804188854628352, + 503527194602536960, + 503652975148285952, + 502932046587904000, + 503281066250354688, + 505515513611845632, + 502842672592068608, + 503668151834640384, + 502820860387135490, + 502879434966589440, + 504732770422521857, + 502761220781658112, + 503204681309765634, + 502886774868570112, + 503905873995907072, + 502756442764763136, + 503625273808797697, + 502885013575462912, + 503681495123652610, + 502953310580932610, + 503654595529572353, + 502917571558268928, + 503461792388251648, + 503293129508663296, + 503174959980900352, + 502916431638720512, + 503874440518582272, + 503677392494559232, + 503590438289567745, + 502906677671493632, + 503509808394543106, + 503545715998474241, + 503251699075932160, + 503274293954756608, + 503203599892348928, + 503565692659314688, + 503529342383980544, + 503275540481310721, + 503603692231458816, + 503254965591506947, + 502954034828156929, + 502739238127824896, + 502957155629432832, + 502720661362851841, + 503680551325556737, + 504064298121826304, + 503322042650083330, + 502911603621502976, + 502845244027977728, + 503835657534709760, + 504834722540044288, + 504557587334172672, + 503293954264428544, + 502835443227168768, + 503869140596453376, + 503639468289843201, + 503641727480397824, + 502743976647340032, + 502875364356415491, + 502853905144107008, + 502869319429402625, + 503262944742764544, + 503676753970470912, + 503905203129966592, + 503192905457348608, + 503539806748827649, + 503589021801803777, + 503100822440660992, + 503278062411055104, + 504324517242875904, + 503229472733429760, + 503253502186246144, + 503209829855670272, + 502832810412240897, + 503604572594921472, + 503529068017766400, + 502786955755929600, + 503538520439668736, + 503676277036154881, + 504184215630802944, + 504187679878447104, + 503209059714334721, + 503093588813561857, + 503186881933496321, + 502840202432221186, + 503276959200059392, + 503320847244079105, + 502856734487379968, + 503001757229002752, + 503273928601919489, + 502831112931246080, + 503963640811487233, + 504252930028208128, + 503191207875719168, + 503217646062424064, + 502874863875678208, + 502950335338774528, + 505429764686229504, + 503301133713289216, + 504045133105745920, + 502906901336977411, + 502827579858894848, + 503587373050241025, + 503461149707616256, + 503539441773056000, + 503240028449808384, + 503306367835598848, + 503871074791325697, + 503128935929225216, + 504250383846629376, + 503293452608888833, + 502825255543799808, + 503841401646612481, + 503184276876460033, + 502859809742282753, + 503066839883464704, + 503209959614451714, + 502764663512117248, + 503202131470340096, + 503244100468879361, + 503662866751574016, + 502823971126267904, + 502940752767643648, + 503198792963723264, + 503926393252880384, + 503189797108600832, + 503618954393554944, + 502908025385279488, + 502914316665122816, + 503634373582024704, + 503288724839346176, + 503874422516621312, + 502889359637352449, + 505053927335661568, + 502868357196943360, + 502757742206267392, + 503526426495041536, + 506046528566591488, + 503201353167286273, + 503188429153529856, + 503619053894660096, + 503143365266112513, + 502817378141360129, + 503142464556134400, + 503496236536971264, + 504088819399147520, + 504004087172857856, + 502806159334461440, + 503533662823280641, + 502811242541506560, + 503522225698639873, + 504594987225726978, + 502961953237905409, + 502868341380247553, + 503210735355559938, + 503884513429454848, + 502809471664418816, + 503877970101280769, + 502739676374241280, + 504284667718029312, + 502855312802861056, + 503532374601519104, + 503684330879991809, + 504276805193580544, + 504300671680913408, + 503957149819883520, + 502745245923430400, + 505524517910097920, + 503292172117225472, + 503687407850749952, + 503875250250346497, + 502718293527244800, + 504678717512101888, + 502954293969047552, + 504581723070279680, + 503292233484091392, + 503714699725508608, + 504156013470449664, + 503318282653274112, + 503887304013135872, + 503050856523382784, + 506094259595145216, + 504045290782220288, + 503266298189873153, + 503529056126513152, + 502893242082664448, + 503276256507740160, + 502934656061550595, + 502808211716456448, + 503341841954398210, + 504389572152029184, + 505388962274615296, + 502787551225470976, + 503892189613948928, + 503525499482558465, + 503315785985454080, + 502852901937893376, + 502889304826609665, + 502788618411606019, + 503805835240165376, + 502913133040513024, + 503539173790593024, + 503635965777547264, + 503900517819363328, + 503633698823352320, + 503534774016036864, + 503646011399876609, + 503679424961970176, + 503424217707474944, + 503840984841879553, + 503995510592917504, + 504325533870882817, + 503092381957500929, + 503751865612247040, + 503293390315085824, + 502912130115727360, + 502882630308986880, + 502741016265633793, + 504604333896663040, + 503623240091054080, + 504326600897622016, + 504228597624999936, + 502849462948364288, + 503532342036541441, + 503928687377797122, + 502954221692805121, + 504345381686497280, + 503205953911947264, + 502894354407903232, + 503590352935063552, + 503541411237875713, + 504742162454827009, + 503688804247805952, + 503608991906562048, + 502848681926594560, + 503526320806973440, + 503192556721557504, + 503531552802750464, + 503976758832812033, + 503559151545753600, + 503618641641107457, + 505941448488144896, + 504466846595436544, + 503644382747443200, + 503813060545347584, + 503571819597922305, + 505947890582585344, + 502874428695662592, + 504244811239813120, + 502728646134878209, + 504183829473792000, + 503470821978152960, + 502853701158318080, + 503873332522262528, + 503880005685112832, + 503656529732833280, + 503739122247532546, + 505406114343571456, + 503135054579916801, + 503678192553443328, + 503910598745149440, + 503196601846743041, + 504705547892187142, + 503287388991664128, + 503496957017718785, + 502766649523851264, + 502786728902799360, + 503528248391639040, + 502781026738135040, + 503496222309892098, + 503872709726846976, + 503248726664949760, + 503847563431534592, + 503529830852198402, + 503170453092204544, + 504263272141316098, + 503291938003750913, + 502891637811732481, + 503520263959773186, + 505107811643445250, + 503614955799982080, + 503479177350504448, + 502918586156199936, + 503906232110174208, + 503645518191685632, + 502747191145144320, + 505748873986715649, + 503044419361062912, + 502807578389532672, + 504275431575805952, + 502933257252777985, + 502929198827462656, + 503530815980961792, + 504045427965329408, + 504722846556635136, + 503017595012800512, + 503188863641468928, + 503093219102838785, + 503304605842046976, + 506159535665717248, + 502721704104591362, + 503905566377639936, + 503773554320478209, + 504373377570975745, + 503307693952872448, + 505512761137582080, + 503527276961480704, + 503740370023636992, + 502817949158498304, + 502903030665465856, + 502740948129185792, + 503650485971484672, + 502809029429968896, + 502787510570057728, + 504652688823713792, + 504231089364549633, + 504083857906606082, + 503915934789009409, + 503218682789892096, + 503566010612719616, + 502912061119418368, + 503282095079555073, + 503239211286536192, + 503968234153213952, + 503548869075271680, + 502843401101135872, + 503805753535127553, + 503904612177285120, + 502906481403232257, + 503140881101520896, + 503463607212855296, + 503044719723945984, + 503625958747045889, + 503188326161997824, + 506139115348557824, + 502798661420867585, + 502885826586767360, + 503888839895969792, + 502824348257116160, + 503043138374860800, + 503150762139353088, + 502909674673672192, + 503270805258924032, + 503127241362919424, + 503670647080636416, + 503282693992640514, + 503127072877715456, + 503920203663966208, + 506214562493132800, + 503956413115559936, + 503572088142430209, + 502789501635534849, + 503732848306573312, + 502918393738321920, + 504683203878469632, + 503593478216237056, + 503640900208058369, + 503612378538586112, + 503579236436021248, + 503969700192460800, + 503232787273756673, + 502792377291919360, + 502836415580090370, + 502924137367863296, + 503158366563487744, + 504669042536632320, + 503535803222736896, + 502899784647462913, + 503965628844498944, + 503858121790746624, + 503353489032888320, + 502808343157551104, + 504010494618140673, + 503771564802732033, + 502965305963208704, + 503946034243186688, + 502808638033895425, + 503296659070402560, + 503932820587560960, + 503772285249921024, + 505373509502377984, + 504572442137100288, + 503411445581627392, + 502936400971718656, + 504065320689336320, + 503136422774456320, + 503945816290369536, + 503108233851310080, + 503269108214153216, + 504089185587052544, + 503601390942711808, + 503820208688336896, + 505699006748844032, + 503700620084514817, + 503502986384265217, + 503877778119622656, + 503616774496337922, + 503521020368945152, + 503604855886581760, + 502863427837382657, + 505087707555840000, + 503859575682916352, + 503342736871682049, + 503297478373179392, + 502931917491437568, + 502726521631801344, + 504279065025855488, + 503091282546552832, + 503308016142524416, + 502902644760129537, + 502925856537595904, + 503244760610783232, + 504066234087137280, + 502870770700521473, + 503621178402291713, + 502907127028264960, + 503592038588497922, + 502925419541434368, + 503265526244986880, + 503900932677967872, + 504193076530003968, + 502870023388823552, + 503618793764294656, + 503256888449179648, + 502881727623487488, + 503169204749873152, + 503979649219973120, + 503074164908249088, + 504309494667825153, + 502887079748325376, + 503439159592493056, + 504617328278269953, + 503635363756519425, + 503289288147365888, + 502821079061393408, + 504693929124839425, + 503100252736749568, + 503276937159385090, + 503240091641593856, + 503625210344775680, + 503938552749887489, + 503889533222797312, + 503632642718593024, + 503127150535655424, + 503814369000816640, + 503538446292746241, + 503224946265690112, + 503305264058359809, + 503952179439632384, + 502833416170381312, + 502808460266725376, + 503450029563330560, + 503526495466557440, + 506172547621068800, + 503604629817810944, + 503195873753706496, + 503992008223252481, + 503278888622239744, + 502901008776048641, + 503545504907948033, + 502905256158978048, + 503632498887507969, + 503148173582696448, + 503507447257260034, + 502884916808646657, + 503215794046898177, + 503165010303258624, + 502897990299033600, + 502804054334914560, + 502777636213776384, + 506133474177482752, + 503605875089895424, + 502836635684593664, + 504356827115847682, + 503375069452980225, + 502896846722068480, + 504593590199541761, + 503534821755617280, + 505007610425532416, + 503933036837470210, + 503600636978823168, + 505154202654752768, + 503263905901465600, + 502943788403531777, + 503973488173264896, + 502905099585605632, + 503250518207369216, + 503998364992958464, + 505923281221074944, + 503978178973827072, + 503482099736002561, + 503213996498231296, + 503271739422674944, + 503183625832398848, + 505478009101774848, + 504008821678047233, + 502881324898983936, + 502773168361443328, + 503760007390040064, + 502902932728479744, + 503310653000781825, + 503488722214866944, + 504201858911854593 + ], + "top_users": [ + "19063323", + "21208832", + "7111412", + "166215202", + "15866430", + "40981798", + "545443555", + "331311644", + "21295636", + "22260085", + "39956893", + "43003845", + "479315245", + "296407843", + "21705931", + "19331448", + "19705747", + "75916180", + "62121556", + "20127529", + "20785288", + "23328929", + "229188693", + "2740134375", + "17392172", + "740865648", + "14100010", + "14146350", + "14451605", + "23671758", + "6761682", + "20155652", + "21955058", + "19811019", + "438897828", + "14994465", + "345593241", + "364827119", + "116710152", + "41601068", + "467601646", + "18734884", + "49608424", + "14925700", + "440963134", + "22908187", + "22060294", + "95380385", + "849517405", + "123790755", + "113749355", + "17793580", + "22515643", + "204204159", + "25589776", + "21211181", + "32385762", + "413485609", + "19238548", + "87818409", + "42190527", + "368930878", + "309857155", + "19494097", + "27844479", + "225064360", + "258915404", + "32855511", + "20435270", + "504529445", + "2740222903", + "143958468", + "302847930", + "461410856", + "22479597", + "45035138", + "89168924", + "1615416433", + "41110545", + "350884062", + "1937534894", + "94581752", + "598519925", + "932686428", + "250557161", + "16887175", + "812946517", + "256542586", + "612473", + "963818137", + "23762505", + "1402020182", + "1941673530", + "19115359", + "381725812", + "435225922", + "16290934", + "87144497", + "176599633", + "34655603" + ] + }, + { + "country_breakdown_percentage": {}, + "country_code": "GB", + "device_breakdown_percentage": {}, + "end_time": "2015-08-31T00:00:00Z", + "event_type": "OTHER", + "gender_breakdown_percentage": {}, + "id": "2y", + "is_global": false, + "name": "The Big Feastival", + "reach": { + "total_reach": null + }, + "start_time": "2015-08-28T00:00:00Z", + "top_hashtags": [], + "top_tweets": [], + "top_users": [] + }, + { + "country_breakdown_percentage": {}, + "country_code": "FR", + "device_breakdown_percentage": {}, + "end_time": "2015-08-31T00:00:00Z", + "event_type": "OTHER", + "gender_breakdown_percentage": {}, + "id": "31", + "is_global": false, + "name": "Rock en Seine", + "reach": { + "total_reach": null + }, + "start_time": "2015-08-28T00:00:00Z", + "top_hashtags": [], + "top_tweets": [], + "top_users": [] + }, + { + "country_breakdown_percentage": {}, + "country_code": "GB", + "device_breakdown_percentage": {}, + "end_time": "2015-08-31T00:00:00Z", + "event_type": "OTHER", + "gender_breakdown_percentage": {}, + "id": "2z", + "is_global": false, + "name": "SW4", + "reach": { + "total_reach": null + }, + "start_time": "2015-08-29T00:00:00Z", + "top_hashtags": [], + "top_tweets": [], + "top_users": [] + }, + { + "country_breakdown_percentage": {}, + "country_code": "GB", + "device_breakdown_percentage": {}, + "end_time": "2015-09-01T00:00:00Z", + "event_type": "HOLIDAY", + "gender_breakdown_percentage": {}, + "id": "30", + "is_global": false, + "name": "Bank Holiday Weekend", + "reach": { + "total_reach": null + }, + "start_time": "2015-08-29T00:00:00Z", + "top_hashtags": [], + "top_tweets": [], + "top_users": [] + }, + { + "country_breakdown_percentage": { + "AE": 0.12, + "AR": 1.9, + "AT": 0.05, + "AU": 1.36, + "AW": 0.02, + "BA": 0.02, + "BE": 0.12, + "BN": 0.05, + "BR": 3.12, + "BS": 0.05, + "BY": 0.02, + "CA": 3.8, + "CH": 0.14, + "CL": 0.67, + "CM": 0.02, + "CN": 0.02, + "CO": 0.78, + "CR": 0.07, + "CY": 0.12, + "CZ": 0.05, + "DE": 0.62, + "DM": 0.02, + "DO": 0.1, + "EC": 0.26, + "EE": 0.02, + "EG": 0.14, + "ES": 3.04, + "FI": 0.05, + "FR": 1.69, + "GB": 9.68, + "GG": 0.02, + "GH": 0.1, + "GI": 0.02, + "GR": 0.26, + "GT": 0.31, + "HK": 0.02, + "HN": 0.05, + "HR": 0.1, + "HU": 0.07, + "ID": 0.93, + "IE": 0.5, + "IL": 0.07, + "IN": 0.38, + "IQ": 0.07, + "IT": 0.81, + "JE": 0.02, + "JM": 0.05, + "JO": 0.02, + "JP": 6.4, + "KE": 0.02, + "KG": 0.02, + "KR": 0.17, + "KW": 0.29, + "KY": 0.02, + "LB": 0.05, + "LT": 0.02, + "LV": 0.05, + "MA": 0.02, + "MT": 0.05, + "MX": 2.69, + "MY": 0.95, + "NG": 0.19, + "NL": 0.74, + "NO": 0.26, + "NP": 0.02, + "NZ": 0.1, + "OM": 0.05, + "PA": 0.07, + "PE": 0.21, + "PH": 1.52, + "PK": 0.05, + "PL": 0.1, + "PS": 0.02, + "PT": 0.14, + "PY": 0.14, + "QA": 0.07, + "RO": 0.02, + "RS": 0.05, + "RU": 0.38, + "SA": 0.98, + "SE": 0.57, + "SG": 0.55, + "SK": 0.02, + "SV": 0.17, + "TH": 0.55, + "TN": 0.02, + "TR": 1.4, + "TT": 0.1, + "UG": 0.05, + "US": 46.94, + "UY": 0.12, + "VE": 1.14, + "VI": 0.02, + "XK": 0.05, + "ZA": 0.48, + "ZM": 0.02 + }, + "country_code": null, + "device_breakdown_percentage": { + "ANDROID": 16.19, + "BLACKBERRY": 0.09, + "DESKTOP": 37.36, + "IOS": 45.9, + "OTHER_MOBILE": 0.47 + }, + "end_time": "2015-08-31T00:00:00Z", + "event_type": "OTHER", + "gender_breakdown_percentage": { + "female": 52.45, + "male": 47.55 + }, + "id": "2h", + "is_global": true, + "name": "MTV Video Music Awards", + "reach": { + "total_impressions": 8539019209, + "total_number_of_tweets": 387171153, + "total_reach": 32113487 + }, + "start_time": "2015-08-30T00:00:00Z", + "top_hashtags": [], + "top_tweets": [ + 503739130811908096, + 503703881944010752, + 503763274182451200, + 503718097019076608, + 503712639898226689, + 503700012149518336, + 503707642083442689, + 503711770674860035, + 502985736237240321, + 503726004951863297, + 503632864324648961, + 503707505940504576, + 503695376344309760, + 503737795639508992, + 503755854429310976, + 503746444009172992, + 503727926412472321, + 503715158431399937, + 503706663476813824, + 503733401094852608, + 503709193858482176, + 503645106788777984, + 503720240736653312, + 503603411200139264, + 503715883701661696, + 503694532865581056, + 503722762095951872, + 503755592649801728, + 503593391246934017, + 503705349703352320, + 503711288791670785, + 503770418671398913, + 503744159497216000, + 503739304389005314, + 503711839759634432, + 503696954644115457, + 503742671215951872, + 503667942656327680, + 503787537492492289, + 503760566226534400, + 503653777048875009, + 503606352220921857, + 503730001532166144, + 503609336782802945, + 503713680341479425, + 503728287974035456, + 503726772500721665, + 503720850030206977, + 503748280338374657, + 503722831637921792, + 503421833371058177, + 503721233671016448, + 503614477313777664, + 503769524928139264, + 503977205438091264, + 503729544486862848, + 503714602589650945, + 503741763945627648, + 503716172081029120, + 503348362200879104, + 503745962188079104, + 503710427705257984, + 505747258458255360, + 503663054404747267, + 503757227069427712, + 504012699815395328, + 503705698556207104, + 503727298097336321, + 503791653144899585, + 503748019230375936, + 503722950483132416, + 503711084541267968, + 503605184887394304, + 503241139320012800, + 504695676635058176, + 503693563268710400, + 503718646393212928, + 503720982826483712, + 503641592662867968, + 503747677914664961, + 503757765685575681, + 503732549407875072, + 501050093080813569, + 503989880649957376, + 503724333655535617, + 503719789018099713, + 503752041513377792, + 503731648261681152, + 503592550649716736, + 503731801077329920, + 503720840698294272, + 503693962540904449, + 503754652328787968, + 503749380650713089, + 503725706485178369, + 503737400011411457, + 503810804592812032, + 503714120412053504, + 503631715643191296, + 503743240789446656, + 503891308847439875, + 503700681153212416, + 503739222918844416, + 503760144376037376, + 503724963757838336, + 503762789522219010, + 503814273273827328, + 503651058980106241, + 503751330809544705, + 503721658067087361, + 503659793383317504, + 503640395108982784, + 503724078256357376, + 503755511616249856, + 503717345907331074, + 506097010270023680, + 503666963810246656, + 503704479284621314, + 503724491705294848, + 503709798899015681, + 503715131348381697, + 503735885691498496, + 503704649351049216, + 503610242195021824, + 503702637829951488, + 502671179115544577, + 503712321579929600, + 503742846323933185, + 503766248002707456, + 503748236717608960, + 504317837691719680, + 503748659264380928, + 503527185190092800, + 503538479381635072, + 503572496830836736, + 503004311240982529, + 503740330077081601, + 503758540105064450, + 503732479724105729, + 505008566777159681, + 503604154460143616, + 503702730431807488, + 503717344833961985, + 503714760052187136, + 503704520874942464, + 503299650678685696, + 503754541926715393, + 503732968167178241, + 503721555398909952, + 503753465286647808, + 503641840156151809, + 503695898313244673, + 503729175371333632, + 502669517500063744, + 503630420357812225, + 503749226715947008, + 505148222273486848, + 503914735750746112, + 503716302138392576, + 503721947117944832, + 503723998791073793, + 503755116953219073, + 505369786885627904, + 503772202270208000, + 503303181758373888, + 503706364661604352, + 503705247030976512, + 503740603046584320, + 503713180955459584, + 503717878009704448, + 503747206516867073, + 503216531028049921, + 503744282843701249, + 503001461945430016, + 504713072075079680, + 503734042614067200, + 503710728939790336, + 502996300292714497, + 502992959134892032, + 503726957302132736, + 503379635086688256, + 503727367010123778, + 503904835734093824, + 503750142193713152, + 503744977877221376, + 503727052844171264, + 504460869892591616, + 502855483577757696, + 503698259643084800, + 503737017910325249, + 503751267035119618, + 505744075971362816, + 503723544212426752, + 503782267618340864, + 503718033005608961, + 504810667862278145, + 503888051744276480, + 503730868364402688, + 502470726176079874, + 503701395632304128, + 505728048105521152, + 503567115119783936, + 503932577041088513, + 503700008487489536, + 503960602646036481, + 503747799507152896, + 503709536717258752, + 502841707541458944, + 503119165729685504, + 503751713149296640, + 503345887284695040, + 503718052652122112, + 503705759264161792, + 503725372094316545, + 503720321141473280, + 504125338281340928, + 503729321286975488, + 503742010915061760, + 503726410603978752, + 503744441103159296, + 503740853924286466, + 503734647315234816, + 503345769798459392, + 503559917257506816, + 503737960588935168, + 503735667503820800, + 503711706661392384, + 503740220194705409, + 506095181981302784, + 503735846307381250, + 503722791309692929, + 503839617934585856, + 503644858288836608, + 503741350471151616, + 503714687377506304, + 503690367976218626, + 503706882079744000, + 503715578419642368, + 503741519866900480, + 503739183404707840, + 503717183328124928, + 503730270034755586, + 503745036878483457, + 503757933981990912, + 503694429044342785, + 503703095256559616, + 503721349647699969, + 503696266946428930, + 503585846994677760, + 503921493861224448, + 503730358467448832, + 503710251372515328, + 503716275399307264, + 503753326517682178, + 503717962482982912, + 503716186811793408, + 503751761900105728, + 503749814941515776, + 505013818506768385, + 503333397918679040, + 503741485364559874, + 503742650701602817, + 503732538536644608, + 502976864009609216, + 503740405654237184, + 503732804057051138, + 503734768677453824, + 503711509923762177, + 503729115946835968, + 503694055419564032, + 503711147464617984, + 503747062295306242, + 503656672548904960, + 502802756487634944, + 503744078589095936, + 503711659308101634, + 503570046057054208, + 503755148372758528, + 503300181949825024, + 505884119398895617, + 503277830533562368, + 501049595724845058, + 504331981463642112, + 503749145728131072, + 503731511674548224, + 503748359723962368, + 503736643472216064, + 503276922076692481, + 503722190261731328, + 503716246211149824, + 503737440708751360, + 503725142103822336, + 503743922829410305, + 503613090177777665, + 503723068607307777, + 504026227691094017, + 503750343797526528, + 504665512945520641, + 503721456682172417, + 503498537997312000, + 504450692807786496, + 503716325399986176, + 503711909841874945, + 503583633953673216, + 503756214782947328, + 503709960782770177, + 503418223874695168, + 503716031047950336, + 503726777228075009, + 503718883430510592, + 504240412371193856, + 502997508042526720, + 503595460339044353, + 503731132354265089, + 503757269192814594, + 503674743967346688, + 503736073688592384, + 503278170976817152, + 503295152358580224, + 503720845182001152, + 503648012543881216, + 503686564812034048, + 503732756040679425, + 503707067811913730, + 506127282411679744, + 503257735631093760, + 503714944383483904, + 503817212453748736, + 502539114659713024, + 503634446826749952, + 503763693058793472, + 503712282187022336, + 503355790871527424, + 503741723965530112, + 503534056894922753, + 504117147296337920, + 502994928759083008, + 505372194554535936, + 503733885185036288, + 503742541452165120, + 503740495802425344, + 503573008032608256, + 503740487497293824, + 505038953892691969, + 503734017003646976, + 503720821680926720, + 503500668036845569, + 503736019666341889, + 504790613187760129, + 503722401411371008, + 503719874561339392, + 503464999168135169, + 503712509522894848, + 503735903005982721, + 503724594671677440, + 503729808266625024, + 503747368697987072, + 503906335713681408, + 503642159971438594, + 503000858892595200, + 503960430084374528, + 503742819467821056, + 503759433223389184, + 503694374409338883, + 503716781249138688, + 503707979775217665, + 503754336405819392, + 502668594107658240, + 503742971385106433, + 503273856874725377, + 503697239785472001, + 503725853864644608, + 503724705447419904, + 503702111021178881, + 503584906182922240, + 503723454785650688, + 503744043784749056, + 503688937626288129, + 503734262106173440, + 503738476907343872, + 503740430601969664, + 503728445252042752, + 503736933558665216, + 503735037897216000, + 503720982721613825, + 503763854883835904, + 503720224559235072, + 503424379968299009, + 503743393399582720, + 503742422044921856, + 503703520269586432, + 503740823528558593, + 503711412074446848, + 503728186833002496, + 503735992223035394, + 504062784041021441, + 503743764695752704, + 503729150117826560, + 503711284412809216, + 503717513747005442, + 503742322077884416, + 503716537011032064, + 503741938655588352, + 504813053163360258, + 503733743925092353, + 503748208615759872, + 503628883795931137, + 503690933347426304, + 503725944881025024, + 503735752552099840, + 504310053524889600, + 503740610361425920, + 503742038584868864, + 503730136664268801, + 503713899875934208, + 503724816688758784, + 503726508628643840, + 505459485784408064, + 503587594660507648, + 503959214184996864, + 503916729131884545, + 503287061068386305, + 503733043501465600, + 503277095607222272, + 503746706140594177, + 503718760680030208, + 502661468962029569, + 503732051477295104, + 503754198551261186, + 503746500930076673, + 503747056851488769, + 503660681686949888, + 503711442215124992, + 504730331103383552, + 503728311831633920, + 503903875502702592, + 503725850706329603, + 503642019219406852, + 503730359775666176, + 503698301909086209, + 503701690223050752, + 503345962073739264, + 503740651880476672, + 503718158377963522, + 503732078522159105, + 503725807014273025, + 503753540842819584, + 503702279779004416, + 503740425887571968, + 503527562849820674, + 505401851106582529, + 503718260903510016, + 503738722530390018, + 503318680869273600, + 503746099514200066, + 503740723569897473, + 503747374104068097, + 503725405845868544, + 503902158996406272, + 503691242400931840, + 503700290231861249, + 503746225934704640, + 503170101609132033, + 505759585597411328, + 503708397024600064, + 503643355931488256, + 503382829519347713, + 503750880584548353, + 503762956610699265, + 503731192256933888, + 503741900826738689, + 504258626224414721, + 503736567140454400, + 503737168972357633, + 503981174336028672, + 503298440340598784, + 503710132027400192, + 503715029997608960, + 503761500142465025, + 503731806621798401, + 503725121434320896, + 503708044745007105, + 503733355674746880, + 503734818132463616, + 503651197417709568, + 503752770579881985, + 503729300500398081, + 503719098782859266, + 503728909910020096, + 504018100279607296, + 503739683994492928, + 504007019167498240, + 503723478370238464, + 503732060578906113, + 503742974321504256, + 503747819409539072, + 503718107920080897, + 503728629298507776, + 503725194989801472, + 503680366797135873, + 502845697641562112, + 503737738135212032, + 503279285830811649, + 503741719133696000, + 503557748462608384, + 503719092529164289, + 503747326864007168, + 503736985232478208, + 503738837324300288, + 503659976431108097, + 503749245644865536, + 503870917038985218, + 503715705372815360, + 503770659827499008, + 503730215663972352, + 503729935433744385, + 503738393625653250, + 503765815628668929, + 503709474343772160, + 503769273064374274, + 503715304934211585, + 503624854050856961, + 503736003912560641, + 503702312716861440, + 503730895803539456, + 503279290063286272, + 503715210423967744, + 503712323748777984, + 503747833384955904, + 503743762858655744, + 503727457258971136, + 502353246992596992, + 503572898921988096, + 503964852009074689, + 503724068323868674, + 504738643513462786, + 503729689899184129, + 503755569811820544, + 503738834014969856, + 503721586755506177, + 502877035128455170, + 503987837763477504, + 503730545088401408, + 503730682070179840, + 503742450536808450, + 503723693965848577, + 503703185223995392, + 503718537924710402, + 503744875007717376, + 503748923442593792, + 503578931841499137, + 503737664005476352, + 503765166493016064, + 503741322952736769, + 503716103055364096, + 503738621447262209, + 503728721891557376, + 505333042194300929, + 504693176121430017, + 503739235808342017, + 503763824001183745, + 503746344071073793, + 503712286268456960, + 503736492028477441, + 503716008339984384, + 503707437107408896, + 502279795234050048, + 503717158745276416, + 503735546041335808, + 503760700322615297, + 502846200702574593, + 503694531364405248, + 503733494309470209, + 503730113868206080, + 503678925315538944, + 503704763486064641, + 503831799030902784, + 503716453078409217, + 503603297971077121, + 503730256172167168, + 503210073074577409, + 503874704688824320, + 503735010474483712, + 503896712826466304, + 503709443519832065, + 503279293028659200, + 503719816491184128, + 503287061777227777, + 503279289383804928, + 503255718506795010, + 503746940282994688, + 503744771127390208, + 503728219770478592, + 503720361838796800, + 503746784808538112, + 503713644052746240, + 503739982864187392, + 503715439680450561, + 503737681936146432, + 503730108260438016, + 503709592094638080, + 503732751359819776, + 503739857588715520, + 503744367455387648, + 503791552527736832, + 503744212408762368, + 503721264377499652, + 502813287164420096, + 503735730871750656, + 503733354802323456, + 503712172703105024, + 503718469519429633, + 503748075693674496, + 503731374692786177, + 503720687757172736, + 503742633500758016, + 503718571319377921, + 503728464432619520, + 503756331241586688, + 503230896229449729, + 504213742695882753, + 503740064220717057, + 502582797287309312, + 503738662979637248, + 503796065481392128, + 503724003039514624, + 503729029686759424, + 503740501359460354, + 503737381019979777, + 503732215591612416, + 503745781640462337, + 503919132387966977, + 504327438654918656, + 503279287462404096, + 503702726199742465, + 503735618531524608, + 503727824235429888, + 503752932089954304, + 503708415504687104, + 505388180280209410, + 503642096960425984, + 503700402672775168, + 503740835071287297, + 503744325910802433, + 503704920172687361, + 500803411936571394, + 503731080915324929, + 503278138059943937, + 503734371589713921, + 503741005514805248, + 503750947760123904, + 503732471775510529, + 503725728220073986, + 504248444819484672, + 503729296830373889, + 504234889953030146, + 503733195305922560, + 503655861768966144, + 503716457625038848, + 503771315325923328, + 503646020837064704, + 503722137908031488, + 503739692768980992, + 503956619021918208, + 503732169517592576, + 503710850293977088, + 503744020355366912, + 503709287818854401, + 503744212647821312, + 503754920877903872, + 503739491463340032, + 503727411402670080, + 503719524441415680, + 503916087768252416, + 503729158292533248, + 503733455042400256, + 503732115532697600, + 503665931848253440, + 503542260361736192, + 503701304829431809, + 502899541956239361, + 503740637477613568, + 503740334824624128, + 503760509418491906, + 503695627755081728, + 503728272925274113, + 505385830794682368, + 503600550944833536, + 503697713901608960, + 503702925848616962, + 503747466362372096, + 503731611670937601, + 503581143497592832, + 503722156447240192, + 501466145149714433, + 503727766961786880, + 503685228750069760, + 503591346976743424, + 503741995911634946, + 503745630066335744, + 503722749345689600, + 503715212688904192, + 503729274898366466, + 503730446874972160, + 505157579212087296, + 503715694597251073, + 503750013269590016, + 503543783913684993, + 503764205627912193, + 503770417111117824, + 503733151428923392, + 503720417039634433, + 503747549455740929, + 503714524512653312, + 503737496375951360, + 503719943095865344, + 503726034660126721, + 504418776839114752, + 503740292982661121, + 503727827116892161, + 503741414342004736, + 503581553524350977, + 503746222084345856, + 503720554025979905, + 503195050969288705, + 503736616209629184, + 505743992110465024, + 503665028332273664, + 503750979691761664, + 503748859294928896, + 503719172476764160, + 503729883110191106, + 504665323321061376, + 503717849404162048, + 503741387578552320, + 503735672784838656, + 503726031409520641, + 503614711892815872, + 503702245494779904, + 503771962208825345, + 503711191122718720, + 503382528863248385, + 503866305573703680, + 504358643764965376, + 503729637961523202, + 503727591748956160, + 503731805665509377, + 503951658296958978, + 503718784319123456, + 503716151852281856, + 503736783985586176, + 503927333288673280, + 503743729325592576, + 503717018319609856, + 503802771645005827, + 503738108698181633, + 503738401192157186, + 503709823234367488, + 503721291879559168, + 503732755390550016, + 501172196828794880, + 503736970242424832, + 503733217774825472, + 503676488311640065, + 503754187969032192, + 503731330832547840, + 503743873752240129, + 503740994026999809, + 503777175581913088, + 503738262247456769, + 503719567126827008, + 501016954744762370, + 503966210984128512, + 503736677278687234, + 504631575535820800, + 503740163642892289, + 503737263054794752, + 503738612920233985, + 503715301968850944, + 503707108387586048, + 503583330898432000, + 503754646964678656, + 503729085848498178, + 503748745998000128, + 503740707748577281, + 503730253672759298, + 503716893178359809, + 503399411113005056, + 503716501443330048, + 503279291350937603, + 503704269267009536, + 503739850869456897, + 503697017558683648, + 503735380966141952, + 503720735613784065, + 503712399304953857, + 503735315522007042, + 503769654574481408, + 504705437774524416, + 501219466256982016, + 503957503840096256, + 503694659323822080, + 503957538732507136, + 503738541667385344, + 503721418966990849, + 503723043886485504, + 503723719593062400, + 503779228870254593, + 503730079982424064, + 503722068530049026, + 503763051003535360, + 503708427571691520, + 503484950520156160, + 503220173063852032, + 503714691995435008, + 503700695212908544, + 503714957993578496, + 503673430752133121, + 503756079072022528, + 503716648386195456, + 503742842586816512, + 503729972239171584, + 503738844999843840, + 504073497048387584, + 503695834996035584, + 503717698275377152, + 503741616197480448, + 503741152357412865, + 503731241322315776, + 503864418136911873, + 503737275717783552, + 503873945087389696, + 503737440344240128, + 503829184826068992, + 504019537961185280, + 503732355602071553, + 503700488739516417, + 503710941066715136, + 503728887784697856, + 501775657466986496, + 503365109549645824, + 502660599093137408, + 503725911288840193, + 503278133882019841, + 503279284140523522, + 503722503215529984, + 503737477752815616, + 503718124093718529, + 503724156777537536, + 503708391274217473, + 503647992423780352, + 503738339112263681, + 503222663092137985, + 503689047542628353, + 503743857675501568, + 503756919677648896, + 503737405807935488, + 503711584498515969, + 504432661901758464, + 503711866284429313, + 503733957239001088, + 503874594369855488, + 503734764621537280, + 503743381538082816, + 503746212210933760, + 503737325990707202, + 503738601717628928, + 503718151805091840, + 503718599782305793, + 503486835645898752, + 503702259989872640, + 503720896905740289, + 503730794657873921, + 503778622369325058, + 503738029706858497, + 503361134842617857, + 503716331376488449, + 503735977391947776, + 503757546021089280, + 503710201430560768, + 503741064076083201, + 503770279793811456, + 503739486283771904, + 504461452573290496, + 503741163195469826, + 503656615141064704, + 503735955212472321, + 503742676802744320, + 503278144594669568, + 503747334077812738, + 503217740166217728, + 502903748440489984, + 503735473848999936, + 503694974580297728, + 503726727634239488, + 503722609834737664, + 503962662460723200, + 503738271923716096, + 503738584516808706, + 503733848057057282, + 503712299127803904, + 502828923668140032, + 504309999590322177, + 503749514269052928, + 505013751599202305, + 503737282898042881, + 503701258243702784, + 503739827108712449, + 503758292120633344, + 503395466722439169, + 503740721052917761, + 503579563029323776, + 503582055083831296, + 503734042303295488, + 503732329681260544, + 503731029991895040, + 503740414986575872, + 503756199016562688, + 503722068631121920, + 505267298614411264, + 503264719730266113, + 503730325994749952, + 503736438610198531, + 503716034722148352, + 503749323788910592, + 503695363040366592, + 503562284418220035, + 503750485174538240, + 503738419500285952, + 503699403543433219, + 503730630782631937, + 503735752136462336, + 503698421337702401, + 503720634120040448, + 502519808723013632, + 503715777539604480, + 504030572197314561, + 503363004486791172, + 503751936727072768, + 503990326772903938, + 503631610453843968, + 503742964594905088, + 503719228344913921, + 503278135945998336, + 503697767873527808, + 503398647900696576, + 503549849602912258, + 503737405552476160, + 503362332487991296, + 503738128990216194, + 503705453419712513, + 504710940093214721, + 503737282344386560, + 503384469748064256, + 503706329782169601, + 503741388820058112, + 503719413728571392, + 503719268404326400, + 503722412953718784, + 503708042592923649, + 503910358008872960, + 503770486766338048, + 503736527902740480, + 503728887654670336, + 503741424714522625, + 503633001369305088, + 503749886781980672, + 503721166549577728, + 503738260699746305, + 503744077289250816, + 503735136358514688, + 503742735573340162, + 503278135022866432, + 502593257948598272, + 503751075036278785, + 503694711677550592, + 503278147199320064, + 503711950740914176, + 503738531035238400, + 503735837449003012, + 503694123782529025, + 503728448431751168, + 504103390180147200, + 503731641219444736, + 503727698888642560, + 503851824798269441, + 503672015820046336, + 503727386009935873, + 503720640646758402, + 503697776174436352, + 503738503998758913, + 503718649275121664, + 504023932425338880, + 503726388093157377, + 503737385331740672, + 503806890888142848, + 503737953395683328, + 503725790240862208, + 503721699431313408, + 503724479617695744 + ], + "top_users": [ + "2367911", + "2883841", + "18139619", + "268414482", + "14222536", + "1107613844", + "5695632", + "17919972", + "275357447", + "21111883", + "1051530510", + "403255314", + "393488321", + "264107729", + "147305691", + "524657792", + "439125710", + "40908929", + "34507480", + "34409159", + "586671909", + "500328872", + "76784890", + "25589776", + "403245020", + "1582853809", + "304185486", + "219049532", + "443216748", + "154048214", + "228388788", + "14423603", + "2546379133", + "23482952", + "15485441", + "21447363", + "1187647735", + "2716078367", + "196795202", + "1901273544", + "30495613", + "128023009", + "19329393", + "110458336", + "403246803", + "739784130", + "872374136", + "25365536", + "355307031", + "306025835", + "891826837", + "434545375", + "16331010", + "28638191", + "19665916", + "49110693", + "275442883", + "180418331", + "132774626", + "557455977", + "158314798", + "95023423", + "78402214", + "58528137", + "287728935", + "1613414952", + "36008570", + "2183760601", + "1414721006", + "266417203", + "409863961", + "75821706", + "612009655", + "35116081", + "56783491", + "956730660", + "38440946", + "22940219", + "20322929", + "53338746", + "23083404", + "464438740", + "15846407", + "114035804", + "40076725", + "98288395", + "29756339", + "552326182", + "160817572", + "427174959", + "557258620", + "539382986", + "618300542", + "1406346067", + "180505807", + "331311644", + "1470631578", + "20012204", + "926308387", + "1462738488" + ] + }, + { + "country_breakdown_percentage": {}, + "country_code": "US", + "device_breakdown_percentage": {}, + "end_time": "2015-09-04T00:00:00Z", + "event_type": "OTHER", + "gender_breakdown_percentage": {}, + "id": "2r", + "is_global": false, + "name": "VM World", + "reach": { + "total_reach": null + }, + "start_time": "2015-08-30T00:00:00Z", + "top_hashtags": [], + "top_tweets": [], + "top_users": [] + }, + { + "country_breakdown_percentage": { + "AE": 0.18, + "AR": 1.64, + "AT": 0.09, + "AU": 1.64, + "AW": 0.02, + "BE": 0.15, + "BG": 0.07, + "BH": 0.02, + "BN": 0.02, + "BR": 1.84, + "BS": 0.02, + "BY": 0.04, + "CA": 4.62, + "CH": 0.35, + "CL": 0.93, + "CN": 0.02, + "CO": 0.97, + "CR": 0.13, + "CY": 0.07, + "CZ": 0.02, + "DE": 0.42, + "DK": 0.11, + "DO": 0.35, + "EC": 0.27, + "EE": 0.02, + "EG": 0.07, + "ES": 3.83, + "FI": 0.09, + "FR": 2.23, + "GB": 12.83, + "GH": 0.07, + "GI": 0.02, + "GR": 0.33, + "GT": 0.31, + "HN": 0.13, + "HR": 0.13, + "HU": 0.02, + "ID": 0.93, + "IE": 0.75, + "IL": 0.04, + "IM": 0.02, + "IN": 0.46, + "IT": 1.35, + "JE": 0.02, + "JM": 0.04, + "JO": 0.02, + "JP": 1.59, + "KE": 0.02, + "KH": 0.02, + "KR": 0.07, + "KW": 0.29, + "KY": 0.02, + "KZ": 0.02, + "LB": 0.13, + "LY": 0.02, + "MT": 0.02, + "MX": 3.16, + "MY": 0.55, + "NG": 0.22, + "NI": 0.02, + "NL": 1.06, + "NO": 0.15, + "NP": 0.09, + "NZ": 0.11, + "OM": 0.07, + "PA": 0.13, + "PE": 0.13, + "PH": 0.53, + "PK": 0.09, + "PL": 0.29, + "PS": 0.02, + "PT": 0.04, + "PY": 0.15, + "QA": 0.04, + "RS": 0.02, + "RU": 0.4, + "SA": 0.6, + "SE": 0.46, + "SG": 0.46, + "SV": 0.07, + "SX": 0.02, + "TH": 0.33, + "TR": 2.1, + "TT": 0.04, + "TZ": 0.02, + "UA": 0.04, + "UG": 0.02, + "US": 46.83, + "UY": 0.15, + "VC": 0.02, + "VE": 0.93, + "VI": 0.04, + "XK": 0.02, + "YE": 0.02, + "ZA": 0.51, + "ZM": 0.02, + "ZW": 0.02 + }, + "country_code": null, + "device_breakdown_percentage": { + "ANDROID": 11.74, + "BLACKBERRY": 0.11, + "DESKTOP": 35.59, + "IOS": 52.18, + "OTHER_MOBILE": 0.38 + }, + "end_time": "2015-09-14T00:00:00Z", + "event_type": "SPORTS", + "gender_breakdown_percentage": { + "female": 32.96, + "male": 67.04 + }, + "id": "2j", + "is_global": true, + "name": "US Open Tennis", + "reach": { + "total_impressions": 405547824, + "total_number_of_tweets": 3247594, + "total_reach": 12373264 + }, + "start_time": "2015-08-31T00:00:00Z", + "top_hashtags": [], + "top_tweets": [ + 504420351078850560, + 504782210608943105, + 505172508979757056, + 503948167012835329, + 505079179986345984, + 504420429973696512, + 504379707828473856, + 505740469939478528, + 506169583946838016, + 505430489990049792, + 505911176362872832, + 503995318996721665, + 504705012983816194, + 505445037614723072, + 505388106409717761, + 504312458803036161, + 505832574158401537, + 504299239263203332, + 505755142806077440, + 504644615920578560, + 504449264244625408, + 506196665880289280, + 503986614155366402, + 506184753369083904, + 504431758037635072, + 505013457335623681, + 503934936621936641, + 504456195654963200, + 504441679999696897, + 505217284852690944, + 505759436783509506, + 503919924616921088, + 505788957343232000, + 505802676358373376, + 503923786602020864, + 505812007996915712, + 505528718920781824, + 506193375348154368, + 503942633962881024, + 503995147693330432, + 503911771510689792, + 505755304848785408, + 506127140161462273, + 504074894905073664, + 504431818284990465, + 505786628150161408, + 504792471755161600, + 503928220433932288, + 503973927333691392, + 505768464825737216, + 504829765480505344, + 506190432251166720, + 504359346604867587, + 503985438441611264, + 505091873284030465, + 505173773507919872, + 505182680682860544, + 504120893803855872, + 504476011866914816, + 505766297146494976, + 505729309995442176, + 504834277851164672, + 505808276970557440, + 505761501920391168, + 505396310510276608, + 505452984239939584, + 505755326348820482, + 504491609418121216, + 504742986954342400, + 505166349984071680, + 505770431207735296, + 506147364542095360, + 506142847306067968, + 504105138693611521, + 505755454514167808, + 503987364738629634, + 505772599516098560, + 504129900769714176, + 504680410274869249, + 504419356844228608, + 504696286927654912, + 505048232255164417, + 503954472314617856, + 504023391205330945, + 504322937135333376, + 505400960983003137, + 505062980149854209, + 503939876493213696, + 503964670257278976, + 504736701584265218, + 504304777648676864, + 505559829025259520, + 505916399668436992, + 505783305883906048, + 505767149269684225, + 505761152836861954, + 503988963678228480, + 503951201252028418, + 504334597199790080, + 504067689615482881, + 505445522380177408, + 503976187241463808, + 503937912317423616, + 504091751649271808, + 504829651970428928, + 506094858222981120, + 504703970892603392, + 505385787194503169, + 503993796682866688, + 504684623956557824, + 506177908260753408, + 506162277436112896, + 505115790363074560, + 504401350268960768, + 505065149028655104, + 504681325220356096, + 505738704431095808, + 504448237240328192, + 505770889708044288, + 506183743116431360, + 504800237761089536, + 505159959727063041, + 505735519427629056, + 506164442581966849, + 504342624174891008, + 504088975410462720, + 505093303692713985, + 506214186318581761, + 504443786932789248, + 504292294292295680, + 504291587208531968, + 505083392447479809, + 503919766877536256, + 505804688177238016, + 504646883869208576, + 504434037885509633, + 503925721153015808, + 505160229131411457, + 503993453702037504, + 503936996696276992, + 504797841714585600, + 505884083818594304, + 503923243057942529, + 505536459529797632, + 504645721422057472, + 505829270992601088, + 505369297817202689, + 504046120247758848, + 504282143489794048, + 505810250256363520, + 503990178277773312, + 504011334410063873, + 504404715665244161, + 504017959229325314, + 505811280125771776, + 504734901698973696, + 505805001856659456, + 505414329567838209, + 505739471602843648, + 504320381109694464, + 504387201434914816, + 504761557478539264, + 504393837868240896, + 503974423293333504, + 504684063098023936, + 504096341984018432, + 506169336240033792, + 503950110888177664, + 504040084740784128, + 503993067603775488, + 505074103808958464, + 505059618973032448, + 504780855412527104, + 506161227811524609, + 504445045496631296, + 505016558717239297, + 505542047982698496, + 504804369892921344, + 505094014887288834, + 506175140959641600, + 505006981292507136, + 504335095587938304, + 503962501676294144, + 505101820973576192, + 504492243580125184, + 505414598581682176, + 506161083959508992, + 506182322543398912, + 505136750214144000, + 505113693978243072, + 506140585955061761, + 504004845095755776, + 503923957742198784, + 504365925718822912, + 504780416814186496, + 504425349242187777, + 503949862132785152, + 505820586908848129, + 505755322007695360, + 504420973891035136, + 504444335585497088, + 504473232494563328, + 505112511113224193, + 505755454048575488, + 504360453402001408, + 504815600984522752, + 505762919037288448, + 505565785402925056, + 505812361299894272, + 504040808606351360, + 503996599128059905, + 504850746815549441, + 505793994216194048, + 503919302031200257, + 504287350566825984, + 504418388345892864, + 505052255976816640, + 504014287787270144, + 504806454793359360, + 504436013222354944, + 504827651371307010, + 504351062313431040, + 505463763278249985, + 504393409281679360, + 505755143988867072, + 505062497796497408, + 505049089193824256, + 504640499396136961, + 506214662690840577, + 505760357546078209, + 505749100227076096, + 505072786042523648, + 505210193723293696, + 505505516911865856, + 504473580516937729, + 505939297657040896, + 506169635814006784, + 505185109994004480, + 505105211250458625, + 503985124481171457, + 503908269568851969, + 505397276043669505, + 506096807982948352, + 504435101019934721, + 506168348045225984, + 505173179396919296, + 505762949621772289, + 504426684050055168, + 505786613972992001, + 503970552059789312, + 505160143156563968, + 505766725603045377, + 506139549333217280, + 505062615455121408, + 505755342182309889, + 504061461694787585, + 504441160736444416, + 505750340462206977, + 505170749955801090, + 504852103735431168, + 504410946840715264, + 505906448749322240, + 505471898307022848, + 504406738569678848, + 504346149613232128, + 506156840573353984, + 506093902554615808, + 501391394481909760, + 503958224232775680, + 505131474430205952, + 504379362545000448, + 505203214388428801, + 506174158603300865, + 505791516166860800, + 506188491080749057, + 504387895063355393, + 505016908828405760, + 505755332862566400, + 504337063270174720, + 505460595345588224, + 505850136216743937, + 504716098164785152, + 505535873543581696, + 505061644221689856, + 504829481781968896, + 505761276652683264, + 504640861934989312, + 504699386442842112, + 505034522044686336, + 505755147222265856, + 505818937817579520, + 503983201870565376, + 504295245925076992, + 505568545779249152, + 506186425252208640, + 504352664780419072, + 505568760418553856, + 504269542601003008, + 503930907209003008, + 504832807152402434, + 504772601483624448, + 505787489077166080, + 503963803315208192, + 506189861121187840, + 504449934343815171, + 504432860636274688, + 506165987175972864, + 504724816700903424, + 504751482839650305, + 505755371458134019, + 506131309304221696, + 505760131335061504, + 505802384166379520, + 504815709633773568, + 505174756799561728, + 505160429715202048, + 504426559022071808, + 504002991150870529, + 504782599395352577, + 504272357197086720, + 505201496112521216, + 504284727130742784, + 503986984495222784, + 504792773216591872, + 503949244404105217, + 503985482414714880, + 504331871275454465, + 506220381305581568, + 504665170652975105, + 504354028612907008, + 505014014393729024, + 505129949867831296, + 503945849593159680, + 504726955573272576, + 504436047208787968, + 505088086984765440, + 505488333594980352, + 505455980835258369, + 504379795254575104, + 505780639887790081, + 504100918389129216, + 505719581152137216, + 504678011719806976, + 505036698099535873, + 504362777301884928, + 504439800272007169, + 504114107692232704, + 503935626019090432, + 504435085664600064, + 504699065335296001, + 504278721604632577, + 505074224826818560, + 502952589588463617, + 505777326832242688, + 505409504826384384, + 503968942369415168, + 503934609886044163, + 505397829645647872, + 505767657342521345, + 505495466721550337, + 506172998689488896, + 503932587786919937, + 506139563576672258, + 505765672379744256, + 505117487386468352, + 504444261446987776, + 505578835316727808, + 505756259824304128, + 506187210832740352, + 505172628211240960, + 504472448520421376, + 505005956473044992, + 505806108934430720, + 504445342369480704, + 503971608873025536, + 505024561499238400, + 506183600019374081, + 506124899967303680, + 505767119880208384, + 504068290411388928, + 505573144317276160, + 505756009676419072, + 505092514916098048, + 506160637961990144, + 505453570377154561, + 504451723747147776, + 504428630727204864, + 505509706358460416, + 503986706278649856, + 504651812058955776, + 504705158337425409, + 505569155060609024, + 505777573427941376, + 504452134398484480, + 505159257579208704, + 505027496983924736, + 503918717131292672, + 504345600746586112, + 503904872073535488, + 504034301995126784, + 505164966559625216, + 505802875801722881, + 505094965501112321, + 505542917998776320, + 505575642797453312, + 504706853029171201, + 504781158723649537, + 504775257677627392, + 504061393969356800, + 506148602092457984, + 504116017698971648, + 503949816104484864, + 506196262547636224, + 505158904406638592, + 505744916245262337, + 503933904428875776, + 504372237609500672, + 506128200792309760, + 505896087551770625, + 505740257850306560, + 505475958351335424, + 505029922658586624, + 505522034609512448, + 505896024284884992, + 505150015480676352, + 506143998365290497, + 504297323732545537, + 506123411245236225, + 505451161139154944, + 505912978579787776, + 504833244559597571, + 506184709559164928, + 505786611251286016, + 506179249464954880, + 504308988436283393, + 504710450114617344, + 505152096854085634, + 506179631914172416, + 505753196187639809, + 504480015828783104, + 505163643978543104, + 505094647946153984, + 505526136756264961, + 504414522724335617, + 503935466266447873, + 505516380192788480, + 504318092558999554, + 504824472063717377, + 505143702734376960, + 504286230213697537, + 504063171041427458, + 504723355027529729, + 505106424536760320, + 505203003708932098, + 504674760848969728, + 504852144898338816, + 505746940689399808, + 505396974343188480, + 504352133605752832, + 505124292573798401, + 504099539482333184, + 505456534244311040, + 505783922715025409, + 504642945065447424, + 506091794682372096, + 505021825810984960, + 504428190983811073, + 504085601608802304, + 505829961962225664, + 506149029068439553, + 505543159930441728, + 504096343988510721, + 505548238129467392, + 505755172845277185, + 505537874788233217, + 505525071889563648, + 506201184500477952, + 505420559778607104, + 504062545423241216, + 506157487595081728, + 504057381425520640, + 505750478756397056, + 505544243113631745, + 505158115499970560, + 505396146412748800, + 505563384616849408, + 503936378544349185, + 504080903040417793, + 505801802516664320, + 504455022323961857, + 504318896589918208, + 504351664598695936, + 503994272085856256, + 505730468486987776, + 503936862835445760, + 504405380324413440, + 505553430900121601, + 504335427688742912, + 504448144042893313, + 504011407403544576, + 504114802277761024, + 504658892841041921, + 505536476793155585, + 505438246965628928, + 506147786018914305, + 505163586537545729, + 505826408992878592, + 505112034586157056, + 505757917732016129, + 505439955070746624, + 504010030233182209, + 506141984411885568, + 504436491699773440, + 505433593918021632, + 506092783397261312, + 504446785033871360, + 505456899622703105, + 504414046485876738, + 504793855078981632, + 504023933533036544, + 504650237504655361, + 505478810456690688, + 505733572440125441, + 504492055549079552, + 504461602507481088, + 504458911127449600, + 505481815659139072, + 505777340329099264, + 506109153367322624, + 505201017185894401, + 503965243652210688, + 505166908757258240, + 504451108169728000, + 504395674033860608, + 505792175561392129, + 505534351611027456, + 506200838252294144, + 504108619307028481, + 506139929119035392, + 505152000795738112, + 504780719831654403, + 506178603416293377, + 504470549280854016, + 505182563003269120, + 504061800200286209, + 504434813789806592, + 505908028311633920, + 505570231402524672, + 505831940688064512, + 505514087120650241, + 504298447928041473, + 506203899968356352, + 505530364333686784, + 505848841930027008, + 505419231627071488, + 505791197076807681, + 503986735983112192, + 505533660167417856, + 505164878450286592, + 504438700731015168, + 505526627057819648, + 505758524321050624, + 504486353019490304, + 506210070422913024, + 504824055598690304, + 505434221054152704, + 505567823989846016, + 504104769309642752, + 505803760900538368, + 505448989546672128, + 505531709883170816, + 505769104561958913, + 504079442218876928, + 504361534403792896, + 505779211421089792, + 504454410316292096, + 504307129117708288, + 506106236941901824, + 505200931877969920, + 504089066166812672, + 504418391915261953, + 504054251380019201, + 504406484277821440, + 506205456201953281, + 504007484223131648, + 505811100961869824, + 504806249930563585, + 504683084126883841, + 505511996184600576, + 504712847851810816, + 505755204797485056, + 505813098583052288, + 505201113021173760, + 506116561267347456, + 504427360620265472, + 505758278379642881, + 506208345486000128, + 506203242502819840, + 506135938846949376, + 505728557856088065, + 504078816923648000, + 505812764578054145, + 505561480381861888, + 504818793244536833, + 505175903320965120, + 506099398955520001, + 504422277258432513, + 504388239583481857, + 504342569153622018, + 505509171593502720, + 505755282719657986, + 506146237058674688, + 504805526858125312, + 506115203138740224, + 503998088827392000, + 504366903209369600, + 504092492388904960, + 504356190282059776, + 505046929274052608, + 504004651096629248, + 504000676314116096, + 506124767758274560, + 505206317212901376, + 505089785677889536, + 505173671703748608, + 506157899857817600, + 506108828337721344, + 505205844313919489, + 505405070067130369, + 505121275279179776, + 504011329007783937, + 502198449266110464, + 506129249498312704, + 504747792665825280, + 505165996685262848, + 505418128034373632, + 505438485642084352, + 505192579068338176, + 506138662648565763, + 504790893287972864, + 506134621030207488, + 506121828876976128, + 504348373869015040, + 504352537416572928, + 505557394794229761, + 506173562710155264, + 505740103722225664, + 506107429936193536, + 504124903436845056, + 504110286849449984, + 505756042228408320, + 504012201137831937, + 505167945946132481, + 505891903637061633, + 505551163761364992, + 504100692466728960, + 506178383559266304, + 505905308380971008, + 505802582510800896, + 504022695479345152, + 505777191725318144, + 506138339872088064, + 505533576171909120, + 505161721825083392, + 504839183660503040, + 505189711552339968, + 506207271815487488, + 505814710986768384, + 505829812376985600, + 505799381384433664, + 505159849932754944, + 504342606868799488, + 505199902788694016, + 505119013140447233, + 504073296531718144, + 505197440639594496, + 505842854586236928, + 504002197361672192, + 505755240965361664, + 503966323223707648, + 505559114958012416, + 505179829302734849, + 504804559005286400, + 504783344081858560, + 505462534200377346, + 504060838022369280, + 504835875629723650, + 505195020002295809, + 505177780779487232, + 504843334834475008, + 505821623212314624, + 505774781573390336, + 505827754529792001, + 504803432012988416, + 505367893954289664, + 505182710261088256, + 504765553429327872, + 504430088604372994, + 504847271356530688, + 505073178104692738, + 504850511326359553, + 506130080888655873, + 505797665435955201, + 503951123783622656, + 505550162437996544, + 505186090761080832, + 505186893102063616, + 505183956825047040, + 503979915017203712, + 505076899694252032, + 505175486507810816, + 505844908931153921, + 505739678658875393, + 504788412843708417, + 504430808825073664, + 504057016072286209, + 504691067623452672, + 505832269756772353, + 504101542056972288, + 503962840165023744, + 504790782189244416, + 505467151910989825, + 505741736959045632, + 505456132396449792, + 505763295371202562, + 504794694925447169, + 504735164446937088, + 504472223621464064, + 505082047694520320, + 504784922855632896, + 504739905725923328, + 504322022596698114, + 505054945796947968, + 505173391083450369, + 504827306909921281, + 504128358180196352, + 505019230417215488, + 505755817111715840, + 505173220375674880, + 505559461965348864, + 503950470717898752, + 504754043915612161, + 504461322164391936, + 504393345289183233, + 506186185388335104, + 504831571892129793, + 505158365610536960, + 504448948833378305, + 505071123696861184, + 505486377342238720, + 505435547524136961, + 503970564349108224, + 505466271069376513, + 505470341561319424, + 505067806908764160, + 505899345599004672, + 505197206832697347, + 506114943683682304, + 503962578595635200, + 505035074417741824, + 504707628086210560, + 505366275703705601, + 506170555356442625, + 505734541093634048, + 506101537635332097, + 504109460189900800, + 505470439851036672, + 505159374797815808, + 505834388844601344, + 505171150457282560, + 505757574248296448, + 504090062322405376, + 503944566295126018, + 505086316720455682, + 504669517956386816, + 504322393771638784, + 505398165999468545, + 503993785991196672, + 506157911933202433, + 504471364364140544, + 503979123912351744, + 504644761102188546, + 505151676152836096, + 503950023462109184, + 505163302666645504, + 505438989697163264, + 505576849351507968, + 505774014724599809, + 505098615262433280, + 506123209822199808, + 505917258460569601, + 503935438311407616, + 505390131717496833, + 505778055248617472, + 505795501628080129, + 503958246684901377, + 504682788608409601, + 505539848628097024, + 503972303026130945, + 504370952419819520, + 505074503333212161, + 505789948469837825, + 505750779509358592, + 505034030127927296, + 504078683989360640, + 504751961703739392, + 504706866593947649, + 504429269540679680, + 504826407890210816, + 505024220276215808, + 505039341828055040, + 506180590601641984, + 504391975479808000, + 504070375815127040, + 504800576350470144, + 505739896061841408, + 503909663617073153, + 505773013107998720, + 504096732498894848, + 506174324416339968, + 505189135578312704, + 505406577893855233, + 504010224643346432, + 505773949742223360, + 506213192415334401, + 505070125079613440, + 505179153206083586, + 505154163224104960, + 505755257998020610, + 505060993039601664, + 503983901455699968, + 504699798469890048, + 505094528970141696, + 505757314532790272, + 503991269237211136, + 504443340406784000, + 505797488381796352, + 505186026638548993, + 505030869586051072, + 506148456919228416, + 505909339790376960, + 506155520462688256, + 505196689695584256, + 504376619742801920, + 503949833850601472, + 505901443254337536, + 506209409211850752, + 505159926445252609, + 505772080961699840, + 506211741467156480, + 504311791753498624, + 504733665872859138, + 504006674160820224, + 505088595359981570, + 505521431737012224, + 505011110114652161, + 505842767114043393, + 505938706914885632, + 505890902846758912, + 505533455510564864, + 504784841595166720, + 505454851703459840, + 505148652264779776, + 504321042077483009, + 504815057864511488, + 504670657083633664, + 505747893165494273, + 505731936422068224, + 505884342808502272, + 505913312354516992, + 505932310601281536, + 504788135583420416, + 505421102605414401, + 505926348209401856, + 504705675927109632, + 505447675689709568, + 505803203863404544, + 505046912522027008, + 504020351865876480, + 504791966513889280, + 505895849977585665, + 505467424653979649, + 505868026181193729, + 505830707751845888, + 505811396484136960, + 504724404194910208, + 505937449931911168, + 504725774079754240, + 504290888940793858, + 505930153881784321, + 505150134624075776, + 504106548713377792, + 505842198127333376, + 505742503958429696, + 504101802309337089, + 505832044082249728, + 505563353742606336, + 504636510394519553, + 504751798062960640, + 505903973875068928, + 504425600808157184, + 503991741356064768, + 505157351821701120, + 505146528122433536, + 505445929818677248, + 505432126213595137, + 505391933385355264, + 504382084597960704, + 504667856563601408, + 506176132249845761, + 504404669557661696, + 505888621921316865, + 504727615047888896, + 505840809405857792, + 504773010906030080, + 505148071202672640, + 506217879016976384, + 504756999557758976, + 504649768564707328, + 506121952957067264, + 504442263830016000, + 505817383563702273, + 504711592198434816, + 504755525368549376, + 505759434132295680, + 504036206674710528, + 504395783886479360, + 505880230654136320, + 505145263606857728, + 506094082683187201, + 504002702742142976, + 505147628619706368, + 506180164381061120, + 505475163886862336, + 504370257868619778, + 504753974361460736, + 504347793570664449, + 504330255994064896, + 505098400824848385, + 504743372368932864, + 505429145812475904, + 505740004745039873, + 506156825784619009, + 505894926488707072, + 504403913593077762, + 504046059115786240, + 505410874648309760, + 505878016321675265, + 504695765621809152, + 503980850543742976, + 504727550531477505, + 504750224888594434, + 505118727067947008, + 504475908309549056, + 504325402144546817, + 505409957513396225, + 505061269305823232, + 505158361059696640, + 505147181594972160, + 504102428921561088, + 504720536748838912, + 504429165429661697, + 505025838342234112, + 504017887238295552, + 504371192166633472, + 505720025605353474, + 505755247487516672, + 505157060565434368, + 504661181509148672, + 506134128073650177, + 505423146875240448, + 503955745050992641, + 505856323830153216, + 505033144484241408, + 504398133443309568, + 505444422524633089, + 504059214218940417, + 504267714001924096, + 504690707777744896, + 503982827637981184, + 506121890998784000, + 504301196358991874, + 505040430632042496, + 504311229876539393, + 504079140023070722, + 504289465687605249, + 505424353195216897, + 505871394836873216, + 504061410276818944, + 503937541687762944, + 505201193564393472, + 504278101715472385, + 505466036125433856, + 503981579069583362, + 506157678184644608, + 504377347261612032, + 505445260911452161, + 505429778451927041, + 505854207787016192, + 505470674534932480 + ], + "top_users": [ + "14836197", + "265902729", + "2557521", + "26257166", + "63668501", + "807095", + "69956111", + "19980499", + "24277551", + "22910295", + "46403451", + "343627165", + "28370738", + "53120768", + "378041590", + "14387275", + "890891", + "25324954", + "108568373", + "14388488", + "425989199", + "94166168", + "3108351", + "19230601", + "7587032", + "126142622", + "872185597", + "9570452", + "52818366", + "34601043", + "19636948", + "43139414", + "167070809", + "742143", + "24744541", + "42220353", + "19212622", + "78183672", + "13838562", + "264498030", + "19339460", + "15095537", + "130617778", + "713993413", + "13213122", + "18091004", + "16331010", + "25375962", + "7996522", + "18936161", + "93131556", + "742011151", + "38491229", + "171117515", + "16193578", + "1337785291", + "15097566", + "25456478", + "20264905", + "15891449", + "51241574", + "16180874", + "136361303", + "60050843", + "98533811", + "48488561", + "171682730", + "74791999", + "61804151", + "275215221", + "43018238", + "17158140", + "15332636", + "776507161", + "543799163", + "259925559", + "18009781", + "1499266621", + "113712551", + "69962890", + "114035804", + "39711910", + "612473", + "241964676", + "13049362", + "821045162", + "27660239", + "39710722", + "218012381", + "15256225", + "91478624", + "288333760", + "29060499", + "194385032", + "68727303", + "19777398", + "26823392", + "2883841", + "32073913", + "7589572" + ] + }, + { + "country_breakdown_percentage": { + "AE": 0.3, + "AR": 0.13, + "AT": 0.11, + "AU": 1.08, + "BB": 0.06, + "BD": 0.02, + "BE": 0.28, + "BG": 0.02, + "BH": 0.13, + "BM": 0.04, + "BN": 0.02, + "BR": 0.71, + "BS": 0.02, + "BW": 0.04, + "BY": 0.02, + "CA": 2.09, + "CG": 0.02, + "CH": 0.19, + "CL": 0.04, + "CO": 0.5, + "CR": 0.04, + "CV": 0.04, + "CY": 0.13, + "DE": 0.24, + "DK": 0.17, + "DO": 0.02, + "DZ": 0.04, + "EC": 0.15, + "EE": 0.04, + "EG": 0.19, + "ES": 2.7, + "FI": 0.09, + "FK": 0.02, + "FR": 0.95, + "GB": 51.67, + "GG": 0.02, + "GH": 0.17, + "GI": 0.06, + "GP": 0.02, + "GR": 0.45, + "GT": 0.15, + "HK": 0.06, + "HN": 0.04, + "HR": 0.04, + "HU": 0.06, + "ID": 1.01, + "IE": 2.65, + "IL": 0.06, + "IM": 0.11, + "IN": 0.37, + "IS": 0.04, + "IT": 0.5, + "JM": 0.09, + "JO": 0.04, + "JP": 0.71, + "KE": 0.06, + "KR": 0.09, + "KW": 0.47, + "KY": 0.02, + "LB": 0.11, + "LR": 0.02, + "LT": 0.02, + "LU": 0.02, + "LV": 0.02, + "LY": 0.06, + "MN": 0.02, + "MT": 0.02, + "MU": 0.04, + "MV": 0.06, + "MW": 0.02, + "MX": 0.97, + "MY": 1.14, + "NG": 0.69, + "NL": 1.21, + "NO": 0.6, + "NP": 0.04, + "NZ": 0.04, + "PA": 0.04, + "PE": 0.09, + "PH": 0.15, + "PK": 0.22, + "PL": 0.06, + "PS": 0.02, + "PT": 0.19, + "QA": 0.06, + "RO": 0.02, + "RU": 0.04, + "SA": 1.36, + "SE": 2.18, + "SG": 0.88, + "SI": 0.02, + "SR": 0.02, + "SV": 0.02, + "TH": 0.26, + "TR": 1.19, + "TT": 0.02, + "TZ": 0.04, + "UG": 0.02, + "US": 17.35, + "UY": 0.06, + "VE": 0.06, + "VI": 0.02, + "VN": 0.02, + "XK": 0.04, + "ZA": 0.6, + "ZM": 0.04, + "ZW": 0.02 + }, + "country_code": null, + "device_breakdown_percentage": { + "ANDROID": 9.54, + "BLACKBERRY": 0.09, + "DESKTOP": 35.57, + "IOS": 54.57, + "OTHER_MOBILE": 0.23 + }, + "end_time": "2015-09-02T00:00:00Z", + "event_type": "SPORTS", + "gender_breakdown_percentage": { + "female": 24.44, + "male": 75.56 + }, + "id": "3f", + "is_global": true, + "name": "Transfer Deadline Day", + "reach": { + "total_impressions": 16531978, + "total_number_of_tweets": 79805, + "total_reach": 2077772 + }, + "start_time": "2015-08-31T00:00:00Z", + "top_hashtags": [], + "top_tweets": [ + 506195883260932096, + 506140698744467456, + 506203847665414144, + 506104509261561856, + 506195159571521537, + 506020683403780097, + 506208196449796097, + 506090675658452992, + 506218118025596928, + 506209001848467457, + 506214947467317248, + 506006127864479744, + 506127241211043840, + 506012342073982976, + 506123659959091200, + 506138875300151296, + 506212464292532225, + 506216101693640705, + 506199327845675008, + 506181064675848194, + 506126856127791104, + 506139956243615744, + 506214608257187840, + 506187782776430592, + 506186896528396288, + 506219776373702656, + 506107079153942529, + 506215081500479488, + 506130137721880577, + 506054217497595904, + 506215287394676736, + 506199938918006784, + 506121302454071296, + 506204862871502848, + 506202692549881856, + 506187554635657216, + 506156057769836544, + 506110612888645632, + 506106098613366784, + 506201422200053760, + 506204721527664641, + 506030158856589312, + 506223203857879040, + 506028930730840064, + 506215386044727296, + 506192646952730625, + 506189907640205314, + 506203556009873408, + 506215109635870720, + 506183081041338368, + 506017324588367872, + 506190795704373250, + 506217383766532097, + 506214879767052288, + 506200274026123264, + 506152710803324929, + 506184555951583232, + 506214136246968320, + 506061701264187392, + 506215011669508096, + 506209558373863425, + 506194543424045056, + 506113437316169728, + 506203145580855296, + 506222423499608065, + 506196320932335616, + 506033722236231680, + 506185429822218240, + 506093399288856576, + 506086547154690049, + 506124207433195520, + 506215212589285377, + 506137994139820032, + 506133996418650112, + 506117947040210944, + 506201559521591296, + 506012678205493248, + 506135464399876096, + 506155468130377728, + 506164845134479360, + 506140241233997824, + 506133087995301888, + 506172638142955520, + 506189160294940672, + 506039150282547200, + 506202729749180417, + 506070795890614272, + 506198079658557440, + 506215737619677184, + 506215285414957056, + 506190489595682816, + 506221488136282112, + 506153464515559424, + 506183187354370048, + 506210264254283778, + 506146365555367936, + 506189453908803584, + 506215612675526656, + 506179679225905152, + 506005207495766016, + 506185271772450816, + 506182306516971521, + 506024602532061184, + 506177171988033536, + 506108361075863552, + 506125806629052416, + 506028687087906816, + 506146289953030144, + 506204813173219328, + 506021803882729472, + 506148413768216577, + 505981491365441537, + 506186719021260800, + 506187085645361152, + 506172604659806209, + 506140252843831296, + 506183792298835968, + 506176320079167489, + 506145076079521792, + 506021088103378944, + 506193376568692736, + 506184550251520000, + 506203590617468928, + 506148086948040705, + 506201593990373376, + 506103713480835072, + 506072148218507265, + 506138769540808704, + 506188148049985536, + 506195289641070592, + 506111904797167617, + 506106926405799936, + 506206906126315520, + 506114177266876416, + 506205562414301184, + 506145375129202688, + 506145431802224640, + 506159985664217088, + 506186078152581120, + 506208950157840384, + 506140940625383424, + 505983576937357312, + 506204838125129728, + 506212602952048640, + 506126808891535361, + 505999181400801280, + 506160487479132160, + 506199991271325696, + 506145356074471426, + 506216114733711360, + 506184291898781696, + 506140052737376256, + 506108224043765760, + 506160847484633088, + 506057195151450112, + 506036796120399874, + 506181761400045568, + 506151141387014144, + 506182536423571457, + 506163740891299841, + 505990640807989248, + 506097862988402688, + 506175805379342336, + 506144471088906243, + 506226056794501120, + 506200674187890689, + 506211099230736384, + 506199358824775681, + 506189915819106305, + 506109453713022976, + 506100634689765376, + 506210523390967809, + 506209881612115969, + 506067755377102848, + 506188878693552129, + 506027077318230016, + 506220710751383552, + 506196934139576320, + 506165801708425216, + 506170219115864065, + 506183613957038080, + 506215100223873024, + 506220453627957248, + 506153058922164224, + 506084346768687104, + 506215282738987009, + 506061454873993216, + 506197697712640000, + 506220374099382272, + 506222267245006849, + 506191008041021441, + 506157508621516800, + 506181244544352256, + 506122558903570432, + 506218730469470208, + 506123036232527872, + 506141540054749184, + 506083908002545664, + 506204612269862912, + 506128929963646976, + 506172015909556224, + 506004916826284032, + 506190428031680513, + 506199812291571712, + 506138943730253825, + 506135411949715456, + 506090453708460032, + 506182688060231680, + 506125978246979586, + 506165247645073409, + 506188724359528448, + 506194534423093248, + 506129900735315968, + 506129771697557505, + 506200785173372928, + 506176983630635008, + 506137199247491072, + 506178690351628289, + 506021931251150848, + 506173114427113472, + 506188007893110784, + 506218156902584320, + 506197951996493824, + 506141079696334848, + 506181724368543744, + 506136651849289730, + 506165801934544896, + 505994719269502976, + 506183549830320128, + 506179586628255744, + 506152409937502208, + 506180157082976258, + 506154553771708417, + 506204570264305665, + 506205958805405697, + 506215601065721856, + 506179801699602433, + 506141695415943169, + 506213209066708993, + 506157133323186176, + 506161190804799488, + 506113443347574784, + 506122992330756097, + 506190463041564672, + 506176728692424704, + 506211419462074369, + 506202069263728640, + 506182100215947265, + 506154553075445760, + 506021899345100801, + 506214097458057216, + 506201781605761024, + 506105823068946432, + 506199803710038016, + 506217750025740288, + 506209223022477315, + 506059077471186944, + 506195705716019201, + 506205883618308097, + 506100404892225536, + 506172897644535809, + 506163703457533952, + 505983390093688832, + 506208363588640768, + 506211027269480448, + 506204366706343936, + 506181873274716160, + 506198634963423232, + 506169976437616641, + 506098533377003521, + 506181780232474624, + 506207291230945282, + 506192195792404481, + 506195856237002752, + 506179087266615298, + 506114739572060161, + 506174582660018176, + 506166467650658304, + 506199849532801024, + 506168133800177664, + 506216514417344512, + 506197899991339009, + 506167891658821632, + 506200099777953793, + 506212198025539584, + 506216811042721794, + 506197603319812096, + 506176701790191617, + 506219593841790976, + 506213312095617024, + 506159170287304705, + 506191313709318144, + 506214890139566080, + 506215906599387137, + 506205472605888513, + 506216420871766016, + 506174395141066753, + 506084453475946496, + 506153174567514113, + 506212573138915331, + 506207394058502144, + 506167162806239232, + 506206404093693952, + 506114044785618944, + 506134681428180993, + 506037261029629952, + 506215671894507520, + 506204265808158720, + 506215079290077186, + 506189872978460673, + 506209456053846016, + 506225825109540865, + 506215662281187329, + 506025040685834240, + 506190472331943936, + 506041887912775680, + 506140153232896002, + 506205284759764992, + 505982545826430976, + 506143912424378368, + 506169680063901696, + 506189920005029889, + 506191531121053696, + 506156828947132416, + 506200570517270528, + 506217255089500160, + 506027879394988032, + 506162950542217216, + 505984133114646528, + 506012288474943488, + 506190833931284480, + 506207260867960832, + 506014909436796928, + 506136879335763968, + 506084890987995136, + 506125769350057984, + 506202498315862016, + 506190509313118210, + 506193666072137728, + 506214753631731712, + 506216954362081280, + 506228409090191360, + 506199933918400512, + 506123069778583553, + 506218927954067456, + 506198305471496192, + 506216215673864192, + 506198838341029889, + 506125415904448512, + 506203551446888448, + 506152653228081152, + 506192651159621632, + 506128001353150466, + 506207818081644544, + 506186728303263744, + 506084371674431488, + 506016990654648320, + 506188304614973441, + 506177316234727425, + 506187408199921664, + 506228600304316416, + 506216092369711104, + 506208681923710977, + 506147960829132800, + 506216286246797312, + 506158692581257217, + 506206861402849280, + 506145485460361217, + 506203538050265089, + 506137506166087681, + 506206726300127232, + 506150161278439424, + 506062078957084672, + 506171083033427968, + 506209331751452675, + 506157987074166785, + 506184198240362496, + 506138019754430465, + 506215562813636608, + 506079931898818560, + 506179727791763457, + 506198756430082048, + 506215461869346816, + 506048978367303681, + 506224824570478593, + 506201191509151744, + 506175122764734464, + 506215710734184448, + 506192919704129537, + 506044079227293696, + 506146308286320640, + 506215051402158080, + 506077262488150016, + 505995983256567808, + 506035858374656000, + 506135856294281216, + 506218614350151680, + 506105887144943616, + 506183557375856640, + 506215318864158721, + 506161390953185280, + 506175667692900352, + 506200920905244674, + 506187279002771456, + 506196527979589632, + 506219165280403456, + 506216243167514624, + 506164435787202560, + 506191542412128256, + 506057533455601664, + 506150674837831681, + 506199834588897281, + 506187446028361728, + 506186146058362880, + 506128150867501058, + 506068145380290561, + 506193803905363969, + 506141329328713728, + 506011484108103680, + 506040227430150144, + 506026174854610945, + 506200046837456897, + 505984110465003520, + 506130231565246464, + 506206420032032769, + 506022410231877633, + 506194749523361792, + 506104201525460992, + 506201449609846785, + 506190417390755840, + 506225024877854720, + 506040632331489280, + 506218946702635009, + 506147997038968832, + 506195902437277696, + 506108112622071808, + 506188283836370945, + 506209933462106113, + 506218267611238400, + 506179937372745729, + 506215589338431488, + 506187318685081600, + 506218031329329152, + 506182639598858240, + 506179501630291968, + 506185205817032705, + 506179617561255936, + 506021655672803328, + 506168157560901632, + 506004446082781184, + 506183063223951360, + 506124344960241665, + 506211377649025024, + 506201411097722880, + 506215123522813952, + 506210010058084352, + 506211148296110080, + 506028505146994688, + 506218994358312960, + 506171810023768064, + 506152619279396864, + 506184357594542080, + 506038973027078144, + 506194042385080320, + 506199812656873472, + 506205944540581888, + 506178121440444417, + 506123899000881152, + 506220673707290624, + 506201260027293696, + 506017581355241472, + 506221870463475712, + 506174506789273601, + 506208627263561728, + 506186707138789376, + 506178082492141569, + 506122502028787713, + 506215566965997568, + 506206993548595200, + 506192379783966720, + 506179499797389312, + 506216670609039361, + 506156844315062272, + 506093185744257024, + 506130185855729664, + 505973921079128064, + 506206482061611009, + 506027762428411904, + 505980311176761344, + 506188861899558912, + 506204440769347584, + 505993312818708480, + 506180180185219073, + 506201382136061952, + 506216344095039488, + 506148214433935360, + 506225444803584001, + 506195884229804032, + 506218151030583297, + 506211094780989440, + 506040069346820096, + 506128841564520449, + 506172485063442432, + 506195645141897217, + 506199099566465024, + 506220336657235968, + 506055681666199552, + 506109169330819072, + 506083701193580544, + 506082379476111361, + 506194979245817857, + 506147524907122690, + 506048835861639168, + 506175788790853633, + 506145668214562816, + 506145190785335297, + 506216628217204736, + 506216914524581888, + 506123847150862337, + 506217903742812160, + 506182010424266752, + 506215570363383808, + 506110568152182784, + 506133504586178560, + 506219396466212864, + 506177620355325952, + 506143352396709890, + 506213877936578561, + 506162966736429057, + 506195587541512192, + 506146512871890944, + 506197371928457217, + 506192336049934337, + 506220625074339840, + 506214531811803136, + 506147964234903552, + 506222759194923008, + 506191327403716609, + 506028474956800000, + 506215117554733056, + 506170470828621824, + 506166002787573761, + 506165363051364352, + 506161896404566016, + 506036833839751168, + 506228327909445632, + 506200570022354944, + 506142874304782337, + 506204221960896512, + 506129322986704896, + 506100187711160320, + 506209415859822593, + 506160433430949890, + 506213077369778176, + 506028805249830913, + 506186482600906753, + 506170205173977088, + 506211289488977920, + 506191112521125888, + 506215228657639424, + 506186512053305344, + 506149606963810305, + 506225845548351488, + 506032177201811456, + 506195870443122689, + 506195530893238274, + 506012269780934656, + 506191532790415360, + 506183697826349056, + 506202439285239808, + 506073535916560385, + 506215583919382528, + 506201275755941889, + 506172429971234816, + 506162878781460480, + 506217200911667200, + 506208192444252161, + 506205867075596288, + 506215191751979008, + 506211187210878976, + 506096673182203904, + 506186091209428992, + 506154616644710400, + 506223019170471936, + 506177179864928257, + 506215377765142529, + 506013312484925440, + 506013323830513664, + 506011300364025856, + 506179387201687553, + 506080975017627648, + 506149120898510849, + 506039676864856065, + 506217533394149376, + 506018082801086465, + 506162401977589760, + 506146179223392256, + 506199427007389696, + 506217710662189056, + 506004941346189312, + 506027956771495936, + 506184106531901441, + 506053757319516160, + 506175129127485440, + 506171255314452480, + 506198607910141952, + 506059987882233856, + 506143517551632384, + 506173913312034816, + 506162526401622017, + 506031617048326144, + 506134114026938368, + 506097563909763072, + 506198242129092608, + 505977961859014656, + 506217039581954048, + 506206239240761344, + 506216745892601856, + 506005156123533312, + 506174410508996608, + 506203702135652354, + 506004941522362368, + 506143292380442624, + 506181209547112448, + 506210432487796737, + 506135467591737344, + 506188846997209088, + 506199840267960320, + 506204191258587138, + 506180444707373056, + 506155637320208384, + 506204192873009152, + 506210785513988096, + 506198584153604097, + 506194895292215297, + 505978565230612480, + 506157739878649857, + 506173144496095234, + 506213159473270785, + 506221768378707968, + 506223640275607552, + 506207295056138240, + 506200676838678528, + 506187791588687873, + 506190821818114051, + 506192449170317312, + 506208822973956097, + 506224492507832320, + 506215471713353728, + 506187187071631360, + 506143127972085762, + 506199406627274752, + 506028060232396800, + 506152375409983488, + 506164918031491072, + 506155239003926528, + 506194249248178177, + 506009747842035712, + 506179632237146112, + 506158252120612864, + 506203651019640832, + 506193286504415232, + 506009653588000768, + 506192705551351810, + 506202124188147712, + 506209541747658752, + 506186149355089920, + 506132070415228928, + 506215511680876544, + 506174406276956160, + 506190112863293440, + 506162991294066688, + 506117928123912193, + 506211676644200448, + 506182064082018305, + 506187771292430336, + 506191400409788417, + 506168495621828608, + 506217440163135488, + 506215209707798528, + 506172118644850688, + 506161155216531456, + 506216042893705216, + 506187198173966336, + 506188302186450944, + 506108936303697920, + 506221979972947968, + 506221075966222336, + 506165362904551424, + 506218131665461248, + 506223902004375552, + 506125997838589953, + 506193820837756928, + 506164556973244417, + 506214154383155201, + 506121227770290176, + 506165524326539264, + 506036000704167936, + 506087947330781184, + 506036903993675776, + 506210160021618688, + 506154676958797824, + 506121963904196608, + 506214839904370688, + 506003070766288896, + 506129964920733696, + 506168041068306433, + 506199761121464323, + 506186642903031808, + 506182406916034560, + 506187966503739393, + 506151365467705344, + 506219224818524161, + 506214164965359616, + 506217215352647680, + 505993597788094464, + 506215292612411392, + 506142291468492800, + 506203155349397504, + 506206983394172929, + 506213521651417088, + 506190356724342784, + 506215731827335168, + 506219360567177216, + 506217307304390658, + 506209734685650944, + 506028086656512000, + 506216698564071424, + 506116922409119745, + 505998978736226304, + 506212761719025665, + 506197570419712000, + 506207592591687680, + 506138201262940160, + 506090699029479424, + 506180731669057536, + 506177838408802304, + 506215566885920768, + 506181771336376320, + 506132779369644032, + 506036215154761728, + 506142965916372992, + 506215496933736448, + 506183871969628160, + 506190631321223168, + 506091071290744832, + 506217672519204864, + 506150402237403136, + 506207999355273218, + 506203031852285952, + 506169980036337666, + 506212825748865024, + 506198420538003458, + 506007856953692160, + 506190279662374912, + 506203596766330880, + 506220667852062720, + 506078955989139456, + 506208772575215616, + 506206318555054080, + 506088723013185536, + 506204975551115264, + 506205242250518528, + 506214265922289667, + 506218940692193280, + 506154777168711681, + 506150316857782273, + 506189931606474752, + 506154253959041024, + 506047043752960000, + 506125686172831744, + 505998240391512065, + 506177290230042626, + 506185372695793664, + 506214281508290561, + 506212504536883200, + 506019139019091968, + 506178970556305408, + 506201185829666816, + 506217491719528448, + 506142352424325121, + 506105714767835136, + 506177406307426305, + 506199942709653504, + 506073403179429888, + 506011084625833984, + 506140736052793344, + 506171528971829248, + 506200156606595072, + 506210300669214720, + 506055362869743616, + 506189045069004800, + 506196547860963329, + 506215976502054912, + 506162272792612864, + 506195356418605056, + 506093680503963648, + 506216762460098562, + 506216292899389441, + 506015681587200000, + 506097347215261696, + 506116331163631616, + 506013522279804928, + 506187723699650562, + 506196242893119488, + 506216409169661954, + 506215916473171970, + 506176116638638081, + 506191796771491841, + 506217502477529089, + 506216086166331392, + 506206436771520514, + 506152279825592320, + 506222635416829952, + 506156028321595393, + 506221756068401153, + 506174973208043520, + 506123284443049984, + 506226350202814464, + 506124588380848129, + 506087169371684865, + 506124934301884416, + 506182813377650688, + 506148319534796800, + 506108133434195968, + 506162764730335232, + 506100805716680704, + 506221294762078209, + 506199328638382080, + 506206859356020738, + 506208709270585344, + 506190416262488064, + 506222600499236865, + 506141721227718657, + 505987982298726400, + 505979797101891584, + 506175748382941184, + 506164714179928065, + 506215087435415555, + 506218093375684608, + 506156549174476800, + 506011347768070144, + 506057508226891776, + 506212560526663680, + 506121395919548417, + 506222271703547904, + 506121216525361152, + 506169795939926016, + 506155487982010369, + 506193688444534784, + 506108502012862465, + 506159918533996544, + 506207333681471488, + 506166085184655360, + 506218291174858752, + 506215301185540096, + 506173190616649729, + 506166790935052289, + 506160325759361024, + 506217472664797184, + 506027664868904960, + 506141854442987520, + 506189721912233984, + 506158857757155328, + 506158617348018177, + 506174088227069954, + 506153671521234944, + 506118973478273024, + 506025996693553152, + 506215331304865792, + 506188770090430465, + 506186986362003456, + 506067875551924224, + 506216251983921154, + 506176514099257344, + 506098532311646208, + 506209450504769536, + 506220643780923392, + 506140330886832129, + 506190543144370176, + 506210016828096514, + 506028187491778560, + 506202992840687616, + 506214940525723648, + 506141789200601088, + 506215351244161024, + 506186957127311362, + 506144498238246912, + 506174545943072769, + 506217039149543425, + 506198551005646848, + 506165932700729345, + 506162874205470720, + 506203064580452352, + 506174194095493120, + 506216253128994816, + 506208815541649409, + 506204356249927682, + 506177167899000832, + 506172584166436864, + 506130746466402304, + 506120240238198785, + 506194815722483713, + 506205036779933696, + 506070389748142080, + 506164544155029504, + 506013362715500544, + 506214047369691136, + 506136924051234816, + 506188219575468032, + 506197673293389825, + 506193410382782464, + 506079530134802433, + 506221177187352576, + 506220496955133952, + 506179340955287552, + 506195121067786240, + 506105266320842753, + 506176731070619648, + 506209473397280769, + 506189341367209984, + 506222846696493057, + 506132566953689089, + 506158382592819200, + 506166963992010752, + 506158594992377857, + 506221059377741824, + 506009578233163776, + 506081535481888769, + 506151510053765120, + 506184533402984448, + 506138517526032385, + 506191978594594816, + 506167271514193920, + 506216870144659456, + 506216391675219968, + 506216032219181058, + 506204098459607040, + 506209388324225024, + 506203735979487232, + 506152142575390722, + 506193240442556416, + 506142882433363968, + 506216084635414528, + 506160009949233152, + 506201813952258048, + 506136410035060736, + 506220245967978496, + 506206559278747649, + 506219277544747009, + 506050715140513792, + 506182298187071490, + 506150324445646849, + 506171377519722496, + 506028267116449792, + 506222486800064512, + 506206718058328064, + 506009828704002048, + 506130115504668672, + 506169298801684481, + 506000538832748544, + 506150928584810496, + 506192254424580098, + 506185186976206848, + 505997824417206273, + 506211796458680322, + 506169744152862722, + 506214928685219840, + 506059890159538176, + 506007245285756928, + 506206135943430144, + 506184392080121856, + 506154196987805696, + 506133574035456000, + 506153061849780224, + 506187455079649280, + 506192070915403776, + 506061919925846016, + 506205324387164161, + 506186003967913985, + 506139744502571008, + 506185611146186752, + 506106201030283264, + 506224929168424960, + 506203651732680704, + 506198100567134208, + 506218684827049984, + 506191270453448704, + 506212516985602048, + 506215914774487040, + 506148415110385664, + 506218723175579649, + 506105653518413824, + 506221944816295937, + 506038699428040704, + 506186822595383298, + 506171612878888960, + 506189913180893184, + 506127686222487552, + 506179686247186432 + ], + "top_users": [ + "365953260", + "713993413", + "1030711922", + "265902729", + "2290170218", + "108568373", + "2551182985", + "384951307", + "1457171660", + "340417174", + "580967619", + "2330299633", + "17336417", + "15332636", + "70133638", + "435225922", + "111556576", + "110758975", + "2570979121", + "592946538", + "985117128", + "16902662", + "789162432", + "2212313540", + "347909288", + "28327049", + "538031518", + "740865648", + "19292816", + "1742526258", + "394170044", + "985172054", + "1627736996", + "2546507294", + "2321418476", + "595343731", + "212560938", + "460538823", + "138751214", + "2228621604", + "462312323", + "167704836", + "17894963", + "68837355", + "47659350", + "385473825", + "291709255", + "51036354", + "50684862", + "489705506", + "20383794", + "1830525626", + "2597679625", + "2415178633", + "1561123663", + "134044293", + "240337795", + "19343918", + "1922910416", + "822085326", + "150677438", + "263576813", + "423284156", + "409117233", + "535066049", + "26809005", + "768341436", + "16996182", + "2519792631", + "65033270", + "1427661955", + "16667278", + "2288125225", + "569289131", + "955805444", + "1123488680", + "451612382", + "14016912", + "19743006", + "146950195", + "127831273", + "2542623596", + "61168871", + "183675164", + "454918914", + "2527532694", + "309396798", + "532497627", + "2707796908", + "1395776430", + "1611697122", + "50596741", + "73840916", + "552803420", + "192184457", + "282182210", + "790371762", + "23925153", + "2707527638", + "430013408" + ] + } + ], + "data_type": "events", + "request": { + "params": {} + } +} \ No newline at end of file diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-interests-params.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-interests-params.json new file mode 100644 index 00000000..5580e9fe --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-interests-params.json @@ -0,0 +1,21 @@ +{ + "data": [ + { + "name": "Hobbies and interests/Birdwatching", + "targeting_type": "INTEREST", + "targeting_value": "13002" + }, + { + "name": "Pets/Birds", + "targeting_type": "INTEREST", + "targeting_value": "19001" + } + ], + "data_type": "targeting_criterion", + "next_cursor": null, + "request": { + "params": { + "q": "bird" + } + } +} \ No newline at end of file diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-interests.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-interests.json new file mode 100644 index 00000000..ee769ec8 --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-interests.json @@ -0,0 +1,1009 @@ +{ + "data": [ + { + "name": "Books and literature/Biographies and memoirs", + "targeting_type": "INTEREST", + "targeting_value": "1001" + }, + { + "name": "Books and literature/Business and finance", + "targeting_type": "INTEREST", + "targeting_value": "1002" + }, + { + "name": "Books and literature/Comics", + "targeting_type": "INTEREST", + "targeting_value": "1003" + }, + { + "name": "Books and literature/Cookbooks, food, and wine", + "targeting_type": "INTEREST", + "targeting_value": "1004" + }, + { + "name": "Books and literature/Health, mind, and body", + "targeting_type": "INTEREST", + "targeting_value": "1005" + }, + { + "name": "Books and literature/Mystery and crime", + "targeting_type": "INTEREST", + "targeting_value": "1006" + }, + { + "name": "Books and literature/Nonfiction", + "targeting_type": "INTEREST", + "targeting_value": "1007" + }, + { + "name": "Books and literature/Politics and current events", + "targeting_type": "INTEREST", + "targeting_value": "1008" + }, + { + "name": "Books and literature/Romance", + "targeting_type": "INTEREST", + "targeting_value": "1009" + }, + { + "name": "Books and literature/Books news and general info", + "targeting_type": "INTEREST", + "targeting_value": "1010" + }, + { + "name": "Movies and television/Action and adventure", + "targeting_type": "INTEREST", + "targeting_value": "2001" + }, + { + "name": "Movies and television/Animation", + "targeting_type": "INTEREST", + "targeting_value": "2002" + }, + { + "name": "Movies and television/Bollywood", + "targeting_type": "INTEREST", + "targeting_value": "2003" + }, + { + "name": "Movies and television/Business and news", + "targeting_type": "INTEREST", + "targeting_value": "2004" + }, + { + "name": "Movies and television/Comedy", + "targeting_type": "INTEREST", + "targeting_value": "2005" + }, + { + "name": "Movies and television/Documentary", + "targeting_type": "INTEREST", + "targeting_value": "2006" + }, + { + "name": "Movies and television/Drama", + "targeting_type": "INTEREST", + "targeting_value": "2007" + }, + { + "name": "Movies and television/Foreign", + "targeting_type": "INTEREST", + "targeting_value": "2008" + }, + { + "name": "Movies and television/Horror", + "targeting_type": "INTEREST", + "targeting_value": "2009" + }, + { + "name": "Movies and television/Independent", + "targeting_type": "INTEREST", + "targeting_value": "2010" + }, + { + "name": "Movies and television/Music", + "targeting_type": "INTEREST", + "targeting_value": "2011" + }, + { + "name": "Movies and television/Reality TV", + "targeting_type": "INTEREST", + "targeting_value": "2012" + }, + { + "name": "Movies and television/Romance", + "targeting_type": "INTEREST", + "targeting_value": "2013" + }, + { + "name": "Movies and television/Sci-fi and fantasy", + "targeting_type": "INTEREST", + "targeting_value": "2014" + }, + { + "name": "Movies and television/Sports themed", + "targeting_type": "INTEREST", + "targeting_value": "2015" + }, + { + "name": "Movies and television/Movie news and general info", + "targeting_type": "INTEREST", + "targeting_value": "2016" + }, + { + "name": "Music and radio/Alternative", + "targeting_type": "INTEREST", + "targeting_value": "3001" + }, + { + "name": "Music and radio/Blues", + "targeting_type": "INTEREST", + "targeting_value": "3002" + }, + { + "name": "Music and radio/Christian and gospel", + "targeting_type": "INTEREST", + "targeting_value": "3003" + }, + { + "name": "Music and radio/Classical", + "targeting_type": "INTEREST", + "targeting_value": "3004" + }, + { + "name": "Music and radio/Country", + "targeting_type": "INTEREST", + "targeting_value": "3005" + }, + { + "name": "Music and radio/DJs", + "targeting_type": "INTEREST", + "targeting_value": "3006" + }, + { + "name": "Music and radio/Dance", + "targeting_type": "INTEREST", + "targeting_value": "3007" + }, + { + "name": "Music and radio/Electronic", + "targeting_type": "INTEREST", + "targeting_value": "3008" + }, + { + "name": "Music and radio/Hip hop and rap", + "targeting_type": "INTEREST", + "targeting_value": "3009" + }, + { + "name": "Music and radio/Indie spotlight", + "targeting_type": "INTEREST", + "targeting_value": "3010" + }, + { + "name": "Music and radio/Jazz", + "targeting_type": "INTEREST", + "targeting_value": "3011" + }, + { + "name": "Music and radio/Latino", + "targeting_type": "INTEREST", + "targeting_value": "3012" + }, + { + "name": "Music and radio/Metal", + "targeting_type": "INTEREST", + "targeting_value": "3013" + }, + { + "name": "Music and radio/Pop", + "targeting_type": "INTEREST", + "targeting_value": "3014" + }, + { + "name": "Music and radio/R&B and soul", + "targeting_type": "INTEREST", + "targeting_value": "3015" + }, + { + "name": "Music and radio/Reggae", + "targeting_type": "INTEREST", + "targeting_value": "3016" + }, + { + "name": "Music and radio/Rock", + "targeting_type": "INTEREST", + "targeting_value": "3017" + }, + { + "name": "Music and radio/Talk radio", + "targeting_type": "INTEREST", + "targeting_value": "3018" + }, + { + "name": "Music and radio/Venues", + "targeting_type": "INTEREST", + "targeting_value": "3019" + }, + { + "name": "Music and radio/World", + "targeting_type": "INTEREST", + "targeting_value": "3020" + }, + { + "name": "Music and radio/Music news and general info", + "targeting_type": "INTEREST", + "targeting_value": "3021" + }, + { + "name": "Gaming/Board gaming", + "targeting_type": "INTEREST", + "targeting_value": "4001" + }, + { + "name": "Gaming/Computer gaming", + "targeting_type": "INTEREST", + "targeting_value": "4002" + }, + { + "name": "Gaming/Console gaming", + "targeting_type": "INTEREST", + "targeting_value": "4003" + }, + { + "name": "Gaming/Mobile gaming", + "targeting_type": "INTEREST", + "targeting_value": "4004" + }, + { + "name": "Gaming/Online gaming", + "targeting_type": "INTEREST", + "targeting_value": "4005" + }, + { + "name": "Gaming/Roleplaying games", + "targeting_type": "INTEREST", + "targeting_value": "4006" + }, + { + "name": "Gaming/Gaming news and general info", + "targeting_type": "INTEREST", + "targeting_value": "4007" + }, + { + "name": "Automotive/Car culture", + "targeting_type": "INTEREST", + "targeting_value": "5001" + }, + { + "name": "Automotive/Convertibles", + "targeting_type": "INTEREST", + "targeting_value": "5002" + }, + { + "name": "Automotive/Hybrid and electric vehicles", + "targeting_type": "INTEREST", + "targeting_value": "5003" + }, + { + "name": "Automotive/Luxury", + "targeting_type": "INTEREST", + "targeting_value": "5004" + }, + { + "name": "Automotive/Minivans", + "targeting_type": "INTEREST", + "targeting_value": "5005" + }, + { + "name": "Automotive/Motorcycles", + "targeting_type": "INTEREST", + "targeting_value": "5006" + }, + { + "name": "Automotive/Offroad vehicles", + "targeting_type": "INTEREST", + "targeting_value": "5007" + }, + { + "name": "Automotive/Performance vehicles", + "targeting_type": "INTEREST", + "targeting_value": "5008" + }, + { + "name": "Automotive/Sedans", + "targeting_type": "INTEREST", + "targeting_value": "5009" + }, + { + "name": "Automotive/SUVs", + "targeting_type": "INTEREST", + "targeting_value": "5010" + }, + { + "name": "Automotive/Trucks", + "targeting_type": "INTEREST", + "targeting_value": "5011" + }, + { + "name": "Automotive/Vintage cars", + "targeting_type": "INTEREST", + "targeting_value": "5012" + }, + { + "name": "Automotive/Automotive news and general info", + "targeting_type": "INTEREST", + "targeting_value": "5013" + }, + { + "name": "Business/Advertising", + "targeting_type": "INTEREST", + "targeting_value": "6001" + }, + { + "name": "Business/Biotech and biomedical", + "targeting_type": "INTEREST", + "targeting_value": "6002" + }, + { + "name": "Business/Business software", + "targeting_type": "INTEREST", + "targeting_value": "6003" + }, + { + "name": "Business/Construction", + "targeting_type": "INTEREST", + "targeting_value": "6004" + }, + { + "name": "Business/Government", + "targeting_type": "INTEREST", + "targeting_value": "6005" + }, + { + "name": "Business/Green solutions", + "targeting_type": "INTEREST", + "targeting_value": "6006" + }, + { + "name": "Business/Human resources", + "targeting_type": "INTEREST", + "targeting_value": "6007" + }, + { + "name": "Business/Marketing", + "targeting_type": "INTEREST", + "targeting_value": "6008" + }, + { + "name": "Business/Entrepreneurship", + "targeting_type": "INTEREST", + "targeting_value": "6009" + }, + { + "name": "Business/Investors and patents", + "targeting_type": "INTEREST", + "targeting_value": "6010" + }, + { + "name": "Business/Small business", + "targeting_type": "INTEREST", + "targeting_value": "6011" + }, + { + "name": "Business/Nonprofit", + "targeting_type": "INTEREST", + "targeting_value": "6012" + }, + { + "name": "Business/Leadership", + "targeting_type": "INTEREST", + "targeting_value": "6013" + }, + { + "name": "Business/Technology", + "targeting_type": "INTEREST", + "targeting_value": "6014" + }, + { + "name": "Business/Organized labor and unions", + "targeting_type": "INTEREST", + "targeting_value": "6015" + }, + { + "name": "Business/Business news and general info", + "targeting_type": "INTEREST", + "targeting_value": "6016" + }, + { + "name": "Careers/Financial aid and scholarships", + "targeting_type": "INTEREST", + "targeting_value": "7001" + }, + { + "name": "Careers/Job fairs", + "targeting_type": "INTEREST", + "targeting_value": "7002" + }, + { + "name": "Careers/Job search", + "targeting_type": "INTEREST", + "targeting_value": "7003" + }, + { + "name": "Careers/U.S. military", + "targeting_type": "INTEREST", + "targeting_value": "7004" + }, + { + "name": "Careers/Career news and general info", + "targeting_type": "INTEREST", + "targeting_value": "7005" + }, + { + "name": "Life stages/Auto intenders", + "targeting_type": "INTEREST", + "targeting_value": "8001" + }, + { + "name": "Life stages/Empty nesters", + "targeting_type": "INTEREST", + "targeting_value": "8002" + }, + { + "name": "Life stages/Moms", + "targeting_type": "INTEREST", + "targeting_value": "8003" + }, + { + "name": "Life stages/Dads", + "targeting_type": "INTEREST", + "targeting_value": "8004" + }, + { + "name": "Life stages/College students", + "targeting_type": "INTEREST", + "targeting_value": "8005" + }, + { + "name": "Life stages/Newlyweds", + "targeting_type": "INTEREST", + "targeting_value": "8006" + }, + { + "name": "Life stages/Veterans", + "targeting_type": "INTEREST", + "targeting_value": "8007" + }, + { + "name": "Education/Adult education", + "targeting_type": "INTEREST", + "targeting_value": "9001" + }, + { + "name": "Education/College life", + "targeting_type": "INTEREST", + "targeting_value": "9002" + }, + { + "name": "Education/Language learning", + "targeting_type": "INTEREST", + "targeting_value": "9003" + }, + { + "name": "Education/Graduate school", + "targeting_type": "INTEREST", + "targeting_value": "9004" + }, + { + "name": "Education/Homeschooling", + "targeting_type": "INTEREST", + "targeting_value": "9005" + }, + { + "name": "Education/Special education", + "targeting_type": "INTEREST", + "targeting_value": "9006" + }, + { + "name": "Education/Online education", + "targeting_type": "INTEREST", + "targeting_value": "9007" + }, + { + "name": "Education/Education news and general info", + "targeting_type": "INTEREST", + "targeting_value": "9008" + }, + { + "name": "Family and parenting/Babies and toddlers", + "targeting_type": "INTEREST", + "targeting_value": "10001" + }, + { + "name": "Family and parenting/Daycare and preschool", + "targeting_type": "INTEREST", + "targeting_value": "10002" + }, + { + "name": "Family and parenting/Parenting K-6 kids", + "targeting_type": "INTEREST", + "targeting_value": "10003" + }, + { + "name": "Family and parenting/Parenting teens", + "targeting_type": "INTEREST", + "targeting_value": "10004" + }, + { + "name": "Family and parenting/Pregnancy", + "targeting_type": "INTEREST", + "targeting_value": "10005" + }, + { + "name": "Family and parenting/Special needs kids", + "targeting_type": "INTEREST", + "targeting_value": "10006" + }, + { + "name": "Family and parenting/Elder care", + "targeting_type": "INTEREST", + "targeting_value": "10007" + }, + { + "name": "Events/Music festivals and concerts", + "targeting_type": "INTEREST", + "targeting_value": "11001" + }, + { + "name": "Events/Movie festivals", + "targeting_type": "INTEREST", + "targeting_value": "11002" + }, + { + "name": "Events/Sporting events", + "targeting_type": "INTEREST", + "targeting_value": "11003" + }, + { + "name": "Events/Holidays", + "targeting_type": "INTEREST", + "targeting_value": "11004" + }, + { + "name": "Events/Political elections", + "targeting_type": "INTEREST", + "targeting_value": "11005" + }, + { + "name": "Events/Entertainment awards", + "targeting_type": "INTEREST", + "targeting_value": "11006" + }, + { + "name": "Events/Tech tradeshows", + "targeting_type": "INTEREST", + "targeting_value": "11007" + }, + { + "name": "Food and drink/American cuisine", + "targeting_type": "INTEREST", + "targeting_value": "12001" + }, + { + "name": "Food and drink/Bars and nightlife", + "targeting_type": "INTEREST", + "targeting_value": "12002" + }, + { + "name": "Food and drink/Barbecues and grilling", + "targeting_type": "INTEREST", + "targeting_value": "12003" + }, + { + "name": "Food and drink/Beer", + "targeting_type": "INTEREST", + "targeting_value": "12004" + }, + { + "name": "Food and drink/Cajun and Creole", + "targeting_type": "INTEREST", + "targeting_value": "12005" + }, + { + "name": "Food and drink/Chinese cuisine", + "targeting_type": "INTEREST", + "targeting_value": "12006" + }, + { + "name": "Food and drink/Cocktails and beer", + "targeting_type": "INTEREST", + "targeting_value": "12007" + }, + { + "name": "Food and drink/Coffee and tea", + "targeting_type": "INTEREST", + "targeting_value": "12008" + }, + { + "name": "Food and drink/Desserts and baking", + "targeting_type": "INTEREST", + "targeting_value": "12009" + }, + { + "name": "Food and drink/Dining out", + "targeting_type": "INTEREST", + "targeting_value": "12010" + }, + { + "name": "Food and drink/Ethnic foods", + "targeting_type": "INTEREST", + "targeting_value": "12011" + }, + { + "name": "Food and drink/Fast food", + "targeting_type": "INTEREST", + "targeting_value": "12012" + }, + { + "name": "Food and drink/Fine dining", + "targeting_type": "INTEREST", + "targeting_value": "12013" + }, + { + "name": "Food and drink/French cuisine", + "targeting_type": "INTEREST", + "targeting_value": "12014" + }, + { + "name": "Food and drink/Cooking", + "targeting_type": "INTEREST", + "targeting_value": "12015" + }, + { + "name": "Food and drink/Italian cuisine", + "targeting_type": "INTEREST", + "targeting_value": "12016" + }, + { + "name": "Food and drink/Japanese cuisine", + "targeting_type": "INTEREST", + "targeting_value": "12017" + }, + { + "name": "Food and drink/Liquor and spirits", + "targeting_type": "INTEREST", + "targeting_value": "12018" + }, + { + "name": "Food and drink/Mexican cuisine", + "targeting_type": "INTEREST", + "targeting_value": "12019" + }, + { + "name": "Food and drink/Vegan", + "targeting_type": "INTEREST", + "targeting_value": "12020" + }, + { + "name": "Food and drink/Vegetarian", + "targeting_type": "INTEREST", + "targeting_value": "12021" + }, + { + "name": "Food and drink/Wine", + "targeting_type": "INTEREST", + "targeting_value": "12022" + }, + { + "name": "Food and drink/Foodie news and general info", + "targeting_type": "INTEREST", + "targeting_value": "12023" + }, + { + "name": "Hobbies and interests/Arts and crafts", + "targeting_type": "INTEREST", + "targeting_value": "13001" + }, + { + "name": "Hobbies and interests/Birdwatching", + "targeting_type": "INTEREST", + "targeting_value": "13002" + }, + { + "name": "Hobbies and interests/Boating", + "targeting_type": "INTEREST", + "targeting_value": "13003" + }, + { + "name": "Hobbies and interests/Performance arts", + "targeting_type": "INTEREST", + "targeting_value": "13004" + }, + { + "name": "Hobbies and interests/Chess", + "targeting_type": "INTEREST", + "targeting_value": "13005" + }, + { + "name": "Hobbies and interests/Cigars", + "targeting_type": "INTEREST", + "targeting_value": "13006" + }, + { + "name": "Hobbies and interests/Drawing and sketching", + "targeting_type": "INTEREST", + "targeting_value": "13007" + }, + { + "name": "Hobbies and interests/Freelance writing", + "targeting_type": "INTEREST", + "targeting_value": "13008" + }, + { + "name": "Hobbies and interests/Genealogy", + "targeting_type": "INTEREST", + "targeting_value": "13009" + }, + { + "name": "Hobbies and interests/Guitar", + "targeting_type": "INTEREST", + "targeting_value": "13010" + }, + { + "name": "Hobbies and interests/Gambling", + "targeting_type": "INTEREST", + "targeting_value": "13011" + }, + { + "name": "Hobbies and interests/Jewelry making", + "targeting_type": "INTEREST", + "targeting_value": "13012" + }, + { + "name": "Hobbies and interests/Needlework", + "targeting_type": "INTEREST", + "targeting_value": "13013" + }, + { + "name": "Hobbies and interests/Painting", + "targeting_type": "INTEREST", + "targeting_value": "13014" + }, + { + "name": "Hobbies and interests/Photography", + "targeting_type": "INTEREST", + "targeting_value": "13015" + }, + { + "name": "Hobbies and interests/Sci-fi and fantasy", + "targeting_type": "INTEREST", + "targeting_value": "13016" + }, + { + "name": "Hobbies and interests/Scrapbooking", + "targeting_type": "INTEREST", + "targeting_value": "13017" + }, + { + "name": "Hobbies and interests/Screenwriting", + "targeting_type": "INTEREST", + "targeting_value": "13018" + }, + { + "name": "Hobbies and interests/Shopping", + "targeting_type": "INTEREST", + "targeting_value": "13019" + }, + { + "name": "Hobbies and interests/Stamps and coins", + "targeting_type": "INTEREST", + "targeting_value": "13020" + }, + { + "name": "Hobbies and interests/Celebrity fan and gossip", + "targeting_type": "INTEREST", + "targeting_value": "13021" + }, + { + "name": "Hobbies and interests/Comedy", + "targeting_type": "INTEREST", + "targeting_value": "13022" + }, + { + "name": "Hobbies and interests/Dance", + "targeting_type": "INTEREST", + "targeting_value": "13023" + }, + { + "name": "Hobbies and interests/Modeling", + "targeting_type": "INTEREST", + "targeting_value": "13024" + }, + { + "name": "Hobbies and interests/Cartoons", + "targeting_type": "INTEREST", + "targeting_value": "13025" + }, + { + "name": "Hobbies and interests/Design", + "targeting_type": "INTEREST", + "targeting_value": "13026" + }, + { + "name": "Hobbies and interests/Astrology", + "targeting_type": "INTEREST", + "targeting_value": "13027" + }, + { + "name": "Hobbies and interests/Paranormal phenomena", + "targeting_type": "INTEREST", + "targeting_value": "13028" + }, + { + "name": "Hobbies and interests/Exercise and fitness", + "targeting_type": "INTEREST", + "targeting_value": "13029" + }, + { + "name": "Home and garden/Appliances", + "targeting_type": "INTEREST", + "targeting_value": "14001" + }, + { + "name": "Home and garden/Entertaining at home", + "targeting_type": "INTEREST", + "targeting_value": "14002" + }, + { + "name": "Home and garden/Gardening", + "targeting_type": "INTEREST", + "targeting_value": "14003" + }, + { + "name": "Home and garden/Home repair", + "targeting_type": "INTEREST", + "targeting_value": "14004" + }, + { + "name": "Home and garden/Interior decorating", + "targeting_type": "INTEREST", + "targeting_value": "14005" + }, + { + "name": "Home and garden/Landscaping", + "targeting_type": "INTEREST", + "targeting_value": "14006" + }, + { + "name": "Home and garden/Remodeling and construction", + "targeting_type": "INTEREST", + "targeting_value": "14007" + }, + { + "name": "Home and garden/General info", + "targeting_type": "INTEREST", + "targeting_value": "14008" + }, + { + "name": "Law, government, and politics/Legal issues", + "targeting_type": "INTEREST", + "targeting_value": "15001" + }, + { + "name": "Law, government, and politics/Government resources", + "targeting_type": "INTEREST", + "targeting_value": "15002" + }, + { + "name": "Law, government, and politics/Politics", + "targeting_type": "INTEREST", + "targeting_value": "15003" + }, + { + "name": "Law, government, and politics/Commentary", + "targeting_type": "INTEREST", + "targeting_value": "15004" + }, + { + "name": "Law, government, and politics/Conservative", + "targeting_type": "INTEREST", + "targeting_value": "15005" + }, + { + "name": "Law, government, and politics/Liberal", + "targeting_type": "INTEREST", + "targeting_value": "15006" + }, + { + "name": "Law, government, and politics/Nonpartisan", + "targeting_type": "INTEREST", + "targeting_value": "15007" + }, + { + "name": "Personal finance/Banking", + "targeting_type": "INTEREST", + "targeting_value": "16001" + }, + { + "name": "Personal finance/Beginning investing", + "targeting_type": "INTEREST", + "targeting_value": "16002" + }, + { + "name": "Personal finance/Credit, debt, and loans", + "targeting_type": "INTEREST", + "targeting_value": "16003" + }, + { + "name": "Personal finance/Financial news", + "targeting_type": "INTEREST", + "targeting_value": "16004" + }, + { + "name": "Personal finance/Financial planning", + "targeting_type": "INTEREST", + "targeting_value": "16005" + }, + { + "name": "Personal finance/Hedge funds", + "targeting_type": "INTEREST", + "targeting_value": "16006" + }, + { + "name": "Personal finance/Insurance", + "targeting_type": "INTEREST", + "targeting_value": "16007" + }, + { + "name": "Personal finance/Investing", + "targeting_type": "INTEREST", + "targeting_value": "16008" + }, + { + "name": "Personal finance/Mortgage", + "targeting_type": "INTEREST", + "targeting_value": "16009" + }, + { + "name": "Personal finance/Mutual funds", + "targeting_type": "INTEREST", + "targeting_value": "16010" + }, + { + "name": "Personal finance/Options", + "targeting_type": "INTEREST", + "targeting_value": "16011" + }, + { + "name": "Personal finance/Real estate", + "targeting_type": "INTEREST", + "targeting_value": "16012" + }, + { + "name": "Personal finance/Retirement planning", + "targeting_type": "INTEREST", + "targeting_value": "16013" + }, + { + "name": "Personal finance/Stocks", + "targeting_type": "INTEREST", + "targeting_value": "16014" + }, + { + "name": "Personal finance/Tax planning", + "targeting_type": "INTEREST", + "targeting_value": "16015" + }, + { + "name": "Society/Dating", + "targeting_type": "INTEREST", + "targeting_value": "17001" + } + ], + "data_type": "targeting_criterion", + "next_cursor": "1913ge0w", + "request": { + "params": {} + } +} \ No newline at end of file diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-languages-params.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-languages-params.json new file mode 100644 index 00000000..a80e4342 --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-languages-params.json @@ -0,0 +1,16 @@ +{ + "data": [ + { + "name": "Norwegian", + "targeting_type": "LANGUAGE", + "targeting_value": "no" + } + ], + "data_type": "targeting_criterion", + "next_cursor": null, + "request": { + "params": { + "q": "norwegian" + } + } +} \ No newline at end of file diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-languages.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-languages.json new file mode 100644 index 00000000..4c120061 --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-languages.json @@ -0,0 +1,114 @@ +{ + "data": [ + { + "name": "Arabic", + "targeting_type": "LANGUAGE", + "targeting_value": "ar" + }, + { + "name": "Chinese", + "targeting_type": "LANGUAGE", + "targeting_value": "zh" + }, + { + "name": "Dutch", + "targeting_type": "LANGUAGE", + "targeting_value": "nl" + }, + { + "name": "English", + "targeting_type": "LANGUAGE", + "targeting_value": "en" + }, + { + "name": "Farsi", + "targeting_type": "LANGUAGE", + "targeting_value": "fa" + }, + { + "name": "Finnish", + "targeting_type": "LANGUAGE", + "targeting_value": "fi" + }, + { + "name": "French", + "targeting_type": "LANGUAGE", + "targeting_value": "fr" + }, + { + "name": "German", + "targeting_type": "LANGUAGE", + "targeting_value": "de" + }, + { + "name": "Hindi", + "targeting_type": "LANGUAGE", + "targeting_value": "hi" + }, + { + "name": "Indonesian", + "targeting_type": "LANGUAGE", + "targeting_value": "id" + }, + { + "name": "Italian", + "targeting_type": "LANGUAGE", + "targeting_value": "it" + }, + { + "name": "Japanese", + "targeting_type": "LANGUAGE", + "targeting_value": "ja" + }, + { + "name": "Korean", + "targeting_type": "LANGUAGE", + "targeting_value": "ko" + }, + { + "name": "Norwegian", + "targeting_type": "LANGUAGE", + "targeting_value": "no" + }, + { + "name": "Polish", + "targeting_type": "LANGUAGE", + "targeting_value": "pl" + }, + { + "name": "Portuguese", + "targeting_type": "LANGUAGE", + "targeting_value": "pt" + }, + { + "name": "Russian", + "targeting_type": "LANGUAGE", + "targeting_value": "ru" + }, + { + "name": "Spanish", + "targeting_type": "LANGUAGE", + "targeting_value": "es" + }, + { + "name": "Swedish", + "targeting_type": "LANGUAGE", + "targeting_value": "sv" + }, + { + "name": "Thai", + "targeting_type": "LANGUAGE", + "targeting_value": "th" + }, + { + "name": "Turkish", + "targeting_type": "LANGUAGE", + "targeting_value": "tr" + } + ], + "data_type": "targeting_criterion", + "next_cursor": null, + "request": { + "params": {} + } +} \ No newline at end of file diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-locations-params.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-locations-params.json new file mode 100644 index 00000000..347b770b --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-locations-params.json @@ -0,0 +1,59 @@ +{ + "data": [ + { + "location_type": "CITY", + "name": "Palo, Huesca, Aragon, Spain", + "targeting_type": "LOCATION", + "targeting_value": "63b6d114834a77e5" + }, + { + "location_type": "CITY", + "name": "Palo, Eastern Visayas, Republic of the Philippines", + "targeting_type": "LOCATION", + "targeting_value": "00dddffa1a4337f7" + }, + { + "location_type": "CITY", + "name": "Palo del Colle, Bari, Puglia, Italy", + "targeting_type": "LOCATION", + "targeting_value": "388bbc752bdec0d4" + }, + { + "location_type": "POSTAL_CODE", + "name": "22337, Huesca, Aragon, Spain", + "targeting_type": "LOCATION", + "targeting_value": "776b0d5f31219aaa" + }, + { + "location_type": "POSTAL_CODE", + "name": "52324, IA, USA", + "targeting_type": "LOCATION", + "targeting_value": "0a230aaf5993f79e" + }, + { + "location_type": "POSTAL_CODE", + "name": "94303, CA, USA", + "targeting_type": "LOCATION", + "targeting_value": "0fe0bf9dce1a5019" + }, + { + "location_type": "POSTAL_CODE", + "name": "94301, CA, USA", + "targeting_type": "LOCATION", + "targeting_value": "205edf12aa812e1c" + }, + { + "location_type": "POSTAL_CODE", + "name": "94306, CA, USA", + "targeting_type": "LOCATION", + "targeting_value": "09dce9f0d7e0a871" + } + ], + "data_type": "targeting_criterion", + "next_cursor": null, + "request": { + "params": { + "q": "Palo%20Alto" + } + } +} diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-locations.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-locations.json new file mode 100644 index 00000000..8e189f5f --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-locations.json @@ -0,0 +1,1209 @@ +{ + "data": [ + { + "location_type": "POSTAL_CODE", + "name": "00601, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "10c4b91189877846" + }, + { + "location_type": "POSTAL_CODE", + "name": "00602, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "f6069e863e29e322" + }, + { + "location_type": "POSTAL_CODE", + "name": "00603, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "84e681a9fb76656f" + }, + { + "location_type": "POSTAL_CODE", + "name": "00606, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "03ee27c08cf99bea" + }, + { + "location_type": "POSTAL_CODE", + "name": "00610, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "f39bb92424252cee" + }, + { + "location_type": "POSTAL_CODE", + "name": "00612, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "8f88713a5e8554ff" + }, + { + "location_type": "POSTAL_CODE", + "name": "00617, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "f8c8159b1d3f7066" + }, + { + "location_type": "POSTAL_CODE", + "name": "00623, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "aefcbacb526e53da" + }, + { + "location_type": "POSTAL_CODE", + "name": "00624, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "df348c4baca1af62" + }, + { + "location_type": "POSTAL_CODE", + "name": "00627, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "e6bdc25f3891c234" + }, + { + "location_type": "POSTAL_CODE", + "name": "00631, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "08abe8ac0336121d" + }, + { + "location_type": "POSTAL_CODE", + "name": "00637, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "05eb0d4ee979e713" + }, + { + "location_type": "POSTAL_CODE", + "name": "00638, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "f0f8bd125cde4f21" + }, + { + "location_type": "POSTAL_CODE", + "name": "00641, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "6749c6ec3750f8b8" + }, + { + "location_type": "POSTAL_CODE", + "name": "00646, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "7c366cd1746ec4c3" + }, + { + "location_type": "POSTAL_CODE", + "name": "00647, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "d52e6b1178829431" + }, + { + "location_type": "POSTAL_CODE", + "name": "00650, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "06a5d4d9926ae0d1" + }, + { + "location_type": "POSTAL_CODE", + "name": "00653, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "8eed404cd06d3b8e" + }, + { + "location_type": "POSTAL_CODE", + "name": "00656, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "2d97991042e47f5e" + }, + { + "location_type": "POSTAL_CODE", + "name": "00659, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "158a9252b5c7defa" + }, + { + "location_type": "POSTAL_CODE", + "name": "00660, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "6c08f2abe7b507e4" + }, + { + "location_type": "POSTAL_CODE", + "name": "00662, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "0d5db929f44b3e55" + }, + { + "location_type": "POSTAL_CODE", + "name": "00664, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "8297417c95ed1be9" + }, + { + "location_type": "POSTAL_CODE", + "name": "00667, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "48febe80ae06a1e6" + }, + { + "location_type": "POSTAL_CODE", + "name": "00669, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "c20ec2e2d23d8f49" + }, + { + "location_type": "POSTAL_CODE", + "name": "00670, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "87f4090520bd0af8" + }, + { + "location_type": "POSTAL_CODE", + "name": "00674, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "ba19e640b3606cc3" + }, + { + "location_type": "POSTAL_CODE", + "name": "00676, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "0b12a33b75f5d424" + }, + { + "location_type": "POSTAL_CODE", + "name": "00677, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "7702a1eec8ad59dc" + }, + { + "location_type": "POSTAL_CODE", + "name": "00678, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "e19b9b8fe74091d6" + }, + { + "location_type": "POSTAL_CODE", + "name": "00680, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "5fffa373a235d503" + }, + { + "location_type": "POSTAL_CODE", + "name": "00682, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "be46d1ad49b7f709" + }, + { + "location_type": "POSTAL_CODE", + "name": "00683, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "1427cef4bfe4b1f5" + }, + { + "location_type": "POSTAL_CODE", + "name": "00685, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "759cc5105247c254" + }, + { + "location_type": "POSTAL_CODE", + "name": "00687, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "46d9c1e6feee7862" + }, + { + "location_type": "POSTAL_CODE", + "name": "00690, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "ef0c4d0b119688d0" + }, + { + "location_type": "POSTAL_CODE", + "name": "00692, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "6111c0dee6afe75d" + }, + { + "location_type": "POSTAL_CODE", + "name": "00693, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "aad8199bef272bc0" + }, + { + "location_type": "POSTAL_CODE", + "name": "00698, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "00d9edc0a738ef0e" + }, + { + "location_type": "POSTAL_CODE", + "name": "00703, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "ed8cffead51813dd" + }, + { + "location_type": "POSTAL_CODE", + "name": "00704, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "df1044486e47f59d" + }, + { + "location_type": "POSTAL_CODE", + "name": "00705, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "70a2f975db6d44d4" + }, + { + "location_type": "POSTAL_CODE", + "name": "00707, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "01ce2b94c85c1d33" + }, + { + "location_type": "POSTAL_CODE", + "name": "00714, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "73cac73531e89f45" + }, + { + "location_type": "POSTAL_CODE", + "name": "00715, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "a8889fd843731ea0" + }, + { + "location_type": "POSTAL_CODE", + "name": "00716, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "d21d308cda909c5f" + }, + { + "location_type": "POSTAL_CODE", + "name": "00717, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "78e2d47d7caa0c26" + }, + { + "location_type": "POSTAL_CODE", + "name": "00718, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "4e881e54531db20a" + }, + { + "location_type": "POSTAL_CODE", + "name": "00719, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "adb120e81315d214" + }, + { + "location_type": "POSTAL_CODE", + "name": "00720, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "4cc0b8a3324d7e2b" + }, + { + "location_type": "POSTAL_CODE", + "name": "00723, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "a6f1846278109db3" + }, + { + "location_type": "POSTAL_CODE", + "name": "00725, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "9ed90dee8326e226" + }, + { + "location_type": "POSTAL_CODE", + "name": "00727, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "cc33f54d28bc4e66" + }, + { + "location_type": "POSTAL_CODE", + "name": "00728, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "b8a0975a3165d2a4" + }, + { + "location_type": "POSTAL_CODE", + "name": "00729, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "13dbef9f15d8550c" + }, + { + "location_type": "POSTAL_CODE", + "name": "00730, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "b4982e47106ddf96" + }, + { + "location_type": "POSTAL_CODE", + "name": "00731, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "ba47f68cc80ba5a8" + }, + { + "location_type": "POSTAL_CODE", + "name": "00735, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "31b7472a8e8eb878" + }, + { + "location_type": "POSTAL_CODE", + "name": "00736, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "0b82fd85fda99f44" + }, + { + "location_type": "POSTAL_CODE", + "name": "00738, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "e6c985aa615630da" + }, + { + "location_type": "POSTAL_CODE", + "name": "00739, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "13eeec620e030e11" + }, + { + "location_type": "POSTAL_CODE", + "name": "00740, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "e508fde1895f891b" + }, + { + "location_type": "POSTAL_CODE", + "name": "00741, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "8796b2daabc2abd3" + }, + { + "location_type": "POSTAL_CODE", + "name": "00745, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "890ab7011cc7ff78" + }, + { + "location_type": "POSTAL_CODE", + "name": "00751, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "d7c99f3aade6c27b" + }, + { + "location_type": "POSTAL_CODE", + "name": "00754, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "7c58431cc36ced44" + }, + { + "location_type": "POSTAL_CODE", + "name": "00757, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "da88ec573bdfd515" + }, + { + "location_type": "POSTAL_CODE", + "name": "00765, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "746a8042a797f478" + }, + { + "location_type": "POSTAL_CODE", + "name": "00766, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "626bbabb1f7672e4" + }, + { + "location_type": "POSTAL_CODE", + "name": "00767, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "6a66d6cf8502016e" + }, + { + "location_type": "POSTAL_CODE", + "name": "00769, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "ef2ce925849898ca" + }, + { + "location_type": "POSTAL_CODE", + "name": "00771, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "4b4188ff2f5e24e9" + }, + { + "location_type": "POSTAL_CODE", + "name": "00772, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "2a598038265144ed" + }, + { + "location_type": "POSTAL_CODE", + "name": "00773, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "defce7c35d298a58" + }, + { + "location_type": "POSTAL_CODE", + "name": "00775, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "17cda568c7332098" + }, + { + "location_type": "POSTAL_CODE", + "name": "00777, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "38e680d73b8e0e5b" + }, + { + "location_type": "POSTAL_CODE", + "name": "00778, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "da19493cf4a9645e" + }, + { + "location_type": "POSTAL_CODE", + "name": "00780, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "17309a1190f93986" + }, + { + "location_type": "POSTAL_CODE", + "name": "00782, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "36c504b4f6305a84" + }, + { + "location_type": "POSTAL_CODE", + "name": "00783, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "6f578dff45e1a364" + }, + { + "location_type": "POSTAL_CODE", + "name": "00784, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "e902da078da923a0" + }, + { + "location_type": "POSTAL_CODE", + "name": "00791, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "81ddcc92db12a17d" + }, + { + "location_type": "POSTAL_CODE", + "name": "00794, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "0e330bc22b69681c" + }, + { + "location_type": "POSTAL_CODE", + "name": "00795, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "7eb6840d762bac41" + }, + { + "location_type": "POSTAL_CODE", + "name": "00901, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "7bce94d60a807b8b" + }, + { + "location_type": "POSTAL_CODE", + "name": "00907, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "4066187134ab3f74" + }, + { + "location_type": "POSTAL_CODE", + "name": "00909, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "9a3b0aa4818459bd" + }, + { + "location_type": "POSTAL_CODE", + "name": "00911, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "b03aa4e82928c5b6" + }, + { + "location_type": "POSTAL_CODE", + "name": "00912, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "10d376a1acbc8392" + }, + { + "location_type": "POSTAL_CODE", + "name": "00913, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "a259aa8e9b87068e" + }, + { + "location_type": "POSTAL_CODE", + "name": "00915, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "ebbab9870ecdede6" + }, + { + "location_type": "POSTAL_CODE", + "name": "00917, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "9b59d8b48c8045c3" + }, + { + "location_type": "POSTAL_CODE", + "name": "00918, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "6dd33636ef199a97" + }, + { + "location_type": "POSTAL_CODE", + "name": "00920, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "7b5a22775b02738a" + }, + { + "location_type": "POSTAL_CODE", + "name": "00921, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "afc161bb3cc6bcdf" + }, + { + "location_type": "POSTAL_CODE", + "name": "00923, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "62c060bd53cb5974" + }, + { + "location_type": "POSTAL_CODE", + "name": "00924, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "e2eb9f69e2a03186" + }, + { + "location_type": "POSTAL_CODE", + "name": "00925, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "46346fd43c822341" + }, + { + "location_type": "POSTAL_CODE", + "name": "00926, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "d5a189cf2e450ba9" + }, + { + "location_type": "POSTAL_CODE", + "name": "00927, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "016f7b28d6d60b82" + }, + { + "location_type": "POSTAL_CODE", + "name": "00934, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "d681aa602bbaa544" + }, + { + "location_type": "POSTAL_CODE", + "name": "00949, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "b74071a9248f9727" + }, + { + "location_type": "POSTAL_CODE", + "name": "00952, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "938864a7f01baa85" + }, + { + "location_type": "POSTAL_CODE", + "name": "00953, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "d2f5b181644cff15" + }, + { + "location_type": "POSTAL_CODE", + "name": "00956, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "0f6dd6901184e5d9" + }, + { + "location_type": "POSTAL_CODE", + "name": "00957, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "a3d47daefc97d442" + }, + { + "location_type": "POSTAL_CODE", + "name": "00959, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "30e77caf1add63f0" + }, + { + "location_type": "POSTAL_CODE", + "name": "00961, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "a247a1e1c0ab2e75" + }, + { + "location_type": "POSTAL_CODE", + "name": "00962, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "f9ac8efa93685dbb" + }, + { + "location_type": "POSTAL_CODE", + "name": "00965, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "c3ec5a31c46e9eda" + }, + { + "location_type": "POSTAL_CODE", + "name": "00966, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "a7d8b63ffc06ddd9" + }, + { + "location_type": "POSTAL_CODE", + "name": "00968, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "c92ae06a575c2e56" + }, + { + "location_type": "POSTAL_CODE", + "name": "00969, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "a31cd52c51512a66" + }, + { + "location_type": "POSTAL_CODE", + "name": "00976, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "08497554d7838172" + }, + { + "location_type": "POSTAL_CODE", + "name": "00979, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "7e6fadb868dff83f" + }, + { + "location_type": "POSTAL_CODE", + "name": "00982, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "7a784f3c428976ba" + }, + { + "location_type": "POSTAL_CODE", + "name": "00983, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "1ceef7de602037a9" + }, + { + "location_type": "POSTAL_CODE", + "name": "00985, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "db3785c25ec07c05" + }, + { + "location_type": "POSTAL_CODE", + "name": "00987, PR, US", + "targeting_type": "LOCATION", + "targeting_value": "2efd29f25df089f2" + }, + { + "location_type": "POSTAL_CODE", + "name": "01000 / Bourg-en-Bresse, FR", + "targeting_type": "LOCATION", + "targeting_value": "02ce6b8a6211cb1e" + }, + { + "location_type": "POSTAL_CODE", + "name": "01000, MX", + "targeting_type": "LOCATION", + "targeting_value": "44e09b48a57c693b" + }, + { + "location_type": "POSTAL_CODE", + "name": "01001 / Vitoria-Gasteiz, ES", + "targeting_type": "LOCATION", + "targeting_value": "388c514e2869630d" + }, + { + "location_type": "POSTAL_CODE", + "name": "01001, MA, US", + "targeting_type": "LOCATION", + "targeting_value": "b468a4da63b00bd0" + }, + { + "location_type": "POSTAL_CODE", + "name": "01002 / Vitoria-Gasteiz, ES", + "targeting_type": "LOCATION", + "targeting_value": "3f22db49e7725e2a" + }, + { + "location_type": "POSTAL_CODE", + "name": "01002, MA, US", + "targeting_type": "LOCATION", + "targeting_value": "6787aff1d1588039" + }, + { + "location_type": "POSTAL_CODE", + "name": "01003 / Vitoria-Gasteiz, ES", + "targeting_type": "LOCATION", + "targeting_value": "6c6278843c06bb0a" + }, + { + "location_type": "POSTAL_CODE", + "name": "01003, MA, US", + "targeting_type": "LOCATION", + "targeting_value": "7384577f5a475a2d" + }, + { + "location_type": "POSTAL_CODE", + "name": "01004 / Vitoria-Gasteiz, ES", + "targeting_type": "LOCATION", + "targeting_value": "7b7e1327b314a2c2" + }, + { + "location_type": "POSTAL_CODE", + "name": "01005 / Vitoria-Gasteiz, ES", + "targeting_type": "LOCATION", + "targeting_value": "4436caf7417c874b" + }, + { + "location_type": "POSTAL_CODE", + "name": "01005, BR", + "targeting_type": "LOCATION", + "targeting_value": "0b475fec75987346" + }, + { + "location_type": "POSTAL_CODE", + "name": "01005, MA, US", + "targeting_type": "LOCATION", + "targeting_value": "7565f8535782a8bb" + }, + { + "location_type": "POSTAL_CODE", + "name": "01006 / Vitoria-Gasteiz, ES", + "targeting_type": "LOCATION", + "targeting_value": "136330cac61dc83b" + }, + { + "location_type": "POSTAL_CODE", + "name": "01007 / Vitoria-Gasteiz, ES", + "targeting_type": "LOCATION", + "targeting_value": "73b6155506af6439" + }, + { + "location_type": "POSTAL_CODE", + "name": "01007, BR", + "targeting_type": "LOCATION", + "targeting_value": "3614542efb7cff54" + }, + { + "location_type": "POSTAL_CODE", + "name": "01007, MA, US", + "targeting_type": "LOCATION", + "targeting_value": "2b8f08e82ecaafe7" + }, + { + "location_type": "POSTAL_CODE", + "name": "01008 / Vitoria-Gasteiz, ES", + "targeting_type": "LOCATION", + "targeting_value": "11ef27775ca90e5f" + }, + { + "location_type": "POSTAL_CODE", + "name": "01008, MA, US", + "targeting_type": "LOCATION", + "targeting_value": "227b9a58d926589c" + }, + { + "location_type": "POSTAL_CODE", + "name": "01009 / Vitoria-Gasteiz, ES", + "targeting_type": "LOCATION", + "targeting_value": "300871b3f49baa3d" + }, + { + "location_type": "POSTAL_CODE", + "name": "01009, BR", + "targeting_type": "LOCATION", + "targeting_value": "6888d37ec6fa3d17" + }, + { + "location_type": "POSTAL_CODE", + "name": "01010 / Seyhan, TR", + "targeting_type": "LOCATION", + "targeting_value": "7472a2fd18cf31f2" + }, + { + "location_type": "POSTAL_CODE", + "name": "01010 / Vitoria-Gasteiz, ES", + "targeting_type": "LOCATION", + "targeting_value": "3e4d4d54909cd152" + }, + { + "location_type": "POSTAL_CODE", + "name": "01010, MA, US", + "targeting_type": "LOCATION", + "targeting_value": "b3a60da78a1dcde6" + }, + { + "location_type": "POSTAL_CODE", + "name": "01010, MX", + "targeting_type": "LOCATION", + "targeting_value": "6bd00f2f7b9daafb" + }, + { + "location_type": "POSTAL_CODE", + "name": "01011, MA, US", + "targeting_type": "LOCATION", + "targeting_value": "496eebfe319326e1" + }, + { + "location_type": "POSTAL_CODE", + "name": "01012 / Vitoria-Gasteiz, ES", + "targeting_type": "LOCATION", + "targeting_value": "2b0b90c1024a0944" + }, + { + "location_type": "POSTAL_CODE", + "name": "01012, BR", + "targeting_type": "LOCATION", + "targeting_value": "2bb6204f6b9fcfb7" + }, + { + "location_type": "POSTAL_CODE", + "name": "01012, MA, US", + "targeting_type": "LOCATION", + "targeting_value": "d815c7194dadedd1" + }, + { + "location_type": "POSTAL_CODE", + "name": "01013 / Vitoria-Gasteiz, ES", + "targeting_type": "LOCATION", + "targeting_value": "4472beedb240320e" + }, + { + "location_type": "POSTAL_CODE", + "name": "01013, MA, US", + "targeting_type": "LOCATION", + "targeting_value": "e4be0d92e6795520" + }, + { + "location_type": "POSTAL_CODE", + "name": "01015 / Vitoria-Gasteiz, ES", + "targeting_type": "LOCATION", + "targeting_value": "077a16d4b8f37448" + }, + { + "location_type": "POSTAL_CODE", + "name": "01015, BR", + "targeting_type": "LOCATION", + "targeting_value": "1cf3019d3d4f508c" + }, + { + "location_type": "POSTAL_CODE", + "name": "01016, BR", + "targeting_type": "LOCATION", + "targeting_value": "4f0fd49eb317c2ff" + }, + { + "location_type": "POSTAL_CODE", + "name": "01017, BR", + "targeting_type": "LOCATION", + "targeting_value": "06a9f48a1849f01a" + }, + { + "location_type": "POSTAL_CODE", + "name": "01019, BR", + "targeting_type": "LOCATION", + "targeting_value": "6b11c65ce8424b67" + }, + { + "location_type": "POSTAL_CODE", + "name": "01020 / Seyhan, TR", + "targeting_type": "LOCATION", + "targeting_value": "69f39b1738244f6f" + }, + { + "location_type": "POSTAL_CODE", + "name": "01020, MA, US", + "targeting_type": "LOCATION", + "targeting_value": "205bced14e952344" + }, + { + "location_type": "POSTAL_CODE", + "name": "01020, MX", + "targeting_type": "LOCATION", + "targeting_value": "3abd162d5fbe2066" + }, + { + "location_type": "POSTAL_CODE", + "name": "01022, BR", + "targeting_type": "LOCATION", + "targeting_value": "1b48e0ad26d9077c" + }, + { + "location_type": "POSTAL_CODE", + "name": "01022, MA, US", + "targeting_type": "LOCATION", + "targeting_value": "1e0c7ee5d333c2c5" + }, + { + "location_type": "POSTAL_CODE", + "name": "01026, BR", + "targeting_type": "LOCATION", + "targeting_value": "3db93400cfd24782" + }, + { + "location_type": "POSTAL_CODE", + "name": "01026, MA, US", + "targeting_type": "LOCATION", + "targeting_value": "08722390374b219c" + }, + { + "location_type": "POSTAL_CODE", + "name": "01027, MA, US", + "targeting_type": "LOCATION", + "targeting_value": "d606c01ed8161619" + }, + { + "location_type": "POSTAL_CODE", + "name": "01028, MA, US", + "targeting_type": "LOCATION", + "targeting_value": "dd967f462d338fab" + }, + { + "location_type": "POSTAL_CODE", + "name": "01030 / Seyhan, TR", + "targeting_type": "LOCATION", + "targeting_value": "429ca0892b9b2700" + }, + { + "location_type": "POSTAL_CODE", + "name": "01030, MA, US", + "targeting_type": "LOCATION", + "targeting_value": "c63450ea8d21df02" + }, + { + "location_type": "POSTAL_CODE", + "name": "01030, MX", + "targeting_type": "LOCATION", + "targeting_value": "38c9d0ef756869a6" + }, + { + "location_type": "POSTAL_CODE", + "name": "01031, BR", + "targeting_type": "LOCATION", + "targeting_value": "00f3d9855f63f8a5" + }, + { + "location_type": "POSTAL_CODE", + "name": "01031, MA, US", + "targeting_type": "LOCATION", + "targeting_value": "eab8f5661b84c3ff" + }, + { + "location_type": "POSTAL_CODE", + "name": "01032, MA, US", + "targeting_type": "LOCATION", + "targeting_value": "9893ff8ef8acd373" + }, + { + "location_type": "POSTAL_CODE", + "name": "01033, BR", + "targeting_type": "LOCATION", + "targeting_value": "625babd754013949" + }, + { + "location_type": "POSTAL_CODE", + "name": "01033, MA, US", + "targeting_type": "LOCATION", + "targeting_value": "1146f758eaa1cb13" + }, + { + "location_type": "POSTAL_CODE", + "name": "01034, MA, US", + "targeting_type": "LOCATION", + "targeting_value": "f9d2caafdeb47ed1" + }, + { + "location_type": "POSTAL_CODE", + "name": "01035, BR", + "targeting_type": "LOCATION", + "targeting_value": "42688abb61249316" + }, + { + "location_type": "POSTAL_CODE", + "name": "01035, MA, US", + "targeting_type": "LOCATION", + "targeting_value": "fa1c7aa4c35fb963" + }, + { + "location_type": "POSTAL_CODE", + "name": "01036, MA, US", + "targeting_type": "LOCATION", + "targeting_value": "0307dbcaa665b4f9" + }, + { + "location_type": "POSTAL_CODE", + "name": "01037, BR", + "targeting_type": "LOCATION", + "targeting_value": "01ca11e289119c72" + }, + { + "location_type": "POSTAL_CODE", + "name": "01038, MA, US", + "targeting_type": "LOCATION", + "targeting_value": "cbb05d349f323c16" + }, + { + "location_type": "POSTAL_CODE", + "name": "01039, MA, US", + "targeting_type": "LOCATION", + "targeting_value": "ae0e8c0cae80c6b9" + }, + { + "location_type": "POSTAL_CODE", + "name": "01040 / Seyhan, TR", + "targeting_type": "LOCATION", + "targeting_value": "32ea23bdc0fc06b0" + }, + { + "location_type": "POSTAL_CODE", + "name": "01040, MA, US", + "targeting_type": "LOCATION", + "targeting_value": "2fc5aa29f1e53d1f" + }, + { + "location_type": "POSTAL_CODE", + "name": "01040, MX", + "targeting_type": "LOCATION", + "targeting_value": "31a41bfedc241e98" + }, + { + "location_type": "POSTAL_CODE", + "name": "01049, MX", + "targeting_type": "LOCATION", + "targeting_value": "2f341c8d6d25c23d" + }, + { + "location_type": "POSTAL_CODE", + "name": "01050 / Seyhan, TR", + "targeting_type": "LOCATION", + "targeting_value": "34b4f65184210d04" + }, + { + "location_type": "POSTAL_CODE", + "name": "01050, BR", + "targeting_type": "LOCATION", + "targeting_value": "6e1a73ad2e6d661e" + }, + { + "location_type": "POSTAL_CODE", + "name": "01050, MA, US", + "targeting_type": "LOCATION", + "targeting_value": "ef768ba694e456d3" + }, + { + "location_type": "POSTAL_CODE", + "name": "01050, MX", + "targeting_type": "LOCATION", + "targeting_value": "4700bd18dc2fb166" + }, + { + "location_type": "POSTAL_CODE", + "name": "01053, MA, US", + "targeting_type": "LOCATION", + "targeting_value": "c27dec25eb6fb8a4" + }, + { + "location_type": "POSTAL_CODE", + "name": "01054, MA, US", + "targeting_type": "LOCATION", + "targeting_value": "3add3f42201c8ad9" + }, + { + "location_type": "POSTAL_CODE", + "name": "01056, MA, US", + "targeting_type": "LOCATION", + "targeting_value": "7de8b973018103ca" + }, + { + "location_type": "POSTAL_CODE", + "name": "01057, MA, US", + "targeting_type": "LOCATION", + "targeting_value": "bcedbfa397784b8c" + }, + { + "location_type": "POSTAL_CODE", + "name": "01060 / Seyhan, TR", + "targeting_type": "LOCATION", + "targeting_value": "25c05d558aca0750" + }, + { + "location_type": "POSTAL_CODE", + "name": "01060, MA, US", + "targeting_type": "LOCATION", + "targeting_value": "989e89030fbb9194" + }, + { + "location_type": "POSTAL_CODE", + "name": "01060, MX", + "targeting_type": "LOCATION", + "targeting_value": "1f6aaa28bb8e315b" + }, + { + "location_type": "POSTAL_CODE", + "name": "01062, MA, US", + "targeting_type": "LOCATION", + "targeting_value": "3e35bddba1c05b80" + }, + { + "location_type": "POSTAL_CODE", + "name": "01063, MA, US", + "targeting_type": "LOCATION", + "targeting_value": "46d30f7f32968c63" + }, + { + "location_type": "POSTAL_CODE", + "name": "01068, MA, US", + "targeting_type": "LOCATION", + "targeting_value": "a887d99ec70103bf" + }, + { + "location_type": "POSTAL_CODE", + "name": "01069, MA, US", + "targeting_type": "LOCATION", + "targeting_value": "66af4fe8f2f4bdcd" + }, + { + "location_type": "POSTAL_CODE", + "name": "01070 / Seyhan, TR", + "targeting_type": "LOCATION", + "targeting_value": "21c8118c31bb518a" + }, + { + "location_type": "POSTAL_CODE", + "name": "01070, MA, US", + "targeting_type": "LOCATION", + "targeting_value": "f49db7bbebe3b257" + }, + { + "location_type": "POSTAL_CODE", + "name": "01070, MX", + "targeting_type": "LOCATION", + "targeting_value": "0d7a95bc769961d4" + } + ], + "data_type": "targeting_criterion", + "next_cursor": "1c27vt9rbi8d60ayq0u3awo3k", + "request": { + "params": {} + } +} \ No newline at end of file diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-network_operators-params.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-network_operators-params.json new file mode 100644 index 00000000..31cbda17 --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-network_operators-params.json @@ -0,0 +1,54 @@ +{ + "data": [ + { + "country_code": "US", + "name": "Big Sky Mobile", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "3n" + }, + { + "country_code": "US", + "name": "Lycamobile", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "41" + }, + { + "country_code": "US", + "name": "MobileTel", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "1a" + }, + { + "country_code": "US", + "name": "SeaMobile", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "1x" + }, + { + "country_code": "US", + "name": "T-Mobile", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "11" + }, + { + "country_code": "US", + "name": "telna Mobile", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "3r" + }, + { + "country_code": "US", + "name": "Virgin Mobile US", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "3k" + } + ], + "data_type": "targeting_criterion", + "next_cursor": null, + "request": { + "params": { + "country_code": "US", + "q": "Mobile" + } + } +} \ No newline at end of file diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-network_operators.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-network_operators.json new file mode 100644 index 00000000..cbd6f115 --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-network_operators.json @@ -0,0 +1,1209 @@ +{ + "data": [ + { + "country_code": "GB", + "name": "3", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "4i" + }, + { + "country_code": "ID", + "name": "3", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "6e" + }, + { + "country_code": "AU", + "name": "3", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "at" + }, + { + "country_code": "SE", + "name": "3", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "f6" + }, + { + "country_code": "IE", + "name": "3", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "gv" + }, + { + "country_code": "IT", + "name": "3 Italia", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "cv" + }, + { + "country_code": "AU", + "name": "3GIS", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "az" + }, + { + "country_code": "UA", + "name": "3Mob", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "ha" + }, + { + "country_code": "SE", + "name": "42 Telecom AB", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "fj" + }, + { + "country_code": "SE", + "name": "42 Telecom LTD", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "g2" + }, + { + "country_code": "NL", + "name": "6GMOBILE B.V.", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "d8" + }, + { + "country_code": "AU", + "name": "AAPT", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "ay" + }, + { + "country_code": "PH", + "name": "ABS-CBN", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "cc" + }, + { + "country_code": "IE", + "name": "Access Telecom", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "gu" + }, + { + "country_code": "AU", + "name": "Advanced Communications Technologies Pty. Ltd.", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "b8" + }, + { + "country_code": "US", + "name": "Advantage", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "2l" + }, + { + "country_code": "BR", + "name": "aeiou", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "6u" + }, + { + "country_code": "US", + "name": "Aeris", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "1b" + }, + { + "country_code": "FR", + "name": "Afone", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "8q" + }, + { + "country_code": "NL", + "name": "AGMS Netherlands B.V.", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "ds" + }, + { + "country_code": "US", + "name": "Airadigm", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "2t" + }, + { + "country_code": "IN", + "name": "AIRCEL", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "7z" + }, + { + "country_code": "DE", + "name": "Airdata", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "aa" + }, + { + "country_code": "US", + "name": "Airlink PCS", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "14" + }, + { + "country_code": "AU", + "name": "Airnet", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "av" + }, + { + "country_code": "US", + "name": "Airpeak", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "1i" + }, + { + "country_code": "US", + "name": "Airtel", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "2m" + }, + { + "country_code": "IN", + "name": "AirTel", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "7w" + }, + { + "country_code": "CA", + "name": "Airtel Wireless", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "j" + }, + { + "country_code": "GB", + "name": "Airtel-Vodafone", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "46" + }, + { + "country_code": "GB", + "name": "Airwave", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "53" + }, + { + "country_code": "TH", + "name": "AIS", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "ec" + }, + { + "country_code": "TH", + "name": "AIS 3G", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "ee" + }, + { + "country_code": "TH", + "name": "AIS GSM 1800", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "ek" + }, + { + "country_code": "SA", + "name": "Al Jawal (STC )", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "6w" + }, + { + "country_code": "US", + "name": "Alaska Digitel", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "15" + }, + { + "country_code": "CA", + "name": "Aliant Mobility", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "5j" + }, + { + "country_code": "US", + "name": "Alltel", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "2r" + }, + { + "country_code": "US", + "name": "Alltel US", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "3l" + }, + { + "country_code": "SE", + "name": "Alltele F\u00f6retag Sverige AB", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "fg" + }, + { + "country_code": "CA", + "name": "ALO", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "5a" + }, + { + "country_code": "MY", + "name": "Altel", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "e6" + }, + { + "country_code": "BR", + "name": "Amazonia Celular", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "6p" + }, + { + "country_code": "US", + "name": "AmeriLink PCS", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "1s" + }, + { + "country_code": "US", + "name": "Appalachian Wireless", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "3q" + }, + { + "country_code": "TW", + "name": "APTG", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "hf" + }, + { + "country_code": "GB", + "name": "aql", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "4q" + }, + { + "country_code": "NL", + "name": "ASPIDER Solutions Nederland B.V.", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "dh" + }, + { + "country_code": "FR", + "name": "Astrium SAS", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "8r" + }, + { + "country_code": "US", + "name": "AT&T", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "1d" + }, + { + "country_code": "MY", + "name": "ATUR 450", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "dx" + }, + { + "country_code": "JP", + "name": "au", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "5z" + }, + { + "country_code": "AU", + "name": "Ausgrid Corporation", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "b4" + }, + { + "country_code": "CO", + "name": "AVANTEL", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "c5" + }, + { + "country_code": "TR", + "name": "Avea", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "77" + }, + { + "country_code": "ID", + "name": "AXIS", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "66" + }, + { + "country_code": "TR", + "name": "Aycell", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "78" + }, + { + "country_code": "ES", + "name": "Barablu", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "7n" + }, + { + "country_code": "MY", + "name": "Baraka Telecom Sdn Bhd (MVNE)", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "e4" + }, + { + "country_code": "BE", + "name": "BASE", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "bv" + }, + { + "country_code": "RU", + "name": "Baykalwestcom", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "99" + }, + { + "country_code": "CA", + "name": "BC Tel Mobility (Telus)", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "5k" + }, + { + "country_code": "RU", + "name": "Beeline", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "9h" + }, + { + "country_code": "UA", + "name": "Beeline", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "h5" + }, + { + "country_code": "SE", + "name": "Beepsend AB", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "ft" + }, + { + "country_code": "CA", + "name": "Bell", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "d" + }, + { + "country_code": "CA", + "name": "Bell / Telus / SaskTel", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "a" + }, + { + "country_code": "CA", + "name": "Bell(Virgin mobile)", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "a1" + }, + { + "country_code": "AU", + "name": "BHP Billiton", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "be" + }, + { + "country_code": "US", + "name": "Big River Broadband", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "42" + }, + { + "country_code": "US", + "name": "Big Sky Mobile", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "3n" + }, + { + "country_code": "IT", + "name": "Blu", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "cu" + }, + { + "country_code": "CL", + "name": "Blue Two Chile S.A.", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "et" + }, + { + "country_code": "NL", + "name": "BodyTrace Netherlands B.V.", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "dp" + }, + { + "country_code": "ZA", + "name": "Bokamoso Consortium", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "gl" + }, + { + "country_code": "US", + "name": "Boost", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "40" + }, + { + "country_code": "FR", + "name": "Bouygues", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "8l" + }, + { + "country_code": "BR", + "name": "Brasil Telecom GSM", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "6n" + }, + { + "country_code": "NL", + "name": "Breezz Nederland B.V.", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "dl" + }, + { + "country_code": "GB", + "name": "BT", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "3e" + }, + { + "country_code": "ES", + "name": "BT", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "7f" + }, + { + "country_code": "IT", + "name": "BT Italia", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "cq" + }, + { + "country_code": "US", + "name": "Bug Tussel Wireless", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "3x" + }, + { + "country_code": "US", + "name": "C Spire Wireless", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "3w" + }, + { + "country_code": "GB", + "name": "Cable & Wireless Guernsey / Sure Mobile (Jersey)", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "52" + }, + { + "country_code": "GB", + "name": "Cable & Wireless UK", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "57" + }, + { + "country_code": "GB", + "name": "Cable & Wireless Worldwide", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "4a" + }, + { + "country_code": "ZA", + "name": "Cape Town Metropolitan Council", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "gk" + }, + { + "country_code": "US", + "name": "Caprock", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "1j" + }, + { + "country_code": "NL", + "name": "CapX B.V.", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "dj" + }, + { + "country_code": "US", + "name": "Carolina Phone", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "r" + }, + { + "country_code": "TH", + "name": "CAT CDMA", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "ed" + }, + { + "country_code": "DE", + "name": "CCC Event", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "ah" + }, + { + "country_code": "UA", + "name": "CDMA Ukraine", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "hc" + }, + { + "country_code": "MY", + "name": "Celcom", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "e1" + }, + { + "country_code": "ZA", + "name": "Cell C", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "gf" + }, + { + "country_code": "US", + "name": "Cell One Amarillo", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "2g" + }, + { + "country_code": "IN", + "name": "CellOne", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "81" + }, + { + "country_code": "US", + "name": "Cellular One", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "23" + }, + { + "country_code": "US", + "name": "Cellular One of East Texas", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "2k" + }, + { + "country_code": "US", + "name": "Cellular Properties", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "x" + }, + { + "country_code": "CL", + "name": "Celupago S.A.", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "ew" + }, + { + "country_code": "ID", + "name": "Ceria", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "6c" + }, + { + "country_code": "AU", + "name": "Challenge Networks Pty. Ltd.", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "b7" + }, + { + "country_code": "US", + "name": "Chariton Valley", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "1p" + }, + { + "country_code": "US", + "name": "Choice Phone", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "y" + }, + { + "country_code": "TW", + "name": "Chunghwa LDM", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "hg" + }, + { + "country_code": "TW", + "name": "Chungwa", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "hi" + }, + { + "country_code": "CL", + "name": "Cibeles Telecom S.A.", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "f0" + }, + { + "country_code": "US", + "name": "Cincinnati Bell", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "2y" + }, + { + "country_code": "US", + "name": "Cingular Wireless", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "1f" + }, + { + "country_code": "CA", + "name": "CityTel Mobility", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "5m" + }, + { + "country_code": "AR", + "name": "Claro", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "9t" + }, + { + "country_code": "CO", + "name": "Claro", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "c2" + }, + { + "country_code": "CL", + "name": "Claro", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "eq" + }, + { + "country_code": "PE", + "name": "Claro (TIM)", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "h2" + }, + { + "country_code": "BR", + "name": "Claro BR", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "6k" + }, + { + "country_code": "IE", + "name": "Clever Communications", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "gx" + }, + { + "country_code": "GB", + "name": "Cloud9", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "3j" + }, + { + "country_code": "SE", + "name": "CLX Networks AB", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "g4" + }, + { + "country_code": "US", + "name": "Coleman County Telecom", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "2n" + }, + { + "country_code": "CO", + "name": "Colombia Telecomunicaciones S.A.", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "by" + }, + { + "country_code": "GB", + "name": "COLT Mobile Telecommunications Limited", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "48" + }, + { + "country_code": "FR", + "name": "Com4Innov", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "8y" + }, + { + "country_code": "US", + "name": "Commnet Wireless", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "27" + }, + { + "country_code": "ES", + "name": "Compatel Limited", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "7s" + }, + { + "country_code": "AU", + "name": "Compatel Limited", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "bd" + }, + { + "country_code": "SE", + "name": "Compatel Limited", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "fz" + }, + { + "country_code": "FR", + "name": "Completel Mobile", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "8f" + }, + { + "country_code": "US", + "name": "Concho", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "2x" + }, + { + "country_code": "US", + "name": "Consolidated Telcom", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "1y" + }, + { + "country_code": "ES", + "name": "Consorcio de Telecomunicaciones Avanzadas, S.A.", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "7q" + }, + { + "country_code": "US", + "name": "Convey", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "1e" + }, + { + "country_code": "SE", + "name": "CoolTEL Aps", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "fv" + }, + { + "country_code": "US", + "name": "Corr", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "25" + }, + { + "country_code": "AU", + "name": "Crazy John's", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "bf" + }, + { + "country_code": "US", + "name": "Cricket Communications", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "2i" + }, + { + "country_code": "BR", + "name": "CTBC Celular", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "6r" + }, + { + "country_code": "PH", + "name": "Cure", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "cb" + }, + { + "country_code": "BR", + "name": "Datora", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "6o" + }, + { + "country_code": "DE", + "name": "DB Netz AG", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "a6" + }, + { + "country_code": "DE", + "name": "DB Telematik", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "aj" + }, + { + "country_code": "DE", + "name": "Debitel", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "an" + }, + { + "country_code": "AU", + "name": "Department of Defence", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "ar" + }, + { + "country_code": "AU", + "name": "Dialogue Communications Pty. Ltd.", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "ba" + }, + { + "country_code": "MY", + "name": "DiGi", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "e7" + }, + { + "country_code": "MY", + "name": "DiGi Telecommunications", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "dy" + }, + { + "country_code": "ES", + "name": "DigiMobil", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "7m" + }, + { + "country_code": "VE", + "name": "Digitel", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "9w" + }, + { + "country_code": "VE", + "name": "Digitel GSM", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "9x" + }, + { + "country_code": "SE", + "name": "Digitel Mobile Srl", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "fs" + }, + { + "country_code": "IN", + "name": "Dishnet Wireless", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "82" + }, + { + "country_code": "SE", + "name": "djuice", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "fc" + }, + { + "country_code": "CA", + "name": "DMTS", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "9" + }, + { + "country_code": "IN", + "name": "DOLPHIN", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "83" + }, + { + "country_code": "DE", + "name": "Dolphin Telecom", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "a7" + }, + { + "country_code": "TH", + "name": "dtac", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "ej" + }, + { + "country_code": "TH", + "name": "dtac TriNet", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "eg" + }, + { + "country_code": "RU", + "name": "DTC", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "97" + }, + { + "country_code": "AE", + "name": "du", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "bx" + }, + { + "country_code": "US", + "name": "Dutch Harbor", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "2e" + }, + { + "country_code": "DE", + "name": "E-Plus", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "a4" + }, + { + "country_code": "US", + "name": "Easterbrooke", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "2w" + }, + { + "country_code": "CA", + "name": "EastLink", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "5b" + }, + { + "country_code": "CO", + "name": "Edatel", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "bz" + }, + { + "country_code": "GB", + "name": "EE", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "54" + }, + { + "country_code": "MY", + "name": "Electcoms Wireless Sdn Bhd", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "ea" + }, + { + "country_code": "NL", + "name": "Elephant Talk Communications Premium Rate Services", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "d0" + }, + { + "country_code": "BE", + "name": "Elephant Talk Communications Schweiz GmbH", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "bu" + }, + { + "country_code": "IT", + "name": "Elsacom", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "ck" + }, + { + "country_code": "CO", + "name": "EMCALI", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "c1" + }, + { + "country_code": "US", + "name": "Emery Telcom Wireless", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "3v" + }, + { + "country_code": "JP", + "name": "eMobile", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "5v" + }, + { + "country_code": "IE", + "name": "eMobile", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "gw" + }, + { + "country_code": "CO", + "name": "Emtelsa", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "c0" + }, + { + "country_code": "US", + "name": "Endless Mountains Wireless", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "1c" + }, + { + "country_code": "CL", + "name": "entel", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "eo" + }, + { + "country_code": "US", + "name": "Epic Touch", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "1z" + }, + { + "country_code": "ZA", + "name": "Ericsson South Africa (Pty) Ltd", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "gp" + }, + { + "country_code": "ES", + "name": "Eroski", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "7o" + }, + { + "country_code": "ID", + "name": "Esia", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "6f" + }, + { + "country_code": "AE", + "name": "Etisalat", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "bw" + }, + { + "country_code": "EG", + "name": "Etisalat", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "f4" + }, + { + "country_code": "IN", + "name": "Etisalat DB(cheers)", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "8a" + }, + { + "country_code": "RU", + "name": "ETK", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "94" + }, + { + "country_code": "ES", + "name": "Euskaltel", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "7e" + }, + { + "country_code": "SE", + "name": "EuTel AB", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "fp" + }, + { + "country_code": "CA", + "name": "Execulink", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "5c" + }, + { + "country_code": "TW", + "name": "FarEasTone", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "he" + }, + { + "country_code": "US", + "name": "Farmers Cellular", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "1g" + }, + { + "country_code": "US", + "name": "Farmers Wireless", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "2o" + }, + { + "country_code": "CA", + "name": "Fido", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "c" + }, + { + "country_code": "CA", + "name": "FIRST", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "2" + }, + { + "country_code": "US", + "name": "First Cellular", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "2u" + }, + { + "country_code": "DE", + "name": "First Telecom GmbH", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "ag" + }, + { + "country_code": "GB", + "name": "FleXtel Limited", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "4g" + }, + { + "country_code": "GB", + "name": "FMS Solutions Ltd", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "47" + }, + { + "country_code": "SE", + "name": "Fogg Mobile AB", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "fu" + }, + { + "country_code": "ES", + "name": "Fonyou", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "7k" + }, + { + "country_code": "FR", + "name": "Free Mobile", + "targeting_type": "NETWORK_OPERATOR", + "targeting_value": "8i" + } + ], + "data_type": "targeting_criterion", + "next_cursor": "9mxdk55xbdthjv0rt9lgzak9vk", + "request": { + "params": {} + } +} \ No newline at end of file diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-platform_versions-params.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-platform_versions-params.json new file mode 100644 index 00000000..79b5d70c --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-platform_versions-params.json @@ -0,0 +1,17 @@ +{ + "data": [ + { + "name": "Cupcake", + "number": "1.5", + "platform": "Android", + "targeting_type": "PLATFORM_VERSION", + "targeting_value": "b" + } + ], + "data_type": "targeting_criterion", + "request": { + "params": { + "q": "cupcake" + } + } +} \ No newline at end of file diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-platform_versions.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-platform_versions.json new file mode 100644 index 00000000..71cf9d1d --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-platform_versions.json @@ -0,0 +1,162 @@ +{ + "data": [ + { + "name": "4.0", + "number": "4.0", + "platform": "iOS", + "targeting_type": "PLATFORM_VERSION", + "targeting_value": "1" + }, + { + "name": "4.1", + "number": "4.1", + "platform": "iOS", + "targeting_type": "PLATFORM_VERSION", + "targeting_value": "2" + }, + { + "name": "4.2", + "number": "4.2", + "platform": "iOS", + "targeting_type": "PLATFORM_VERSION", + "targeting_value": "3" + }, + { + "name": "4.3", + "number": "4.3", + "platform": "iOS", + "targeting_type": "PLATFORM_VERSION", + "targeting_value": "4" + }, + { + "name": "5.0", + "number": "5.0", + "platform": "iOS", + "targeting_type": "PLATFORM_VERSION", + "targeting_value": "5" + }, + { + "name": "5.1", + "number": "5.1", + "platform": "iOS", + "targeting_type": "PLATFORM_VERSION", + "targeting_value": "6" + }, + { + "name": "6.0", + "number": "6.0", + "platform": "iOS", + "targeting_type": "PLATFORM_VERSION", + "targeting_value": "7" + }, + { + "name": "6.1", + "number": "6.1", + "platform": "iOS", + "targeting_type": "PLATFORM_VERSION", + "targeting_value": "8" + }, + { + "name": "7.0", + "number": "7.0", + "platform": "iOS", + "targeting_type": "PLATFORM_VERSION", + "targeting_value": "9" + }, + { + "name": "7.1", + "number": "7.1", + "platform": "iOS", + "targeting_type": "PLATFORM_VERSION", + "targeting_value": "a" + }, + { + "name": "8.0", + "number": "8.0", + "platform": "iOS", + "targeting_type": "PLATFORM_VERSION", + "targeting_value": "j" + }, + { + "name": "8.3", + "number": "8.3", + "platform": "iOS", + "targeting_type": "PLATFORM_VERSION", + "targeting_value": "m" + }, + { + "name": "Cupcake", + "number": "1.5", + "platform": "Android", + "targeting_type": "PLATFORM_VERSION", + "targeting_value": "b" + }, + { + "name": "Donut", + "number": "1.6", + "platform": "Android", + "targeting_type": "PLATFORM_VERSION", + "targeting_value": "c" + }, + { + "name": "Eclair", + "number": "2.0", + "platform": "Android", + "targeting_type": "PLATFORM_VERSION", + "targeting_value": "d" + }, + { + "name": "Froyo", + "number": "2.2", + "platform": "Android", + "targeting_type": "PLATFORM_VERSION", + "targeting_value": "e" + }, + { + "name": "Gingerbread", + "number": "2.3", + "platform": "Android", + "targeting_type": "PLATFORM_VERSION", + "targeting_value": "f" + }, + { + "name": "Honeycomb", + "number": "3.0", + "platform": "Android", + "targeting_type": "PLATFORM_VERSION", + "targeting_value": "g" + }, + { + "name": "Ice Cream Sandwich", + "number": "4.0", + "platform": "Android", + "targeting_type": "PLATFORM_VERSION", + "targeting_value": "h" + }, + { + "name": "Jelly Bean", + "number": "4.1", + "platform": "Android", + "targeting_type": "PLATFORM_VERSION", + "targeting_value": "i" + }, + { + "name": "Kit Kat", + "number": "4.4", + "platform": "Android", + "targeting_type": "PLATFORM_VERSION", + "targeting_value": "k" + }, + { + "name": "Lollipop", + "number": "5.0", + "platform": "Android", + "targeting_type": "PLATFORM_VERSION", + "targeting_value": "l" + } + ], + "data_type": "targeting_criterion", + "request": { + "params": {} + } +} \ No newline at end of file diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-platforms-params.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-platforms-params.json new file mode 100644 index 00000000..d38fbe5e --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-platforms-params.json @@ -0,0 +1,15 @@ +{ + "data": [ + { + "name": "BlackBerry phones and tablets", + "targeting_type": "PLATFORM", + "targeting_value": "2" + } + ], + "data_type": "targeting_criterion", + "request": { + "params": { + "q": "blackberry" + } + } +} \ No newline at end of file diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-platforms.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-platforms.json new file mode 100644 index 00000000..9a9a0134 --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-platforms.json @@ -0,0 +1,33 @@ +{ + "data": [ + { + "name": "iOS", + "targeting_type": "PLATFORM", + "targeting_value": "0" + }, + { + "name": "Android", + "targeting_type": "PLATFORM", + "targeting_value": "1" + }, + { + "name": "BlackBerry phones and tablets", + "targeting_type": "PLATFORM", + "targeting_value": "2" + }, + { + "name": "Mobile web on other devices", + "targeting_type": "PLATFORM", + "targeting_value": "3" + }, + { + "name": "Desktop and laptop computers", + "targeting_type": "PLATFORM", + "targeting_value": "4" + } + ], + "data_type": "targeting_criterion", + "request": { + "params": {} + } +} \ No newline at end of file diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-tv_channels.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-tv_channels.json new file mode 100644 index 00000000..f22dbb0d --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-tv_channels.json @@ -0,0 +1,809 @@ +{ + "data": [ + { + "id": "1003", + "name": "ESPN" + }, + { + "id": "1004", + "name": "Cartoon Network" + }, + { + "id": "1005", + "name": "MTV" + }, + { + "id": "1006", + "name": "ABC" + }, + { + "id": "1007", + "name": "NBC" + }, + { + "id": "1008", + "name": "CBS" + }, + { + "id": "1009", + "name": "MSNBC" + }, + { + "id": "1010", + "name": "TNT" + }, + { + "id": "1011", + "name": "Spike" + }, + { + "id": "1021", + "name": "CNN" + }, + { + "id": "1897", + "name": "FOX" + }, + { + "id": "1898", + "name": "AMC" + }, + { + "id": "1900", + "name": "BET" + }, + { + "id": "1901", + "name": "BRAVO" + }, + { + "id": "1908", + "name": "HLN" + }, + { + "id": "1909", + "name": "Comedy Central" + }, + { + "id": "1947", + "name": "SYFY" + }, + { + "id": "1964", + "name": "USA" + }, + { + "id": "1981", + "name": "CW" + }, + { + "id": "1997", + "name": "ESPN2" + }, + { + "id": "2002", + "name": "FOOD" + }, + { + "id": "2025", + "name": "FX" + }, + { + "id": "2041", + "name": "HGTV" + }, + { + "id": "2075", + "name": "Fox News" + }, + { + "id": "2811", + "name": "TBS" + }, + { + "id": "2833", + "name": "A&E" + }, + { + "id": "2834", + "name": "E!" + }, + { + "id": "2835", + "name": "TLC" + }, + { + "id": "2836", + "name": "WE tv" + }, + { + "id": "2838", + "name": "OXYGEN" + }, + { + "id": "2839", + "name": "LOGO" + }, + { + "id": "2840", + "name": "OWN" + }, + { + "id": "2841", + "name": "CNBC" + }, + { + "id": "2842", + "name": "History" + }, + { + "id": "2843", + "name": "Discovery Channel" + }, + { + "id": "2844", + "name": "Travel Channel" + }, + { + "id": "2846", + "name": "VH1" + }, + { + "id": "2847", + "name": "MTV2" + }, + { + "id": "2848", + "name": "National Geographic Channel" + }, + { + "id": "2849", + "name": "ESPNU" + }, + { + "id": "2850", + "name": "TRUTV" + }, + { + "id": "2851", + "name": "Lifetime" + }, + { + "id": "2852", + "name": "TV Land" + }, + { + "id": "2853", + "name": "CBS Sports Network" + }, + { + "id": "2855", + "name": "Disney Channel" + }, + { + "id": "2856", + "name": "Nickelodeon" + }, + { + "id": "2857", + "name": "Fuse" + }, + { + "id": "2858", + "name": "NBC Sports Network" + }, + { + "id": "2860", + "name": "NFL NETWORK" + }, + { + "id": "2861", + "name": "SCIENCE" + }, + { + "id": "2862", + "name": "ABC Family" + }, + { + "id": "2863", + "name": "Hallmark" + }, + { + "id": "2864", + "name": "GSN" + }, + { + "id": "2866", + "name": "Investigation Discovery" + }, + { + "id": "2867", + "name": "WGN America" + }, + { + "id": "2870", + "name": "Animal Planet" + }, + { + "id": "2889", + "name": "BBCA" + }, + { + "id": "2892", + "name": "Cinemax" + }, + { + "id": "2893", + "name": "CMT Country Music Television" + }, + { + "id": "2895", + "name": "HBO" + }, + { + "id": "2898", + "name": "Showtime" + }, + { + "id": "2901", + "name": "Starz" + }, + { + "id": "2907", + "name": "IFC" + }, + { + "id": "2911", + "name": "Sundance" + }, + { + "id": "2919", + "name": "Disney XD" + }, + { + "id": "2922", + "name": "Lifetime Movie Network" + }, + { + "id": "2923", + "name": "Nick Jr" + }, + { + "id": "2934", + "name": "Nicktoons Network" + }, + { + "id": "2937", + "name": "Chiller" + }, + { + "id": "2938", + "name": "Teen Nick" + }, + { + "id": "2939", + "name": "Hallmark Movie" + }, + { + "id": "2941", + "name": "National Geographic Wild" + }, + { + "id": "2945", + "name": "fyi" + }, + { + "id": "2952", + "name": "Telemundo" + }, + { + "id": "2954", + "name": "Univision" + }, + { + "id": "2955", + "name": "The Weather Channel" + }, + { + "id": "2961", + "name": "NBC-U" + }, + { + "id": "2962", + "name": "Centric" + }, + { + "id": "2963", + "name": "The Golf Channel" + }, + { + "id": "2965", + "name": "Fox Deportes" + }, + { + "id": "2967", + "name": "Great American Country" + }, + { + "id": "2971", + "name": "ESPNEWS" + }, + { + "id": "2973", + "name": "Discovery Family" + }, + { + "id": "2980", + "name": "DIY" + }, + { + "id": "2988", + "name": "Boomerang" + }, + { + "id": "2989", + "name": "VH1 Classic" + }, + { + "id": "2992", + "name": "ESPN Deportes" + }, + { + "id": "2999", + "name": "PBS" + }, + { + "id": "3003", + "name": "Cooking Channel" + }, + { + "id": "3006", + "name": "NBA TV" + }, + { + "id": "3014", + "name": "mtv-U" + }, + { + "id": "3019", + "name": "PBS Kids" + }, + { + "id": "3029", + "name": "Big Ten Network" + }, + { + "id": "3031", + "name": "Fox Business" + }, + { + "id": "3037", + "name": "H2" + }, + { + "id": "3047", + "name": "Adult Swim" + }, + { + "id": "3048", + "name": "Nick at Nite" + }, + { + "id": "3049", + "name": "TV ONE" + }, + { + "id": "3051", + "name": "nuvoTV" + }, + { + "id": "3052", + "name": "Pay Per View" + }, + { + "id": "3082", + "name": "ITV" + }, + { + "id": "3083", + "name": "Channel 4" + }, + { + "id": "3084", + "name": "Channel 5" + }, + { + "id": "3085", + "name": "ITV2" + }, + { + "id": "3086", + "name": "More4" + }, + { + "id": "3087", + "name": "ITV3" + }, + { + "id": "3088", + "name": "E4" + }, + { + "id": "3089", + "name": "Film4" + }, + { + "id": "3090", + "name": "Dave" + }, + { + "id": "3091", + "name": "ITV4" + }, + { + "id": "3092", + "name": "Sky 1" + }, + { + "id": "3095", + "name": "Sky News" + }, + { + "id": "3098", + "name": "Sky Living" + }, + { + "id": "3099", + "name": "Sky Sports 1" + }, + { + "id": "3101", + "name": "Comedy Central" + }, + { + "id": "3102", + "name": "BBC One" + }, + { + "id": "3103", + "name": "BBC Two" + }, + { + "id": "3104", + "name": "BBC Three" + }, + { + "id": "3106", + "name": "BBC News" + }, + { + "id": "3107", + "name": "BBC Four" + }, + { + "id": "3109", + "name": "MTV" + }, + { + "id": "3110", + "name": "5*" + }, + { + "id": "3111", + "name": "Fox Sports 1" + }, + { + "id": "3114", + "name": "Fox Sports 2" + }, + { + "id": "3115", + "name": "FXX" + }, + { + "id": "3117", + "name": "Esquire" + }, + { + "id": "3122", + "name": "France TV" + }, + { + "id": "3125", + "name": "Sky Atlantic" + }, + { + "id": "3130", + "name": "UniM\u00e1s" + }, + { + "id": "3134", + "name": "Japan\b TV" + }, + { + "id": "3135", + "name": "Germany\b TV" + }, + { + "id": "3136", + "name": "Italy\b TV" + }, + { + "id": "3137", + "name": "SBT" + }, + { + "id": "3138", + "name": "TV Cultura" + }, + { + "id": "3139", + "name": "SporTV" + }, + { + "id": "3140", + "name": "GNT" + }, + { + "id": "3141", + "name": "Multishow" + }, + { + "id": "3142", + "name": "ESPN Brasil" + }, + { + "id": "3144", + "name": "CTV Two" + }, + { + "id": "3145", + "name": "City" + }, + { + "id": "3146", + "name": "Showcase" + }, + { + "id": "3147", + "name": "Discovery Canada" + }, + { + "id": "3148", + "name": "W Network" + }, + { + "id": "3149", + "name": "MTV Brasil" + }, + { + "id": "3150", + "name": "Gazeta" + }, + { + "id": "3151", + "name": "Canal Fox" + }, + { + "id": "3152", + "name": "Warner Channel" + }, + { + "id": "3153", + "name": "Canal Sony" + }, + { + "id": "3154", + "name": "CTV" + }, + { + "id": "3155", + "name": "HBO Canada" + }, + { + "id": "3156", + "name": "France 2" + }, + { + "id": "3157", + "name": "Antena 3" + }, + { + "id": "3158", + "name": "Nova" + }, + { + "id": "3159", + "name": "Neox" + }, + { + "id": "3161", + "name": "BFM TV" + }, + { + "id": "3162", + "name": "24 Horas" + }, + { + "id": "3163", + "name": "Canal+" + }, + { + "id": "3164", + "name": "Canal+" + }, + { + "id": "3165", + "name": "Cuatro" + }, + { + "id": "3166", + "name": "D8" + }, + { + "id": "3169", + "name": "FDF" + }, + { + "id": "3170", + "name": "France 3" + }, + { + "id": "3171", + "name": "OLN" + }, + { + "id": "3172", + "name": "FXE" + }, + { + "id": "3174", + "name": "MTV-Canada" + }, + { + "id": "3176", + "name": "France 5" + }, + { + "id": "3177", + "name": "La Sexta" + }, + { + "id": "3178", + "name": "W9" + }, + { + "id": "3179", + "name": "M6" + }, + { + "id": "3180", + "name": "MTV" + }, + { + "id": "3181", + "name": "MTV" + }, + { + "id": "3182", + "name": "Space" + }, + { + "id": "3183", + "name": "NRJ 12" + }, + { + "id": "3184", + "name": "NT1" + }, + { + "id": "3185", + "name": "TV3" + }, + { + "id": "3186", + "name": "La 1" + }, + { + "id": "3187", + "name": "La 2" + }, + { + "id": "3188", + "name": "Telecinco" + }, + { + "id": "3189", + "name": "TF1" + }, + { + "id": "3190", + "name": "TMC" + }, + { + "id": "3191", + "name": "Divinity" + }, + { + "id": "3193", + "name": "CBC" + }, + { + "id": "3195", + "name": "France 4" + }, + { + "id": "3196", + "name": "Global" + }, + { + "id": "3198", + "name": "Intereconom\u00eda" + }, + { + "id": "3199", + "name": "Rede TV!" + }, + { + "id": "3200", + "name": "Energy" + }, + { + "id": "3201", + "name": "TNT" + }, + { + "id": "3202", + "name": "Record" + }, + { + "id": "3203", + "name": "Band" + }, + { + "id": "3205", + "name": "Food Network Canada" + }, + { + "id": "3206", + "name": "Rede Globo" + }, + { + "id": "3207", + "name": "HD1" + }, + { + "id": "3208", + "name": "6ter" + }, + { + "id": "3269", + "name": "BT Sport 1" + }, + { + "id": "3272", + "name": "SportsNet" + }, + { + "id": "3273", + "name": "TSN" + }, + { + "id": "3275", + "name": "Das Erste" + }, + { + "id": "3276", + "name": "Canale 5" + }, + { + "id": "3277", + "name": "sport1" + } + ], + "data_type": "tv_channel", + "next_cursor": "c-5k", + "request": { + "params": {} + } +} \ No newline at end of file diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-tv_genres.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-tv_genres.json new file mode 100644 index 00000000..af313b54 --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-tv_genres.json @@ -0,0 +1,88 @@ +{ + "data": [ + { + "id": "2", + "name": "COMEDY" + }, + { + "id": "11", + "name": "SPORTS" + }, + { + "id": "6", + "name": "OTHER" + }, + { + "id": "4", + "name": "DRAMA" + }, + { + "id": "16", + "name": "MUSIC" + }, + { + "id": "1", + "name": "CHILDREN_FAMILY" + }, + { + "id": "14", + "name": "VARIETY" + }, + { + "id": "18", + "name": "SPORTS_TALK" + }, + { + "id": "19", + "name": "MINISERIES" + }, + { + "id": "12", + "name": "TALK" + }, + { + "id": "8", + "name": "REALITY" + }, + { + "id": "3", + "name": "DOCUMENTARY_SPECIAL_INTEREST" + }, + { + "id": "15", + "name": "GAME_SHOW" + }, + { + "id": "21", + "name": "ANIME" + }, + { + "id": "10", + "name": "SPECIAL" + }, + { + "id": "9", + "name": "SCI_FI" + }, + { + "id": "13", + "name": "NEWS" + }, + { + "id": "7", + "name": "PAID" + }, + { + "id": "5", + "name": "MOVIES" + }, + { + "id": "17", + "name": "SOAP_OPERA" + } + ], + "data_type": "tv_genre", + "request": { + "params": {} + } +} \ No newline at end of file diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-tv_markets.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-tv_markets.json new file mode 100644 index 00000000..4aabd390 --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-tv_markets.json @@ -0,0 +1,110 @@ +{ + "data": [ + { + "country_code": "FR", + "id": "6", + "locale": "fr-FR", + "name": "France" + }, + { + "country_code": "CL", + "id": "i", + "locale": "es-CL", + "name": "Chile" + }, + { + "country_code": "DE", + "id": "a", + "locale": "de-DE", + "name": "Germany" + }, + { + "country_code": "NL", + "id": "p", + "locale": "nl-NL", + "name": "Netherlands" + }, + { + "country_code": "US", + "id": "1", + "locale": "en-US", + "name": "United States" + }, + { + "country_code": "VE", + "id": "k", + "locale": "es-VE", + "name": "Venezuela" + }, + { + "country_code": "BR", + "id": "5", + "locale": "pt-BR", + "name": "Brazil" + }, + { + "country_code": "MX", + "id": "d", + "locale": "es-MX", + "name": "Mexico" + }, + { + "country_code": "CO", + "id": "g", + "locale": "es-CO", + "name": "Colombia" + }, + { + "country_code": "GB", + "id": "2", + "locale": "en-GB", + "name": "United Kingdom" + }, + { + "country_code": "AR", + "id": "c", + "locale": "es-AR", + "name": "Argentina" + }, + { + "country_code": "JP", + "id": "9", + "locale": "ja-JP", + "name": "Japan" + }, + { + "country_code": "CA", + "id": "3", + "locale": "en-CA", + "name": "Canada" + }, + { + "country_code": "ES", + "id": "7", + "locale": "es-ES", + "name": "Spain" + }, + { + "country_code": "IT", + "id": "b", + "locale": "it-IT", + "name": "Italy" + }, + { + "country_code": "US", + "id": "4", + "locale": "es-US", + "name": "United States - Hispanic" + }, + { + "country_code": "IE", + "id": "f", + "locale": "en-IE", + "name": "Ireland" + } + ], + "data_type": "tv_market", + "request": { + "params": {} + } +} \ No newline at end of file diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-tv_shows-params.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-tv_shows-params.json new file mode 100644 index 00000000..9f96175e --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-tv_shows-params.json @@ -0,0 +1,16 @@ +{ + "data": [ + { + "estimated_users": 99754, + "genre": "DRAMA", + "id": 10028587441, + "name": "Glee" + } + ], + "data_type": "targeting_criterion", + "next_cursor": null, + "request": { + "params": {} + }, + "total_count": 1 +} \ No newline at end of file diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-tv_shows.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-tv_shows.json new file mode 100644 index 00000000..fdfe12b3 --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/ad-targetings-tv_shows.json @@ -0,0 +1,312 @@ +{ + "request":{ + "params":{ + + } + }, + "data":[ + { + "name":"Debate 2014 - Presidente", + "id":10032876335, + "estimated_users":1000, + "genre":"SPECIAL" + }, + { + "name":"2014 FIBA World Cup", + "id":10032994279, + "estimated_users":1000, + "genre":"SPORTS" + }, + { + "name":"Teleton 2014", + "id":10034234711, + "estimated_users":49903, + "genre":"SPECIAL" + }, + { + "name":"Debate 2014 - Governadores", + "id":10033124297, + "estimated_users":1000, + "genre":"SPECIAL" + }, + { + "name":"Ol\u00EDmpiadas de Inverno Sochi 2014", + "id":10028488857, + "estimated_users":1000, + "genre":"SPORTS" + }, + { + "name":"Academy Awards 2015", + "id":10028635956, + "estimated_users":23707, + "genre":"SPECIAL" + }, + { + "name":"Samba Bras\u00EDlia", + "id":10032742639, + "estimated_users":1000, + "genre":"SPECIAL" + }, + { + "name":"Circuito banco do Brasil", + "id":10034146629, + "estimated_users":1000, + "genre":"SPECIAL" + }, + { + "name":"NBA", + "id":10031646970, + "estimated_users":128587, + "genre":"SPORTS" + }, + { + "name":"Frozen", + "id":10034447890, + "estimated_users":1000, + "genre":"MOVIES" + }, + { + "name":"Golden Globe 2015", + "id":10028597044, + "estimated_users":14947, + "genre":"SPECIAL" + }, + { + "name":"F\u00F3rmula 1", + "id":10029035313, + "estimated_users":60390, + "genre":"SPORTS" + }, + { + "name":"SuperStar", + "id":10029301064, + "estimated_users":169753, + "genre":"REALITY" + }, + { + "name":"Copa Am\u00E9rica", + "id":10036396046, + "estimated_users":150438, + "genre":"SPORTS" + }, + { + "name":"The Brit Awards 2015", + "id":10035547851, + "estimated_users":17563, + "genre":"SPECIAL" + }, + { + "name":"Game of Thrones", + "id":10028727706, + "estimated_users":132304, + "genre":"SCI_FI" + }, + { + "name":"Grammy Awards 2015", + "id":10028654902, + "estimated_users":70907, + "genre":"SPECIAL" + }, + { + "name":"Billboard Music Awards 2015", + "id":10029792412, + "estimated_users":176727, + "genre":"SPECIAL" + }, + { + "name":"UEFA Champions League Soccer", + "id":10029008212, + "estimated_users":348578, + "genre":"SPORTS" + }, + { + "name":"Saturday Night Live", + "id":10028727700, + "estimated_users":20231, + "genre":"COMEDY" + }, + { + "name":"People's Choice Awards 2015", + "id":10028587449, + "estimated_users":44997, + "genre":"SPECIAL" + }, + { + "name":"American Music Awards", + "id":10034396305, + "estimated_users":18106, + "genre":"SPECIAL" + }, + { + "name":"Copa do Mundo de Futebol Feminino de 2015", + "id":10037239015, + "estimated_users":27914, + "genre":"SPORTS" + }, + { + "name":"Copa Libertadores", + "id":10029035271, + "estimated_users":258211, + "genre":"SPORTS" + }, + { + "name":"Memorial Day 2015", + "id":10037100917, + "estimated_users":18200, + "genre":"SPECIAL" + }, + { + "name":"The Walking Dead", + "id":10028588302, + "estimated_users":132870, + "genre":"DRAMA" + }, + { + "name":"The Vampire Diaries", + "id":10028762216, + "estimated_users":197347, + "genre":"SCI_FI" + }, + { + "name":"Copa do Rei", + "id":10035422924, + "estimated_users":32048, + "genre":"SPORTS" + }, + { + "name":"Screen Actors Guild Awards 2015", + "id":10028603569, + "estimated_users":2478, + "genre":"SPECIAL" + }, + { + "name":"Miss Universo 2014", + "id":10035406593, + "estimated_users":5539, + "genre":"SPECIAL" + }, + { + "name":"Bola de ouro FIFA", + "id":10035453999, + "estimated_users":10496, + "genre":"SPECIAL" + }, + { + "name":"Os Simpsons", + "id":10028414416, + "estimated_users":67212, + "genre":"COMEDY" + }, + { + "name":"Campeonatos Estaduais", + "id":10029035307, + "estimated_users":206048, + "genre":"SPORTS" + }, + { + "name":"Mil e uma noites", + "id":10036412471, + "estimated_users":17860, + "genre":"SOAP_OPERA" + }, + { + "name":"The Ellen Degeneres Show", + "id":10033820068, + "estimated_users":344783, + "genre":"TALK" + }, + { + "name":"Once Upon a Time", + "id":10028597068, + "estimated_users":58570, + "genre":"SCI_FI" + }, + { + "name":"American Horror Story", + "id":10028597049, + "estimated_users":76608, + "genre":"DRAMA" + }, + { + "name":"Doctor Who", + "id":10032051182, + "estimated_users":29086, + "genre":"SCI_FI" + }, + { + "name":"Arrow", + "id":10028635048, + "estimated_users":73832, + "genre":"SCI_FI" + }, + { + "name":"Scandal", + "id":10028635050, + "estimated_users":21248, + "genre":"DRAMA" + }, + { + "name":"Tomorrowland Brasil", + "id":10037121738, + "estimated_users":217308, + "genre":"SPECIAL" + }, + { + "name":"Father's Day 2015", + "id":10037100922, + "estimated_users":1054, + "genre":"SPECIAL" + }, + { + "name":"Futebol NFL", + "id":10033407327, + "estimated_users":101464, + "genre":"SPORTS" + }, + { + "name":"Amistosos Internacionais", + "id":10033116280, + "estimated_users":64836, + "genre":"SPORTS" + }, + { + "name":"Supernatural", + "id":10028407900, + "estimated_users":154066, + "genre":"SCI_FI" + }, + { + "name":"Pretty Little Liars", + "id":10028787788, + "estimated_users":143969, + "genre":"DRAMA" + }, + { + "name":"Glee", + "id":10028587441, + "estimated_users":100278, + "genre":"DRAMA" + }, + { + "name":"Breaking Bad", + "id":10028694298, + "estimated_users":52420, + "genre":"DRAMA" + }, + { + "name":"The Taste Brasil", + "id":10036434776, + "estimated_users":7989, + "genre":"REALITY" + }, + { + "name":"Campeonato espanhol", + "id":10029035055, + "estimated_users":27136, + "genre":"SPORTS" + } + ], + "data_type":"targeting_criterion", + "total_count":2188, + "next_cursor":"c-1e" +} \ No newline at end of file diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/line-item-placements-params.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/line-item-placements-params.json new file mode 100644 index 00000000..52b13626 --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/line-item-placements-params.json @@ -0,0 +1,18 @@ +{ + "data": [ + { + "placements": [ + [ + "ALL_ON_TWITTER" + ] + ], + "product_type": "PROMOTED_ACCOUNT" + } + ], + "data_type": "placement", + "request": { + "params": { + "product_type": "PROMOTED_ACCOUNT" + } + } +} \ No newline at end of file diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/line-item-placements.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/line-item-placements.json new file mode 100644 index 00000000..1876971b --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/line-item-placements.json @@ -0,0 +1,41 @@ +{ + "data": [ + { + "placements": [ + [ + "ALL_ON_TWITTER" + ], + [ + "ALL_ON_TWITTER", + "PUBLISHER_NETWORK" + ], + [ + "PUBLISHER_NETWORK" + ], + [ + "PUBLISHER_NETWORK", + "TWITTER_TIMELINE" + ], + [ + "TWITTER_SEARCH" + ], + [ + "TWITTER_TIMELINE" + ] + ], + "product_type": "PROMOTED_TWEETS" + }, + { + "placements": [ + [ + "ALL_ON_TWITTER" + ] + ], + "product_type": "PROMOTED_ACCOUNT" + } + ], + "data_type": "placement", + "request": { + "params": {} + } +} diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/line-items-single.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/line-items-single.json new file mode 100644 index 00000000..c03752b1 --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/line-items-single.json @@ -0,0 +1,30 @@ +{ + "data": { + "account_id": "hkk5", + "bid_unit": "LINK_CLICK", + "bid_amount_local_micro": 1750000, + "campaign_id": "7wdy", + "created_at": "2012-11-30T22:58:11Z", + "currency": "GBP", + "deleted": false, + "id": "69ob", + "include_sentiment": null, + "paused": false, + "product_type":"PROMOTED_ACCOUNT", + "placements": [ + "ALL_ON_TWITTER", + "PUBLISHER_NETWORK" + ], + "updated_at": "2012-11-30T22:58:11Z", + "objective": "FOLLOWERS", + "optimization": "DEFAULT", + "primary_web_event_tag": null + }, + "data_type": "line_item", + "request": { + "params": { + "account_id": "hkk5", + "line_item_id": "69ob" + } + } +} \ No newline at end of file diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/line-items.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/line-items.json new file mode 100644 index 00000000..1f5fcae1 --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/line-items.json @@ -0,0 +1,606 @@ +{ + "data": [ + { + "account_id": "gq0vqj", + "advertiser_domain": null, + "automatically_select_bid": false, + "bid_amount_local_micro": 10000000, + "bid_type": "MAX", + "bid_unit": "APP_CLICK", + "campaign_id": "e094", + "categories": [], + "created_at": "2015-05-29T20:32:20Z", + "currency": "USD", + "deleted": false, + "id": "awvv", + "include_sentiment": "POSITIVE_ONLY", + "name": "Untitled", + "objective": "APP_ENGAGEMENTS", + "optimization": "DEFAULT", + "paused": true, + "placement_type": "PROMOTED_TWEETS", + "placements": [ + "ALL_ON_TWITTER" + ], + "primary_web_event_tag": null, + "product_type": "PROMOTED_TWEETS", + "total_budget_amount_local_micro": 100000000, + "updated_at": "2015-05-29T20:38:43Z" + }, + { + "account_id": "gq0vqj", + "advertiser_domain": null, + "automatically_select_bid": false, + "bid_amount_local_micro": 100010000, + "bid_type": "MAX", + "bid_unit": "APP_CLICK", + "campaign_id": "e136", + "categories": [], + "created_at": "2015-06-01T20:04:03Z", + "currency": "USD", + "deleted": false, + "id": "axf3", + "include_sentiment": "POSITIVE_ONLY", + "name": "Untitled", + "objective": "APP_ENGAGEMENTS", + "optimization": "DEFAULT", + "paused": false, + "placement_type": "PROMOTED_TWEETS", + "placements": [ + "ALL_ON_TWITTER" + ], + "primary_web_event_tag": null, + "product_type": "PROMOTED_TWEETS", + "total_budget_amount_local_micro": 1000010000, + "updated_at": "2015-06-01T20:04:05Z" + }, + { + "account_id": "gq0vqj", + "advertiser_domain": null, + "automatically_select_bid": false, + "bid_amount_local_micro": 10000000, + "bid_type": "MAX", + "bid_unit": "APP_CLICK", + "campaign_id": "e098", + "categories": [], + "created_at": "2015-06-02T09:20:03Z", + "currency": "USD", + "deleted": false, + "id": "axok", + "include_sentiment": "POSITIVE_ONLY", + "name": "Untitled", + "objective": "APP_ENGAGEMENTS", + "optimization": "DEFAULT", + "paused": true, + "placement_type": "PROMOTED_TWEETS", + "placements": [ + "ALL_ON_TWITTER" + ], + "primary_web_event_tag": null, + "product_type": "PROMOTED_TWEETS", + "total_budget_amount_local_micro": 100000000, + "updated_at": "2015-06-02T09:20:03Z" + }, + { + "account_id": "gq0vqj", + "advertiser_domain": null, + "automatically_select_bid": false, + "bid_amount_local_micro": 10000000, + "bid_type": "MAX", + "bid_unit": "APP_CLICK", + "campaign_id": "e098", + "categories": [], + "created_at": "2015-06-02T09:46:14Z", + "currency": "USD", + "deleted": false, + "id": "axol", + "include_sentiment": "POSITIVE_ONLY", + "name": "Untitled", + "objective": "APP_ENGAGEMENTS", + "optimization": "DEFAULT", + "paused": true, + "placement_type": "PROMOTED_TWEETS", + "placements": [ + "ALL_ON_TWITTER" + ], + "primary_web_event_tag": null, + "product_type": "PROMOTED_TWEETS", + "total_budget_amount_local_micro": 100000000, + "updated_at": "2015-06-02T09:46:14Z" + }, + { + "account_id": "gq0vqj", + "advertiser_domain": null, + "automatically_select_bid": false, + "bid_amount_local_micro": 10000000, + "bid_type": "MAX", + "bid_unit": "APP_CLICK", + "campaign_id": "e098", + "categories": [], + "created_at": "2015-06-02T09:46:42Z", + "currency": "USD", + "deleted": false, + "id": "axom", + "include_sentiment": "POSITIVE_ONLY", + "name": "Untitled", + "objective": "APP_ENGAGEMENTS", + "optimization": "DEFAULT", + "paused": true, + "placement_type": "PROMOTED_TWEETS", + "placements": [ + "ALL_ON_TWITTER" + ], + "primary_web_event_tag": null, + "product_type": "PROMOTED_TWEETS", + "total_budget_amount_local_micro": 100000000, + "updated_at": "2015-06-02T09:46:42Z" + }, + { + "account_id": "gq0vqj", + "advertiser_domain": null, + "automatically_select_bid": false, + "bid_amount_local_micro": 10000000, + "bid_type": "MAX", + "bid_unit": "APP_CLICK", + "campaign_id": "e098", + "categories": [], + "created_at": "2015-06-02T09:47:33Z", + "currency": "USD", + "deleted": false, + "id": "axon", + "include_sentiment": "POSITIVE_ONLY", + "name": "Untitled", + "objective": "APP_ENGAGEMENTS", + "optimization": "DEFAULT", + "paused": true, + "placement_type": "PROMOTED_TWEETS", + "placements": [ + "ALL_ON_TWITTER" + ], + "primary_web_event_tag": null, + "product_type": "PROMOTED_TWEETS", + "total_budget_amount_local_micro": 100000000, + "updated_at": "2015-06-02T09:47:33Z" + }, + { + "account_id": "gq0vqj", + "advertiser_domain": null, + "automatically_select_bid": false, + "bid_amount_local_micro": 10000000, + "bid_type": "MAX", + "bid_unit": "APP_CLICK", + "campaign_id": "e098", + "categories": [], + "created_at": "2015-06-02T09:48:00Z", + "currency": "USD", + "deleted": false, + "id": "axoo", + "include_sentiment": "POSITIVE_ONLY", + "name": "Untitled", + "objective": "APP_ENGAGEMENTS", + "optimization": "DEFAULT", + "paused": true, + "placement_type": "PROMOTED_TWEETS", + "placements": [ + "ALL_ON_TWITTER" + ], + "primary_web_event_tag": null, + "product_type": "PROMOTED_TWEETS", + "total_budget_amount_local_micro": 100000000, + "updated_at": "2015-06-02T09:48:00Z" + }, + { + "account_id": "gq0vqj", + "advertiser_domain": null, + "automatically_select_bid": false, + "bid_amount_local_micro": 10000000, + "bid_type": "MAX", + "bid_unit": "APP_CLICK", + "campaign_id": "e098", + "categories": [], + "created_at": "2015-06-02T09:49:10Z", + "currency": "USD", + "deleted": false, + "id": "axop", + "include_sentiment": "POSITIVE_ONLY", + "name": "Untitled", + "objective": "APP_ENGAGEMENTS", + "optimization": "DEFAULT", + "paused": true, + "placement_type": "PROMOTED_TWEETS", + "placements": [ + "ALL_ON_TWITTER" + ], + "primary_web_event_tag": null, + "product_type": "PROMOTED_TWEETS", + "total_budget_amount_local_micro": 100000000, + "updated_at": "2015-06-02T09:49:10Z" + }, + { + "account_id": "gq0vqj", + "advertiser_domain": null, + "automatically_select_bid": false, + "bid_amount_local_micro": 10000000, + "bid_type": "MAX", + "bid_unit": "APP_CLICK", + "campaign_id": "e098", + "categories": [], + "created_at": "2015-06-02T09:49:38Z", + "currency": "USD", + "deleted": false, + "id": "axoq", + "include_sentiment": "POSITIVE_ONLY", + "name": "Untitled", + "objective": "APP_ENGAGEMENTS", + "optimization": "DEFAULT", + "paused": true, + "placement_type": "PROMOTED_TWEETS", + "placements": [ + "ALL_ON_TWITTER" + ], + "primary_web_event_tag": null, + "product_type": "PROMOTED_TWEETS", + "total_budget_amount_local_micro": 100000000, + "updated_at": "2015-06-02T09:49:38Z" + }, + { + "account_id": "gq0vqj", + "advertiser_domain": null, + "automatically_select_bid": false, + "bid_amount_local_micro": 10000000, + "bid_type": "MAX", + "bid_unit": "APP_CLICK", + "campaign_id": "e098", + "categories": [], + "created_at": "2015-06-02T09:50:44Z", + "currency": "USD", + "deleted": false, + "id": "axor", + "include_sentiment": "POSITIVE_ONLY", + "name": "Untitled", + "objective": "APP_ENGAGEMENTS", + "optimization": "DEFAULT", + "paused": true, + "placement_type": "PROMOTED_TWEETS", + "placements": [ + "ALL_ON_TWITTER" + ], + "primary_web_event_tag": null, + "product_type": "PROMOTED_TWEETS", + "total_budget_amount_local_micro": 100000000, + "updated_at": "2015-06-02T09:50:44Z" + }, + { + "account_id": "gq0vqj", + "advertiser_domain": null, + "automatically_select_bid": false, + "bid_amount_local_micro": 10000000, + "bid_type": "MAX", + "bid_unit": "APP_CLICK", + "campaign_id": "e098", + "categories": [], + "created_at": "2015-06-02T09:51:17Z", + "currency": "USD", + "deleted": false, + "id": "axos", + "include_sentiment": "POSITIVE_ONLY", + "name": "Untitled", + "objective": "APP_ENGAGEMENTS", + "optimization": "DEFAULT", + "paused": true, + "placement_type": "PROMOTED_TWEETS", + "placements": [ + "ALL_ON_TWITTER" + ], + "primary_web_event_tag": null, + "product_type": "PROMOTED_TWEETS", + "total_budget_amount_local_micro": 100000000, + "updated_at": "2015-06-02T09:51:17Z" + }, + { + "account_id": "gq0vqj", + "advertiser_domain": null, + "automatically_select_bid": false, + "bid_amount_local_micro": 10000000, + "bid_type": "MAX", + "bid_unit": "APP_CLICK", + "campaign_id": "e098", + "categories": [], + "created_at": "2015-06-02T09:56:06Z", + "currency": "USD", + "deleted": false, + "id": "axot", + "include_sentiment": "POSITIVE_ONLY", + "name": "Untitled", + "objective": "APP_ENGAGEMENTS", + "optimization": "DEFAULT", + "paused": true, + "placement_type": "PROMOTED_TWEETS", + "placements": [ + "ALL_ON_TWITTER" + ], + "primary_web_event_tag": null, + "product_type": "PROMOTED_TWEETS", + "total_budget_amount_local_micro": 100000000, + "updated_at": "2015-06-02T09:56:06Z" + }, + { + "account_id": "gq0vqj", + "advertiser_domain": null, + "automatically_select_bid": false, + "bid_amount_local_micro": 10000000, + "bid_type": "MAX", + "bid_unit": "APP_CLICK", + "campaign_id": "e094", + "categories": [], + "created_at": "2015-06-02T14:15:06Z", + "currency": "USD", + "deleted": false, + "id": "axpe", + "include_sentiment": "POSITIVE_ONLY", + "name": "Untitled", + "objective": "APP_ENGAGEMENTS", + "optimization": "DEFAULT", + "paused": true, + "placement_type": "PROMOTED_TWEETS", + "placements": [ + "ALL_ON_TWITTER" + ], + "primary_web_event_tag": null, + "product_type": "PROMOTED_TWEETS", + "total_budget_amount_local_micro": 100000000, + "updated_at": "2015-06-02T14:15:06Z" + }, + { + "account_id": "gq0vqj", + "advertiser_domain": null, + "automatically_select_bid": false, + "bid_amount_local_micro": 10000000, + "bid_type": "MAX", + "bid_unit": "APP_CLICK", + "campaign_id": "e094", + "categories": [], + "created_at": "2015-06-02T14:22:47Z", + "currency": "USD", + "deleted": false, + "id": "axpw", + "include_sentiment": "POSITIVE_ONLY", + "name": "Untitled", + "objective": "APP_ENGAGEMENTS", + "optimization": "DEFAULT", + "paused": true, + "placement_type": "PROMOTED_TWEETS", + "placements": [ + "ALL_ON_TWITTER" + ], + "primary_web_event_tag": null, + "product_type": "PROMOTED_TWEETS", + "total_budget_amount_local_micro": 100000000, + "updated_at": "2015-06-02T14:22:47Z" + }, + { + "account_id": "gq0vqj", + "advertiser_domain": null, + "automatically_select_bid": false, + "bid_amount_local_micro": 10000000, + "bid_type": "MAX", + "bid_unit": "APP_CLICK", + "campaign_id": "e094", + "categories": [], + "created_at": "2015-06-02T14:25:27Z", + "currency": "USD", + "deleted": false, + "id": "axpx", + "include_sentiment": "POSITIVE_ONLY", + "name": "Untitled", + "objective": "APP_ENGAGEMENTS", + "optimization": "DEFAULT", + "paused": true, + "placement_type": "PROMOTED_TWEETS", + "placements": [ + "ALL_ON_TWITTER" + ], + "primary_web_event_tag": null, + "product_type": "PROMOTED_TWEETS", + "total_budget_amount_local_micro": 100000000, + "updated_at": "2015-06-02T14:25:27Z" + }, + { + "account_id": "gq0vqj", + "advertiser_domain": null, + "automatically_select_bid": false, + "bid_amount_local_micro": 10000000, + "bid_type": "MAX", + "bid_unit": "APP_CLICK", + "campaign_id": "e094", + "categories": [], + "created_at": "2015-06-02T14:26:51Z", + "currency": "USD", + "deleted": false, + "id": "axpy", + "include_sentiment": "POSITIVE_ONLY", + "name": "Untitled", + "objective": "APP_ENGAGEMENTS", + "optimization": "DEFAULT", + "paused": true, + "placement_type": "PROMOTED_TWEETS", + "placements": [ + "ALL_ON_TWITTER" + ], + "primary_web_event_tag": null, + "product_type": "PROMOTED_TWEETS", + "total_budget_amount_local_micro": 100000000, + "updated_at": "2015-06-02T14:26:51Z" + }, + { + "account_id": "gq0vqj", + "advertiser_domain": null, + "automatically_select_bid": false, + "bid_amount_local_micro": 10000000, + "bid_type": "MAX", + "bid_unit": "APP_CLICK", + "campaign_id": "e094", + "categories": [], + "created_at": "2015-06-02T14:44:06Z", + "currency": "USD", + "deleted": false, + "id": "axq0", + "include_sentiment": "POSITIVE_ONLY", + "name": "Untitled", + "objective": "APP_ENGAGEMENTS", + "optimization": "DEFAULT", + "paused": true, + "placement_type": "PROMOTED_TWEETS", + "placements": [ + "ALL_ON_TWITTER" + ], + "primary_web_event_tag": null, + "product_type": "PROMOTED_TWEETS", + "total_budget_amount_local_micro": 100000000, + "updated_at": "2015-06-02T14:44:06Z" + }, + { + "account_id": "gq0vqj", + "advertiser_domain": null, + "automatically_select_bid": false, + "bid_amount_local_micro": 10000000, + "bid_type": "MAX", + "bid_unit": "APP_CLICK", + "campaign_id": "e094", + "categories": [], + "created_at": "2015-06-02T14:46:13Z", + "currency": "USD", + "deleted": false, + "id": "axq1", + "include_sentiment": "POSITIVE_ONLY", + "name": "Untitled", + "objective": "APP_ENGAGEMENTS", + "optimization": "DEFAULT", + "paused": true, + "placement_type": "PROMOTED_TWEETS", + "placements": [ + "ALL_ON_TWITTER" + ], + "primary_web_event_tag": null, + "product_type": "PROMOTED_TWEETS", + "total_budget_amount_local_micro": 100000000, + "updated_at": "2015-06-02T14:46:13Z" + }, + { + "account_id": "gq0vqj", + "advertiser_domain": null, + "automatically_select_bid": false, + "bid_amount_local_micro": 10000000, + "bid_type": "MAX", + "bid_unit": "APP_CLICK", + "campaign_id": "e094", + "categories": [], + "created_at": "2015-06-02T14:47:03Z", + "currency": "USD", + "deleted": false, + "id": "axq2", + "include_sentiment": "POSITIVE_ONLY", + "name": "Untitled", + "objective": "APP_ENGAGEMENTS", + "optimization": "DEFAULT", + "paused": true, + "placement_type": "PROMOTED_TWEETS", + "placements": [ + "ALL_ON_TWITTER" + ], + "primary_web_event_tag": null, + "product_type": "PROMOTED_TWEETS", + "total_budget_amount_local_micro": 100000000, + "updated_at": "2015-06-02T14:47:03Z" + }, + { + "account_id": "gq0vqj", + "advertiser_domain": null, + "automatically_select_bid": false, + "bid_amount_local_micro": 10000000, + "bid_type": "MAX", + "bid_unit": "APP_CLICK", + "campaign_id": "e094", + "categories": [], + "created_at": "2015-06-02T14:51:47Z", + "currency": "USD", + "deleted": false, + "id": "axq3", + "include_sentiment": "POSITIVE_ONLY", + "name": "Untitled", + "objective": "APP_ENGAGEMENTS", + "optimization": "DEFAULT", + "paused": true, + "placement_type": "PROMOTED_TWEETS", + "placements": [ + "ALL_ON_TWITTER" + ], + "primary_web_event_tag": null, + "product_type": "PROMOTED_TWEETS", + "total_budget_amount_local_micro": 100000000, + "updated_at": "2015-06-02T14:51:47Z" + }, + { + "account_id": "gq0vqj", + "advertiser_domain": null, + "automatically_select_bid": false, + "bid_amount_local_micro": 10000000, + "bid_type": "MAX", + "bid_unit": "APP_CLICK", + "campaign_id": "e094", + "categories": [], + "created_at": "2015-06-02T17:40:48Z", + "currency": "USD", + "deleted": false, + "id": "axra", + "include_sentiment": "POSITIVE_ONLY", + "name": "Untitled", + "objective": "APP_ENGAGEMENTS", + "optimization": "DEFAULT", + "paused": true, + "placement_type": "PROMOTED_TWEETS", + "placements": [ + "ALL_ON_TWITTER" + ], + "primary_web_event_tag": null, + "product_type": "PROMOTED_TWEETS", + "total_budget_amount_local_micro": 100000000, + "updated_at": "2015-06-02T17:40:48Z" + }, + { + "account_id": "gq0vqj", + "advertiser_domain": null, + "automatically_select_bid": false, + "bid_amount_local_micro": 100010000, + "bid_type": "MAX", + "bid_unit": "APP_CLICK", + "campaign_id": "e1hk", + "categories": [], + "created_at": "2015-06-02T18:23:28Z", + "currency": "USD", + "deleted": false, + "id": "axrs", + "include_sentiment": "POSITIVE_ONLY", + "name": "Untitled", + "objective": "APP_ENGAGEMENTS", + "optimization": "DEFAULT", + "paused": false, + "placement_type": "PROMOTED_TWEETS", + "placements": [ + "ALL_ON_TWITTER" + ], + "primary_web_event_tag": null, + "product_type": "PROMOTED_TWEETS", + "total_budget_amount_local_micro": 1000010000, + "updated_at": "2015-06-02T18:23:31Z" + } + ], + "data_type": "line_item", + "next_cursor": null, + "request": { + "params": { + "account_id": "gq0vqj" + } + }, + "total_count": 22 +} diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/statistics-snapshot.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/statistics-snapshot.json new file mode 100644 index 00000000..6e583643 --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/advertising/statistics-snapshot.json @@ -0,0 +1,157 @@ +{ + "data": { + "billed_engagements": [ + 0, + 0, + 0 + ], + "billed_follows": [ + 0, + 0, + 0 + ], + "end_time": "2015-05-04T07:00:00Z", + "granularity": "DAY", + "id": "8484d", + "promoted_account_follow_rate": [ + 0.0, + 0.0, + 0.0 + ], + "promoted_account_follows": [ + 0, + 0, + 0 + ], + "promoted_account_impressions": [ + 0, + 0, + 0 + ], + "promoted_account_profile_visits": [ + 0, + 0, + 0 + ], + "promoted_tweet_app_install_attempts": [ + 0, + 0, + 0 + ], + "promoted_tweet_app_open_attempts": [ + 0, + 0, + 0 + ], + "promoted_tweet_search_card_engagements": [ + 0, + 0, + 0 + ], + "promoted_tweet_search_clicks": [ + 0, + 0, + 0 + ], + "promoted_tweet_search_engagement_rate": [ + 0.0, + 0.0, + 0.0 + ], + "promoted_tweet_search_engagements": [ + 0, + 0, + 0 + ], + "promoted_tweet_search_favorites": [ + 0, + 0, + 0 + ], + "promoted_tweet_search_follows": [ + 0, + 0, + 0 + ], + "promoted_tweet_search_impressions": [ + 0, + 0, + 0 + ], + "promoted_tweet_search_replies": [ + 0, + 0, + 0 + ], + "promoted_tweet_search_retweets": [ + 0, + 0, + 0 + ], + "promoted_tweet_search_url_clicks": [ + 0, + 0, + 0 + ], + "promoted_tweet_timeline_card_engagements": [ + 0, + 0, + 0 + ], + "promoted_tweet_timeline_clicks": [ + 0, + 0, + 0 + ], + "promoted_tweet_timeline_engagement_rate": [ + 0.0, + 0.0, + 0.0 + ], + "promoted_tweet_timeline_engagements": [ + 0, + 0, + 0 + ], + "promoted_tweet_timeline_favorites": [ + 0, + 0, + 0 + ], + "promoted_tweet_timeline_follows": [ + 0, + 0, + 0 + ], + "promoted_tweet_timeline_impressions": [ + 0, + 0, + 0 + ], + "promoted_tweet_timeline_replies": [ + 0, + 0, + 0 + ], + "promoted_tweet_timeline_retweets": [ + 0, + 0, + 0 + ], + "promoted_tweet_timeline_url_clicks": [ + 0, + 0, + 0 + ], + "start_time": "2015-05-01T07:00:00Z" + }, + "data_type": "stats", + "request": { + "params": { + "account_id": "hahaj", + "end_time": "2015-05-04T07:00:00Z", + "granularity": "DAY", + "start_time": "2015-05-01T07:00:00Z" + } + } +} \ No newline at end of file diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/ton/hashed_twitter.txt b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/ton/hashed_twitter.txt new file mode 100644 index 00000000..5c2ce580 --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/ton/hashed_twitter.txt @@ -0,0 +1,4 @@ +62ffac4f290ca19943e4c431e565b5ebe11cbe89b88b5e28f0472b336a3f09f0 +77ca232242f628075642947a6c0cb5d51eba64045b7fc69d6c38e03ce17286d8 +8b26507bcdc96014f9150885340869390d635c8993dd6961b785113188a8fa9b +21035f585b32700b721d05a6711f7465a31c4ef5cf5cb53b422ee13caf108303 diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/upload/finalize.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/upload/finalize.json new file mode 100644 index 00000000..dc27afbf --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/upload/finalize.json @@ -0,0 +1,9 @@ +{ + "media_id":623694170260049925, + "media_id_string":"623694170260049925", + "size":383631, + "expires_after_secs":3600, + "video": { + "video_type":"video\/mp4" + } +} diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/upload/init.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/upload/init.json new file mode 100644 index 00000000..bd4a3e44 --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/upload/init.json @@ -0,0 +1,5 @@ +{ + "media_id":623694170260049925, + "media_id_string":"623694170260049925", + "expires_after_secs":3599 +} diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/upload/profilepic.gif b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/upload/profilepic.gif new file mode 100644 index 00000000..a36e4738 Binary files /dev/null and b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/upload/profilepic.gif differ diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/upload/small.mp4 b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/upload/small.mp4 new file mode 100644 index 00000000..1fc47884 Binary files /dev/null and b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/upload/small.mp4 differ diff --git a/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/upload/upload.json b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/upload/upload.json new file mode 100644 index 00000000..f9661dd2 --- /dev/null +++ b/spring-social-twitter/src/test/resources/org/springframework/social/twitter/api/impl/upload/upload.json @@ -0,0 +1,12 @@ +{ + "media_id":622149702012669952, + "media_id_string":"622149702012669952", + "size":12302, + "expires_after_secs":3600, + "image": + { + "image_type":"image\/png", + "w":97, + "h":127 + } +} \ No newline at end of file