[
  {
    "path": ".gitignore",
    "content": "## OS X\n.DS_Store\n"
  },
  {
    "path": ".gitmodules",
    "content": "[submodule \"iOS/Vendor/xctoolchain\"]\n\tpath = iOS/Vendor/xctoolchain\n\turl = https://github.com/ParsePlatform/xctoolchain.git\n"
  },
  {
    "path": ".travis.yml",
    "content": "branches:\n  only:\n    - master\nmatrix:\n  include:\n    - language: objective-c\n      os: osx\n      osx_image: xcode7.3\n      env: TEST_TYPE=iOS\n    - language: objective-c\n      os: osx\n      osx_image: xcode7.3\n      env: TEST_TYPE=CocoaPods\n    - language: objective-c\n      os: osx\n      osx_image: xcode7.3\n      env: TEST_TYPE=Carthage\n    - language: android\n      sudo: false\n      env: TEST_TYPE=Android\n      android:\n        components:\n          - tools\n          - build-tools-23.0.3\n          - android-23\n          - doc-23\n          - extra-android-support\n          - extra-android-m2repository\n          - extra-google-m2repository\n          - extra-google-google_play_services\ninstall:\n- |\n  if [ \"$TEST_TYPE\" = \"iOS\" ]; then\n    gem install xcpretty -N --no-ri --no-rdoc\n  elif [ \"$TEST_TYPE\" = Carthage ]; then\n    brew install carthage || brew upgrade carthage\n  fi\nscript:\n- |\n  if [ \"$TEST_TYPE\" = \"iOS\" ]; then\n    cd iOS\n    set -o pipefail\n    xcodebuild build -workspace FBNotifications.xcworkspace -scheme FBNotifications-iOS -sdk iphonesimulator -configuration Release | xcpretty -c\n    xcodebuild build -workspace FBNotifications.xcworkspace -scheme FBNotificationsExample -sdk iphonesimulator -configuration Release | xcpretty -c\n  elif [ \"$TEST_TYPE\" = Android ]; then\n    cd Android\n    ./gradlew clean assemble -p notifications\n  elif [ \"$TEST_TYPE\" = CocoaPods ]; then\n    pod lib lint FBNotifications.podspec\n    pod lib lint --use-libraries FBNotifications.podspec\n  elif [ \"$TEST_TYPE\" = Carthage ]; then\n    carthage build --no-skip-current\n  fi\n"
  },
  {
    "path": "Android/.gitignore",
    "content": "# built application files\n*.apk\n*.ap_\n\n# files for the dex VM\n*.dex\n\n# Java class files\n*.class\n\n# generated files\nbin/\ngen/\n\n# Local configuration file (sdk path, etc)\nlocal.properties\n\n# Android Studio\n.idea\n*.iml\n*.ipr\n*.iws\nclasses\ngen-external-apklibs\n\n# Gradle\n.gradle\nbuild\n\n# Other\n.metadata\n*/bin/*\n*/gen/*\n"
  },
  {
    "path": "Android/build.gradle",
    "content": "buildscript {\n    repositories {\n        jcenter()\n    }\n\n    dependencies {\n        classpath 'com.android.tools.build:gradle:2.1.0'\n        classpath 'com.google.gms:google-services:1.3.0'\n    }\n}\n\nallprojects {\n    repositories {\n        jcenter()\n    }\n}\n\ntask clean(type: Delete) {\n    delete rootProject.buildDir\n}\n"
  },
  {
    "path": "Android/gradle/wrapper/gradle-wrapper.properties",
    "content": "#Mon Feb 08 14:52:05 PST 2016\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-2.10-all.zip\n"
  },
  {
    "path": "Android/gradle.properties",
    "content": "# Project-wide Gradle settings.\n\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\n# Default value: -Xmx10248m -XX:MaxPermSize=256m\n# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8\n\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\n# org.gradle.parallel=true"
  },
  {
    "path": "Android/gradlew",
    "content": "#!/usr/bin/env bash\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS=\"\"\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn ( ) {\n    echo \"$*\"\n}\n\ndie ( ) {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\nesac\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules\nfunction splitJvmOpts() {\n    JVM_OPTS=(\"$@\")\n}\neval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS\nJVM_OPTS[${#JVM_OPTS[*]}]=\"-Dorg.gradle.appname=$APP_BASE_NAME\"\n\nexec \"$JAVACMD\" \"${JVM_OPTS[@]}\" -classpath \"$CLASSPATH\" org.gradle.wrapper.GradleWrapperMain \"$@\"\n"
  },
  {
    "path": "Android/gradlew.bat",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@rem  Gradle startup script for Windows\r\n@rem\r\n@rem ##########################################################################\r\n\r\n@rem Set local scope for the variables with windows NT shell\r\nif \"%OS%\"==\"Windows_NT\" setlocal\r\n\r\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r\nset DEFAULT_JVM_OPTS=\r\n\r\nset DIRNAME=%~dp0\r\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\r\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\r\n\r\n@rem Find java.exe\r\nif defined JAVA_HOME goto findJavaFromJavaHome\r\n\r\nset JAVA_EXE=java.exe\r\n%JAVA_EXE% -version >NUL 2>&1\r\nif \"%ERRORLEVEL%\" == \"0\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:findJavaFromJavaHome\r\nset JAVA_HOME=%JAVA_HOME:\"=%\r\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\r\n\r\nif exist \"%JAVA_EXE%\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:init\r\n@rem Get command-line arguments, handling Windowz variants\r\n\r\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\r\nif \"%@eval[2+2]\" == \"4\" goto 4NT_args\r\n\r\n:win9xME_args\r\n@rem Slurp the command line arguments.\r\nset CMD_LINE_ARGS=\r\nset _SKIP=2\r\n\r\n:win9xME_args_slurp\r\nif \"x%~1\" == \"x\" goto execute\r\n\r\nset CMD_LINE_ARGS=%*\r\ngoto execute\r\n\r\n:4NT_args\r\n@rem Get arguments from the 4NT Shell from JP Software\r\nset CMD_LINE_ARGS=%$\r\n\r\n:execute\r\n@rem Setup the command line\r\n\r\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\r\n\r\n@rem Execute Gradle\r\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\r\n\r\n:end\r\n@rem End local scope for the variables with windows NT shell\r\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\r\n\r\n:fail\r\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r\nrem the _cmd.exe /c_ return code!\r\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\r\nexit /b 1\r\n\r\n:mainEnd\r\nif \"%OS%\"==\"Windows_NT\" endlocal\r\n\r\n:omega\r\n"
  },
  {
    "path": "Android/notifications/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\ngroup = 'com.facebook.android'\n\nbuildscript {\n    repositories {\n        mavenCentral()\n    }\n}\n\nandroid {\n    compileSdkVersion 23\n    buildToolsVersion \"23.0.3\"\n\n    defaultConfig {\n        minSdkVersion 15\n        targetSdkVersion 23\n        versionCode 1\n        versionName project.version\n    }\n}\n\nconfigurations {\n    javadoc\n}\n\ndependencies {\n    testCompile 'junit:junit:4.12'\n    compile 'com.android.support:appcompat-v7:23.2.1'\n    javadoc 'com.android.support:appcompat-v7:23.2.1'\n}\n\napply plugin: 'maven'\napply plugin: 'signing'\n\ndef isSnapshot = version.endsWith('-SNAPSHOT')\ndef ossrhUsername = hasProperty('NEXUS_USERNAME') ? NEXUS_USERNAME : System.getenv('CI_NEXUS_USERNAME')\ndef ossrhPassword = hasProperty('NEXUS_PASSWORD') ? NEXUS_PASSWORD : System.getenv('CI_NEXUS_PASSWORD')\n\ntask setVersion {\n    // The version will be derived from source\n    project.version = null\n    def sdkVersionFile = file('src/main/java/com/facebook/notifications/NotificationsManager.java')\n    sdkVersionFile.eachLine{\n        def matcher = (it =~ /(?:.*LIBRARY_VERSION = \\\")(.*)(?:\\\".*)/)\n        if (matcher.matches()) {\n            project.version = matcher[0][1]\n            return\n        }\n    }\n    if (project.version.is('unspecified')) {\n        throw new GradleScriptException('Version could not be found.', null)\n    }\n}\n\nuploadArchives {\n    repositories.mavenDeployer {\n        beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }\n\n        repository(url: \"https://oss.sonatype.org/service/local/staging/deploy/maven2/\") {\n            authentication(userName: ossrhUsername, password: ossrhPassword)\n        }\n\n        snapshotRepository(url: \"https://oss.sonatype.org/content/repositories/snapshots/\") {\n            authentication(userName: ossrhUsername, password: ossrhPassword)\n        }\n\n        pom.project {\n            name 'In-App Notifications Framework'\n            artifactId = 'notifications'\n            packaging 'aar'\n            description 'Facebook In-App Notifications Framework for Android'\n            url 'https://github.com/facebook/FBNotifications'\n\n            scm {\n                connection 'scm:git@github.com:facebook/FBNotifications.git'\n                developerConnection 'scm:git@github.com:facebook/FBNotifications.git'\n                url 'https://github.com/facebook/FBNotifications'\n            }\n\n            licenses {\n                license {\n                    name 'Facebook Platform License'\n                    url 'https://github.com/facebook/FBNotifications/blob/master/LICENSE'\n                    distribution 'repo'\n                }\n            }\n\n            developers {\n                developer {\n                    id 'facebook'\n                    name 'Facebook'\n                }\n            }\n        }\n    }\n}\n\nuploadArchives.dependsOn(setVersion)\n\nsigning {\n    required { !isSnapshot && gradle.taskGraph.hasTask(\"uploadArchives\") }\n    sign configurations.archives\n}\n\ntask androidJavadocs(type: Javadoc) {\n    source = android.sourceSets.main.java.srcDirs\n    ext.androidJar = \"${android.sdkDirectory}/platforms/${android.compileSdkVersion}/android.jar\"\n\n    classpath += project.files(android.getBootClasspath().join(File.pathSeparator))\n    classpath += configurations.javadoc\n\n    options.linksOffline(\"http://d.android.com/reference\", \"${android.sdkDirectory}/docs/reference\")\n\n    // JDK 1.8 is more strict then 1.7. Have JDK 1.8 behave like 1.7 for javadoc generation\n    if (org.gradle.internal.jvm.Jvm.current().getJavaVersion() == JavaVersion.VERSION_1_8) {\n        options.addStringOption('Xdoclint:none', '-quiet')\n    }\n\n    exclude '**/internal/**'\n}\n\ntask androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) {\n    classifier = 'javadoc'\n    from androidJavadocs.destinationDir\n}\n\ntask androidSourcesJar(type: Jar) {\n    classifier = 'sources'\n    from android.sourceSets.main.java.sourceFiles\n}\n\nartifacts {\n    archives androidSourcesJar\n    archives androidJavadocsJar\n}\n"
  },
  {
    "path": "Android/notifications/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in /Users/richardross/Library/Android/sdk/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the proguardFiles\n# directive in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n"
  },
  {
    "path": "Android/notifications/src/main/AndroidManifest.xml",
    "content": "<manifest package=\"com.facebook.notifications\"\n          xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <application>\n        <activity android:name=\".internal.activity.CardActivity\"\n                  android:theme=\"@android:style/Theme.Translucent.NoTitleBar\"\n                  android:configChanges=\"orientation|screenSize\" />\n    </application>\n</manifest>\n"
  },
  {
    "path": "Android/notifications/src/main/java/com/facebook/notifications/NotificationCardResult.java",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\npackage com.facebook.notifications;\n\nimport android.net.Uri;\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.support.annotation.Nullable;\n\npublic class NotificationCardResult implements Parcelable {\n  public static final Creator<NotificationCardResult> CREATOR = new Creator<NotificationCardResult>() {\n    @Override\n    public NotificationCardResult createFromParcel(Parcel source) {\n      return new NotificationCardResult(source);\n    }\n\n    @Override\n    public NotificationCardResult[] newArray(int size) {\n      return new NotificationCardResult[size];\n    }\n  };\n\n  private final @Nullable Uri actionUri;\n\n  public NotificationCardResult(@Nullable Uri actionUri) {\n    this.actionUri = actionUri;\n  }\n\n  private NotificationCardResult(Parcel parcel) {\n    this.actionUri = parcel.readParcelable(getClass().getClassLoader());\n  }\n\n  @Nullable\n  public Uri getActionUri() {\n    return actionUri;\n  }\n\n  @Override\n  public int describeContents() {\n    return 0;\n  }\n\n  @Override\n  public void writeToParcel(Parcel dest, int flags) {\n    dest.writeParcelable(actionUri, flags);\n  }\n}\n"
  },
  {
    "path": "Android/notifications/src/main/java/com/facebook/notifications/NotificationsManager.java",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\npackage com.facebook.notifications;\n\nimport android.app.Activity;\nimport android.app.Notification;\nimport android.app.NotificationManager;\nimport android.app.PendingIntent;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.os.Looper;\nimport android.support.annotation.NonNull;\nimport android.support.annotation.Nullable;\nimport android.util.Log;\n\nimport com.facebook.notifications.internal.activity.CardActivity;\nimport com.facebook.notifications.internal.appevents.AppEventsLogger;\nimport com.facebook.notifications.internal.asset.Asset;\nimport com.facebook.notifications.internal.asset.AssetManager;\nimport com.facebook.notifications.internal.asset.handlers.BitmapAssetHandler;\nimport com.facebook.notifications.internal.asset.handlers.ColorAssetHandler;\nimport com.facebook.notifications.internal.asset.handlers.GifAssetHandler;\nimport com.facebook.notifications.internal.configuration.CardConfiguration;\nimport com.facebook.notifications.internal.content.ContentManager;\nimport com.facebook.notifications.internal.utilities.Version;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\n/**\n * Manages incoming remote notifications for push card presentation.\n */\npublic final class NotificationsManager {\n  /**\n   * Represents handlers to be invoked when preparation of a card is completed.\n   */\n  public interface PrepareCallback {\n    void onPrepared(@NonNull Intent presentationIntent);\n\n    void onError(@NonNull Exception exception);\n  }\n\n  /**\n   * Allows for customizing of notifications before they are displayed.\n   */\n  public interface NotificationExtender {\n    Notification.Builder extendNotification(@NonNull Notification.Builder notification);\n  }\n\n  /**\n   * The request code to use for intents returned by {@link PrepareCallback}\n   */\n  public static final int REQUEST_CODE = 0xCA4D; // CARD\n\n  /**\n   * The intent extra key to be used for pending intents used in notifications created by\n   * `presentNotification()`\n   */\n  public static final String EXTRA_PAYLOAD_INTENT = \"notification_push_payload_intent\";\n\n  /**\n   * The highest supported payload version by this version of the Notifications SDK\n   */\n  public static final String PAYLOAD_VERSION = \"1.0\";\n\n  /**\n   * The version of the In-App Notifications Library\n   */\n  public static final String LIBRARY_VERSION = \"1.0.2\";\n\n  private static final @NonNull Version PAYLOAD_VERSION_OBJECT = new Version(1, 0, 0);\n\n  private static final String LOG_TAG = NotificationsManager.class.getCanonicalName();\n  private static final String NOTIFICATION_TAG = \"fb_notification_tag\";\n  private static final String PUSH_PAYLOAD_KEY = \"fb_push_payload\";\n  private static final String CARD_PAYLOAD_KEY = \"fb_push_card\";\n\n  private static final AssetManager ASSET_MANAGER = new AssetManager();\n  private static final ContentManager CONTENT_MANAGER = new ContentManager();\n\n  static {\n    ASSET_MANAGER.registerHandler(BitmapAssetHandler.TYPE, new BitmapAssetHandler());\n    ASSET_MANAGER.registerHandler(ColorAssetHandler.TYPE, new ColorAssetHandler());\n    ASSET_MANAGER.registerHandler(GifAssetHandler.TYPE, new GifAssetHandler());\n  }\n\n  private NotificationsManager() {\n  }\n\n  @Nullable\n  private static JSONObject getPushJSON(@NonNull Bundle bundle) throws JSONException {\n    String pushPayload = bundle.getString(PUSH_PAYLOAD_KEY);\n    if (pushPayload == null) {\n      return null;\n    }\n    return new JSONObject(pushPayload);\n  }\n\n  @Nullable\n  private static JSONObject getCardJSON(@NonNull Bundle bundle) throws JSONException {\n    String cardPayload = bundle.getString(CARD_PAYLOAD_KEY);\n    if (cardPayload == null) {\n      return null;\n    }\n\n    return new JSONObject(cardPayload);\n  }\n\n  @Nullable\n  private static Intent intentForBundle(\n    @NonNull Context context,\n    @Nullable JSONObject pushJSON,\n    @NonNull JSONObject cardJSON,\n    @NonNull AssetManager assetManager,\n    @NonNull ContentManager contentManager\n  ) throws JSONException {\n    Version cardVersion = Version.parse(cardJSON.optString(\"version\"));\n\n    if (cardVersion == null || cardVersion.compareTo(PAYLOAD_VERSION_OBJECT) > 0) {\n      return null;\n    }\n\n    Intent intent = new Intent(context, CardActivity.class);\n\n    if (pushJSON != null) {\n      String campaignIdentifier = AppEventsLogger.getCampaignIdentifier(pushJSON);\n      if (campaignIdentifier != null) {\n        intent.putExtra(CardActivity.EXTRA_CAMPAIGN_IDENTIFIER, campaignIdentifier);\n      }\n    }\n    intent.putExtra(CardActivity.EXTRA_ASSET_MANAGER, assetManager);\n    intent.putExtra(CardActivity.EXTRA_CONTENT_MANAGER, contentManager);\n    intent.putExtra(CardActivity.EXTRA_CARD_PAYLOAD, cardJSON.toString());\n\n    return intent;\n  }\n\n  @NonNull\n  private static AssetManager getAssetManager(@NonNull Context context) {\n    AssetManager manager = new AssetManager(ASSET_MANAGER);\n    manager.setContext(context);\n    return manager;\n  }\n\n  @NonNull\n  private static ContentManager getContentManager(@NonNull Context context) {\n    ContentManager manager = new ContentManager(CONTENT_MANAGER);\n    manager.setContext(context);\n    return manager;\n  }\n\n  /**\n   * Returns whether or not a notification bundle has a valid push payload.\n   *\n   * @param notificationBundle The bundle to check for a push payload\n   */\n  public static boolean canPresentCard(@NonNull Bundle notificationBundle) {\n    return notificationBundle.containsKey(CARD_PAYLOAD_KEY);\n  }\n\n  /**\n   * Present an intent from a given activity to show the notification bundle contained in notificationBundle.\n   *\n   * @param activity           The activity to present from\n   * @param notificationBundle The bundle containing the notification payload to present\n   * @return whether or not the activity could successfully be presented\n   */\n  public static boolean presentCard(@NonNull Activity activity, @NonNull Bundle notificationBundle) {\n    try {\n      JSONObject cardJSON = getCardJSON(notificationBundle);\n      if (cardJSON == null) {\n        return false;\n      }\n\n      JSONObject pushJSON = getPushJSON(notificationBundle);\n\n      Intent presentationIntent = intentForBundle(activity,\n        pushJSON, cardJSON,\n        getAssetManager(activity), getContentManager(activity)\n      );\n      if (presentationIntent == null) {\n        return false;\n      }\n\n      activity.startActivityForResult(presentationIntent, REQUEST_CODE);\n      return true;\n    } catch (JSONException ex) {\n      Log.e(LOG_TAG, \"Error while parsing JSON\", ex);\n      return false;\n    }\n  }\n\n  /**\n   * Prepare and pre-load a notification bundle into memory.\n   *\n   * @param context            The current context of your program. Usually an activity, application, or\n   *                           service context.\n   * @param notificationBundle The bundle containing the notification payload to present\n   * @param callback           The callback to invoke once preparation is complete. This is guaranteed to be\n   *                           invoked on the same thread as this method is invoked from.\n   */\n  public static void prepareCard(\n    @NonNull final Context context,\n    @NonNull final Bundle notificationBundle,\n    @NonNull final PrepareCallback callback\n  ) {\n    final Handler handler = new Handler();\n    final AssetManager assetManager = getAssetManager(context);\n    final ContentManager contentManager = getContentManager(context);\n\n    // Cache and prepare in background.\n    new Thread() {\n      @Override\n      public void run() {\n        try {\n          JSONObject cardJSON = getCardJSON(notificationBundle);\n          if (cardJSON == null) {\n            throw new NullPointerException(\"No content present in the notification bundle.\");\n          }\n          Version cardVersion = Version.parse(cardJSON.optString(\"version\"));\n          if (cardVersion == null || cardVersion.compareTo(PAYLOAD_VERSION_OBJECT) > 0) {\n            throw new Exception(\"Payload version \" + cardVersion + \" not supported by this version of the notifications SDK.\");\n          }\n\n          assetManager.cachePayload(cardJSON, new AssetManager.CacheCompletionCallback() {\n            @Override\n            public void onCacheCompleted(@NonNull JSONObject payload) {\n              assetManager.stopCaching();\n\n              try {\n                JSONObject cardJSON = getCardJSON(notificationBundle);\n                final Intent presentIntent = intentForBundle(context, getPushJSON(notificationBundle), cardJSON, assetManager, contentManager);\n                if (presentIntent == null) {\n                  throw new NullPointerException(\"presentIntent was null, this should never happen!\");\n                }\n\n                CardConfiguration configuration = new CardConfiguration(cardJSON, assetManager, contentManager);\n                presentIntent.putExtra(CardActivity.EXTRA_CONFIGURATION, configuration);\n\n                handler.post(new Runnable() {\n                  @Override\n                  public void run() {\n                    callback.onPrepared(presentIntent);\n                  }\n                });\n              } catch (final Exception ex) {\n                handler.post(new Runnable() {\n                  @Override\n                  public void run() {\n                    callback.onError(ex);\n                  }\n                });\n              }\n            }\n          });\n        } catch (final Exception ex) {\n          handler.post(new Runnable() {\n            @Override\n            public void run() {\n              callback.onError(ex);\n            }\n          });\n        }\n      }\n    }.start();\n  }\n\n  /**\n   * Handle the result of an activity started using\n   * {@code prepare(Context, Bundle, PrepareCallback)} or {@code present(Activity, Bundle)}.\n   *\n   * @param requestCode The request code used to start the activity\n   * @param resultCode  The result code returned by the activity\n   * @param data        The data returned by the activity\n   * @return The notification card result of the activity if it exists, or null if it does not.\n   */\n  public static NotificationCardResult handleActivityResult(int requestCode, int resultCode, @Nullable Intent data) {\n    if (requestCode != REQUEST_CODE) {\n      return null;\n    }\n    if (resultCode != Activity.RESULT_OK || data == null) {\n      return null;\n    }\n\n    return data.getParcelableExtra(CardActivity.EXTRA_NOTIFICATION_CARD_RESULT);\n  }\n\n  /**\n   * Present a {@link Notification} to be presented from a GCM push bundle.\n   * <p/>\n   * This does not present a notification immediately, instead it caches the assets from the\n   * notification bundle, and then presents a notification to the user. This allows for a smoother\n   * interaction without loading indicators for the user.\n   * <p/>\n   * Note that only one notification can be created for a specific push bundle, should you attempt\n   * to present a new notification with the same payload bundle as an existing notification, it will\n   * replace and update the old notification.\n   *\n   * @param context            The context to send the notification from\n   * @param notificationBundle The content of the push notification\n   * @param launcherIntent     The launcher intent that contains your Application's activity.\n   *                           This will be modified with the FLAG_ACTIVITY_CLEAR_TOP and\n   *                           FLAG_ACTIVITY_SINGLE_TOP flags, in order to properly show the\n   *                           notification in an already running application.\n   *                           <p/>\n   *                           Should you not want this behavior, you may use the notificationExtender\n   *                           parameter to customize the contentIntent of the notification before\n   *                           presenting it.\n   */\n  public static boolean presentNotification(\n    @NonNull Context context,\n    @NonNull Bundle notificationBundle,\n    @NonNull Intent launcherIntent) {\n    return presentNotification(context, notificationBundle, launcherIntent, null);\n  }\n\n  /**\n   * Present a {@link Notification} to be presented from a GCM push bundle.\n   * <p/>\n   * This does not present a notification immediately, instead it caches the assets from the\n   * notification bundle, and then presents a notification to the user. This allows for a smoother\n   * interaction without loading indicators for the user.\n   * <p/>\n   * Note that only one notification can be created for a specific push bundle, should you attempt\n   * to present a new notification with the same payload bundle as an existing notification, it will\n   * replace and update the old notification.\n   *\n   * @param context              The context to send the notification from\n   * @param notificationBundle   The content of the push notification\n   * @param launcherIntent       The launcher intent that contains your Application's activity.\n   *                             This will be modified with the FLAG_ACTIVITY_CLEAR_TOP and\n   *                             FLAG_ACTIVITY_SINGLE_TOP flags, in order to properly show the\n   *                             notification in an already running application.\n   *                             <p/>\n   *                             Should you not want this behavior, you may use the notificationExtender\n   *                             parameter to customize the contentIntent of the notification before\n   *                             presenting it.\n   * @param notificationExtender A nullable argument that allows you to customize the notification\n   *                             before displaying it. Use this to configure Icons, text, sounds,\n   *                             etc. before we pass the notification off to the OS.\n   */\n  public static boolean presentNotification(\n    @NonNull final Context context,\n    @NonNull final Bundle notificationBundle,\n    @NonNull final Intent launcherIntent,\n    @Nullable final NotificationExtender notificationExtender) {\n    final JSONObject alert;\n    final int payloadHash;\n\n    try {\n      String payload = notificationBundle.getString(CARD_PAYLOAD_KEY);\n      if (payload == null) {\n        return false;\n      }\n      payloadHash = payload.hashCode();\n\n      JSONObject payloadObject = new JSONObject(payload);\n      alert = payloadObject.optJSONObject(\"alert\") != null\n        ? payloadObject.optJSONObject(\"alert\")\n        : new JSONObject();\n    } catch (JSONException ex) {\n      Log.e(LOG_TAG, \"Error while parsing notification bundle JSON\", ex);\n      return false;\n    }\n\n    final boolean[] success = new boolean[1];\n\n    final Thread backgroundThread = new Thread(new Runnable() {\n      @Override\n      public void run() {\n        Looper.prepare();\n        prepareCard(context, notificationBundle, new PrepareCallback() {\n          @Override\n          public void onPrepared(@NonNull Intent presentationIntent) {\n            Intent contentIntent = new Intent(launcherIntent);\n            contentIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);\n            contentIntent.putExtra(EXTRA_PAYLOAD_INTENT, presentationIntent);\n\n            NotificationManager manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);\n            Notification.Builder builder = new Notification.Builder(context)\n              .setSmallIcon(android.R.drawable.ic_dialog_alert)\n              .setContentTitle(alert.optString(\"title\"))\n              .setContentText(alert.optString(\"body\"))\n              .setAutoCancel(true)\n              .setContentIntent(\n                PendingIntent.getActivity(\n                  context.getApplicationContext(),\n                  payloadHash,\n                  contentIntent,\n                  PendingIntent.FLAG_ONE_SHOT\n                )\n              );\n\n            if (notificationExtender != null) {\n              builder = notificationExtender.extendNotification(builder);\n            }\n\n            manager.notify(NOTIFICATION_TAG, payloadHash, builder.getNotification());\n            success[0] = true;\n            Looper.myLooper().quit();\n          }\n\n          @Override\n          public void onError(@NonNull Exception exception) {\n            Log.e(LOG_TAG, \"Error while preparing card\", exception);\n            Looper.myLooper().quit();\n          }\n        });\n\n        Looper.loop();\n      }\n    });\n\n    backgroundThread.start();\n\n    try {\n      backgroundThread.join();\n    } catch (InterruptedException ex) {\n      Log.e(LOG_TAG, \"Failed to wait for background thread\", ex);\n      return false;\n    }\n    return success[0];\n  }\n\n  /**\n   * Present a card from the notification this activity\n   * was created from, if the notification exists.\n   *\n   * @param activity The activity to present from.\n   * @return Whether or not a card was presented.\n   */\n  public static boolean presentCardFromNotification(@NonNull Activity activity) {\n    return presentCardFromNotification(activity, activity.getIntent());\n  }\n\n  /**\n   * Present a card from the notification this activity\n   * was relaunched from, if the notification exists.\n   *\n   * @param activity The activity to present from.\n   * @param intent   Intent that was used to re-launch the activity.\n   * @return Whether or not a card was presented.\n   */\n  public static boolean presentCardFromNotification(@NonNull Activity activity,\n                                                    @NonNull Intent intent) {\n    Intent notificationIntent = intent.getParcelableExtra(EXTRA_PAYLOAD_INTENT);\n    if (notificationIntent == null) {\n      return false;\n    }\n\n    activity.startActivityForResult(notificationIntent, REQUEST_CODE);\n    return true;\n  }\n\n  /**\n   * Registers an Asset Handler for use.\n   *\n   * @param assetType         The type of the asset to register for.\n   * @param assetHandler      The asset handler to register.\n   */\n  private static void registerAssetHandler(\n    @NonNull String assetType,\n    @NonNull AssetManager.AssetHandler<? extends Asset> assetHandler\n  ) {\n    ASSET_MANAGER.registerHandler(assetType, assetHandler);\n  }\n}\n"
  },
  {
    "path": "Android/notifications/src/main/java/com/facebook/notifications/internal/activity/CardActivity.java",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\npackage com.facebook.notifications.internal.activity;\n\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.support.annotation.NonNull;\nimport android.support.annotation.Nullable;\nimport android.util.Log;\nimport android.view.Gravity;\nimport android.widget.FrameLayout;\nimport android.widget.FrameLayout.LayoutParams;\nimport android.widget.ProgressBar;\n\nimport com.facebook.notifications.NotificationCardResult;\nimport com.facebook.notifications.internal.appevents.AppEventsLogger;\nimport com.facebook.notifications.internal.asset.AssetManager;\nimport com.facebook.notifications.internal.asset.handlers.ColorAssetHandler;\nimport com.facebook.notifications.internal.configuration.CardConfiguration;\nimport com.facebook.notifications.internal.content.ContentManager;\nimport com.facebook.notifications.internal.view.ActionButton;\nimport com.facebook.notifications.internal.view.ActionsView;\nimport com.facebook.notifications.internal.view.CardView;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\n/**\n * An activity which displays a push card.\n */\npublic class CardActivity extends Activity implements ActionsView.Delegate {\n  /**\n   * The intent extra key to be set with the JSON payload of your push card payload.\n   */\n  public static final String EXTRA_CARD_PAYLOAD = \"fb_push_card_payload\";\n  /**\n   * If the configuration has already been cached and parsed, you may pass simply the entire\n   * configuration object to the activity. This is significantly faster than re-parsing the entire\n   * JSON object.\n   */\n  public static final String EXTRA_CONFIGURATION = \"fb_push_card_configuration\";\n  /**\n   * The intent extra key to be set with the push campaign identifier.\n   */\n  public static final String EXTRA_CAMPAIGN_IDENTIFIER = \"fb_push_campaign\";\n  /**\n   * The intent extra key to be set with an instance of {@link AssetManager}\n   */\n  public static final String EXTRA_ASSET_MANAGER = \"fb_push_card_asset_manager\";\n  /**\n   * The intent extra key to be set with an instance of {@link ContentManager}\n   */\n  public static final String EXTRA_CONTENT_MANAGER = \"fb_push_card_content_manager\";\n  /**\n   * The intent extra key to be set with the card result.\n   */\n  public static final String EXTRA_NOTIFICATION_CARD_RESULT = \"fb_notification_card_result\";\n  private static final String LOG_TAG = CardActivity.class.getCanonicalName();\n\n  private @Nullable String campaignIdentifier;\n  private @Nullable JSONObject configurationPayload;\n\n  private @NonNull AssetManager assetManager;\n  private @NonNull ContentManager contentManager;\n  private @NonNull AppEventsLogger appEventsLogger;\n  private @Nullable CardView cardView;\n\n  @Override\n  protected void onCreate(Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n\n    appEventsLogger = new AppEventsLogger(this);\n\n    Intent intent = getIntent();\n    campaignIdentifier = intent.getStringExtra(EXTRA_CAMPAIGN_IDENTIFIER);\n\n    String payloadString = intent.getStringExtra(EXTRA_CARD_PAYLOAD);\n    CardConfiguration configuration = intent.getParcelableExtra(EXTRA_CONFIGURATION);\n\n    AssetManager assetManager = intent.getParcelableExtra(EXTRA_ASSET_MANAGER);\n    ContentManager contentManager = intent.getParcelableExtra(EXTRA_CONTENT_MANAGER);\n\n    assetManager = assetManager != null ? assetManager : new AssetManager();\n    contentManager = contentManager != null ? contentManager : new ContentManager();\n\n    assetManager.setContext(this);\n    contentManager.setContext(this);\n\n    this.assetManager = assetManager;\n    this.contentManager = contentManager;\n\n    try {\n      configurationPayload = new JSONObject(payloadString);\n    } catch (JSONException ex) {\n      Log.e(LOG_TAG, \"Error parsing JSON payload\", ex);\n    }\n\n    if (configuration == null) {\n      beginLoadingContent();\n    } else {\n      displayConfiguration(configuration);\n    }\n\n    appEventsLogger.logPushOpen(campaignIdentifier);\n  }\n\n  @Override\n  protected void onDestroy() {\n    super.onDestroy();\n    if (assetManager == null) {\n      return;\n    }\n    assetManager.stopCaching();\n    if (configurationPayload == null) {\n      return;\n    }\n    assetManager.clearCache(configurationPayload);\n  }\n\n  private void beginLoadingContent() {\n    if (assetManager == null || contentManager == null) {\n      Log.e(LOG_TAG, \"Asset & content manager should be available!\");\n      return;\n    }\n\n    if (configurationPayload == null) {\n      Log.e(LOG_TAG, \"No card payload is available!\");\n      return;\n    }\n\n    ProgressBar loadingView = new ProgressBar(this);\n    loadingView.setIndeterminate(true);\n\n    int backgroundColor = ColorAssetHandler.fromRGBAHex(configurationPayload.optString(\"backdropColor\"));\n\n    FrameLayout loadingViewFrame = new FrameLayout(this);\n    loadingViewFrame.setBackgroundColor(backgroundColor);\n\n    LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);\n    layoutParams.gravity = Gravity.CENTER;\n    loadingViewFrame.addView(loadingView, layoutParams);\n\n    setContentView(loadingViewFrame);\n\n    final Handler handler = new Handler();\n    if (configurationPayload == null) {\n      return;\n    }\n\n    assetManager.cachePayload(configurationPayload, new AssetManager.CacheCompletionCallback() {\n      @Override\n      public void onCacheCompleted(@NonNull JSONObject payload) {\n        final CardConfiguration configuration;\n        try {\n          configuration = new CardConfiguration(configurationPayload, assetManager, contentManager);\n        } catch (JSONException ex) {\n          Log.e(LOG_TAG, \"Error while parsing JSON\", ex);\n          return;\n        }\n\n        handler.post(new Runnable() {\n          @Override\n          public void run() {\n            displayConfiguration(configuration);\n          }\n        });\n      }\n    });\n  }\n\n  private void displayConfiguration(CardConfiguration configuration) {\n    if (assetManager == null || contentManager == null) {\n      Log.e(LOG_TAG, \"Asset or content manager has unloaded since beginLoadingContent()!\");\n      return;\n    }\n\n    cardView = new CardView(this, assetManager, contentManager, this, configuration);\n    setContentView(cardView);\n  }\n\n  @Override\n  public void onBackPressed() {\n    appEventsLogger.logButtonAction(ActionButton.Type.Dismiss, campaignIdentifier);\n\n    Intent resultIntent = new Intent();\n    resultIntent.putExtra(EXTRA_NOTIFICATION_CARD_RESULT, new NotificationCardResult(null));\n    setResult(RESULT_OK, resultIntent);\n    finish();\n  }\n\n  @Override\n  public void actionButtonClicked(ActionButton.Type type, @Nullable Uri actionUri) {\n    appEventsLogger.logButtonAction(type, campaignIdentifier);\n\n    Intent resultIntent = new Intent();\n    resultIntent.putExtra(EXTRA_NOTIFICATION_CARD_RESULT, new NotificationCardResult(actionUri));\n    setResult(RESULT_OK, resultIntent);\n    finish();\n\n    if (actionUri == null) {\n      return;\n    }\n    Intent actionIntent = new Intent(Intent.ACTION_VIEW, actionUri);\n    startActivity(actionIntent);\n  }\n}\n"
  },
  {
    "path": "Android/notifications/src/main/java/com/facebook/notifications/internal/appevents/AppEventsLogger.java",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\npackage com.facebook.notifications.internal.appevents;\n\nimport android.content.Context;\nimport android.os.Bundle;\nimport android.support.annotation.NonNull;\nimport android.support.annotation.Nullable;\nimport android.util.Log;\n\nimport com.facebook.notifications.internal.view.ActionButton;\n\nimport org.json.JSONObject;\n\nimport java.lang.reflect.Method;\n\n/**\n * Simple class to call into core Facebook SDK and create/invoke the logger from there to report\n * App Events that have been triggered by a push card.\n */\npublic class AppEventsLogger {\n  private static final String LOG_TAG = AppEventsLogger.class.getCanonicalName();\n\n  private static final String PUSH_OPEN_EVENT = \"fb_mobile_push_opened\";\n  private static final String PUSH_CAMPAIGN_KEY = \"fb_push_campaign\";\n\n  private @Nullable Object fbSDKLogger;\n  private @Nullable Method fbSDKLogMethod;\n\n  public AppEventsLogger(@NonNull Context context) {\n    try {\n      Class<?> loggerClass = Class.forName(\"com.facebook.appevents.AppEventsLogger\");\n      Method instantiateMethod = loggerClass.getMethod(\"newLogger\", Context.class);\n      fbSDKLogMethod = loggerClass.getMethod(\"logEvent\", String.class, Bundle.class);\n      fbSDKLogger = instantiateMethod.invoke(null, context);\n    } catch (Exception ex) {\n      Log.w(\n        LOG_TAG,\n        \"Failed to initialize AppEventsLogger. \" +\n          \"Did you forget to include the Facebook SDK in your application?\",\n        ex\n      );\n    }\n  }\n\n  @Nullable\n  public static String getCampaignIdentifier(@NonNull JSONObject payload) {\n    return payload.optString(\"campaign\", null);\n  }\n\n  @NonNull\n  private static String getAppEventName(ActionButton.Type action) {\n    switch (action) {\n      case Primary:\n        return \"fb_mobile_push_card_action_primary\";\n      case Secondary:\n        return \"fb_mobile_push_card_action_secondary\";\n      case Dismiss:\n        return \"fb_mobile_push_card_action_dismiss\";\n      default:\n        throw new RuntimeException(\"Unknown action type: \" + action);\n    }\n  }\n\n  public void logPushOpen(@Nullable String campaignIdentifier) {\n    logEvent(PUSH_OPEN_EVENT, campaignIdentifier);\n  }\n\n  public void logButtonAction(ActionButton.Type action, @Nullable String campaignIdentifier) {\n    logEvent(getAppEventName(action), campaignIdentifier);\n  }\n\n  private void logEvent(@NonNull String eventName, @Nullable String campaignIdentifier) {\n    if (campaignIdentifier == null || campaignIdentifier.equals(\"\") ||\n      fbSDKLogger == null || fbSDKLogMethod == null) {\n      return;\n    }\n\n    Bundle parameters = new Bundle();\n    parameters.putString(PUSH_CAMPAIGN_KEY, campaignIdentifier);\n\n    try {\n      fbSDKLogMethod.invoke(fbSDKLogger, eventName, parameters);\n    } catch (Exception ex) {\n      Log.w(\n        LOG_TAG,\n        \"Failed to invoke AppEventsLogger.\" +\n          \"Did you forget to include the Facebook SDK in your application?\",\n        ex\n      );\n    }\n  }\n}\n"
  },
  {
    "path": "Android/notifications/src/main/java/com/facebook/notifications/internal/asset/Asset.java",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\npackage com.facebook.notifications.internal.asset;\n\nimport android.os.Parcelable;\nimport android.support.annotation.NonNull;\n\nimport com.facebook.notifications.internal.utilities.InvalidParcelException;\n\n/**\n * A 'marker' interface used for identifying an object as a resource. On its own, doesn't do much.\n */\npublic interface Asset extends Parcelable {\n\n  /**\n   * Get the type of this Asset. Used by {@link AssetManager} to find the proper\n   * {@link AssetManager.AssetHandler} for this asset.\n   *\n   * @return The asset type of the asset.\n   */\n  @NonNull\n  String getType();\n\n  /**\n   * Validate that all of the content for this asset has been properly cached and prepared.\n   *\n   * @throws InvalidParcelException\n   */\n  void validate() throws InvalidParcelException;\n}\n"
  },
  {
    "path": "Android/notifications/src/main/java/com/facebook/notifications/internal/asset/AssetManager.java",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\npackage com.facebook.notifications.internal.asset;\n\nimport android.content.Context;\nimport android.os.Bundle;\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.support.annotation.NonNull;\nimport android.support.annotation.Nullable;\nimport android.util.Log;\nimport android.view.View;\n\nimport com.facebook.notifications.internal.asset.cache.ContentCache;\nimport com.facebook.notifications.internal.utilities.InvalidParcelException;\nimport com.facebook.notifications.internal.utilities.JSONObjectVisitor;\n\nimport org.json.JSONObject;\n\nimport java.io.File;\nimport java.net.URL;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\n\n/**\n * Creates different Asset types based on the contents of a JSON payload\n */\npublic class AssetManager implements Parcelable {\n  /**\n   * Allows for the fetching of previously-fetched content from an on-disk cache.\n   */\n  public interface AssetCache {\n    /**\n     * Gets the on-disk file for a previously cached URL.\n     *\n     * @param url The url to fetch from the cache\n     * @return The file which contains the contents of the url, or null if the URL was not\n     * previously cached, or if caching failed\n     */\n    File getCachedFile(URL url);\n  }\n\n  /**\n   * An interface that allows different types of {@link Asset} to be displayed and used by the push\n   * card.\n   *\n   * This must be either {@link Parcelable} or constructable with a default constructor.\n   */\n  public interface AssetHandler<AssetType extends Asset> {\n    /**\n     * Invoked by {@link AssetManager} when an asset is being cached\n     *\n     * @param payload The payload to cache\n     * @return A set of URLs that contains the content to download into the asset cache, or null if\n     * no URLs exist to cache.\n     */\n    @Nullable\n    Set<URL> getCacheURLs(@NonNull JSONObject payload);\n\n    /**\n     * Invoked by {@link AssetManager} when an asset should be inflated from a JSON payload\n     * All of the URLs returned by `getCacheURLs()` are guaranteed to have been fully downloaded\n     *\n     * @param payload The payload to inflate from\n     * @param cache   The cache which contains the URLs that have been requested to be downloaded\n     * @return The fully inflated asset, or null if inflation fails\n     */\n    @Nullable\n    AssetType createAsset(@NonNull JSONObject payload, @NonNull AssetCache cache);\n\n    /**\n     * Invoked by {@link AssetManager} when an asset from this handler has been requested to be\n     * displayed\n     *\n     * @param asset   The asset to create a view for\n     * @param context The context to create a view for\n     * @return A new view\n     */\n    @NonNull\n    View createView(@NonNull AssetType asset, @NonNull Context context);\n  }\n\n  /**\n   * An interface for receiving a callback when the caching of a set of resources has completed.\n   */\n  public interface CacheCompletionCallback {\n    /**\n     * Invoked by the {@link AssetManager} whenever caching has finished.\n     *\n     * @param payload The payload which has been cached.\n     */\n    void onCacheCompleted(@NonNull JSONObject payload);\n  }\n\n  public static final Creator<AssetManager> CREATOR = new Creator<AssetManager>() {\n    @Override\n    public AssetManager createFromParcel(Parcel source) {\n      try {\n        AssetManager assetManager = new AssetManager(source);\n        assetManager.validate();\n\n        return assetManager;\n      } catch (InvalidParcelException ex) {\n        Log.w(LOG_TAG, \"Failed to decode asset manager\", ex);\n        return null;\n      }\n    }\n\n    @Override\n    public AssetManager[] newArray(int size) {\n      return new AssetManager[size];\n    }\n  };\n  private static final String LOG_TAG = AssetManager.class.getCanonicalName();\n\n  private @Nullable ContentCache contentCache;\n  private final @NonNull Map<String, ParcelableAssetHandler> registeredHandlers;\n\n  public AssetManager() {\n    registeredHandlers = new ConcurrentHashMap<>();\n  }\n\n  /**\n   * Creates a new AssetManager from another manager's handlers, but without a context set.\n   * @param other The asset manager to clone\n   */\n  public AssetManager(AssetManager other) {\n    registeredHandlers = new ConcurrentHashMap<>(other.registeredHandlers);\n  }\n\n  public AssetManager(@NonNull Parcel parcel) {\n    registeredHandlers = new ConcurrentHashMap<>();\n\n    Bundle handlersBundle = parcel.readBundle(getClass().getClassLoader());\n    for (String type : handlersBundle.keySet()) {\n      registeredHandlers.put(type, (ParcelableAssetHandler)handlersBundle.getParcelable(type));\n    }\n  }\n\n  public void setContext(@NonNull Context context) {\n    if (contentCache != null) {\n      throw new UnsupportedOperationException(\"Can only call setContext() once on an AssetManager!\");\n    }\n\n    contentCache = new ContentCache(context);\n  }\n\n  private void validate() throws InvalidParcelException {\n    for (ParcelableAssetHandler handler : registeredHandlers.values()) {\n      handler.validate();\n    }\n  }\n\n  public void registerHandler(@NonNull String assetType, @NonNull AssetHandler<? extends Asset> handler) {\n    registeredHandlers.put(assetType, new ParcelableAssetHandler(handler));\n  }\n\n  @Nullable\n  public Asset inflateAsset(@Nullable JSONObject payload) {\n    if (contentCache == null) {\n      throw new UnsupportedOperationException(\"Cannot call inflateAsset() before setContext() has been called!\");\n    }\n\n    if (payload == null) {\n      return null;\n    }\n\n    String type = payload.optString(\"_type\");\n    AssetHandler<? extends Asset> handler = registeredHandlers.get(type);\n    if (handler == null) {\n      return null;\n    }\n\n    return handler.createAsset(payload, contentCache);\n  }\n\n  @NonNull\n  public <AssetType extends Asset> View inflateView(@NonNull AssetType asset, @NonNull Context context) {\n    String type = asset.getType();\n\n    @SuppressWarnings(\"unchecked\")\n    AssetHandler<AssetType> handler = (AssetHandler<AssetType>) registeredHandlers.get(type);\n    if (handler == null) {\n      throw new IllegalArgumentException(\"Asset type \\\"\" + type + \"\\\" not registered!\");\n    }\n\n    return handler.createView(asset, context);\n  }\n\n  /**\n   * Caches a given JSON payload in the background.\n   *\n   * @param payload  The payload to cache\n   * @param callback The callback to be invoked when caching completes.\n   */\n  public void cachePayload(final @NonNull JSONObject payload, final @NonNull CacheCompletionCallback callback) {\n    if (contentCache == null) {\n      throw new UnsupportedOperationException(\"Cannot call cachePayload() before setContext() has been called!\");\n    }\n\n    contentCache.cache(getCacheURLs(payload), new ContentCache.CompletionCallback() {\n      @Override\n      public void onCacheCompleted(@NonNull Set<URL> urlsToCache) {\n        callback.onCacheCompleted(payload);\n      }\n    });\n  }\n\n  /**\n   * Clears the cache for a given JSON payload.\n   *\n   * @param payload The payload to clear the cache for.\n   */\n  public void clearCache(@NonNull JSONObject payload) {\n    if (contentCache == null) {\n      throw new UnsupportedOperationException(\"Cannot call cachePayload() before setContext() has been called!\");\n    }\n\n    contentCache.clear(getCacheURLs(payload));\n  }\n\n  /**\n   * Stops any caching that may be occurring in the background.\n   */\n  public void stopCaching() {\n    if (contentCache == null) {\n      throw new UnsupportedOperationException(\"Cannot call stopCaching() before setContext() has been called!\");\n    }\n    contentCache.stop();\n  }\n\n  @NonNull\n  private Set<URL> getCacheURLs(@Nullable JSONObject payload) {\n    if (contentCache == null) {\n      throw new UnsupportedOperationException(\"Cannot call stopCaching() before setContext() has been called!\");\n    }\n\n    if (payload == null) {\n      return new HashSet<>();\n    }\n\n    final Set<URL> cacheURLs = new HashSet<>();\n    JSONObjectVisitor.walk(payload, new JSONObjectVisitor() {\n      @Override\n      protected void visit(JSONObject object) {\n        super.visit(object);\n\n        String type = object.optString(\"_type\");\n        AssetHandler<? extends Asset> handler = registeredHandlers.get(type);\n        if (handler == null) {\n          return;\n        }\n\n        Set<URL> newURLs = handler.getCacheURLs(object);\n        if (newURLs == null) {\n          return;\n        }\n\n        cacheURLs.addAll(newURLs);\n      }\n    });\n\n    return cacheURLs;\n  }\n\n  @Override\n  public int describeContents() {\n    return 0;\n  }\n\n  @Override\n  public void writeToParcel(Parcel dest, int flags) {\n    Bundle bundle = new Bundle();\n    for (Map.Entry<String, ParcelableAssetHandler> entry : registeredHandlers.entrySet()) {\n      bundle.putParcelable(entry.getKey(), entry.getValue());\n    }\n\n    dest.writeBundle(bundle);\n  }\n}\n"
  },
  {
    "path": "Android/notifications/src/main/java/com/facebook/notifications/internal/asset/ParcelableAssetHandler.java",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\npackage com.facebook.notifications.internal.asset;\n\nimport android.content.Context;\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.support.annotation.NonNull;\nimport android.support.annotation.Nullable;\nimport android.view.View;\n\nimport com.facebook.notifications.internal.utilities.InvalidParcelException;\n\nimport org.json.JSONObject;\n\nimport java.net.URL;\nimport java.util.Set;\n\n/**\n * Represents a parcelable entry in {@link AssetManager}'s handler list.\n */\nclass ParcelableAssetHandler implements AssetManager.AssetHandler<Asset>, Parcelable {\n  public static final Creator<ParcelableAssetHandler> CREATOR = new Creator<ParcelableAssetHandler>() {\n    @Override\n    public ParcelableAssetHandler createFromParcel(Parcel source) {\n      return new ParcelableAssetHandler(source);\n    }\n\n    @Override\n    public ParcelableAssetHandler[] newArray(int size) {\n      return new ParcelableAssetHandler[size];\n    }\n  };\n\n  private final @Nullable AssetManager.AssetHandler<Asset> handler;\n  private final @Nullable InvalidParcelException exception;\n\n  @SuppressWarnings(\"unchecked\")\n  public ParcelableAssetHandler(@NonNull AssetManager.AssetHandler<? extends Asset> handler) {\n    this.handler = (AssetManager.AssetHandler) handler;\n    this.exception = null;\n  }\n\n  @SuppressWarnings(\"unchecked\")\n  public ParcelableAssetHandler(Parcel source) {\n    boolean isParcelable = source.readInt() != 0;\n\n    if (isParcelable) {\n      handler = source.readParcelable(getClass().getClassLoader());\n      exception = null;\n    } else {\n      AssetManager.AssetHandler handler = null;\n      InvalidParcelException exception = null;\n\n      try {\n        Class assetHandlerClass = (Class) Class.forName(source.readString(), true, getClass().getClassLoader());\n        handler = (AssetManager.AssetHandler) assetHandlerClass.newInstance();\n      } catch (Exception ex) {\n        exception = new InvalidParcelException(ex);\n      }\n\n      this.handler = handler;\n      this.exception = exception;\n    }\n  }\n\n  public void validate() throws InvalidParcelException {\n    if (exception != null) {\n      throw exception;\n    }\n\n    if (handler == null) {\n      throw new IllegalStateException(\"AssetHandler should not be null when parceling if no exception was thrown!\");\n    }\n  }\n\n  @Nullable\n  @Override\n  public Set<URL> getCacheURLs(@NonNull JSONObject payload) {\n    if (handler == null) {\n      throw new IllegalStateException(\"AssetHandler should not be null, did you forget to call validate()?\");\n    }\n    return handler.getCacheURLs(payload);\n  }\n\n  @Nullable\n  @Override\n  public Asset createAsset(@NonNull JSONObject payload, @NonNull AssetManager.AssetCache cache) {\n    if (handler == null) {\n      throw new IllegalStateException(\"AssetHandler should not be null, did you forget to call validate()?\");\n    }\n    return handler.createAsset(payload, cache);\n  }\n\n  @NonNull\n  @Override\n  public View createView(@NonNull Asset asset, @NonNull Context context) {\n    if (handler == null) {\n      throw new IllegalStateException(\"AssetHandler should not be null, did you forget to call validate()?\");\n    }\n    return handler.createView(asset, context);\n  }\n\n  @Override\n  public int describeContents() {\n    return 0;\n  }\n\n  @Override\n  public void writeToParcel(Parcel dest, int flags) {\n    if (handler == null) {\n      throw new IllegalStateException(\"AssetHandler should not be null, did you forget to call validate()?\");\n    }\n\n    if (handler instanceof Parcelable) {\n      dest.writeInt(1);\n      dest.writeParcelable((Parcelable)handler, flags);\n    } else {\n      dest.writeInt(0);\n      dest.writeString(handler.getClass().getName());\n    }\n  }\n}\n"
  },
  {
    "path": "Android/notifications/src/main/java/com/facebook/notifications/internal/asset/cache/CacheOperation.java",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\npackage com.facebook.notifications.internal.asset.cache;\n\nimport android.support.annotation.NonNull;\nimport android.support.annotation.Nullable;\n\nimport java.io.File;\nimport java.net.URL;\nimport java.util.HashSet;\nimport java.util.Set;\n\nclass CacheOperation implements ContentDownloader.DownloadCallback {\n  private final @NonNull Object mutex;\n  private final @NonNull Set<URL> urlsToCache;\n  private final @NonNull Set<URL> remainingURLs;\n  private final @NonNull ContentCache.CompletionCallback completion;\n\n  public CacheOperation(@NonNull Set<URL> urlsToCache, @NonNull ContentCache.CompletionCallback completion) {\n    this.mutex = new Object();\n    this.urlsToCache = urlsToCache;\n    this.remainingURLs = new HashSet<>(urlsToCache);\n    this.completion = completion;\n  }\n\n  @NonNull\n  public Set<URL> getUrlsToCache() {\n    return urlsToCache;\n  }\n\n  @NonNull\n  public ContentCache.CompletionCallback getCompletion() {\n    return completion;\n  }\n\n  @Override\n  public void onResourceDownloaded(@NonNull URL url, @Nullable File targetFile) {\n    boolean invoke;\n    synchronized (mutex) {\n      remainingURLs.remove(url);\n      invoke = remainingURLs.size() == 0;\n    }\n\n    if (invoke) {\n      completion.onCacheCompleted(urlsToCache);\n    }\n  }\n}\n"
  },
  {
    "path": "Android/notifications/src/main/java/com/facebook/notifications/internal/asset/cache/ContentCache.java",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\npackage com.facebook.notifications.internal.asset.cache;\n\nimport android.content.Context;\nimport android.support.annotation.NonNull;\nimport android.support.annotation.Nullable;\n\nimport com.facebook.notifications.internal.asset.Asset;\nimport com.facebook.notifications.internal.asset.AssetManager;\n\nimport java.io.File;\nimport java.net.URL;\nimport java.nio.charset.Charset;\nimport java.security.MessageDigest;\nimport java.security.NoSuchAlgorithmException;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Iterator;\nimport java.util.Map;\nimport java.util.Set;\n\n/**\n * Manages the caching of an {@link Asset}'s resources\n * from the internet\n */\npublic class ContentCache implements AssetManager.AssetCache {\n  public interface CompletionCallback {\n    void onCacheCompleted(@NonNull Set<URL> urlsToCache);\n  }\n\n  private static final String LOG_TAG = ContentCache.class.getCanonicalName();\n\n  private final @NonNull Context context;\n\n  private final @NonNull ContentDownloader downloader;\n  private final @NonNull Thread downloadThread;\n\n  private final @NonNull DiskCache diskCache;\n\n  private final @NonNull Object synchronizationMutex;\n  private final @NonNull Map<String, Set<CacheOperation>> cacheOperations;\n  private @Nullable Set<String> cachedKeys;\n\n  public ContentCache(@NonNull Context context) {\n    this.context = context;\n\n    downloader = new ContentDownloader();\n    diskCache = new DiskCache(context);\n\n    downloadThread = new Thread(downloader);\n\n    synchronizationMutex = new Object();\n    cacheOperations = new HashMap<>();\n\n    downloadThread.start();\n  }\n\n  @NonNull\n  private static String getCacheKey(@NonNull URL url) {\n    String urlString = url.toString();\n\n    try {\n      MessageDigest MD5 = MessageDigest.getInstance(\"MD5\");\n      Charset UTF8 = Charset.forName(\"UTF-8\");\n\n      byte[] toDigest = urlString.getBytes(UTF8);\n      byte[] digested = MD5.digest(toDigest);\n\n      return String.format(\n        \"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\",\n        digested[0], digested[1], digested[2], digested[3], digested[4], digested[5], digested[6],\n        digested[7], digested[8], digested[9], digested[10], digested[11], digested[12],\n        digested[13], digested[14], digested[15]);\n    } catch (NoSuchAlgorithmException ex) {\n      // If for some ungodly reason MD5 doesn't exist in this JVM, use the string's built-in hash\n      // code.\n      return Integer.toHexString(urlString.hashCode());\n    }\n  }\n\n  public void stop() {\n    downloadThread.interrupt();\n\n    try {\n      downloadThread.join();\n    } catch (InterruptedException ex) {\n      // If we were interrupted while waiting to have our children die, re-interrupt the\n      // child thread and hope for the best.\n      downloadThread.interrupt();\n    }\n  }\n\n  @NonNull\n  public Context getContext() {\n    return context;\n  }\n\n  public void cache(@NonNull Set<URL> urlsToCache, @NonNull CompletionCallback completion) {\n    CacheOperation operation = new CacheOperation(urlsToCache, completion);\n\n    synchronized (synchronizationMutex) {\n      int scheduledCount = 0;\n      for (Iterator<URL> urlIterator = operation.getUrlsToCache().iterator(); urlIterator.hasNext(); ) {\n        URL url = urlIterator.next();\n        final String hashKey = getCacheKey(url);\n        if (hasCachedData(hashKey)) {\n          urlIterator.remove();\n          continue;\n        }\n\n        if (cacheOperations.containsKey(hashKey)) {\n          Set<CacheOperation> existingOperations = cacheOperations.get(hashKey);\n          existingOperations.add(operation);\n          continue;\n        }\n\n        final Set<CacheOperation> newOperations = new HashSet<>();\n        newOperations.add(operation);\n\n        cacheOperations.put(hashKey, newOperations);\n        downloader.downloadAsync(url, diskCache.fetch(getCacheKey(url)), new ContentDownloader.DownloadCallback() {\n          @Override\n          public void onResourceDownloaded(@NonNull URL url, @Nullable File file) {\n            Set<CacheOperation> operations;\n            synchronized (synchronizationMutex) {\n              operations = new HashSet<>(newOperations);\n            }\n\n            for (CacheOperation operation : operations) {\n              operation.onResourceDownloaded(url, file);\n            }\n          }\n        });\n\n        scheduledCount++;\n      }\n\n      if (scheduledCount == 0) {\n        completion.onCacheCompleted(urlsToCache);\n      }\n    }\n  }\n\n  public void clear(@NonNull Set<URL> urlsToClear) {\n    synchronized (synchronizationMutex) {\n      for (URL url : urlsToClear) {\n        String cacheKey = getCacheKey(url);\n        diskCache.remove(cacheKey);\n        if (cachedKeys != null) {\n          cachedKeys.remove(cacheKey);\n        }\n      }\n    }\n  }\n\n  @Nullable\n  @Override\n  public File getCachedFile(@NonNull URL contentURL) {\n    File file = diskCache.fetch(getCacheKey(contentURL));\n    if (!file.exists()) {\n      return null;\n    }\n    return file;\n  }\n\n  private boolean hasCachedData(@NonNull String cacheKey) {\n    synchronized (synchronizationMutex) {\n      if (cachedKeys == null) {\n        cachedKeys = diskCache.getCacheKeys();\n      }\n\n      return cachedKeys.contains(cacheKey);\n    }\n  }\n}\n"
  },
  {
    "path": "Android/notifications/src/main/java/com/facebook/notifications/internal/asset/cache/ContentDownloader.java",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\npackage com.facebook.notifications.internal.asset.cache;\n\nimport android.support.annotation.NonNull;\nimport android.support.annotation.Nullable;\nimport android.util.Log;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.net.HttpURLConnection;\nimport java.net.URL;\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.LinkedBlockingQueue;\n\nclass ContentDownloader implements Runnable {\n  public interface DownloadCallback {\n    void onResourceDownloaded(@NonNull URL url, @Nullable File file);\n  }\n\n  private interface DownloadOperation extends Runnable {\n  }\n\n  private static final String LOG_TAG = ContentDownloader.class.getCanonicalName();\n  private final @NonNull BlockingQueue<DownloadOperation> operations;\n\n  public ContentDownloader() {\n    operations = new LinkedBlockingQueue<>();\n  }\n\n  @Override\n  public void run() {\n    while (true) {\n      try {\n        DownloadOperation operation = operations.take();\n        operation.run();\n      } catch (InterruptedException ex) {\n        // This means our parent thread requested us killed, RIP.\n        return;\n      }\n    }\n  }\n\n  public void downloadAsync(final @NonNull URL url, final @NonNull File targetFile, final @NonNull DownloadCallback callback) {\n    operations.offer(new DownloadOperation() {\n      private File download(@NonNull URL url) {\n        HttpURLConnection connection = null;\n        InputStream inputStream = null;\n        OutputStream outputStream = null;\n\n        try {\n          connection = (HttpURLConnection) url.openConnection();\n          if (connection.getResponseCode() != 200) {\n            return null;\n          }\n\n          inputStream = connection.getInputStream();\n          outputStream = new FileOutputStream(targetFile);\n          byte[] buffer = new byte[4096];\n\n          while (true) {\n            int read = inputStream.read(buffer);\n            if (read == -1) {\n              break;\n            }\n\n            outputStream.write(buffer, 0, read);\n          }\n\n          return targetFile;\n        } catch (Exception ex) {\n          Log.e(LOG_TAG, \"Failed to download content for url \" + url, ex);\n          return null;\n        } finally {\n          try {\n            if (inputStream != null) {\n              inputStream.close();\n            }\n\n            if (outputStream != null) {\n              outputStream.close();\n            }\n          } catch (IOException ex) {\n            Log.e(LOG_TAG, \"Failed to close streams\", ex);\n          }\n\n          if (connection != null) {\n            connection.disconnect();\n          }\n        }\n      }\n\n      @Override\n      public void run() {\n        callback.onResourceDownloaded(url, download(url));\n      }\n    });\n  }\n}\n"
  },
  {
    "path": "Android/notifications/src/main/java/com/facebook/notifications/internal/asset/cache/DiskCache.java",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\npackage com.facebook.notifications.internal.asset.cache;\n\nimport android.content.Context;\nimport android.support.annotation.NonNull;\nimport android.util.Log;\n\nimport java.io.File;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.Set;\n\nclass DiskCache {\n  private static final String LOG_TAG = DiskCache.class.getCanonicalName();\n\n  private final @NonNull File cacheDirectory;\n\n  public DiskCache(@NonNull Context context) {\n    cacheDirectory = context.getCacheDir();\n  }\n\n  public void remove(final @NonNull String key) {\n    File diskFile = new File(cacheDirectory, key);\n    if (!diskFile.delete()) {\n      Log.w(LOG_TAG, \"Failed to delete cache file \\\"\" + diskFile.getAbsolutePath() + \"\\\"\");\n    }\n  }\n\n  @NonNull\n  public File fetch(@NonNull String key) {\n    return new File(cacheDirectory, key);\n  }\n\n  @NonNull\n  public Set<String> getCacheKeys() {\n    String[] files = cacheDirectory.list();\n    Set<String> keys = new HashSet<>(files.length);\n    Collections.addAll(keys, files);\n    return keys;\n  }\n}\n"
  },
  {
    "path": "Android/notifications/src/main/java/com/facebook/notifications/internal/asset/handlers/BitmapAssetHandler.java",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\npackage com.facebook.notifications.internal.asset.handlers;\n\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\nimport android.os.Parcel;\nimport android.support.annotation.NonNull;\nimport android.support.annotation.Nullable;\nimport android.util.Log;\nimport android.view.View;\nimport android.widget.ImageView;\n\nimport com.facebook.notifications.internal.asset.Asset;\nimport com.facebook.notifications.internal.asset.AssetManager;\nimport com.facebook.notifications.internal.utilities.InvalidParcelException;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.MalformedURLException;\nimport java.net.URL;\nimport java.util.HashSet;\nimport java.util.Set;\n\n/**\n * Handles assets of the bitmap type\n */\npublic class BitmapAssetHandler implements AssetManager.AssetHandler<BitmapAssetHandler.BitmapAsset> {\n  /**\n   * A resource implementation for Bitmaps read from disk\n   */\n  static class BitmapAsset implements Asset {\n    public static final Creator<BitmapAsset> CREATOR = new Creator<BitmapAsset>() {\n      @Override\n      public BitmapAsset createFromParcel(Parcel source) {\n        return new BitmapAsset(source);\n      }\n\n      @Override\n      public BitmapAsset[] newArray(int size) {\n        return new BitmapAsset[size];\n      }\n    };\n    private final @NonNull File createdFrom;\n    private transient @Nullable Bitmap bitmap;\n\n    private BitmapAsset(@NonNull File createdFrom) {\n      this.createdFrom = createdFrom;\n    }\n\n    private BitmapAsset(@NonNull Parcel parcel) {\n      createdFrom = new File(parcel.readString());\n    }\n\n    @Nullable\n    private static Bitmap decodeBitmap(@NonNull File file) {\n      try {\n        // NOTE: We must be careful when decoding images on android. If a malicious push sends down\n        // a payload image that is too large for us to reasonably decode, we must ensure that we can\n        // safely fall back to a lower resolution if we don't have the memory for it.\n        BitmapFactory.Options options = new BitmapFactory.Options();\n        options.inSampleSize = 1;\n\n        while (true) {\n          InputStream cachedData = new FileInputStream(file);\n\n          try {\n            return BitmapFactory.decodeStream(cachedData, null, options);\n          } catch (OutOfMemoryError ex) {\n            // Ignore out of memory, try loading with less requested resolution.\n            System.gc();\n            options.inSampleSize *= 2;\n          } finally {\n            cachedData.close();\n          }\n        }\n      } catch (IOException ex) {\n        Log.e(LOG_TAG, \"IO Exception!\", ex);\n        return null;\n      }\n    }\n\n    @NonNull\n    public File getCreatedFrom() {\n      return createdFrom;\n    }\n\n    @NonNull\n    public Bitmap getBitmap() {\n      if (bitmap == null) {\n        bitmap = decodeBitmap(createdFrom);\n        if (bitmap == null) {\n          throw new RuntimeException(\"Failed to decode bitmap from file\");\n        }\n      }\n      return bitmap;\n    }\n\n    @NonNull\n    @Override\n    public String getType() {\n      return TYPE;\n    }\n\n    @Override\n    public void validate() throws InvalidParcelException {\n      if (!createdFrom.exists()) {\n        throw new InvalidParcelException(\n          new FileNotFoundException(\n            \"Bitmap cache file does not exist: \" + createdFrom.getAbsolutePath()\n          )\n        );\n      }\n    }\n\n    @Override\n    public int describeContents() {\n      return 0;\n    }\n\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n      dest.writeString(createdFrom.getAbsolutePath());\n    }\n  }\n\n  public static final String TYPE = \"Image\";\n  private static final String LOG_TAG = BitmapAssetHandler.class.getCanonicalName();\n\n  @Nullable\n  @Override\n  public Set<URL> getCacheURLs(@NonNull JSONObject payload) {\n    try {\n      URL url = new URL(payload.getString(\"url\"));\n      Set<URL> set = new HashSet<>();\n      set.add(url);\n\n      return set;\n    } catch (MalformedURLException ex) {\n      return null;\n    } catch (JSONException ex) {\n      return null;\n    }\n  }\n\n  @Nullable\n  @Override\n  public BitmapAsset createAsset(@NonNull JSONObject payload, @NonNull AssetManager.AssetCache cache) {\n    try {\n      URL url = new URL(payload.getString(\"url\"));\n      File cacheFile = cache.getCachedFile(url);\n      if (cacheFile == null) {\n        return null;\n      }\n\n      return new BitmapAsset(cacheFile);\n    } catch (MalformedURLException ex) {\n      Log.e(LOG_TAG, \"JSON key 'url' was not a valid URL\", ex);\n      return null;\n    } catch (JSONException ex) {\n      Log.e(LOG_TAG, \"JSON exception\", ex);\n      return null;\n    }\n  }\n\n  @NonNull\n  @Override\n  public View createView(@NonNull BitmapAsset asset, @NonNull Context context) {\n    ImageView imageView = new ImageView(context);\n    imageView.setImageBitmap(asset.getBitmap());\n    imageView.setScaleType(ImageView.ScaleType.FIT_CENTER);\n    imageView.setAdjustViewBounds(true);\n\n    return imageView;\n  }\n}\n"
  },
  {
    "path": "Android/notifications/src/main/java/com/facebook/notifications/internal/asset/handlers/ColorAssetHandler.java",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\npackage com.facebook.notifications.internal.asset.handlers;\n\nimport android.content.Context;\nimport android.os.Parcel;\nimport android.support.annotation.NonNull;\nimport android.support.annotation.Nullable;\nimport android.util.Log;\nimport android.view.View;\nimport android.widget.FrameLayout;\n\nimport com.facebook.notifications.internal.asset.Asset;\nimport com.facebook.notifications.internal.asset.AssetManager;\nimport com.facebook.notifications.internal.utilities.InvalidParcelException;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.net.URL;\nimport java.util.Set;\n\n/**\n * Handles assets of Color type.\n */\npublic class ColorAssetHandler implements AssetManager.AssetHandler<ColorAssetHandler.ColorAsset> {\n  /**\n   * An asset implementation for a single static color\n   */\n  static class ColorAsset implements Asset {\n    public static final Creator<ColorAsset> CREATOR = new Creator<ColorAsset>() {\n      @Override\n      public ColorAsset createFromParcel(Parcel source) {\n        return new ColorAsset(source);\n      }\n\n      @Override\n      public ColorAsset[] newArray(int size) {\n        return new ColorAsset[size];\n      }\n    };\n\n    private final int color;\n\n    private ColorAsset(int color) {\n      this.color = color;\n    }\n\n    private ColorAsset(@NonNull Parcel parcel) {\n      color = parcel.readInt();\n    }\n\n    public int getColor() {\n      return color;\n    }\n\n    @NonNull\n    @Override\n    public String getType() {\n      return TYPE;\n    }\n\n    @Override\n    public void validate() throws InvalidParcelException {\n      // Nothing to validate\n    }\n\n    @Override\n    public int describeContents() {\n      return 0;\n    }\n\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n      dest.writeInt(color);\n    }\n  }\n\n  @SuppressWarnings(\"ViewConstructor\")\n  private static class ColorView extends FrameLayout {\n    public ColorView(Context context, int color) {\n      super(context);\n      setBackgroundColor(color);\n    }\n  }\n\n  public static final String TYPE = \"Color\";\n  private static final String LOG_TAG = ColorAssetHandler.class.getCanonicalName();\n\n  /**\n   * Parses a string in the format '#RRGGBBAA', and returns it as an android-compatible color\n   *\n   * @param input The string to parse\n   * @return The color, in an android-compatible format\n   */\n  public static int fromRGBAHex(@Nullable String input) {\n    if (input == null || input.equals(\"\")) {\n      return 0;\n    }\n    input = input.substring(1);\n\n    try {\n      long value = Long.parseLong(input, 16);\n\n      // Android color has alpha first, not last. Flip the bytes around.\n      return (int) ((value >> 8) | ((value & 0xFF) << 24));\n    } catch (NumberFormatException ex) {\n      return 0;\n    }\n  }\n\n  @Nullable\n  @Override\n  public Set<URL> getCacheURLs(@NonNull JSONObject payload) {\n    return null;\n  }\n\n  @Nullable\n  @Override\n  public ColorAsset createAsset(@NonNull JSONObject payload, @NonNull AssetManager.AssetCache cache) {\n    try {\n      return new ColorAsset(fromRGBAHex(payload.getString(\"rgbaHex\")));\n    } catch (JSONException ex) {\n      Log.e(LOG_TAG, \"JSON Exception\", ex);\n      return null;\n    }\n  }\n\n  @NonNull\n  @Override\n  public View createView(@NonNull ColorAsset asset, @NonNull Context context) {\n    return new ColorView(context, asset.getColor());\n  }\n}\n"
  },
  {
    "path": "Android/notifications/src/main/java/com/facebook/notifications/internal/asset/handlers/GifAssetHandler.java",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\npackage com.facebook.notifications.internal.asset.handlers;\n\nimport android.content.Context;\nimport android.os.Parcel;\nimport android.support.annotation.NonNull;\nimport android.support.annotation.Nullable;\nimport android.util.Log;\nimport android.view.View;\n\nimport com.facebook.notifications.internal.asset.Asset;\nimport com.facebook.notifications.internal.asset.AssetManager;\nimport com.facebook.notifications.internal.utilities.GifDecoder;\nimport com.facebook.notifications.internal.utilities.InvalidParcelException;\nimport com.facebook.notifications.internal.view.GifView;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.net.MalformedURLException;\nimport java.net.URL;\nimport java.util.HashSet;\nimport java.util.Set;\n\n/**\n * Handles assets of the GIF type.\n */\npublic class GifAssetHandler implements AssetManager.AssetHandler<GifAssetHandler.GifAsset> {\n  /**\n   * A resource implementation for GIFs read from disk\n   */\n  static class GifAsset implements Asset {\n    public static final Creator<GifAsset> CREATOR = new Creator<GifAsset>() {\n      @Override\n      public GifAsset createFromParcel(Parcel source) {\n        return new GifAsset(source);\n      }\n\n      @Override\n      public GifAsset[] newArray(int size) {\n        return new GifAsset[size];\n      }\n    };\n    private final @NonNull File createdFrom;\n    private transient @Nullable GifDecoder decoder;\n\n    private GifAsset(@NonNull File createdFrom) {\n      this.createdFrom = createdFrom;\n    }\n\n    private GifAsset(@NonNull Parcel source) {\n      createdFrom = new File(source.readString());\n    }\n\n    @Nullable\n    private static GifDecoder decodeGif(@NonNull File file) {\n      long fileLength = file.length();\n      if (fileLength == 0 || fileLength > Integer.MAX_VALUE) {\n        return null;\n      }\n\n      byte[] bytes = new byte[(int) fileLength];\n\n      try {\n        FileInputStream fileInputStream = new FileInputStream(file);\n        int fileOffset = 0;\n\n        try {\n          while (true) {\n            int remaining = (bytes.length - fileOffset);\n            if (remaining == 0) {\n              break;\n            }\n            int read = fileInputStream.read(bytes, fileOffset, remaining);\n            if (read == -1) {\n              throw new IOException(\"File was shorter than expected!\");\n            }\n            fileOffset += read;\n          }\n        } finally {\n          fileInputStream.close();\n        }\n      } catch (IOException ex) {\n        Log.e(LOG_TAG, \"IO Exception while reading GIF data\", ex);\n        return null;\n      }\n\n      GifDecoder decoder = new GifDecoder();\n      decoder.read(bytes);\n\n      return decoder;\n    }\n\n    @NonNull\n    public File getCreatedFrom() {\n      return createdFrom;\n    }\n\n    @NonNull\n    public GifDecoder getDecoder() {\n      if (decoder == null) {\n        decoder = decodeGif(createdFrom);\n        if (decoder == null) {\n          throw new RuntimeException(\"Failed to decode GIF\");\n        }\n      }\n      return decoder;\n    }\n\n    @NonNull\n    @Override\n    public String getType() {\n      return TYPE;\n    }\n\n    @Override\n    public void validate() throws InvalidParcelException {\n      if (!createdFrom.exists()) {\n        throw new InvalidParcelException(\n          new FileNotFoundException(\n            \"GIF cache file does not exist: \" + createdFrom.getAbsolutePath()\n          )\n        );\n      }\n    }\n\n    @Override\n    public int describeContents() {\n      return 0;\n    }\n\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n      dest.writeString(createdFrom.getAbsolutePath());\n    }\n  }\n\n  public static final String TYPE = \"GIF\";\n  private static final String LOG_TAG = GifAssetHandler.class.getCanonicalName();\n\n  @Nullable\n  @Override\n  public Set<URL> getCacheURLs(@NonNull JSONObject payload) {\n    try {\n      URL url = new URL(payload.getString(\"url\"));\n      Set<URL> set = new HashSet<>();\n      set.add(url);\n\n      return set;\n    } catch (MalformedURLException ex) {\n      return null;\n    } catch (JSONException ex) {\n      return null;\n    }\n  }\n\n  @Nullable\n  @Override\n  public GifAsset createAsset(@NonNull JSONObject payload, @NonNull AssetManager.AssetCache cache) {\n    try {\n      URL url = new URL(payload.getString(\"url\"));\n      File cacheFile = cache.getCachedFile(url);\n      if (cacheFile == null) {\n        return null;\n      }\n\n      return new GifAsset(cacheFile);\n    } catch (MalformedURLException ex) {\n      Log.e(LOG_TAG, \"JSON key 'url' was not a valid URL.\", ex);\n      return null;\n    } catch (JSONException ex) {\n      Log.e(LOG_TAG, \"JSON exception\", ex);\n      return null;\n    }\n  }\n\n  @NonNull\n  @Override\n  public View createView(@NonNull GifAsset asset, @NonNull Context context) {\n    return new GifView(context, asset.getDecoder());\n  }\n}\n"
  },
  {
    "path": "Android/notifications/src/main/java/com/facebook/notifications/internal/configuration/ActionConfiguration.java",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\npackage com.facebook.notifications.internal.configuration;\n\nimport android.net.Uri;\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.support.annotation.Nullable;\n\nimport com.facebook.notifications.internal.content.Content;\nimport com.facebook.notifications.internal.content.TextContent;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport static com.facebook.notifications.internal.asset.handlers.ColorAssetHandler.fromRGBAHex;\n\npublic class ActionConfiguration implements Parcelable {\n  public static final Creator<ActionConfiguration> CREATOR = new Creator<ActionConfiguration>() {\n    @Override\n    public ActionConfiguration createFromParcel(Parcel source) {\n      return new ActionConfiguration(source);\n    }\n\n    @Override\n    public ActionConfiguration[] newArray(int size) {\n      return new ActionConfiguration[size];\n    }\n  };\n\n  private final int backgroundColor;\n  private final int borderColor;\n  private final float borderWidth;\n\n  private final @Nullable Content content;\n  private final @Nullable Uri actionUri;\n\n  public ActionConfiguration(JSONObject json) throws JSONException {\n    backgroundColor = fromRGBAHex(json.optString(\"backgroundColor\"));\n    borderColor = fromRGBAHex(json.optString(\"borderColor\"));\n\n    borderWidth = (float) json.optDouble(\"borderWidth\", 0);\n\n    JSONObject contentJSON = json.optJSONObject(\"content\");\n    content = contentJSON == null ? null : new TextContent(contentJSON);\n\n    String jsonUri = json.optString(\"url\", null);\n    actionUri = jsonUri == null ? null : Uri.parse(jsonUri);\n  }\n\n  private ActionConfiguration(Parcel source) {\n    ClassLoader classLoader = getClass().getClassLoader();\n\n    backgroundColor = source.readInt();\n    borderColor = source.readInt();\n\n    borderWidth = source.readFloat();\n    content = source.readParcelable(classLoader);\n\n    actionUri = source.readParcelable(classLoader);\n  }\n\n  public int getBackgroundColor() {\n    return backgroundColor;\n  }\n\n  public int getBorderColor() {\n    return borderColor;\n  }\n\n  public float getBorderWidth() {\n    return borderWidth;\n  }\n\n  @Nullable\n  public Content getContent() {\n    return content;\n  }\n\n  @Nullable\n  public Uri getActionUri() {\n    return actionUri;\n  }\n\n  @Override\n  public int describeContents() {\n    return 0;\n  }\n\n  @Override\n  public void writeToParcel(Parcel dest, int flags) {\n    dest.writeInt(backgroundColor);\n    dest.writeInt(borderColor);\n\n    dest.writeFloat(borderWidth);\n    dest.writeParcelable(content, flags);\n\n    dest.writeParcelable(actionUri, flags);\n  }\n}\n"
  },
  {
    "path": "Android/notifications/src/main/java/com/facebook/notifications/internal/configuration/ActionsConfiguration.java",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\npackage com.facebook.notifications.internal.configuration;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.support.annotation.NonNull;\nimport android.support.annotation.Nullable;\n\nimport com.facebook.notifications.internal.asset.Asset;\nimport com.facebook.notifications.internal.asset.AssetManager;\nimport com.facebook.notifications.internal.utilities.EnumCreator;\nimport com.facebook.notifications.internal.utilities.InvalidParcelException;\n\nimport org.json.JSONArray;\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\npublic class ActionsConfiguration implements Parcelable {\n  public enum ActionsStyle implements Parcelable {\n    Attached,\n    Detached;\n\n    public static final Creator<ActionsStyle> CREATOR = new EnumCreator<>(ActionsStyle.class, values());\n\n    public static ActionsStyle parse(String input) {\n      switch (input) {\n        case \"attached\":\n          return ActionsStyle.Attached;\n        case \"detached\":\n          return ActionsStyle.Detached;\n        default:\n          return ActionsStyle.Attached;\n      }\n    }\n\n    @Override\n    public int describeContents() {\n      return 0;\n    }\n\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n      dest.writeInt(ordinal());\n    }\n  }\n\n  public enum ActionsLayoutStyle implements Parcelable {\n    Vertical,\n    Horizontal;\n\n    public static final Creator<ActionsLayoutStyle> CREATOR = new EnumCreator<>(ActionsLayoutStyle.class, values());\n\n    public static ActionsLayoutStyle parse(String input) {\n      switch (input) {\n        case \"vertical\":\n          return ActionsLayoutStyle.Vertical;\n        case \"horizontal\":\n          return ActionsLayoutStyle.Horizontal;\n        default:\n          return ActionsLayoutStyle.Vertical;\n      }\n    }\n\n    @Override\n    public int describeContents() {\n      return 0;\n    }\n\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n      dest.writeInt(ordinal());\n    }\n  }\n\n  public static final Creator<ActionsConfiguration> CREATOR = new Creator<ActionsConfiguration>() {\n    @Override\n    public ActionsConfiguration createFromParcel(Parcel source) {\n      return new ActionsConfiguration(source);\n    }\n\n    @Override\n    public ActionsConfiguration[] newArray(int size) {\n      return new ActionsConfiguration[size];\n    }\n  };\n  private final ActionsStyle style;\n  private final ActionsLayoutStyle layoutStyle;\n\n  private final Asset background;\n\n  private final float topInset;\n  private final float contentInset;\n  private final float cornerRadius;\n\n  private final @NonNull ActionConfiguration[] actions;\n  private final float height;\n\n  private ActionsConfiguration(@NonNull JSONObject json, @NonNull AssetManager assetManager) throws JSONException {\n    style = ActionsStyle.parse(json.optString(\"style\"));\n    layoutStyle = ActionsLayoutStyle.parse(json.optString(\"layoutStyle\"));\n\n    background = assetManager.inflateAsset(json.optJSONObject(\"background\"));\n\n    topInset = (float) json.optDouble(\"topInset\", 0);\n    contentInset = (float) json.optDouble(\"contentInset\", 0);\n    cornerRadius = (float) json.optDouble(\"cornerRadius\", 0);\n\n    JSONArray rawActions = json.getJSONArray(\"actions\");\n    actions = new ActionConfiguration[rawActions.length()];\n\n    for (int jsonIndex = 0; jsonIndex < actions.length; jsonIndex++) {\n      actions[jsonIndex] = new ActionConfiguration(rawActions.getJSONObject(jsonIndex));\n    }\n\n    height = (float) json.optDouble(\"height\", 44);\n  }\n\n  private ActionsConfiguration(Parcel source) {\n    ClassLoader loader = getClass().getClassLoader();\n\n    style = source.readParcelable(loader);\n    layoutStyle = source.readParcelable(loader);\n\n    background = source.readParcelable(loader);\n\n    topInset = source.readFloat();\n    contentInset = source.readFloat();\n    cornerRadius = source.readFloat();\n\n    actions = source.createTypedArray(ActionConfiguration.CREATOR);\n    height = source.readFloat();\n  }\n\n  @Nullable\n  public static ActionsConfiguration fromJSON(@Nullable JSONObject json, @NonNull AssetManager assetManager) throws JSONException {\n    if (json == null) {\n      return null;\n    }\n    return new ActionsConfiguration(json, assetManager);\n  }\n\n  public void validate() throws InvalidParcelException {\n    if (background != null) {\n      background.validate();\n    }\n  }\n\n  public ActionsStyle getStyle() {\n    return style;\n  }\n\n  public ActionsLayoutStyle getLayoutStyle() {\n    return layoutStyle;\n  }\n\n  public Asset getBackground() {\n    return background;\n  }\n\n  public float getTopInset() {\n    return topInset;\n  }\n\n  public float getContentInset() {\n    return contentInset;\n  }\n\n  public float getCornerRadius() {\n    return cornerRadius;\n  }\n\n  @NonNull\n  public ActionConfiguration[] getActions() {\n    return actions;\n  }\n\n  public float getHeight() {\n    return height;\n  }\n\n  @Override\n  public int describeContents() {\n    return 0;\n  }\n\n  @Override\n  public void writeToParcel(Parcel dest, int flags) {\n    dest.writeParcelable(style, flags);\n    dest.writeParcelable(layoutStyle, flags);\n\n    dest.writeParcelable(background, flags);\n\n    dest.writeFloat(topInset);\n    dest.writeFloat(contentInset);\n    dest.writeFloat(cornerRadius);\n\n    dest.writeTypedArray(actions, flags);\n    dest.writeFloat(height);\n  }\n}\n"
  },
  {
    "path": "Android/notifications/src/main/java/com/facebook/notifications/internal/configuration/BodyConfiguration.java",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\npackage com.facebook.notifications.internal.configuration;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.support.annotation.NonNull;\nimport android.support.annotation.Nullable;\n\nimport com.facebook.notifications.internal.asset.Asset;\nimport com.facebook.notifications.internal.asset.AssetManager;\nimport com.facebook.notifications.internal.content.Content;\nimport com.facebook.notifications.internal.content.ContentManager;\nimport com.facebook.notifications.internal.content.TextContent;\nimport com.facebook.notifications.internal.utilities.InvalidParcelException;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\npublic class BodyConfiguration implements Parcelable {\n  public static final Creator<BodyConfiguration> CREATOR = new Creator<BodyConfiguration>() {\n    @Override\n    public BodyConfiguration createFromParcel(Parcel source) {\n      return new BodyConfiguration(source);\n    }\n\n    @Override\n    public BodyConfiguration[] newArray(int size) {\n      return new BodyConfiguration[size];\n    }\n  };\n\n  private final @Nullable Asset background;\n  private final @Nullable Content content;\n\n  private BodyConfiguration(\n    @NonNull JSONObject json,\n    @NonNull AssetManager assetManager,\n    @NonNull ContentManager contentManager\n  ) throws JSONException {\n    background = assetManager.inflateAsset(json.getJSONObject(\"background\"));\n\n    // TODO: Go through content manager\n    JSONObject contentJSON = json.optJSONObject(\"content\");\n    content = contentJSON != null\n      ? new TextContent(contentJSON)\n      : null;\n  }\n\n  private BodyConfiguration(Parcel source) {\n    ClassLoader loader = getClass().getClassLoader();\n\n    background = source.readParcelable(loader);\n    content = source.readParcelable(loader);\n  }\n\n  @Nullable\n  public static BodyConfiguration fromJSON(@Nullable JSONObject json, @NonNull AssetManager assetManager, @NonNull ContentManager contentManager) throws JSONException {\n    if (json == null) {\n      return null;\n    }\n    return new BodyConfiguration(json, assetManager, contentManager);\n  }\n\n  public void validate() throws InvalidParcelException {\n    if (background != null) {\n      background.validate();\n    }\n  }\n\n  @Nullable\n  public Asset getBackground() {\n    return background;\n  }\n\n  @Nullable\n  public Content getContent() {\n    return content;\n  }\n\n  @Override\n  public int describeContents() {\n    return 0;\n  }\n\n  @Override\n  public void writeToParcel(Parcel dest, int flags) {\n    dest.writeParcelable(background, flags);\n    dest.writeParcelable(content, flags);\n  }\n}\n"
  },
  {
    "path": "Android/notifications/src/main/java/com/facebook/notifications/internal/configuration/CardConfiguration.java",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\npackage com.facebook.notifications.internal.configuration;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.support.annotation.NonNull;\nimport android.support.annotation.Nullable;\nimport android.util.Log;\n\nimport com.facebook.notifications.internal.asset.AssetManager;\nimport com.facebook.notifications.internal.asset.handlers.ColorAssetHandler;\nimport com.facebook.notifications.internal.content.ContentManager;\nimport com.facebook.notifications.internal.utilities.EnumCreator;\nimport com.facebook.notifications.internal.utilities.InvalidParcelException;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\npublic class CardConfiguration implements Parcelable {\n  public enum CardSize implements Parcelable {\n    Invalid,\n    Small,\n    Medium,\n    Large;\n\n    public static final Creator<CardSize> CREATOR = new EnumCreator<>(CardSize.class, values());\n\n    public static CardSize parse(String input) {\n      switch (input) {\n        case \"small\":\n          return CardSize.Small;\n        case \"medium\":\n          return CardSize.Medium;\n        case \"large\":\n          return CardSize.Large;\n        default:\n          return CardSize.Invalid;\n      }\n    }\n\n    @Override\n    public int describeContents() {\n      return 0;\n    }\n\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n      dest.writeInt(ordinal());\n    }\n  }\n\n  private static final String LOG_TAG = CardConfiguration.class.getCanonicalName();\n  private final CardSize cardSize;\n  private final float cornerRadius;\n  private final float contentInset;\n  private final int backdropColor;\n  private final @Nullable HeroConfiguration heroConfiguration;\n  private final @Nullable BodyConfiguration bodyConfiguration;\n  private final @Nullable ActionsConfiguration actionsConfiguration;\n  public static final Creator<CardConfiguration> CREATOR = new Creator<CardConfiguration>() {\n    @Override\n    public CardConfiguration createFromParcel(Parcel source) {\n      try {\n        CardConfiguration configuration = new CardConfiguration(source);\n        configuration.validate();\n\n        return configuration;\n      } catch (InvalidParcelException ex) {\n        Log.w(LOG_TAG, \"Failed to decode card configuration\", ex);\n        return null;\n      }\n    }\n\n    @Override\n    public CardConfiguration[] newArray(int size) {\n      return new CardConfiguration[size];\n    }\n  };\n\n  public CardConfiguration(@NonNull JSONObject jsonObject, @NonNull AssetManager assetManager, @NonNull ContentManager contentManager) throws JSONException {\n    cardSize = CardSize.parse(jsonObject.getString(\"size\"));\n    cornerRadius = (float) jsonObject.optDouble(\"cornerRadius\", 0.0);\n    contentInset = (float) jsonObject.optDouble(\"contentInset\", 10.0);\n\n    backdropColor = ColorAssetHandler.fromRGBAHex(jsonObject.getString(\"backdropColor\"));\n\n    heroConfiguration = HeroConfiguration.fromJSON(jsonObject.optJSONObject(\"hero\"), assetManager, contentManager);\n    bodyConfiguration = BodyConfiguration.fromJSON(jsonObject.optJSONObject(\"body\"), assetManager, contentManager);\n    actionsConfiguration = ActionsConfiguration.fromJSON(jsonObject.optJSONObject(\"actions\"), assetManager);\n  }\n\n  private CardConfiguration(@NonNull Parcel source) {\n    ClassLoader loader = getClass().getClassLoader();\n\n    cardSize = source.readParcelable(loader);\n    cornerRadius = source.readFloat();\n    contentInset = source.readFloat();\n\n    backdropColor = source.readInt();\n\n    heroConfiguration = source.readParcelable(loader);\n    bodyConfiguration = source.readParcelable(loader);\n    actionsConfiguration = source.readParcelable(loader);\n  }\n\n  public void validate() throws InvalidParcelException {\n    if (heroConfiguration != null) {\n      heroConfiguration.validate();\n    }\n\n    if (bodyConfiguration != null) {\n      bodyConfiguration.validate();\n    }\n\n    if (actionsConfiguration != null) {\n      actionsConfiguration.validate();\n    }\n  }\n\n  public CardSize getCardSize() {\n    return cardSize;\n  }\n\n  public float getCornerRadius() {\n    return cornerRadius;\n  }\n\n  public float getContentInset() {\n    return contentInset;\n  }\n\n  public int getBackdropColor() {\n    return backdropColor;\n  }\n\n  @Nullable\n  public HeroConfiguration getHeroConfiguration() {\n    return heroConfiguration;\n  }\n\n  @Nullable\n  public BodyConfiguration getBodyConfiguration() {\n    return bodyConfiguration;\n  }\n\n  @Nullable\n  public ActionsConfiguration getActionsConfiguration() {\n    return actionsConfiguration;\n  }\n\n  @Override\n  public int describeContents() {\n    return 0;\n  }\n\n  @Override\n  public void writeToParcel(Parcel dest, int flags) {\n    dest.writeParcelable(cardSize, flags);\n    dest.writeFloat(cornerRadius);\n    dest.writeFloat(contentInset);\n\n    dest.writeInt(backdropColor);\n\n    dest.writeParcelable(heroConfiguration, flags);\n    dest.writeParcelable(bodyConfiguration, flags);\n    dest.writeParcelable(actionsConfiguration, flags);\n  }\n}\n"
  },
  {
    "path": "Android/notifications/src/main/java/com/facebook/notifications/internal/configuration/HeroConfiguration.java",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\npackage com.facebook.notifications.internal.configuration;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.support.annotation.NonNull;\nimport android.support.annotation.Nullable;\n\nimport com.facebook.notifications.internal.asset.Asset;\nimport com.facebook.notifications.internal.asset.AssetManager;\nimport com.facebook.notifications.internal.content.Content;\nimport com.facebook.notifications.internal.content.ContentManager;\nimport com.facebook.notifications.internal.content.TextContent;\nimport com.facebook.notifications.internal.utilities.InvalidParcelException;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\npublic class HeroConfiguration implements Parcelable {\n  public static final Creator<HeroConfiguration> CREATOR = new Creator<HeroConfiguration>() {\n    @Override\n    public HeroConfiguration createFromParcel(Parcel source) {\n      return new HeroConfiguration(source);\n    }\n\n    @Override\n    public HeroConfiguration[] newArray(int size) {\n      return new HeroConfiguration[size];\n    }\n  };\n\n  private final float height;\n  private final @Nullable Asset background;\n\n  private final @Nullable Content content;\n  private final Content.VerticalAlignment contentVerticalAlignment;\n\n  private HeroConfiguration(\n    @NonNull JSONObject json,\n    @NonNull AssetManager assetManager,\n    @NonNull ContentManager contentManager\n  ) throws JSONException {\n    height = (float) json.optDouble(\"height\", -1);\n    background = assetManager.inflateAsset(json.getJSONObject(\"background\"));\n\n    // TODO: Go through content manager\n    JSONObject contentJSON = json.optJSONObject(\"content\");\n    content = contentJSON != null\n      ? new TextContent(contentJSON)\n      : null;\n\n    contentVerticalAlignment = Content.VerticalAlignment.parse(json.optString(\"contentAlign\"));\n  }\n\n  private HeroConfiguration(Parcel parcel) {\n    ClassLoader loader = getClass().getClassLoader();\n\n    height = parcel.readFloat();\n    background = parcel.readParcelable(loader);\n\n    content = parcel.readParcelable(loader);\n    contentVerticalAlignment = parcel.readParcelable(loader);\n  }\n\n  /**\n   * Create a hero configuration from a possibly `null` JSON payload\n   *\n   * @param json           JSON Payload. Can be null\n   * @param assetManager   Asset manager to use for any assets in the hero\n   * @param contentManager Content manager to use for any content in the hero\n   * @return A hero configuration if the JSON payload exists, or `null` if it does not\n   * @throws JSONException if the JSON is in an invalid format\n   */\n  @Nullable\n  public static HeroConfiguration fromJSON(\n    @Nullable JSONObject json,\n    @NonNull AssetManager assetManager,\n    @NonNull ContentManager contentManager\n  ) throws JSONException {\n    if (json == null) {\n      return null;\n    }\n    return new HeroConfiguration(json, assetManager, contentManager);\n  }\n\n  public void validate() throws InvalidParcelException {\n    if (background != null) {\n      background.validate();\n    }\n  }\n\n  public float getHeight() {\n    return height;\n  }\n\n  @Nullable\n  public Asset getBackground() {\n    return background;\n  }\n\n  @Nullable\n  public Content getContent() {\n    return content;\n  }\n\n  public Content.VerticalAlignment getContentVerticalAlignment() {\n    return contentVerticalAlignment;\n  }\n\n  @Override\n  public int describeContents() {\n    return 0;\n  }\n\n  @Override\n  public void writeToParcel(Parcel dest, int flags) {\n    dest.writeFloat(height);\n    dest.writeParcelable(background, flags);\n\n    dest.writeParcelable(content, flags);\n    dest.writeParcelable(contentVerticalAlignment, flags);\n  }\n}\n"
  },
  {
    "path": "Android/notifications/src/main/java/com/facebook/notifications/internal/content/Content.java",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\npackage com.facebook.notifications.internal.content;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.support.annotation.NonNull;\nimport android.view.View;\n\nimport com.facebook.notifications.internal.utilities.EnumCreator;\n\npublic interface Content extends Parcelable {\n  enum VerticalAlignment implements Parcelable {\n    Top,\n    Center,\n    Bottom;\n\n    public static final Creator<VerticalAlignment> CREATOR = new EnumCreator<>(VerticalAlignment.class, values());\n\n    public static VerticalAlignment parse(String input) {\n      switch (input) {\n        case \"top\":\n          return VerticalAlignment.Top;\n        case \"center\":\n          return VerticalAlignment.Center;\n        case \"bottom\":\n          return VerticalAlignment.Bottom;\n        default:\n          return VerticalAlignment.Center;\n      }\n    }\n\n    @Override\n    public int describeContents() {\n      return 0;\n    }\n\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n      dest.writeInt(ordinal());\n    }\n  }\n\n  /**\n   * Attempt to apply this content to a given view\n   * @param view The view to apply to\n   */\n  void applyTo(@NonNull View view);\n}\n"
  },
  {
    "path": "Android/notifications/src/main/java/com/facebook/notifications/internal/content/ContentManager.java",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\npackage com.facebook.notifications.internal.content;\n\nimport android.content.Context;\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.support.annotation.NonNull;\n\nimport com.facebook.notifications.internal.utilities.InvalidParcelException;\n\n/**\n * Manager for content\n */\npublic class ContentManager implements Parcelable {\n  public static final Creator<ContentManager> CREATOR = new Creator<ContentManager>() {\n    @Override\n    public ContentManager createFromParcel(Parcel source) {\n      return new ContentManager(source);\n    }\n\n    @Override\n    public ContentManager[] newArray(int size) {\n      return new ContentManager[size];\n    }\n  };\n\n  // TODO: Extensible like AssetManager, but for content\n  public ContentManager() {\n  }\n\n  public ContentManager(ContentManager other) {\n  }\n\n  public ContentManager(@NonNull Parcel source) {\n  }\n\n  public void setContext(@NonNull Context context) {\n  }\n\n  public void validate() throws InvalidParcelException {\n  }\n\n  @Override\n  public int describeContents() {\n    return 0;\n  }\n\n  @Override\n  public void writeToParcel(Parcel dest, int flags) {\n  }\n}\n"
  },
  {
    "path": "Android/notifications/src/main/java/com/facebook/notifications/internal/content/TextContent.java",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\npackage com.facebook.notifications.internal.content;\n\nimport android.graphics.Typeface;\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.support.annotation.NonNull;\nimport android.support.annotation.Nullable;\nimport android.view.Gravity;\nimport android.view.View;\nimport android.widget.TextView;\n\nimport com.facebook.notifications.internal.asset.handlers.ColorAssetHandler;\nimport com.facebook.notifications.internal.utilities.EnumCreator;\nimport com.facebook.notifications.internal.utilities.FontUtilities;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\npublic class TextContent implements Content {\n  public enum Alignment implements Parcelable {\n    Left,\n    Right,\n    Center;\n\n    public static final Creator<Alignment> CREATOR = new EnumCreator<>(Alignment.class, values());\n\n    public static Alignment parse(@NonNull String input) {\n      switch (input) {\n        case \"left\":\n          return Left;\n        case \"right\":\n          return Right;\n        case \"center\":\n          return Center;\n        default:\n          return Left;\n      }\n    }\n\n    @Override\n    public int describeContents() {\n      return 0;\n    }\n\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n      dest.writeInt(ordinal());\n    }\n  }\n\n  public static final Creator<TextContent> CREATOR = new Creator<TextContent>() {\n    @Override\n    public TextContent createFromParcel(Parcel source) {\n      return new TextContent(source);\n    }\n\n    @Override\n    public TextContent[] newArray(int size) {\n      return new TextContent[size];\n    }\n  };\n\n  private final @NonNull String text;\n  private final int textColor;\n\n  private final @Nullable String typeface;\n  private final float typefaceSize;\n\n  private final Alignment textAlignment;\n\n  public TextContent(@NonNull JSONObject json) throws JSONException {\n    text = json.optString(\"text\", \"\");\n    textColor = ColorAssetHandler.fromRGBAHex(json.optString(\"color\"));\n\n    typeface = json.optString(\"font\");\n    typefaceSize = (float) json.optDouble(\"size\", 18); // Default to 18sp, or 'medium' size.\n\n    textAlignment = Alignment.parse(json.optString(\"align\", \"center\"));\n  }\n\n  private TextContent(Parcel source) {\n    text = source.readString();\n    textColor = source.readInt();\n\n    typeface = source.readString();\n    typefaceSize = source.readFloat();\n\n    textAlignment = source.readParcelable(getClass().getClassLoader());\n  }\n\n  @Override\n  public void applyTo(@NonNull View view) {\n    if (view instanceof TextView) {\n      TextView textView = (TextView)view;\n\n      textView.setText(getText());\n      textView.setTextColor(getTextColor());\n\n      Typeface typeface = FontUtilities.parseFont(getTypeface());\n      typeface = typeface != null ? typeface : Typeface.DEFAULT;\n\n      textView.setTypeface(typeface);\n      textView.setTextSize(getTypefaceSize());\n\n      switch (getTextAlignment()) {\n        case Left:\n          textView.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL);\n          break;\n\n        case Center:\n          textView.setGravity(Gravity.CENTER);\n          break;\n\n        case Right:\n          textView.setGravity(Gravity.RIGHT | Gravity.CENTER_VERTICAL);\n          break;\n      }\n    }\n  }\n\n  @NonNull\n  public String getText() {\n    return text;\n  }\n\n  public int getTextColor() {\n    return textColor;\n  }\n\n  @Nullable\n  public String getTypeface() {\n    return typeface;\n  }\n\n  public float getTypefaceSize() {\n    return typefaceSize;\n  }\n\n  public Alignment getTextAlignment() {\n    return textAlignment;\n  }\n\n  @Override\n  public int describeContents() {\n    return 0;\n  }\n\n  @Override\n  public void writeToParcel(Parcel dest, int flags) {\n    dest.writeString(text);\n    dest.writeInt(textColor);\n\n    dest.writeString(typeface);\n    dest.writeFloat(typefaceSize);\n\n    dest.writeParcelable(textAlignment, flags);\n  }\n}\n"
  },
  {
    "path": "Android/notifications/src/main/java/com/facebook/notifications/internal/utilities/EnumCreator.java",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\npackage com.facebook.notifications.internal.utilities;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport java.lang.reflect.Array;\n\npublic class EnumCreator<T extends Enum> implements Parcelable.Creator<T> {\n  private final Class<T> kls;\n  private final T[] values;\n\n  public EnumCreator(Class<T> kls, T[] values) {\n    this.kls = kls;\n    this.values = values;\n  }\n\n  @Override\n  public T createFromParcel(Parcel source) {\n    return values[source.readInt()];\n  }\n\n  @Override\n  @SuppressWarnings(\"unchecked\")\n  public T[] newArray(int size) {\n    return (T[]) Array.newInstance(kls, size);\n  }\n}\n"
  },
  {
    "path": "Android/notifications/src/main/java/com/facebook/notifications/internal/utilities/FontUtilities.java",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\npackage com.facebook.notifications.internal.utilities;\n\nimport android.graphics.Typeface;\nimport android.support.annotation.Nullable;\n\npublic class FontUtilities {\n  public static @Nullable Typeface parseFont(@Nullable String fontName) {\n    if (fontName == null) {\n      return Typeface.DEFAULT;\n    }\n    switch (fontName.toLowerCase()) {\n      case \"system-regular\": return Typeface.DEFAULT;\n      case \"system-light\": return Typeface.create(\"sans-serif-light\", Typeface.NORMAL);\n      case \"system-bold\": return Typeface.DEFAULT_BOLD;\n      case \"system-italic\": return Typeface.defaultFromStyle(Typeface.ITALIC);\n      case \"system-bolditalic\": return Typeface.defaultFromStyle(Typeface.BOLD_ITALIC);\n      default: return Typeface.create(fontName, Typeface.NORMAL);\n    }\n  }\n}\n"
  },
  {
    "path": "Android/notifications/src/main/java/com/facebook/notifications/internal/utilities/GifDecoder.java",
    "content": "/**\n * Copyright (c) 2013 Xcellent Creations, Inc.\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\n * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\n * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\n * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\npackage com.facebook.notifications.internal.utilities;\n\nimport android.graphics.Bitmap;\nimport android.util.Log;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.nio.BufferUnderflowException;\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.util.ArrayList;\n\n/**\n * Reads frame data from a GIF image source and decodes it into individual frames\n * for animation purposes.  Image data can be read from either and InputStream source\n * or a byte[].\n *\n * This class is optimized for running animations with the frames, there\n * are no methods to get individual frame images, only to decode the next frame in the\n * animation sequence.  Instead, it lowers its memory footprint by only housing the minimum\n * data necessary to decode the next frame in the animation sequence.\n *\n * The animation must be manually moved forward using {@link #advance()} before requesting the next\n * frame.  This method must also be called before you request the first frame or an error will\n * occur.\n *\n * Implementation adapted from sample code published in Lyons. (2004). <em>Java for Programmers</em>,\n * republished under the MIT Open Source License\n */\n@SuppressWarnings(\"ALL\")\npublic class GifDecoder {\n  private static final String TAG = GifDecoder.class.getSimpleName();\n\n  /**\n   * File read status: No errors.\n   */\n  public static final int STATUS_OK = 0;\n  /**\n   * File read status: Error decoding file (may be partially decoded)\n   */\n  public static final int STATUS_FORMAT_ERROR = 1;\n  /**\n   * File read status: Unable to open source.\n   */\n  public static final int STATUS_OPEN_ERROR = 2;\n  /**\n   * max decoder pixel stack size\n   */\n  protected static final int MAX_STACK_SIZE = 4096;\n\n  /**\n   * GIF Disposal Method meaning take no action\n   */\n  private static final int DISPOSAL_UNSPECIFIED = 0;\n  /**\n   * GIF Disposal Method meaning leave canvas from previous frame\n   */\n  private static final int DISPOSAL_NONE = 1;\n  /**\n   * GIF Disposal Method meaning clear canvas to background color\n   */\n  private static final int DISPOSAL_BACKGROUND = 2;\n  /**\n   * GIF Disposal Method meaning clear canvas to frame before last\n   */\n  private static final int DISPOSAL_PREVIOUS = 3;\n\n  /**\n   * Global status code of GIF data parsing\n   */\n  protected int status;\n\n  //Global File Header values and parsing flags\n  protected int width; // full image width\n  protected int height; // full image height\n  protected boolean gctFlag; // global color table used\n  protected int gctSize; // size of global color table\n  protected int loopCount = 1; // iterations; 0 = repeat forever\n  protected int[] gct; // global color table\n  protected int[] act; // active color table\n  protected int bgIndex; // background color index\n  protected int bgColor; // background color\n  protected int pixelAspect; // pixel aspect ratio\n  protected boolean lctFlag; // local color table flag\n  protected int lctSize; // local color table size\n\n  // Raw GIF data from input source\n  protected ByteBuffer rawData;\n\n  // Raw data read working array\n  protected byte[] block = new byte[256]; // current data block\n  protected int blockSize = 0; // block size last graphic control extension info\n\n  // LZW decoder working arrays\n  protected short[] prefix;\n  protected byte[] suffix;\n  protected byte[] pixelStack;\n  protected byte[] mainPixels;\n  protected int[] mainScratch, copyScratch;\n\n  protected ArrayList<GifFrame> frames; // frames read from current file\n  protected GifFrame currentFrame;\n  protected Bitmap previousImage, currentImage, renderImage;\n\n  protected int framePointer;\n  protected int frameCount;\n\n  /**\n   * Inner model class housing metadata for each frame\n   */\n  private static class GifFrame {\n    public int ix, iy, iw, ih;\n    /* Control Flags */\n    public boolean interlace;\n    public boolean transparency;\n    /* Disposal Method */\n    public int dispose;\n    /* Transparency Index */\n    public int transIndex;\n    /* Delay, in ms, to next frame */\n    public int delay;\n    /* Index in the raw buffer where we need to start reading to decode */\n    public int bufferFrameStart;\n    /* Local Color Table */\n    public int[] lct;\n  }\n\n  /**\n   * Move the animation frame counter forward\n   */\n  public void advance() {\n    framePointer = (framePointer + 1) % frameCount;\n  }\n\n  /**\n   * Recycle any bitmaps held by this GIF decoder, as well as any intermediate data. After\n   * recycling, the decoder can no longer be used.\n   */\n  public void recycle() {\n    if (previousImage != null) {\n      previousImage.recycle();\n    }\n\n    if (currentImage != null) {\n      currentImage.recycle();\n    }\n\n    if (renderImage != null) {\n      renderImage.recycle();\n    }\n\n    gct = null;\n    act = null;\n    block = null;\n    prefix = null;\n    suffix = null;\n    pixelStack = null;\n    mainPixels = null;\n    mainScratch = null;\n    copyScratch = null;\n    currentFrame = null;\n    frames = null;\n  }\n\n  /**\n   * Gets display duration for specified frame.\n   *\n   * @param n int index of frame\n   * @return delay in milliseconds\n   */\n  public int getDelay(int n) {\n    int delay = -1;\n    if ((n >= 0) && (n < frameCount)) {\n      delay = frames.get(n).delay;\n    }\n    return delay;\n  }\n\n  /**\n   * Gets display duration for the upcoming frame\n   */\n  public int getNextDelay() {\n    if (frameCount <=0 || framePointer < 0) {\n      return -1;\n    }\n\n    return getDelay(framePointer);\n  }\n\n  /**\n   * Gets the number of frames read from file.\n   *\n   * @return frame count\n   */\n  public int getFrameCount() {\n    return frameCount;\n  }\n\n  /**\n   * Gets the current index of the animation frame, or -1 if animation hasn't not yet started\n   *\n   * @return frame index\n   */\n  public int getCurrentFrameIndex() {\n    return framePointer;\n  }\n\n  /**\n   * Gets the \"Netscape\" iteration count, if any. A count of 0 means repeat indefinitiely.\n   *\n   * @return iteration count if one was specified, else 1.\n   */\n  public int getLoopCount() {\n    return loopCount;\n  }\n\n  public int getWidth() {\n    return width;\n  }\n\n  public int getHeight() {\n    return height;\n  }\n\n  /**\n   * Get the next frame in the animation sequence.\n   *\n   * @return Bitmap representation of frame\n   */\n  public Bitmap getNextFrame() {\n    if (frameCount <= 0 || framePointer < 0 || currentImage == null) {\n      return null;\n    }\n\n    GifFrame frame = frames.get(framePointer);\n\n    //Set the appropriate color table\n    if (frame.lct == null) {\n      act = gct;\n    } else {\n      act = frame.lct;\n      if (bgIndex == frame.transIndex) {\n        bgColor = 0;\n      }\n    }\n\n    int save = 0;\n    if (frame.transparency) {\n      save = act[frame.transIndex];\n      act[frame.transIndex] = 0; // set transparent color if specified\n    }\n    if (act == null) {\n      Log.w(TAG, \"No Valid Color Table\");\n      status = STATUS_FORMAT_ERROR; // no color table defined\n      return null;\n    }\n\n    setPixels(framePointer); // transfer pixel data to image\n\n    // Reset the transparent pixel in the color table\n    if (frame.transparency) {\n      act[frame.transIndex] = save;\n    }\n\n    return currentImage;\n  }\n\n  /**\n   * Reads GIF image from stream\n   *\n   * @param is containing GIF file.\n   * @return read status code (0 = no errors)\n   */\n  public int read(InputStream is, int contentLength) {\n    long startTime = System.currentTimeMillis();\n    if (is != null) {\n      try {\n        int capacity = (contentLength > 0) ? (contentLength + 4096) : 4096;\n        ByteArrayOutputStream buffer = new ByteArrayOutputStream(capacity);\n        int nRead;\n        byte[] data = new byte[16384];\n        while ((nRead = is.read(data, 0, data.length)) != -1) {\n          buffer.write(data, 0, nRead);\n        }\n        buffer.flush();\n\n        read(buffer.toByteArray());\n      } catch (IOException e) {\n        Log.w(TAG, \"Error reading data from stream\", e);\n      }\n    } else {\n      status = STATUS_OPEN_ERROR;\n    }\n\n    try {\n      is.close();\n    } catch (Exception e) {\n      Log.w(TAG, \"Error closing stream\", e);\n    }\n\n    return status;\n  }\n\n  /**\n   * Reads GIF image from byte array\n   *\n   * @param data containing GIF file.\n   * @return read status code (0 = no errors)\n   */\n  public int read(byte[] data) {\n    init();\n    if (data != null) {\n      //Initiliaze the raw data buffer\n      rawData = ByteBuffer.wrap(data);\n      rawData.rewind();\n      rawData.order(ByteOrder.LITTLE_ENDIAN);\n\n      readHeader();\n      if (!err()) {\n        readContents();\n        if (frameCount < 0) {\n          status = STATUS_FORMAT_ERROR;\n        }\n      }\n    } else {\n      status = STATUS_OPEN_ERROR;\n    }\n\n    return status;\n  }\n\n  /**\n   * Creates new frame image from current data (and previous frames as specified by their disposition codes).\n   */\n  protected void setPixels(int frameIndex) {\n    GifFrame currentFrame = frames.get(frameIndex);\n    GifFrame previousFrame = null;\n    int previousIndex = frameIndex - 1;\n    if (previousIndex >= 0) {\n      previousFrame = frames.get(previousIndex);\n    }\n\n    // final location of blended pixels\n    final int[] dest = mainScratch;\n\n    // fill in starting image contents based on last image's dispose code\n    if (previousFrame != null && previousFrame.dispose > DISPOSAL_UNSPECIFIED) {\n      if (previousFrame.dispose == DISPOSAL_NONE && currentImage != null) {\n        // Start with the current image\n        currentImage.getPixels(dest, 0, width, 0, 0, width, height);\n      }\n      if (previousFrame.dispose == DISPOSAL_BACKGROUND) {\n        // Start with a canvas filled with the background color\n        int c = 0;\n        if (!currentFrame.transparency) {\n          c = bgColor;\n        }\n        for (int i = 0; i < previousFrame.ih; i++) {\n          int n1 = (previousFrame.iy + i) * width + previousFrame.ix;\n          int n2 = n1 + previousFrame.iw;\n          for (int k = n1; k < n2; k++) {\n            dest[k] = c;\n          }\n        }\n      }\n      if (previousFrame.dispose == DISPOSAL_PREVIOUS && previousImage != null) {\n        // Start with the previous frame\n        previousImage.getPixels(dest, 0, width, 0, 0, width, height);\n      }\n    }\n\n    //Decode pixels for this frame  into the global pixels[] scratch\n    decodeBitmapData(currentFrame, mainPixels); // decode pixel data\n\n    // copy each source line to the appropriate place in the destination\n    int pass = 1;\n    int inc = 8;\n    int iline = 0;\n    for (int i = 0; i < currentFrame.ih; i++) {\n      int line = i;\n      if (currentFrame.interlace) {\n        if (iline >= currentFrame.ih) {\n          pass++;\n          switch (pass) {\n            case 2:\n              iline = 4;\n              break;\n            case 3:\n              iline = 2;\n              inc = 4;\n              break;\n            case 4:\n              iline = 1;\n              inc = 2;\n              break;\n            default:\n              break;\n          }\n        }\n        line = iline;\n        iline += inc;\n      }\n      line += currentFrame.iy;\n      if (line < height) {\n        int k = line * width;\n        int dx = k + currentFrame.ix; // start of line in dest\n        int dlim = dx + currentFrame.iw; // end of dest line\n        if ((k + width) < dlim) {\n          dlim = k + width; // past dest edge\n        }\n        int sx = i * currentFrame.iw; // start of line in source\n        while (dx < dlim) {\n          // map color and insert in destination\n          int index = ((int) mainPixels[sx++]) & 0xff;\n          int c = act[index];\n          if (c != 0) {\n            dest[dx] = c;\n          }\n          dx++;\n        }\n      }\n    }\n\n    //Copy pixels into previous image\n    currentImage.getPixels(copyScratch, 0, width, 0, 0, width, height);\n    previousImage.setPixels(copyScratch, 0, width, 0, 0, width, height);\n    //Set pixels for current image\n    currentImage.setPixels(dest, 0, width, 0, 0, width, height);\n  }\n\n  /**\n   * Decodes LZW image data into pixel array. Adapted from John Cristy's BitmapMagick.\n   */\n  protected void decodeBitmapData(GifFrame frame, byte[] dstPixels) {\n    long startTime = System.currentTimeMillis();\n    long stepOne, stepTwo, stepThree;\n    if (frame != null) {\n      //Jump to the frame start position\n      rawData.position(frame.bufferFrameStart);\n    }\n\n    int nullCode = -1;\n    int npix = (frame == null) ? width * height : frame.iw * frame.ih;\n    int available, clear, code_mask, code_size, end_of_information, in_code, old_code, bits, code, count, i, datum, data_size, first, top, bi, pi;\n\n    if (dstPixels == null || dstPixels.length < npix) {\n      dstPixels = new byte[npix]; // allocate new pixel array\n    }\n    if (prefix == null) {\n      prefix = new short[MAX_STACK_SIZE];\n    }\n    if (suffix == null) {\n      suffix = new byte[MAX_STACK_SIZE];\n    }\n    if (pixelStack == null) {\n      pixelStack = new byte[MAX_STACK_SIZE + 1];\n    }\n\n    // Initialize GIF data stream decoder.\n    data_size = read();\n    clear = 1 << data_size;\n    end_of_information = clear + 1;\n    available = clear + 2;\n    old_code = nullCode;\n    code_size = data_size + 1;\n    code_mask = (1 << code_size) - 1;\n    for (code = 0; code < clear; code++) {\n      prefix[code] = 0; // XXX ArrayIndexOutOfBoundsException\n      suffix[code] = (byte) code;\n    }\n\n    // Decode GIF pixel stream.\n    datum = bits = count = first = top = pi = bi = 0;\n    for (i = 0; i < npix; ) {\n      if (top == 0) {\n        if (bits < code_size) {\n          // Load bytes until there are enough bits for a code.\n          if (count == 0) {\n            // Read a new data block.\n            count = readBlock();\n            if (count <= 0) {\n              break;\n            }\n            bi = 0;\n          }\n          datum += (((int) block[bi]) & 0xff) << bits;\n          bits += 8;\n          bi++;\n          count--;\n          continue;\n        }\n        // Get the next code.\n        code = datum & code_mask;\n        datum >>= code_size;\n        bits -= code_size;\n        // Interpret the code\n        if ((code > available) || (code == end_of_information)) {\n          break;\n        }\n        if (code == clear) {\n          // Reset decoder.\n          code_size = data_size + 1;\n          code_mask = (1 << code_size) - 1;\n          available = clear + 2;\n          old_code = nullCode;\n          continue;\n        }\n        if (old_code == nullCode) {\n          pixelStack[top++] = suffix[code];\n          old_code = code;\n          first = code;\n          continue;\n        }\n        in_code = code;\n        if (code == available) {\n          pixelStack[top++] = (byte) first;\n          code = old_code;\n        }\n        while (code > clear) {\n          pixelStack[top++] = suffix[code];\n          code = prefix[code];\n        }\n        first = ((int) suffix[code]) & 0xff;\n        // Add a new string to the string table,\n        if (available >= MAX_STACK_SIZE) {\n          break;\n        }\n        pixelStack[top++] = (byte) first;\n        prefix[available] = (short) old_code;\n        suffix[available] = (byte) first;\n        available++;\n        if (((available & code_mask) == 0) && (available < MAX_STACK_SIZE)) {\n          code_size++;\n          code_mask += available;\n        }\n        old_code = in_code;\n      }\n      // Pop a pixel off the pixel stack.\n      top--;\n      dstPixels[pi++] = pixelStack[top];\n      i++;\n    }\n\n    for (i = pi; i < npix; i++) {\n      dstPixels[i] = 0; // clear missing pixels\n    }\n  }\n\n  /**\n   * Returns true if an error was encountered during reading/decoding\n   */\n  protected boolean err() {\n    return status != STATUS_OK;\n  }\n\n  /**\n   * Initializes or re-initializes reader\n   */\n  protected void init() {\n    status = STATUS_OK;\n    frameCount = 0;\n    framePointer = -1;\n    frames = new ArrayList<GifFrame>();\n    gct = null;\n  }\n\n  /**\n   * Reads a single byte from the input stream.\n   */\n  protected int read() {\n    int curByte = 0;\n    try {\n      curByte = (rawData.get() & 0xFF);\n    } catch (Exception e) {\n      status = STATUS_FORMAT_ERROR;\n    }\n    return curByte;\n  }\n\n  /**\n   * Reads next variable length block from input.\n   *\n   * @return number of bytes stored in \"buffer\"\n   */\n  protected int readBlock() {\n    blockSize = read();\n    int n = 0;\n    if (blockSize > 0) {\n      try {\n        int count;\n        while (n < blockSize) {\n          count = blockSize - n;\n          rawData.get(block, n, count);\n\n          n += count;\n        }\n      } catch (Exception e) {\n        Log.w(TAG, \"Error Reading Block\", e);\n        status = STATUS_FORMAT_ERROR;\n      }\n    }\n    return n;\n  }\n\n  /**\n   * Reads color table as 256 RGB integer values\n   *\n   * @param ncolors int number of colors to read\n   * @return int array containing 256 colors (packed ARGB with full alpha)\n   */\n  protected int[] readColorTable(int ncolors) {\n    int nbytes = 3 * ncolors;\n    int[] tab = null;\n    byte[] c = new byte[nbytes];\n\n    try {\n      rawData.get(c);\n\n      tab = new int[256]; // max size to avoid bounds checks\n      int i = 0;\n      int j = 0;\n      while (i < ncolors) {\n        int r = ((int) c[j++]) & 0xff;\n        int g = ((int) c[j++]) & 0xff;\n        int b = ((int) c[j++]) & 0xff;\n        tab[i++] = 0xff000000 | (r << 16) | (g << 8) | b;\n      }\n    } catch (BufferUnderflowException e) {\n      Log.w(TAG, \"Format Error Reading Color Table\", e);\n      status = STATUS_FORMAT_ERROR;\n    }\n\n    return tab;\n  }\n\n  /**\n   * Main file parser. Reads GIF content blocks.\n   */\n  protected void readContents() {\n    // read GIF file content blocks\n    boolean done = false;\n    while (!(done || err())) {\n      int code = read();\n      switch (code) {\n        case 0x2C: // image separator\n          readBitmap();\n          break;\n        case 0x21: // extension\n          code = read();\n          switch (code) {\n            case 0xf9: // graphics control extension\n              //Start a new frame\n              currentFrame = new GifFrame();\n              readGraphicControlExt();\n              break;\n            case 0xff: // application extension\n              readBlock();\n              String app = \"\";\n              for (int i = 0; i < 11; i++) {\n                app += (char) block[i];\n              }\n              if (app.equals(\"NETSCAPE2.0\")) {\n                readNetscapeExt();\n              } else {\n                skip(); // don't care\n              }\n              break;\n            case 0xfe:// comment extension\n              skip();\n              break;\n            case 0x01:// plain text extension\n              skip();\n              break;\n            default: // uninteresting extension\n              skip();\n          }\n          break;\n        case 0x3b: // terminator\n          done = true;\n          break;\n        case 0x00: // bad byte, but keep going and see what happens break;\n        default:\n          status = STATUS_FORMAT_ERROR;\n      }\n    }\n  }\n\n  /**\n   * Reads GIF file header information.\n   */\n  protected void readHeader() {\n    String id = \"\";\n    for (int i = 0; i < 6; i++) {\n      id += (char) read();\n    }\n    if (!id.startsWith(\"GIF\")) {\n      status = STATUS_FORMAT_ERROR;\n      return;\n    }\n    readLSD();\n    if (gctFlag && !err()) {\n      gct = readColorTable(gctSize);\n      bgColor = gct[bgIndex];\n    }\n  }\n\n  /**\n   * Reads Graphics Control Extension values\n   */\n  protected void readGraphicControlExt() {\n    read(); // block size\n    int packed = read(); // packed fields\n    currentFrame.dispose = (packed & 0x1c) >> 2; // disposal method\n    if (currentFrame.dispose == 0) {\n      currentFrame.dispose = 1; // elect to keep old image if discretionary\n    }\n    currentFrame.transparency = (packed & 1) != 0;\n    currentFrame.delay = readShort() * 10; // delay in milliseconds\n    currentFrame.transIndex = read(); // transparent color index\n    read(); // block terminator\n  }\n\n  /**\n   * Reads next frame image\n   */\n  protected void readBitmap() {\n    currentFrame.ix = readShort(); // (sub)image position & size\n    currentFrame.iy = readShort();\n    currentFrame.iw = readShort();\n    currentFrame.ih = readShort();\n\n    int packed = read();\n    lctFlag = (packed & 0x80) != 0; // 1 - local color table flag interlace\n    lctSize = (int) Math.pow(2, (packed & 0x07) + 1);\n    // 3 - sort flag\n    // 4-5 - reserved lctSize = 2 << (packed & 7); // 6-8 - local color\n    // table size\n    currentFrame.interlace = (packed & 0x40) != 0;\n    if (lctFlag) {\n      currentFrame.lct = readColorTable(lctSize); // read table\n    } else {\n      currentFrame.lct = null; //No local color table\n    }\n\n    currentFrame.bufferFrameStart = rawData.position(); //Save this as the decoding position pointer\n\n    decodeBitmapData(null, mainPixels); // false decode pixel data to advance buffer\n    skip();\n    if (err()) {\n      return;\n    }\n\n    frameCount++;\n    frames.add(currentFrame); // add image to frame\n  }\n\n  /**\n   * Reads Logical Screen Descriptor\n   */\n  protected void readLSD() {\n    // logical screen size\n    width = readShort();\n    height = readShort();\n    // packed fields\n    int packed = read();\n    gctFlag = (packed & 0x80) != 0; // 1 : global color table flag\n    // 2-4 : color resolution\n    // 5 : gct sort flag\n    gctSize = 2 << (packed & 7); // 6-8 : gct size\n    bgIndex = read(); // background color index\n    pixelAspect = read(); // pixel aspect ratio\n\n    //Now that we know the size, init scratch arrays\n    mainPixels = new byte[width * height];\n    mainScratch = new int[width * height];\n    copyScratch = new int[width * height];\n\n    previousImage = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);\n    currentImage = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);\n  }\n\n  /**\n   * Reads Netscape extenstion to obtain iteration count\n   */\n  protected void readNetscapeExt() {\n    do {\n      readBlock();\n      if (block[0] == 1) {\n        // loop count sub-block\n        int b1 = ((int) block[1]) & 0xff;\n        int b2 = ((int) block[2]) & 0xff;\n        loopCount = (b2 << 8) | b1;\n      }\n    } while ((blockSize > 0) && !err());\n  }\n\n  /**\n   * Reads next 16-bit value, LSB first\n   */\n  protected int readShort() {\n    // read 16-bit value\n    return rawData.getShort();\n  }\n\n  /**\n   * Skips variable length blocks up to and including next zero length block.\n   */\n  protected void skip() {\n    do {\n      readBlock();\n    } while ((blockSize > 0) && !err());\n  }\n}\n"
  },
  {
    "path": "Android/notifications/src/main/java/com/facebook/notifications/internal/utilities/InvalidParcelException.java",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\npackage com.facebook.notifications.internal.utilities;\n\n/**\n * Represents an exception that occurs when validating\n * the results of a object created from a parcel\n */\npublic class InvalidParcelException extends Exception {\n  public InvalidParcelException() {\n  }\n\n  public InvalidParcelException(String detailMessage) {\n    super(detailMessage);\n  }\n\n  public InvalidParcelException(String detailMessage, Throwable throwable) {\n    super(detailMessage, throwable);\n  }\n\n  public InvalidParcelException(Throwable throwable) {\n    super(throwable);\n  }\n}\n"
  },
  {
    "path": "Android/notifications/src/main/java/com/facebook/notifications/internal/utilities/JSONObjectVisitor.java",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\npackage com.facebook.notifications.internal.utilities;\n\nimport org.json.JSONArray;\nimport org.json.JSONObject;\n\nimport java.util.Iterator;\n\npublic abstract class JSONObjectVisitor {\n  public static void walk(JSONObject object, JSONObjectVisitor visitor) {\n    visitor.visit(object);\n  }\n\n  public static void walk(JSONArray array, JSONObjectVisitor visitor) {\n    visitor.visit(array);\n  }\n\n  protected void visit(JSONObject object) {\n    for (Iterator<String> keys = object.keys(); keys.hasNext(); ) {\n      String key = keys.next();\n      Object value = object.opt(key);\n\n      if (value instanceof JSONObject) {\n        visit((JSONObject) value);\n      }\n\n      if (value instanceof JSONArray) {\n        visit((JSONArray) value);\n      }\n    }\n  }\n\n  protected void visit(JSONArray array) {\n    for (int index = 0; index < array.length(); index++) {\n      Object value = array.opt(index);\n\n      if (value instanceof JSONObject) {\n        visit((JSONObject) value);\n      }\n\n      if (value instanceof JSONArray) {\n        visit((JSONArray) value);\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "Android/notifications/src/main/java/com/facebook/notifications/internal/utilities/RoundedViewHelper.java",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\npackage com.facebook.notifications.internal.utilities;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.graphics.Canvas;\nimport android.graphics.Path;\nimport android.graphics.RectF;\nimport android.support.annotation.NonNull;\n\npublic class RoundedViewHelper {\n  public static final int TOP_LEFT = 1 << 0;\n  public static final int TOP_RIGHT = 1 << 1;\n  public static final int BOTTOM_LEFT = 1 << 2;\n  public static final int BOTTOM_RIGHT = 1 << 3;\n  public static final int ALL = TOP_LEFT | TOP_RIGHT | BOTTOM_LEFT | BOTTOM_RIGHT;\n\n  private final float cornerRadius;\n  private final int corners;\n\n  private final @NonNull RectF rect;\n  private final @NonNull Path clipPath;\n\n  /**\n   * Create a new {@link RoundedViewHelper}, with a specified corner radius and corners.\n   *\n   * @param context         The context to help inside (usually an {@link Activity})\n   * @param cornerRadiusDip The corner radius to use.\n   * @param cornersMask     The corners to automatically round.\n   */\n  public RoundedViewHelper(@NonNull Context context, float cornerRadiusDip, int cornersMask) {\n    corners = cornersMask;\n    cornerRadius = context.getResources().getDisplayMetrics().density * cornerRadiusDip;\n    rect = new RectF();\n    clipPath = new Path();\n  }\n\n  public void onLayout(boolean changed, int l, int t, int r, int b) {\n    if (corners == 0 || !changed) {\n      return;\n    }\n\n    clipPath.reset();\n    rect.set(0, 0, (r - l), (b - t));\n    float[] radii = {0, 0, 0, 0, 0, 0, 0, 0};\n\n    if ((corners & TOP_LEFT) != 0) {\n      radii[0] = cornerRadius;\n      radii[1] = cornerRadius;\n    }\n\n    if ((corners & TOP_RIGHT) != 0) {\n      radii[2] = cornerRadius;\n      radii[3] = cornerRadius;\n    }\n\n    if ((corners & BOTTOM_LEFT) != 0) {\n      radii[4] = cornerRadius;\n      radii[5] = cornerRadius;\n    }\n\n    if ((corners & BOTTOM_RIGHT) != 0) {\n      radii[6] = cornerRadius;\n      radii[7] = cornerRadius;\n    }\n\n    clipPath.addRoundRect(rect, radii, Path.Direction.CW);\n  }\n\n  public void preDraw(Canvas canvas) {\n    if (corners == 0) {\n      return;\n    }\n\n    if (canvas.isOpaque()) {\n      canvas.saveLayerAlpha(0, 0, canvas.getWidth(), canvas.getHeight(), 255, Canvas.HAS_ALPHA_LAYER_SAVE_FLAG);\n    }\n    canvas.clipPath(clipPath);\n  }\n}\n"
  },
  {
    "path": "Android/notifications/src/main/java/com/facebook/notifications/internal/utilities/TransparentStateListDrawable.java",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\npackage com.facebook.notifications.internal.utilities;\n\nimport android.graphics.PixelFormat;\nimport android.graphics.drawable.StateListDrawable;\n\n/**\n * HACK:\n * <p/>\n * Due to an optimization in how canvases work, drawables which have an 'opaque' opacity\n * setting actually still get immediately blitted to the screen, regardless of what canvas\n * they're drawing in, which means they ignore the clip path of the canvas they're drawing into.\n * <p/>\n * We need a button that can be properly clipped, so we just simply extend the existing, working\n * drawable, and make it transparent.\n */\npublic class TransparentStateListDrawable extends StateListDrawable {\n  @Override\n  public int getOpacity() {\n    return PixelFormat.TRANSPARENT;\n  }\n}\n"
  },
  {
    "path": "Android/notifications/src/main/java/com/facebook/notifications/internal/utilities/Version.java",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\npackage com.facebook.notifications.internal.utilities;\n\nimport android.support.annotation.NonNull;\nimport android.support.annotation.Nullable;\n\nimport java.util.NoSuchElementException;\nimport java.util.Scanner;\n\n/**\n * Simple version class\n */\npublic class Version implements Comparable<Version> {\n  private final int major;\n  private final int minor;\n  private final int patch;\n\n  public Version(int major, int minor, int patch) {\n    this.major = major;\n    this.minor = minor;\n    this.patch = patch;\n  }\n\n  @Nullable\n  public static Version parse(String input) {\n    Scanner scanner = new Scanner(input);\n    scanner.useDelimiter(\"\\\\.\");\n\n    int major = Integer.MIN_VALUE, minor = Integer.MIN_VALUE, patch = 0;\n\n    try {\n      major = scanner.nextInt();\n      minor = scanner.nextInt();\n      patch = scanner.nextInt();\n    } catch (NoSuchElementException ex) {\n      if (major == Integer.MIN_VALUE && minor == Integer.MIN_VALUE) {\n        return null;\n      }\n    }\n\n    return new Version(major, minor, patch);\n  }\n\n  public int getPatch() {\n    return patch;\n  }\n\n  public int getMinor() {\n    return minor;\n  }\n\n  public int getMajor() {\n    return major;\n  }\n\n  @Override\n  public String toString() {\n    return \"Version{\" + major + \".\" + minor + \".\" + patch + '}';\n  }\n\n  @Override\n  public boolean equals(Object o) {\n    if (this == o) return true;\n    if (o == null || getClass() != o.getClass()) return false;\n\n    Version version = (Version) o;\n\n    return\n      major == version.major &&\n        minor == version.minor &&\n        patch == version.patch;\n  }\n\n  @Override\n  public int hashCode() {\n    int result = major;\n    result = 31 * result + minor;\n    result = 31 * result + patch;\n    return result;\n  }\n\n  @Override\n  public int compareTo(@NonNull Version another) {\n    int major = this.major - another.major;\n    int minor = this.minor - another.minor;\n    int patch = this.patch - another.patch;\n\n    return major != 0 ? major :\n      minor != 0 ? minor :\n        patch;\n  }\n}\n"
  },
  {
    "path": "Android/notifications/src/main/java/com/facebook/notifications/internal/view/ActionButton.java",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\npackage com.facebook.notifications.internal.view;\n\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.graphics.Color;\nimport android.graphics.drawable.GradientDrawable;\nimport android.os.Build;\nimport android.support.annotation.NonNull;\nimport android.util.DisplayMetrics;\nimport android.util.StateSet;\nimport android.widget.Button;\n\nimport com.facebook.notifications.internal.configuration.ActionConfiguration;\nimport com.facebook.notifications.internal.content.Content;\nimport com.facebook.notifications.internal.utilities.TransparentStateListDrawable;\n\n@SuppressLint(\"ViewConstructor\")\npublic class ActionButton extends Button {\n  public enum Type {\n    Primary,\n    Secondary,\n    Dismiss\n  }\n\n  private final @NonNull ActionConfiguration configuration;\n  private final Type type;\n\n  public ActionButton(@NonNull Context context, @NonNull final ActionConfiguration config, @NonNull Type t, final float cornerRadius) {\n    super(context, null, android.R.attr.borderlessButtonStyle);\n\n    configuration = config;\n    type = t;\n\n    setTransformationMethod(null);\n    setPadding(0, 0, 0, 0);\n\n    final DisplayMetrics metrics = getResources().getDisplayMetrics();\n    final int backgroundColor = configuration.getBackgroundColor();\n    final int pressedColor;\n    final int borderWidth = Math.round(configuration.getBorderWidth() * metrics.density);\n\n    Content content = config.getContent();\n    if (content != null) {\n      content.applyTo(this);\n    }\n\n    float[] hsv = {0, 0, 0};\n    Color.colorToHSV(backgroundColor, hsv);\n    hsv[2] *= 0.5;\n\n    pressedColor = Color.HSVToColor(backgroundColor >> 24, hsv);\n\n    GradientDrawable backgroundGradient = new GradientDrawable() {{\n      setCornerRadius(cornerRadius * metrics.density);\n      setShape(GradientDrawable.RECTANGLE);\n      setStroke(borderWidth, configuration.getBorderColor());\n      setColor(backgroundColor);\n    }};\n\n    GradientDrawable pressedGradient = new GradientDrawable() {{\n      setCornerRadius(cornerRadius * metrics.density);\n      setShape(RECTANGLE);\n      setStroke(borderWidth, configuration.getBorderColor());\n      setColor(pressedColor);\n    }};\n\n    TransparentStateListDrawable stateListDrawable = new TransparentStateListDrawable();\n    stateListDrawable.addState(new int[]{android.R.attr.state_pressed}, pressedGradient);\n    stateListDrawable.addState(StateSet.WILD_CARD, backgroundGradient);\n\n    setBackgroundDrawable(stateListDrawable);\n    setWillNotDraw(false);\n\n    // ClipPath is not hardware-accelerated before 4.3\n    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {\n      setLayerType(LAYER_TYPE_SOFTWARE, null);\n    }\n  }\n\n  @NonNull\n  public ActionConfiguration getConfiguration() {\n    return configuration;\n  }\n\n  public Type getType() {\n    return type;\n  }\n}\n"
  },
  {
    "path": "Android/notifications/src/main/java/com/facebook/notifications/internal/view/ActionsView.java",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\npackage com.facebook.notifications.internal.view;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.graphics.Canvas;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.support.annotation.NonNull;\nimport android.support.annotation.Nullable;\nimport android.util.DisplayMetrics;\nimport android.view.View;\nimport android.widget.LinearLayout;\nimport android.widget.RelativeLayout;\n\nimport com.facebook.notifications.internal.asset.AssetManager;\nimport com.facebook.notifications.internal.configuration.ActionConfiguration;\nimport com.facebook.notifications.internal.configuration.ActionsConfiguration;\nimport com.facebook.notifications.internal.configuration.CardConfiguration;\nimport com.facebook.notifications.internal.utilities.RoundedViewHelper;\n\n@SuppressWarnings(\"ResourceType\")\n@SuppressLint(\"ViewConstructor\")\npublic class ActionsView extends RelativeLayout implements View.OnClickListener {\n  public interface Delegate {\n    void actionButtonClicked(ActionButton.Type type, @Nullable Uri actionUri);\n  }\n\n  private static final int ASSET_VIEW_ID = 0x78d5c27b;\n  private static final int BUTTONS_LAYOUT_ID = 0x7cc9a8c8;\n\n  private final @NonNull Delegate delegate;\n  private final @Nullable ActionsConfiguration configuration;\n\n  private final @NonNull RoundedViewHelper roundedViewHelper;\n  private final @NonNull AssetView assetView;\n  private final @NonNull LinearLayout buttonsLayout;\n  private final @NonNull ActionButton[] actionButtons;\n\n  public ActionsView(@NonNull Context context, @NonNull AssetManager assetManager, @NonNull Delegate del, @NonNull final CardConfiguration config) {\n    super(context);\n    delegate = del;\n    configuration = config.getActionsConfiguration();\n\n    if (configuration == null) {\n      roundedViewHelper = new RoundedViewHelper(context, 0, 0);\n      assetView = new AssetView(context, assetManager, null);\n      buttonsLayout = new LinearLayout(context);\n      actionButtons = new ActionButton[0];\n      return;\n    }\n\n    roundedViewHelper = new RoundedViewHelper(context, config.getCornerRadius(), getRoundedCorners(config));\n    assetView = new AssetView(context, assetManager, configuration.getBackground());\n\n    ActionConfiguration[] actions = configuration.getActions();\n    actionButtons = new ActionButton[actions.length];\n\n    final DisplayMetrics metrics = getResources().getDisplayMetrics();\n\n    int margin = Math.round(configuration.getContentInset() * metrics.density);\n    int topMargin = Math.round(configuration.getTopInset() * metrics.density);\n    int marginLeft = 0, marginTop = 0;\n    int buttonWidth = 0, buttonWeight = 0;\n    int buttonHeight = Math.round(configuration.getHeight() * metrics.density);\n\n    buttonsLayout = new LinearLayout(context);\n    switch (configuration.getLayoutStyle()) {\n      case Vertical:\n        buttonWidth = LayoutParams.MATCH_PARENT;\n        marginTop = margin;\n        buttonsLayout.setOrientation(LinearLayout.VERTICAL);\n        break;\n\n      case Horizontal:\n        buttonWeight = 1;\n        marginLeft = margin;\n        buttonsLayout.setOrientation(LinearLayout.HORIZONTAL);\n        break;\n\n      default:\n        throw new RuntimeException(\"Unknown layout style: \" + configuration.getLayoutStyle());\n    }\n\n    boolean primary = true;\n    for (int actionIndex = 0; actionIndex < actions.length; actionIndex++) {\n      ActionConfiguration configuration = actions[actionIndex];\n      ActionButton.Type buttonType;\n      if (configuration.getActionUri() != null) {\n        buttonType = primary ? ActionButton.Type.Primary : ActionButton.Type.Secondary;\n        primary = false;\n      } else {\n        buttonType = ActionButton.Type.Dismiss;\n      }\n\n      actionButtons[actionIndex] = new ActionButton(context, actions[actionIndex], buttonType, this.configuration.getCornerRadius());\n      actionButtons[actionIndex].setOnClickListener(this);\n\n      LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(buttonWidth, buttonHeight);\n      layoutParams.weight = buttonWeight;\n\n      if (actionIndex > 0) {\n        layoutParams.setMargins(marginLeft, marginTop, 0, 0);\n      }\n      buttonsLayout.addView(actionButtons[actionIndex], layoutParams);\n    }\n\n    assetView.setId(ASSET_VIEW_ID);\n    buttonsLayout.setId(BUTTONS_LAYOUT_ID);\n\n    addView(assetView, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT) {{\n      addRule(ALIGN_TOP, BUTTONS_LAYOUT_ID);\n      addRule(ALIGN_BOTTOM, BUTTONS_LAYOUT_ID);\n    }});\n\n    buttonsLayout.setPadding(margin, topMargin, margin, margin);\n    addView(buttonsLayout, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));\n\n    setWillNotDraw(false);\n\n    // ClipPath is not hardware-accelerated before 4.3\n    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {\n      setLayerType(LAYER_TYPE_SOFTWARE, null);\n    }\n  }\n\n  private static int getRoundedCorners(@NonNull CardConfiguration configuration) {\n    if (configuration.getActionsConfiguration() == null) {\n      return 0;\n    }\n\n    int corners = RoundedViewHelper.BOTTOM_LEFT | RoundedViewHelper.BOTTOM_RIGHT;\n    if (configuration.getHeroConfiguration() == null &&\n      configuration.getBodyConfiguration() == null) {\n      corners |= RoundedViewHelper.TOP_LEFT | RoundedViewHelper.TOP_RIGHT;\n    }\n\n    return corners;\n  }\n\n  @Override\n  protected void onLayout(boolean changed, int l, int t, int r, int b) {\n    super.onLayout(changed, l, t, r, b);\n    roundedViewHelper.onLayout(changed, l, t, r, b);\n  }\n\n  @Override\n  public void draw(Canvas canvas) {\n    roundedViewHelper.preDraw(canvas);\n    super.draw(canvas);\n  }\n\n  @Override\n  public void onClick(View v) {\n    ActionButton button = (ActionButton) v;\n    delegate.actionButtonClicked(button.getType(), button.getConfiguration().getActionUri());\n  }\n}\n"
  },
  {
    "path": "Android/notifications/src/main/java/com/facebook/notifications/internal/view/AssetView.java",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\npackage com.facebook.notifications.internal.view;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.support.annotation.NonNull;\nimport android.support.annotation.Nullable;\nimport android.view.View;\nimport android.widget.FrameLayout;\n\nimport com.facebook.notifications.internal.asset.Asset;\nimport com.facebook.notifications.internal.asset.AssetManager;\n\n/**\n * Implements a view that draws a asset.\n */\n@SuppressLint(\"ViewConstructor\")\npublic class AssetView extends FrameLayout {\n  private final @Nullable Asset asset;\n\n  public AssetView(@NonNull Context context, @NonNull AssetManager assetManager, @Nullable Asset asset) {\n    super(context);\n    this.asset = asset;\n\n    if (asset != null) {\n      View viewForAsset = assetManager.inflateView(asset, context);\n      addView(viewForAsset, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));\n    }\n  }\n}\n"
  },
  {
    "path": "Android/notifications/src/main/java/com/facebook/notifications/internal/view/BodyView.java",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\npackage com.facebook.notifications.internal.view;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.graphics.Canvas;\nimport android.os.Build;\nimport android.support.annotation.NonNull;\nimport android.support.annotation.Nullable;\nimport android.util.DisplayMetrics;\nimport android.widget.RelativeLayout;\n\nimport com.facebook.notifications.internal.asset.AssetManager;\nimport com.facebook.notifications.internal.configuration.ActionsConfiguration;\nimport com.facebook.notifications.internal.configuration.BodyConfiguration;\nimport com.facebook.notifications.internal.configuration.CardConfiguration;\nimport com.facebook.notifications.internal.content.ContentManager;\nimport com.facebook.notifications.internal.utilities.RoundedViewHelper;\n\n@SuppressWarnings(\"ResourceType\")\n@SuppressLint(\"ViewConstructor\")\npublic class BodyView extends RelativeLayout {\n  private final int RESOURCE_VIEW_ID = 0xa55d68f4;\n  private final int CONTENT_VIEW_ID = 0x2facb6c8;\n\n  private final @Nullable BodyConfiguration configuration;\n\n  private final @NonNull RoundedViewHelper roundedViewHelper;\n  private final @NonNull AssetView assetView;\n  private final @NonNull ContentView contentView;\n\n  public BodyView(@NonNull Context context, @NonNull AssetManager assetManager, @NonNull ContentManager contentManager, @NonNull CardConfiguration config) {\n    super(context);\n    configuration = config.getBodyConfiguration();\n\n    ActionsConfiguration actionsConfiguration = config.getActionsConfiguration();\n    ActionsConfiguration.ActionsStyle actionsStyle = actionsConfiguration != null\n      ? actionsConfiguration.getStyle()\n      : ActionsConfiguration.ActionsStyle.Detached;\n\n    int corners = actionsStyle == ActionsConfiguration.ActionsStyle.Detached\n      ? RoundedViewHelper.BOTTOM_LEFT | RoundedViewHelper.BOTTOM_RIGHT\n      : 0;\n    if (config.getHeroConfiguration() == null && configuration != null) {\n      corners |= RoundedViewHelper.TOP_LEFT | RoundedViewHelper.TOP_RIGHT;\n    }\n\n    roundedViewHelper = new RoundedViewHelper(context, config.getCornerRadius(), corners);\n\n    if (configuration == null) {\n      assetView = new AssetView(context, assetManager, null);\n      contentView = new ContentView(context, contentManager, null);\n      return;\n    }\n\n    assetView = new AssetView(context, assetManager, configuration.getBackground());\n    contentView = new ContentView(context, contentManager, configuration.getContent());\n\n    assetView.setId(RESOURCE_VIEW_ID);\n    contentView.setId(CONTENT_VIEW_ID);\n\n    DisplayMetrics metrics = getResources().getDisplayMetrics();\n    final int padding = Math.round(config.getContentInset() * metrics.density);\n\n    contentView.setPadding(padding, padding, padding, padding);\n\n    addView(assetView, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT) {{\n      addRule(ALIGN_TOP, CONTENT_VIEW_ID);\n      addRule(ALIGN_BOTTOM, CONTENT_VIEW_ID);\n    }});\n    addView(contentView, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));\n\n    setWillNotDraw(false);\n\n    // ClipPath is not hardware-accelerated before 4.3\n    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {\n      setLayerType(LAYER_TYPE_SOFTWARE, null);\n    }\n  }\n\n  @Override\n  protected void onLayout(boolean changed, int l, int t, int r, int b) {\n    super.onLayout(changed, l, t, r, b);\n    roundedViewHelper.onLayout(changed, l, t, r, b);\n  }\n\n  @Override\n  public void draw(Canvas canvas) {\n    roundedViewHelper.preDraw(canvas);\n    super.draw(canvas);\n  }\n}\n"
  },
  {
    "path": "Android/notifications/src/main/java/com/facebook/notifications/internal/view/CardView.java",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\npackage com.facebook.notifications.internal.view;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.support.annotation.NonNull;\nimport android.util.DisplayMetrics;\nimport android.view.Gravity;\nimport android.widget.LinearLayout;\n\nimport com.facebook.notifications.internal.asset.AssetManager;\nimport com.facebook.notifications.internal.configuration.CardConfiguration;\nimport com.facebook.notifications.internal.configuration.HeroConfiguration;\nimport com.facebook.notifications.internal.content.ContentManager;\n\n/**\n * This class is the start of the Push Card hierarchy.\n * <p/>\n * It contains a {@link HeroView}, a {@link BodyView}, and a {@link ActionsView}.\n */\n// As this class will only be created via code, suppress the following warning.\n@SuppressLint(\"ViewConstructor\")\npublic class CardView extends LinearLayout {\n  private final @NonNull CardConfiguration configuration;\n\n  private final @NonNull HeroView heroView;\n  private final @NonNull BodyView bodyView;\n  private final @NonNull ActionsView actionsView;\n\n  /**\n   * Create a new card view, from the given configuration.\n   *\n   * @param context The context of the view (usually an activity).\n   * @param config  The configuration of the push card to display.\n   */\n  public CardView(\n    @NonNull Context context,\n    @NonNull AssetManager assetManager,\n    @NonNull ContentManager contentManager,\n    @NonNull ActionsView.Delegate actionsDelegate,\n    @NonNull CardConfiguration config\n  ) {\n    super(context);\n    configuration = config;\n\n    heroView = new HeroView(context, assetManager, contentManager, configuration);\n    bodyView = new BodyView(context, assetManager, contentManager, configuration);\n    actionsView = new ActionsView(context, assetManager, actionsDelegate, configuration);\n\n    setOrientation(VERTICAL);\n    setGravity(Gravity.CENTER_VERTICAL);\n\n    addView(heroView, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));\n    addView(bodyView, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));\n    addView(actionsView, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));\n\n    setBackgroundColor(configuration.getBackdropColor());\n  }\n\n  /**\n   * Get a card size that fits for the given dimensions\n   *\n   * @param sizes    An array of two floats (width and height) **measured in DIP**.\n   * @param cardSize The target card size to fit\n   * @return A new array with the proper card size for the given dimensions.\n   */\n  private static\n  @NonNull\n  float[] sizeForCardSize(@NonNull float[] sizes, CardConfiguration.CardSize cardSize) {\n    float layoutW = Math.min(400, sizes[0]);\n    float layoutH = Math.min(700, sizes[1]);\n\n    switch (cardSize) {\n      case Invalid:\n        return new float[]{0, 0};\n      case Small:\n        layoutW *= 0.75;\n        layoutH *= 0.7;\n        break;\n      case Medium:\n        layoutW *= 0.83;\n        layoutH *= 0.9;\n        break;\n      case Large:\n        break;\n    }\n\n    return new float[]{layoutW, layoutH};\n  }\n\n  @Override\n  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n    DisplayMetrics metrics = getResources().getDisplayMetrics();\n    int totalWidth = MeasureSpec.getSize(widthMeasureSpec);\n    int totalHeight = MeasureSpec.getSize(heightMeasureSpec);\n\n    float[] size = {\n      totalWidth / metrics.density,\n      totalHeight / metrics.density\n    };\n    float[] cardSize = sizeForCardSize(size, configuration.getCardSize());\n    cardSize[0] *= metrics.density;\n    cardSize[1] *= metrics.density;\n\n    int hPadding = Math.round((totalWidth - cardSize[0]) / 2);\n\n    setPadding(hPadding, 0, hPadding, 0);\n\n    int measuredContentHeight = Integer.MAX_VALUE;\n    HeroConfiguration heroConfiguration = configuration.getHeroConfiguration();\n\n    float heroHeight = 1;\n    if (heroConfiguration == null || heroConfiguration.getHeight() == -1) {\n      // Measure the total hero content size\n      heroView.getLayoutParams().height = LayoutParams.WRAP_CONTENT;\n      super.onMeasure(widthMeasureSpec, heightMeasureSpec);\n\n      measuredContentHeight = heroView.getMeasuredHeight();\n    } else {\n      heroHeight = heroConfiguration.getHeight();\n    }\n\n    // Reset the hero view's height to zero so we can measure everything else\n    heroView.getLayoutParams().height = 0;\n\n    // NOTE: It is extremely important that this call is in the middle of the function. It feels\n    // strange, but if we do not call it *after* we set our padding, it will calculate the width of\n    // our children without taking the padding into account and cause things to flow off of the\n    // screen.\n    // Also note that android 6.0+ does not require an explicit second call to `onMeasure`, the View\n    // subsystem appears to do it automatically whenever the padding is changed.\n    super.onMeasure(widthMeasureSpec, heightMeasureSpec);\n\n    int bodyHeight = bodyView.getMeasuredHeight();\n    int actionsHeight = actionsView.getMeasuredHeight();\n\n    int availableHeight = Math.round(cardSize[1]);\n    int remainingHeight = availableHeight - bodyHeight - actionsHeight;\n\n    int maxHeight = Math.round(remainingHeight * Math.abs(heroHeight));\n    heroView.getLayoutParams().height = Math.min(maxHeight, measuredContentHeight);\n\n    // We must explicitly tell the view subsystem to re-calculate with the new hero height,\n    // otherwise it will assume we want to keep the height of zero that we last measured with.\n    super.onMeasure(widthMeasureSpec, heightMeasureSpec);\n  }\n}\n"
  },
  {
    "path": "Android/notifications/src/main/java/com/facebook/notifications/internal/view/ContentView.java",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\npackage com.facebook.notifications.internal.view;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.support.annotation.NonNull;\nimport android.support.annotation.Nullable;\nimport android.widget.TextView;\n\nimport com.facebook.notifications.internal.content.Content;\nimport com.facebook.notifications.internal.content.ContentManager;\n\n/**\n * Implements a view that draws content.\n */\n@SuppressLint(\"ViewConstructor\")\npublic class ContentView extends TextView {\n  private final @Nullable Content content;\n\n  public ContentView(@NonNull Context context, @NonNull ContentManager assetManager, @Nullable Content content) {\n    super(context);\n    this.content = content;\n\n    if (content != null) {\n      content.applyTo(this);\n    }\n  }\n}\n"
  },
  {
    "path": "Android/notifications/src/main/java/com/facebook/notifications/internal/view/GifView.java",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\npackage com.facebook.notifications.internal.view;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.graphics.Canvas;\nimport android.graphics.Paint;\nimport android.graphics.Rect;\nimport android.graphics.RectF;\nimport android.support.annotation.NonNull;\nimport android.support.annotation.Nullable;\nimport android.util.Log;\nimport android.view.View;\n\nimport com.facebook.notifications.internal.utilities.GifDecoder;\n\n@SuppressLint(\"ViewConstructor\")\npublic class GifView extends View {\n  private class DecoderThread extends Thread {\n    private final @Nullable GifDecoder decoder;\n    private @Nullable Bitmap currentFrame;\n\n    public DecoderThread(@Nullable GifDecoder decoder) {\n      this.decoder = decoder;\n    }\n\n    @Override\n    public void run() {\n      if (decoder == null) {\n        return;\n      }\n\n      while (true) {\n        long frameStart = System.nanoTime();\n\n        decoder.advance();\n\n        int frameDelay = decoder.getNextDelay();\n        long targetNextFrame = frameStart + (frameDelay * 1000000);\n\n        synchronized (this) {\n          currentFrame = decoder.getNextFrame();\n          notifyAll();\n        }\n\n        // Naive: assume all frames take the same amount of time to decode.\n        long currentTime = System.nanoTime();\n        long frameDecodeTime = currentTime - frameStart;\n\n        long sleepTimeNs = (targetNextFrame - currentTime) - frameDecodeTime;\n        long sleepTimeMs = Math.max(0, sleepTimeNs / 1000000);\n\n        postInvalidate();\n\n        try {\n          Thread.sleep(sleepTimeMs);\n          if (Thread.interrupted()) {\n            break;\n          }\n        } catch (InterruptedException ex) {\n          // Thread was killed by View, RIP.\n          break;\n        }\n      }\n\n      currentFrame = null;\n      decoder.recycle();\n    }\n  }\n\n  private static final String LOG_TAG = GifView.class.getCanonicalName();\n\n  private final @NonNull DecoderThread decoderThread;\n  private final @NonNull Paint antiAliasPaint;\n  private final @NonNull Rect sourceRect;\n  private final @NonNull RectF targetRect;\n\n  public GifView(@NonNull Context context, @Nullable GifDecoder decoder) {\n    super(context);\n    setDrawingCacheEnabled(false);\n    setWillNotCacheDrawing(true);\n\n    decoderThread = new DecoderThread(decoder);\n    antiAliasPaint = new Paint();\n    sourceRect = new Rect();\n    targetRect = new RectF();\n\n    antiAliasPaint.setAntiAlias(true);\n    antiAliasPaint.setFilterBitmap(true);\n    antiAliasPaint.setDither(true);\n  }\n\n  @Override\n  protected void onAttachedToWindow() {\n    super.onAttachedToWindow();\n\n    decoderThread.start();\n  }\n\n  @Override\n  protected void onDetachedFromWindow() {\n    decoderThread.interrupt();\n\n    try {\n      decoderThread.join();\n    } catch (InterruptedException ex) {\n      Log.e(LOG_TAG, \"Failed to kill decoder thread\", ex);\n    }\n\n    super.onDetachedFromWindow();\n  }\n\n  @Override\n  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n    GifDecoder decoder = decoderThread.decoder;\n    if (decoder == null) {\n      setMeasuredDimension(0, 0);\n      return;\n    }\n\n    boolean variableWidth = MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.EXACTLY;\n    boolean variableHeight = MeasureSpec.getMode(heightMeasureSpec) != MeasureSpec.EXACTLY;\n\n    int measuredWidth = MeasureSpec.getSize(widthMeasureSpec);\n    int measuredHeight = MeasureSpec.getSize(heightMeasureSpec);\n\n    float sourceWidth = decoder.getWidth();\n    float sourceHeight = decoder.getHeight();\n\n    float destWidth = measuredWidth;\n    float destHeight = measuredHeight;\n\n    float heightRatio = destHeight / sourceHeight;\n    float widthRatio = destWidth / sourceWidth;\n\n    if (variableWidth && variableHeight) {\n      float scale = Math.min(heightRatio, widthRatio);\n\n      measuredWidth = Math.round(measuredWidth * scale);\n      measuredHeight = Math.round(measuredHeight * scale);\n    } else if (variableWidth) {\n      measuredWidth = Math.round(measuredHeight * (sourceWidth / sourceHeight));\n    } else if (variableHeight) {\n      measuredHeight = Math.round(measuredWidth * (sourceHeight / sourceWidth));\n    }\n\n    setMeasuredDimension(measuredWidth, measuredHeight);\n  }\n\n  @Override\n  protected void onDraw(Canvas canvas) {\n    super.onDraw(canvas);\n\n    Bitmap currentFrame;\n    synchronized (decoderThread) {\n      currentFrame = decoderThread.currentFrame;\n      if (currentFrame == null) {\n        try {\n          decoderThread.wait(100);\n          currentFrame = decoderThread.currentFrame;\n        } catch (InterruptedException e) {\n          Log.e(LOG_TAG, \"Failed to wait\", e);\n        }\n      }\n    }\n\n    if (currentFrame == null) {\n      return;\n    }\n\n    // Scale the frame that we have already in our bitmap and draw it.\n    // This is the CENTER_CROP algorithm that we use for displaying images.\n    float sourceWidth = currentFrame.getWidth();\n    float sourceHeight = currentFrame.getHeight();\n\n    float destWidth = getWidth();\n    float destHeight = getHeight();\n\n    float heightRatio = destHeight / sourceHeight;\n    float widthRatio = destWidth / sourceWidth;\n\n    float scale = Math.max(heightRatio, widthRatio);\n\n    float targetWidth = sourceWidth * scale;\n    float targetHeight = sourceHeight * scale;\n\n    float offsetW = (destWidth - targetWidth) / 2f;\n    float offsetH = (destHeight - targetHeight) / 2f;\n\n    sourceRect.set(0, 0, currentFrame.getWidth(), currentFrame.getHeight());\n    targetRect.set(offsetW, offsetH, offsetW + targetWidth, offsetH + targetHeight);\n\n    canvas.drawBitmap(currentFrame, sourceRect, targetRect, antiAliasPaint);\n  }\n}\n"
  },
  {
    "path": "Android/notifications/src/main/java/com/facebook/notifications/internal/view/HeroView.java",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\npackage com.facebook.notifications.internal.view;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.graphics.Canvas;\nimport android.os.Build;\nimport android.support.annotation.NonNull;\nimport android.support.annotation.Nullable;\nimport android.util.DisplayMetrics;\nimport android.widget.RelativeLayout;\n\nimport com.facebook.notifications.internal.asset.AssetManager;\nimport com.facebook.notifications.internal.configuration.ActionsConfiguration;\nimport com.facebook.notifications.internal.configuration.CardConfiguration;\nimport com.facebook.notifications.internal.configuration.HeroConfiguration;\nimport com.facebook.notifications.internal.content.ContentManager;\nimport com.facebook.notifications.internal.utilities.RoundedViewHelper;\n\n@SuppressWarnings(\"ResourceType\")\n@SuppressLint(\"ViewConstructor\")\npublic class HeroView extends RelativeLayout {\n  // Just some random generated IDs.\n  private static final int ASSET_VIEW_ID = 0x53ec9fc7;\n  private static final int CONTENT_VIEW_ID = 0xa5e76c35;\n\n  private final @Nullable HeroConfiguration configuration;\n\n  private final @NonNull RoundedViewHelper roundedViewHelper;\n  private final @NonNull AssetView assetView;\n  private final @NonNull ContentView contentView;\n\n  private final int padding;\n\n  public HeroView(@NonNull Context context, @NonNull AssetManager assetManager, @NonNull ContentManager contentManager, @NonNull CardConfiguration config) {\n    super(context);\n\n    configuration = config.getHeroConfiguration();\n    roundedViewHelper = new RoundedViewHelper(context, config.getCornerRadius(), getRoundedCorners(config));\n\n    if (configuration == null) {\n      assetView = new AssetView(context, assetManager, null);\n      contentView = new ContentView(context, contentManager, null);\n      padding = 0;\n      return;\n    }\n\n    assetView = new AssetView(context, assetManager, configuration.getBackground());\n    contentView = new ContentView(context, contentManager, configuration.getContent());\n\n    assetView.setId(ASSET_VIEW_ID);\n    contentView.setId(CONTENT_VIEW_ID);\n\n    DisplayMetrics metrics = getResources().getDisplayMetrics();\n    padding = Math.round(config.getContentInset() * metrics.density);\n\n    addView(assetView, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));\n    addView(contentView, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT) {{\n      setMargins(padding, padding, padding, padding);\n\n      switch (configuration.getContentVerticalAlignment()) {\n        case Top:\n          addRule(ALIGN_TOP, ASSET_VIEW_ID);\n          break;\n\n        case Center:\n          addRule(CENTER_VERTICAL);\n          break;\n\n        case Bottom:\n          addRule(ALIGN_BOTTOM, ASSET_VIEW_ID);\n          break;\n      }\n    }});\n\n    setWillNotDraw(false);\n\n    // ClipPath is not hardware-accelerated before 4.3\n    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {\n      setLayerType(LAYER_TYPE_SOFTWARE, null);\n    }\n  }\n\n  private static int getRoundedCorners(@NonNull CardConfiguration cardConfiguration) {\n    if (cardConfiguration.getHeroConfiguration() == null) {\n      return 0;\n    }\n\n    int corners = RoundedViewHelper.TOP_LEFT | RoundedViewHelper.TOP_RIGHT;\n    if (cardConfiguration.getBodyConfiguration() == null &&\n      cardConfiguration.getActionsConfiguration() != null &&\n      cardConfiguration.getActionsConfiguration().getStyle() == ActionsConfiguration.ActionsStyle.Detached) {\n      corners |= RoundedViewHelper.BOTTOM_LEFT | RoundedViewHelper.BOTTOM_RIGHT;\n    }\n\n    return corners;\n  }\n\n  @Override\n  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n    LayoutParams params = (LayoutParams) assetView.getLayoutParams();\n    // Params can return null if the assetView is not yet attached to the screen.\n    if (params == null) {\n      super.onMeasure(widthMeasureSpec, heightMeasureSpec);\n      return;\n    }\n\n    params.height = LayoutParams.WRAP_CONTENT;\n\n    super.onMeasure(widthMeasureSpec, heightMeasureSpec);\n\n    int assetHeight = assetView.getMeasuredHeight();\n    int contentHeight = contentView.getMeasuredHeight() + (padding * 2);\n\n    params.height = Math.max(assetHeight, contentHeight);\n\n    super.onMeasure(widthMeasureSpec, heightMeasureSpec);\n  }\n\n  @Override\n  protected void onLayout(boolean changed, int l, int t, int r, int b) {\n    super.onLayout(changed, l, t, r, b);\n    roundedViewHelper.onLayout(changed, l, t, r, b);\n  }\n\n  @Override\n  public void draw(Canvas canvas) {\n    roundedViewHelper.preDraw(canvas);\n    super.draw(canvas);\n  }\n}\n"
  },
  {
    "path": "Android/notifications-example/build.gradle",
    "content": "apply plugin: 'com.android.application'\n\nandroid {\n    compileSdkVersion 23\n    buildToolsVersion \"23.0.3\"\n\n    defaultConfig {\n        applicationId \"com.facebook.notifications.sample\"\n        minSdkVersion 15\n        targetSdkVersion 23\n        versionCode 1\n        versionName \"1.0\"\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n}\n\nrepositories {\n    mavenCentral()\n}\n\ndependencies {\n    compile fileTree(dir: 'libs', include: ['*.jar'])\n    compile 'com.android.support:appcompat-v7:23.1.1'\n    compile 'com.android.support:design:23.1.1'\n    compile 'com.google.android.gms:play-services:8.4.0'\n    compile 'com.facebook.android:facebook-android-sdk:4.+'\n    compile 'commons-io:commons-io:2.4'\n    compile project(':notifications')\n\n    apply plugin: 'com.google.gms.google-services'\n}\n"
  },
  {
    "path": "Android/notifications-example/google-services.json",
    "content": "{\n  \"project_info\": {\n    \"project_id\": \"fbiantestapp\",\n    \"project_number\": \"903525066365\",\n    \"name\": \"FBIANTestApp\"\n  },\n  \"client\": [\n    {\n      \"client_info\": {\n        \"mobilesdk_app_id\": \"1:903525066365:android:43f558a669a2aaaa\",\n        \"client_id\": \"android:com.facebook.notifications.sample\",\n        \"client_type\": 1,\n        \"android_client_info\": {\n          \"package_name\": \"com.facebook.notifications.sample\",\n          \"certificate_hash\": []\n        }\n      },\n      \"oauth_client\": [],\n      \"api_key\": [],\n      \"services\": {\n        \"analytics_service\": {\n          \"status\": 1\n        },\n        \"cloud_messaging_service\": {\n          \"status\": 2,\n          \"apns_config\": []\n        },\n        \"appinvite_service\": {\n          \"status\": 1,\n          \"other_platform_oauth_client\": []\n        },\n        \"google_signin_service\": {\n          \"status\": 1\n        },\n        \"ads_service\": {\n          \"status\": 1\n        }\n      }\n    }\n  ],\n  \"client_info\": [],\n  \"ARTIFACT_VERSION\": \"1\"\n}"
  },
  {
    "path": "Android/notifications-example/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in /Users/richardross/Library/Android/sdk/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the proguardFiles\n# directive in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n"
  },
  {
    "path": "Android/notifications-example/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.facebook.notifications.sample\" >\n\n    <uses-permission android:name=\"android.permission.INTERNET\" />\n    <uses-permission android:name=\"com.google.android.c2dm.permission.RECEIVE\"/>\n\n    <permission\n        android:name=\"com.facebook.notifications.sample.permission.C2D_MESSAGE\"\n        android:protectionLevel=\"signature\"/>\n    <uses-permission android:name=\"com.facebook.notifications.sample.permission.C2D_MESSAGE\"/>\n\n    <application\n        android:allowBackup=\"true\"\n        android:icon=\"@mipmap/ic_launcher\"\n        android:label=\"@string/app_name\"\n        android:supportsRtl=\"true\"\n        android:theme=\"@style/AppTheme\" >\n\n        <activity android:name=\"com.facebook.FacebookActivity\"\n                  android:configChanges=\n                      \"keyboard|keyboardHidden|screenLayout|screenSize|orientation\"\n                  android:theme=\"@android:style/Theme.Translucent.NoTitleBar\"\n                  android:label=\"@string/app_name\" />\n\n        <activity\n            android:name=\".MainActivity\"\n            android:label=\"@string/app_name\"\n            android:theme=\"@style/AppTheme.NoActionBar\"\n            android:launchMode=\"singleTop\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n        </activity>\n\n        <receiver\n            android:name=\"com.google.android.gms.gcm.GcmReceiver\"\n            android:exported=\"true\"\n            android:permission=\"com.google.android.c2dm.permission.SEND\">\n            <intent-filter>\n                <action android:name=\"com.google.android.c2dm.intent.RECEIVE\"/>\n                <category android:name=\"com.facebook.notifications.sample\"/>\n            </intent-filter>\n        </receiver>\n\n        <service\n            android:name=\".MyGcmListenerService\"\n            android:exported=\"false\">\n            <intent-filter>\n                <action android:name=\"com.google.android.c2dm.intent.RECEIVE\"/>\n            </intent-filter>\n        </service>\n\n        <service\n            android:name=\".MyInstanceIDListenerService\"\n            android:exported=\"false\">\n            <intent-filter>\n                <action android:name=\"com.google.android.gms.iid.InstanceID\"/>\n            </intent-filter>\n        </service>\n        <service android:name=\".RegistrationIntentService\" android:exported=\"false\"/>\n    </application>\n</manifest>\n"
  },
  {
    "path": "Android/notifications-example/src/main/assets/example1.json",
    "content": "{\n  \"fb_push_card\": {\n    \"version\" : \"1.0\",\n    \"dismissColor\": \"#334D5CFF\",\n    \"size\": \"small\",\n    \"cornerRadius\": 12.0,\n    \"contentInset\" : 10,\n    \"backdropColor\": \"#000000CC\",\n    \"hero\": {\n      \"background\": {\n        \"_type\": \"Color\",\n        \"rgbaHex\": \"#FFFFFFFF\"\n      },\n      \"content\": {\n        \"_type\": \"StyledText\",\n        \"size\": 17,\n        \"text\": \"There are item(s) in your cart\",\n        \"align\": \"left\",\n        \"color\": \"#334D5CFF\"\n      },\n      \"contentAlign\" : \"bottom\"\n    },\n    \"body\": {\n      \"background\": {\n        \"_type\": \"Color\",\n        \"rgbaHex\": \"#FFFFFFFF\"\n      },\n      \"content\": {\n        \"_type\": \"StyledText\",\n        \"size\": 15,\n        \"text\": \"Oops! It seems like you left some item(s) in your cart. You can remove them or checkout.\",\n        \"align\": \"left\",\n        \"color\": \"#334D5CFF\"\n      }\n    },\n    \"alert\" : {\n      \"title\": \"Oops!\",\n      \"body\" : \"There are item(s) in your cart!\"\n    },\n    \"actions\": {\n      \"style\": \"attached\",\n      \"layoutStyle\" : \"vertical\",\n      \"background\": {\n        \"_type\": \"Color\",\n        \"rgbaHex\": \"#FFFFFFFF\"\n      },\n      \"contentInset\" : 10,\n      \"cornerRadius\" : 8,\n      \"actions\": [\n        {\n          \"backgroundColor\": \"#61B6E5FF\",\n          \"content\": {\n            \"_type\": \"StyledText\",\n            \"size\": 18,\n            \"text\": \"GO TO CART\",\n            \"color\": \"#FFFFFFFF\"\n          },\n          \"url\": \"https://parse.com/\"\n        }\n      ]\n    }\n  }\n}\n"
  },
  {
    "path": "Android/notifications-example/src/main/assets/example2.json",
    "content": "{\n  \"fb_push_payload\" : {\n    \"campaign\" : \"2\"\n  },\n  \"fb_push_card\": {\n    \"version\": \"1.0\",\n    \"size\": \"medium\",\n    \"cornerRadius\": 12,\n    \"contentInset\" : 16,\n    \"backdropColor\": \"#334D5CF5\",\n    \"hero\": {\n      \"background\": {\n        \"_type\": \"Color\",\n        \"rgbaHex\": \"#50CCB4FF\"\n      },\n      \"content\": {\n        \"_type\": \"StyledText\",\n        \"size\": 24,\n        \"text\": \"Introducing Messaging!\",\n        \"font\": \"system-bold\",\n        \"align\": \"center\",\n        \"color\": \"#FFFFFFFF\"\n      }\n    },\n    \"body\": {\n      \"background\": {\n        \"_type\": \"Color\",\n        \"rgbaHex\": \"#FFFFFFFF\"\n      },\n      \"content\": {\n        \"_type\": \"StyledText\",\n        \"size\": 16,\n        \"text\": \"The AnyApp team is proud to launch our in app messaging feature! Give it a try today and message your friends.\",\n        \"font\": \"system-light\",\n        \"align\": \"left\",\n        \"color\": \"#334D5CFF\"\n      }\n    },\n    \"alert\" : {\n      \"body\" : \"Introducing Messaging!\"\n    },\n    \"actions\": {\n      \"style\": \"attached\",\n      \"layoutStyle\" : \"horizontal\",\n      \"actionsHeight\" : 60.0,\n      \"actions\": [\n        {\n          \"backgroundColor\": \"#C6D9E0FF\",\n          \"title\": \"Not Now\",\n          \"content\": {\n            \"_type\": \"StyledText\",\n            \"size\": 18,\n            \"text\": \"Not Now\",\n            \"color\": \"#FFFFFFFF\"\n          }\n        },\n        {\n          \"backgroundColor\": \"#9167EFFF\",\n          \"content\": {\n            \"_type\": \"StyledText\",\n            \"size\": 18,\n            \"text\": \"Try It\",\n            \"color\": \"#FFFFFFFF\"\n          },\n          \"url\": \"https://messenger.com\"\n        }\n      ]\n    }\n  }\n}\n"
  },
  {
    "path": "Android/notifications-example/src/main/assets/example3.json",
    "content": "{\n  \"fb_push_payload\" : {\n    \"campaign\" : \"3\"\n  },\n  \"fb_push_card\": {\n    \"version\": \"1.0\",\n    \"size\": \"medium\",\n    \"cornerRadius\": 16,\n    \"contentInset\" : 16,\n    \"backdropColor\": \"#332D2DF0\",\n    \"hero\": {\n      \"background\": {\n        \"_type\": \"GIF\",\n        \"url\": \"https://s3.amazonaws.com/f.cl.ly/items/3S3a3I0a0l2w3M2v2h30/fall.gif\"\n      }\n    },\n    \"body\": {\n      \"background\": {\n        \"_type\": \"Color\",\n        \"rgbaHex\": \"#FFFFFFFF\"\n      },\n      \"content\": {\n        \"_type\": \"StyledText\",\n        \"size\": 14,\n        \"text\": \"September 22nd marks the first day of fall and the release of our new fall clothing line. We’re celebrating with a 20% off sale!\",\n        \"align\": \"left\",\n        \"color\": \"#33251FFF\"\n      }\n    },\n    \"alert\" : {\n      \"title\": \"New Clothing Line\",\n      \"body\" : \"20% fall sale!\"\n    },\n    \"actions\": {\n      \"style\": \"attached\",\n      \"layoutStyle\" : \"horizontal\", \n      \"contentInset\" : 16.0,\n      \"cornerRadius\" : 6,\n      \"background\": {\n        \"_type\": \"Color\",\n        \"rgbaHex\": \"#FFFFFFFF\"\n      },\n      \"actions\": [\n        {\n          \"backgroundColor\": \"#690200FF\",\n          \"content\": {\n            \"_type\": \"StyledText\",\n            \"size\": 18,\n            \"text\": \"Yes, please!\",\n            \"color\": \"#FFFFFFFF\"\n          },\n          \"url\": \"https://parse.com/\"\n        },\n        {\n          \"backgroundColor\": \"#CCC4BCFF\",\n          \"content\": {\n            \"_type\": \"StyledText\",\n            \"size\": 18,\n            \"text\": \"No, thanks!\",\n            \"color\": \"#FFFFFFFF\"\n          }\n        }\n      ]\n    }\n  }\n}\n"
  },
  {
    "path": "Android/notifications-example/src/main/assets/example4.json",
    "content": "{\n  \"fb_push_payload\" : {\n    \"campaign\" : \"4\"\n  },\n  \"fb_push_card\": {\n    \"version\": \"1.0\",\n    \"size\": \"medium\",\n    \"cornerRadius\": 20,\n    \"backdropColor\": \"#332D2DF0\",\n    \"dismissColor\": \"#000000FF\",\n    \"hero\": {\n      \"background\": {\n        \"_type\": \"Image\",\n        \"url\": \"https://s3.amazonaws.com/f.cl.ly/items/3n2d2G3V3w2h261x0r0i/pizzzza.png\"\n      }\n    },\n    \"alert\" : {\n      \"title\": \"Yum!\",\n      \"body\" : \"Bob's now delivers!\"\n    },\n    \"actions\": {\n      \"style\": \"detached\",\n      \"layoutStyle\" : \"horizontal\",   \n      \"topInset\": 20,\n      \"cornerRadius\": 20,\n      \"actions\": [\n        {\n          \"borderColor\": \"#FFC84DFF\",\n          \"borderWidth\" : 2,\n          \"content\": {\n            \"_type\": \"StyledText\",\n            \"size\": 18,\n            \"text\": \"Deliver Me Pizzza\",\n            \"color\": \"#FFC84DFF\"\n          },\n          \"url\": \"https://facebook.com/\"\n        }\n      ]\n    }\n  }\n}\n"
  },
  {
    "path": "Android/notifications-example/src/main/assets/example5.json",
    "content": "{\n  \"fb_push_payload\" : {\n    \"campaign\" : \"5\"\n  },\n  \"fb_push_card\": {\n    \"version\": \"1.0\",\n    \"size\": \"large\",\n    \"contentInset\" : 20,\n    \"backdropColor\": \"#FFF9F8F5\",\n    \"hero\": {\n      \"background\": {\n        \"_type\": \"Image\",\n        \"url\": \"https://s3.amazonaws.com/f.cl.ly/items/2s0J0S1a0B2G1n0b421R/PirateBooty.png\"\n      }\n    },\n    \"alert\" : {\n      \"title\": \"Yarr!\",\n      \"body\" : \"Get the free pirate expansion!\"\n    },\n    \"actions\": {\n      \"style\": \"attached\",\n      \"layoutStyle\" : \"vertical\", \n      \"contentInset\" : 10.0,\n      \"height\" : 50,\n      \"cornerRadius\" : 8,\n      \"actions\": [\n        {\n          \"backgroundColor\": \"#EF5B5BFF\",\n          \"content\": {\n            \"_type\": \"StyledText\",\n            \"size\": 18,\n            \"text\": \"Get the free pirate expansion\",\n            \"color\": \"#FFFFFFFF\"\n          },\n          \"url\": \"http://worth1000.s3.amazonaws.com/submissions/384000/384447_858b_625x1000.jpg\"\n        },\n        {\n          \"backgroundColor\": \"#00000000\",\n          \"content\": {\n            \"_type\": \"StyledText\",\n            \"size\": 14,\n            \"text\": \"Nah, I don't like free\",\n            \"color\": \"#EF5B5BFF\"\n          }\n        }\n      ]\n    }\n  }\n}\n"
  },
  {
    "path": "Android/notifications-example/src/main/java/com/facebook/notifications/sample/MainActivity.java",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\npackage com.facebook.notifications.sample;\n\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.support.annotation.NonNull;\nimport android.support.v7.app.AppCompatActivity;\nimport android.support.v7.widget.Toolbar;\nimport android.util.Log;\nimport android.view.View;\nimport android.widget.Toast;\n\nimport com.facebook.FacebookSdk;\nimport com.facebook.notifications.NotificationCardResult;\nimport com.facebook.notifications.NotificationsManager;\n\nimport org.apache.commons.io.IOUtils;\nimport org.json.JSONObject;\n\nimport java.io.InputStream;\nimport java.io.StringWriter;\nimport java.nio.charset.Charset;\n\npublic class MainActivity extends AppCompatActivity {\n  private static final String LOG_TAG = MainActivity.class.getCanonicalName();\n\n  @Override\n  protected void onCreate(Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n    setContentView(R.layout.activity_main);\n\n    FacebookSdk.sdkInitialize(getApplicationContext());\n    NotificationsManager.presentCardFromNotification(this);\n\n    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);\n    setSupportActionBar(toolbar);\n\n    // register for GCM\n    Intent intent = new Intent(this, RegistrationIntentService.class);\n    startService(intent);\n  }\n\n  @Override\n  protected void onNewIntent(Intent intent) {\n    super.onNewIntent(intent);\n    NotificationsManager.presentCardFromNotification(this, intent);\n  }\n\n  @Override\n  protected void onActivityResult(int requestCode, int resultCode, Intent data) {\n    super.onActivityResult(requestCode, resultCode, data);\n    NotificationCardResult result = NotificationsManager.handleActivityResult(requestCode, resultCode, data);\n\n    if (result != null) {\n      Toast.makeText(this, \"Result: \" + result.getActionUri(), Toast.LENGTH_LONG).show();\n    }\n  }\n\n  /**\n   * Mock an example push notification bundle from one of our local example JSON files.\n   * @param exampleId The example id of the asset to load\n   * @return a bundle with the contents of the specified example id\n   */\n  @NonNull\n  private Bundle getBundle(int exampleId) {\n    try {\n      InputStream inputStream = getAssets().open(\"example\" + exampleId + \".json\");\n\n      StringWriter output = new StringWriter();\n      IOUtils.copy(inputStream, output, Charset.forName(\"UTF-8\"));\n\n      JSONObject json = new JSONObject(output.toString());\n\n      Bundle bundle = new Bundle();\n      bundle.putString(\"fb_push_card\", json.getJSONObject(\"fb_push_card\").toString());\n      JSONObject pushPayload = json.optJSONObject(\"fb_push_payload\");\n      if (pushPayload != null) {\n        bundle.putString(\"fb_push_payload\", pushPayload.toString());\n      }\n\n\n      output.close();\n      inputStream.close();\n\n      return bundle;\n    } catch (Exception ex) {\n      Log.e(LOG_TAG, \"Error while getting bundle\", ex);\n      return new Bundle();\n    }\n  }\n\n  public void showExample(View view) {\n    Bundle exampleBundle = getBundle(Integer.parseInt(view.getTag().toString()));\n\n    NotificationsManager.presentCard(this, exampleBundle);\n  }\n\n  public void showNotification(View view) {\n    Bundle exampleBundle = getBundle(Integer.parseInt(view.getTag().toString()));\n\n    NotificationsManager.presentNotification(this, exampleBundle, getIntent());\n  }\n}\n"
  },
  {
    "path": "Android/notifications-example/src/main/java/com/facebook/notifications/sample/MyGcmListenerService.java",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\npackage com.facebook.notifications.sample;\n\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.util.Log;\n\nimport com.facebook.notifications.NotificationsManager;\nimport com.google.android.gms.gcm.GcmListenerService;\n\n/**\n * Sample GCM listener service\n */\npublic class MyGcmListenerService extends GcmListenerService {\n  private static final String LOG_TAG = MyGcmListenerService.class.getCanonicalName();\n\n  @Override\n  public void onMessageReceived(String from, final Bundle data) {\n    Log.v(LOG_TAG, \"onMessageReceived(\" + from + \", \" + data + \")\");\n\n    NotificationsManager.presentNotification(\n      this,\n      data,\n      new Intent(getApplicationContext(), MainActivity.class)\n    );\n  }\n}\n"
  },
  {
    "path": "Android/notifications-example/src/main/java/com/facebook/notifications/sample/MyInstanceIDListenerService.java",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\npackage com.facebook.notifications.sample;\n\nimport android.content.Intent;\n\nimport com.google.android.gms.iid.InstanceIDListenerService;\n\npublic class MyInstanceIDListenerService extends InstanceIDListenerService {\n  @Override\n  public void onTokenRefresh() {\n    Intent intent = new Intent(this, RegistrationIntentService.class);\n    startService(intent);\n  }\n}\n"
  },
  {
    "path": "Android/notifications-example/src/main/java/com/facebook/notifications/sample/RegistrationIntentService.java",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\npackage com.facebook.notifications.sample;\n\nimport android.app.IntentService;\nimport android.content.Intent;\nimport android.util.Log;\n\nimport com.google.android.gms.gcm.GoogleCloudMessaging;\nimport com.google.android.gms.iid.InstanceID;\n\npublic class RegistrationIntentService extends IntentService {\n  private static final String LOG_TAG = RegistrationIntentService.class.getCanonicalName();\n\n  public RegistrationIntentService() {\n    super(LOG_TAG);\n  }\n\n  @Override\n  protected void onHandleIntent(Intent intent) {\n    try {\n      synchronized (this) {\n        InstanceID instanceID = InstanceID.getInstance(this);\n        String token = instanceID.getToken(getString(R.string.gcm_defaultSenderId), GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);\n        Log.i(LOG_TAG, \"GCM Registration Token: \" + token);\n      }\n    } catch (Exception e) {\n      Log.e(LOG_TAG, \"Failed to complete token refresh\", e);\n    }\n  }\n}\n"
  },
  {
    "path": "Android/notifications-example/src/main/res/layout/activity_main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<android.support.design.widget.CoordinatorLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:fitsSystemWindows=\"true\"\n    tools:context=\"com.facebook.notifications.sample.MainActivity\">\n\n    <android.support.design.widget.AppBarLayout\n        android:layout_height=\"wrap_content\"\n        android:layout_width=\"match_parent\"\n        android:theme=\"@style/AppTheme.AppBarOverlay\">\n\n        <android.support.v7.widget.Toolbar\n            android:id=\"@+id/toolbar\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"?attr/actionBarSize\"\n            android:background=\"?attr/colorPrimary\"\n            app:popupTheme=\"@style/AppTheme.PopupOverlay\" />\n\n    </android.support.design.widget.AppBarLayout>\n\n    <include layout=\"@layout/content_main\"/>\n\n</android.support.design.widget.CoordinatorLayout>\n"
  },
  {
    "path": "Android/notifications-example/src/main/res/layout/content_main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:paddingLeft=\"@dimen/activity_horizontal_margin\"\n    android:paddingRight=\"@dimen/activity_horizontal_margin\"\n    android:paddingTop=\"@dimen/activity_vertical_margin\"\n    android:paddingBottom=\"@dimen/activity_vertical_margin\"\n    android:orientation=\"vertical\"\n    app:layout_behavior=\"@string/appbar_scrolling_view_behavior\"\n    tools:showIn=\"@layout/activity_main\"\n    tools:context=\"com.facebook.notifications.sample.MainActivity\">\n\n    <LinearLayout\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\">\n\n        <Button\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/example_1\"\n            android:onClick=\"showExample\"\n            android:tag=\"1\" />\n\n        <Button\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/notification_1\"\n            android:onClick=\"showNotification\"\n            android:tag=\"1\" />\n\n    </LinearLayout>\n\n    <LinearLayout\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\">\n\n        <Button\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/example_2\"\n            android:onClick=\"showExample\"\n            android:tag=\"2\" />\n\n        <Button\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/notification_2\"\n            android:onClick=\"showNotification\"\n            android:tag=\"2\" />\n\n    </LinearLayout>\n\n    <LinearLayout\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\">\n\n        <Button\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/example_3\"\n            android:onClick=\"showExample\"\n            android:tag=\"3\" />\n\n        <Button\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/notification_3\"\n            android:onClick=\"showNotification\"\n            android:tag=\"3\" />\n\n    </LinearLayout>\n\n    <LinearLayout\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\">\n\n        <Button\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/example_4\"\n            android:onClick=\"showExample\"\n            android:tag=\"4\" />\n\n        <Button\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/notification_4\"\n            android:onClick=\"showNotification\"\n            android:tag=\"4\" />\n\n    </LinearLayout>\n\n    <LinearLayout\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\">\n\n        <Button\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/example_5\"\n            android:onClick=\"showExample\"\n            android:tag=\"5\" />\n\n        <Button\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/notification_5\"\n            android:onClick=\"showNotification\"\n            android:tag=\"5\" />\n\n    </LinearLayout>\n\n</LinearLayout>\n"
  },
  {
    "path": "Android/notifications-example/src/main/res/menu/menu_main.xml",
    "content": "<menu\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    tools:context=\"com.facebook.notifications.sample.MainActivity\">\n</menu>\n"
  },
  {
    "path": "Android/notifications-example/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"colorPrimary\">#3F51B5</color>\n    <color name=\"colorPrimaryDark\">#303F9F</color>\n    <color name=\"colorAccent\">#FF4081</color>\n</resources>\n"
  },
  {
    "path": "Android/notifications-example/src/main/res/values/dimens.xml",
    "content": "<resources>\n    <!-- Default screen margins, per the Android Design guidelines. -->\n    <dimen name=\"activity_horizontal_margin\">16dp</dimen>\n    <dimen name=\"activity_vertical_margin\">16dp</dimen>\n    <dimen name=\"fab_margin\">16dp</dimen>\n</resources>\n"
  },
  {
    "path": "Android/notifications-example/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">FBNotificationsSample</string>\n    <string name=\"action_settings\">Settings</string>\n\n    <string name=\"example_1\">Show Example #1</string>\n    <string name=\"example_2\">Show Example #2</string>\n    <string name=\"example_3\">Show Example #3</string>\n    <string name=\"example_4\">Show Example #4</string>\n    <string name=\"example_5\">Show Example #5</string>\n\n    <string name=\"notification_1\">Show Notification #1</string>\n    <string name=\"notification_2\">Show Notification #2</string>\n    <string name=\"notification_3\">Show Notification #3</string>\n    <string name=\"notification_4\">Show Notification #4</string>\n    <string name=\"notification_5\">Show Notification #5</string>\n</resources>\n"
  },
  {
    "path": "Android/notifications-example/src/main/res/values/styles.xml",
    "content": "<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.DarkActionBar\">\n        <!-- Customize your theme here. -->\n        <item name=\"colorPrimary\">@color/colorPrimary</item>\n        <item name=\"colorPrimaryDark\">@color/colorPrimaryDark</item>\n        <item name=\"colorAccent\">@color/colorAccent</item>\n    </style>\n    <style name=\"AppTheme.NoActionBar\">\n        <item name=\"windowActionBar\">false</item>\n        <item name=\"windowNoTitle\">true</item>\n    </style>\n    <style name=\"AppTheme.AppBarOverlay\" parent=\"ThemeOverlay.AppCompat.Dark.ActionBar\"/>\n    <style name=\"AppTheme.PopupOverlay\" parent=\"ThemeOverlay.AppCompat.Light\"/>\n\n</resources>\n"
  },
  {
    "path": "Android/notifications-example/src/main/res/values-v21/styles.xml",
    "content": "<resources>>\n            <style name=\"AppTheme.NoActionBar\">\n            <item name=\"windowActionBar\">false</item>\n            <item name=\"windowNoTitle\">true</item>\n            <item name=\"android:windowDrawsSystemBarBackgrounds\">true</item>\n            <item name=\"android:statusBarColor\">@android:color/transparent</item>\n        </style>\n</resources>\n"
  },
  {
    "path": "Android/notifications-example/src/main/res/values-w820dp/dimens.xml",
    "content": "<resources>\n    <!-- Example customization of dimensions originally defined in res/values/dimens.xml\n         (such as screen margins) for screens with more than 820dp of available width. This\n         would include 7\" and 10\" devices in landscape (~960dp and ~1280dp respectively). -->\n    <dimen name=\"activity_horizontal_margin\">64dp</dimen>\n</resources>\n"
  },
  {
    "path": "Android/settings.gradle",
    "content": "include ':notifications', ':notifications-example'\n"
  },
  {
    "path": "CHANGELOG-Android.md",
    "content": "# Facebook In-App Notifications for Android Changelog\n\n## [1.0.2] - 2016-06-01\n### Added\n- Added automatic logging for push opened and back button events.  \n  [#9](https://github.com/facebook/FBNotifications/pull/9)\n  by [Nikita Lutsenko](https://github.com/nlutsenko)\n\n### Updated\n- Removed requirement on containing a push campaign identifier in the payload.  \n  [#18](https://github.com/facebook/FBNotifications/pull/18)\n  by [Nikita Lutsenko](https://github.com/nlutsenko)\n- Updated Gradle to latest stable version (2.1.0).  \n  [#18](https://github.com/facebook/FBNotifications/pull/18)\n  by [Nikita Lutsenko](https://github.com/nlutsenko)\n\nView all issues and pull requests associated with this release [here](https://github.com/facebook/FBNotifications/issues?utf8=✓&q=milestone%3AAndroid-1.0.2)\n\n## [1.0.1] - 2016-04-21\n### Added\n- Added a method to check if a payload exists for a notification.  \n  [#7](https://github.com/facebook/FBNotifications/pull/7)\n  by [Richard Ross](https://github.com/richardjrossiii)\n- Added convenience method for presenting cards when the activity is relaunched.  \n  [#6](https://github.com/facebook/FBNotifications/pull/6)\n  by [Nikita Lutsenko](https://github.com/nlutsenko)\n\n### Updated\n- Updated Gradle to latest stable version (2.0.0).  \n  [#4](https://github.com/facebook/FBNotifications/pull/4)\n  by [Nikita Lutsenko](https://github.com/nlutsenko)\n  \n### Fixed\n- Fixed NullPointerException when there is no HeroView on Android.  \n  [#5](https://github.com/facebook/FBNotifications/pull/5)\n  by [Nikita Lutsenko](https://github.com/nlutsenko)\n\nView all issues and pull requests associated with this release [here](https://github.com/facebook/FBNotifications/issues?utf8=✓&q=milestone%3AAndroid-1.0.1)\n\n## 1.0 - 2016-04-12\n\nInitial Release\n\n[1.0.1]: (https://github.com/facebook/FBNotifications/releases/tag/android-1.0.1)"
  },
  {
    "path": "CHANGELOG-iOS.md",
    "content": "# Facebook In-App Notifications for iOS Changelog\n\n## [1.0.1] - 2016-05-10\n\n### Added\n- Added automatic logging of push opened events on card view appear.\n  [#10](https://github.com/facebook/FBNotifications/pull/10)\n  by [Nikita Lutsenko](https://github.com/nlutsenko)\n  \n### Fixed\n- Fixed incorrect submodule setup blocking installation via Carthage.\n  [#12](https://github.com/facebook/FBNotifications/pull/12)\n  by [Nikita Lutsenko](https://github.com/nlutsenko)\n\nView all issues and pull requests associated with this release [here](https://github.com/facebook/FBNotifications/issues?utf8=✓&q=milestone%3AiOS-1.0.1)\n\n## 1.0 - 2016-04-12\n\nInitial Release\n\n[1.0.1]: (https://github.com/facebook/FBNotifications/releases/tag/ios-1.0.1)"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing to Facebook In-App Notifications\nWe want to make contributing to this project as easy and transparent as possible.\n\n## Pull Requests\nWe actively welcome your pull requests.\n\n1. Fork the repo and create your branch from `master`. \n2. If you've added code that should be tested, add tests.\n3. If you've changed APIs, update the documentation. \n4. Ensure the test suite passes. \n5. Make sure your code lints. \n6. If you haven't already, complete the Contributor License Agreement (\"CLA\").\n\n## Contributor License Agreement (\"CLA\")\nIn order to accept your pull request, we need you to submit a CLA. You only need\nto do this once to work on any of Facebook's open source projects.\n\nComplete your CLA here: <https://developers.facebook.com/opensource/cla>\n\n## Issues  \nWe use GitHub issues to track public bugs. Please ensure your description is\nclear and has sufficient instructions to be able to reproduce the issue.\n\nFacebook has a [bounty program](https://www.facebook.com/whitehat/) for the safe\ndisclosure of security bugs. In those cases, please go through the process\noutlined on that page and do not file a public issue.\n\n## Coding Style  \n* Most importantly, match the existing code style as much as possible.\n* Try to keep lines under 140 characters, if possible.\n\n## License\nSee the `LICENSE` file.\n"
  },
  {
    "path": "FBNotifications.podspec",
    "content": "Pod::Spec.new do |s|\n  s.name             = 'FBNotifications'\n  s.version          = '1.0.1'\n  s.license          =  { :type => 'Facebook Platform License', :file => 'LICENSE' }\n  s.summary          = 'Facebook In-App Notifications Framework'\n  s.homepage         = 'https://developers.facebook.com/products/analytics'\n  s.authors          = { 'Nikita Lutsenko' => 'nlutsenko@me.com' }\n  \n  s.source       = { :git => 'https://github.com/facebook/FBNotifications.git', :tag => s.version.to_s }\n\n  s.requires_arc = true\n\n  s.ios.deployment_target = '8.0'\n  \n  s.source_files = 'iOS/FBNotifications/FBNotifications/**/*.{h,m}'\n  s.public_header_files = 'iOS/FBNotifications/FBNotifications/*.h'\n\n  s.frameworks = 'ImageIO', 'MobileCoreServices'\nend\n"
  },
  {
    "path": "Format/Format-1.0.md",
    "content": "# [1.0] Facebook In-App Notifications Format\n\n## Types\n\nWe use basic JSON types to describe everything, since it's portable and supported on all platforms.\n\nThere are more complex types that form a JSON object by themselves (e.g. %CARD_BACKGROUND%) to eliminate ambiguity on the values as well as to be future compatible. When you see anything that starts and ends with a '%' - it means it's a custom type, that has separate piece of documentation in this document.\n\n## Card Components\n\nThese components are attached to specific portions of content and are used only in a single place.\n\n### %CARD_PAYLOAD%\n\nPush Card consists of 3 basic parts: Hero, Body, Actions, which are going to be represented by JSON Objects.\nEach one is going to be described in a separate section, in addition to the payload itself. \nThis is a description for the basic payload, since it has few more things:\n\n```\n{\n  \"alert\" : %ALERT%,\n  \"version\" : \"1.0\", // \"major.minor.patch\", where 'patch' is optional.\n  \n  \"size\" : \"small\" // Values: \"small\", \"medium\", \"large\". Non-optional.\n  \"cornerRadius\" : 2.0, // Default: 0\n  \"contentInset\" : 5.0, // Default: 10.0\n  \n  \"backdropColor\" : \"#ABABABFF\", // RGBA Hex Value. Default: #00000000.\n  \"dismissColor\" : \"#ABABABFF\", // RGBA Hex Value. Default: #000000FF.\n\n  \"hero\" : %CARD_HERO%, // Optional\n  \"body\" : %CARD_BODY%, // Optional\n  \"actions\" : %CARD_ACTIONS% // Optional\n}\n```\n\n### %ALERT%\n\nThis is used to specify the local system notification title/body.\n\n```\n{\n  \"title\" : \"Yarr!\",\n  \"body\" : \"The quick brown fox jumps over the lazy dawg.\"\n}\n```\n\n### %CARD_HERO%\n\n```\n{\n  \"height\" : 0.5, // 0.0 to 1.0. Optional.\n  \"background\" : %IMAGE%, // Values: %IMAGE%/%COLOR%/%GIF%\n  \"content\" : %STYLED_TEXT%, // Optional.\n  \"contentAlign\" : \"center\" // Values: \"top\"/\"center\"/\"bottom\". Default: \"center\".\n}\n```\n\n### %CARD_BODY%\n\n```\n{\n  \"background\" : %IMAGE%, // Values: %IMAGE% or %COLOR%\n  \"content\" : %STYLED_TEXT% // Optional.\n}\n```\n\n### %CARD_ACTIONS%\n\n```\n{\n  \"style\" : \"attached\", // Values: \"attached\" or \"detached\"\n  \"layoutStyle\" : \"horizontal\", // Values: \"horizontal\" or \"vertical\"\n  \n  \"background\" : %COLOR%, // Values: %IMAGE% or %COLOR%\n\n  \"height\" : 50.0, // Default: 44.0\n  \"topInset\" : 5.0, // Default: 0.0\n  \"contentInset\" : 5.0, // Default: 0.0\n  \"cornerRadius\": 0.0, // Default: 0.0\n  \n  \"actions\" : [ %CARD_ACTION% ] // Array of actions\n}\n```\n\n### %CARD_ACTION%\n\n```\n{\n  \"backgroundColor\" : \"#ABABABFF\", // RGBA Hex Value. Optional.\n  \"borderColor\" : \"#ABABABFF\", // RGBA Hex Value. Optional.\n  \"borderWidth\" : 2.0, // Default: 0.0\n  \"content\" : %STYLED_TEXT%, // Optional\n  \"url\" : \"https://parse.com/\" // Optional. Will dismiss card if none set.\n}\n```\n\n## Basic Components\n\nThese components could be used in different types throughout the payload.\n\n### %IMAGE%\n\n```\n{\n  \"_type\" : \"Image\",\n  \"url\" : \"https://parse.com/favicon.ico\"\n}\n```\n\n### %COLOR%\n\n```\n{\n  \"_type\" : \"Color\",\n  \"rgbaHex\" : \"#101010FF\" // RGBA Hex Value\n}\n```\n\n### %GIF%\n\n```\n{\n  \"_type\" : \"GIF\",\n  \"url\" : \"https://parse.com/yolo.gif\"\n}  \n```\n\n### %STYLED_TEXT%\n\n```\n{\n  \"_type\" : \"StyledText\",\n  \"align\" : \"left\", // Values: \"left\" or \"center\" or \"right\".\n  \"size\" : 15.0,\n  \"font\" : %FONT%, // Optional. Default: System Font in Regular weight.\n  \"text\" : \"Hello World!\",\n  \"color\" : \"#EDEDEDFF\" // RGBA Hex Value\n}\n```\n\n### %FONT%\n\nA string representation of the font name with optional weight.\nBuilt-in values that should be handled are:\n```\n\"system-regular\"\n\"system-light\"\n\"system-bold\"\n\"system-italic\"\n\"system-bolditalic\"\n```\n\n## Example Payload\n\n```json\n{\n  \"fb_push_payload\" : {\n    \"campaign\" : \"3\"\n  },\n  \"fb_push_card\": {\n    \"version\": \"1.0\",\n    \"size\": \"medium\",\n    \"cornerRadius\": 16,\n    \"contentInset\" : 16,\n    \"backdropColor\": \"#332D2DF0\",\n    \"hero\": {\n      \"background\": {\n        \"_type\": \"GIF\",\n        \"url\": \"https://s3.amazonaws.com/f.cl.ly/items/3S3a3I0a0l2w3M2v2h30/fall.gif\"\n      }\n    },\n    \"body\": {\n      \"background\": {\n        \"_type\": \"Color\",\n        \"rgbaHex\": \"#FFFFFFFF\"\n      },\n      \"content\": {\n        \"_type\": \"StyledText\",\n        \"size\": 14,\n        \"text\": \"September 22nd marks the first day of fall and the release of our new fall clothing line. We’re celebrating with a 20% off sale!\",\n        \"align\": \"left\",\n        \"color\": \"#33251FFF\"\n      }\n    },\n    \"alert\" : {\n      \"title\": \"New Clothing Line\",\n      \"body\" : \"20% fall sale!\"\n    },\n    \"actions\": {\n      \"style\": \"attached\",\n      \"layoutStyle\" : \"horizontal\", \n      \"contentInset\" : 16.0,\n      \"cornerRadius\" : 6,\n      \"background\": {\n        \"_type\": \"Color\",\n        \"rgbaHex\": \"#FFFFFFFF\"\n      },\n      \"actions\": [\n        {\n          \"backgroundColor\": \"#690200FF\",\n          \"content\": {\n            \"_type\": \"StyledText\",\n            \"size\": 18,\n            \"text\": \"Yes, please!\",\n            \"color\": \"#FFFFFFFF\"\n          },\n          \"url\": \"https://parse.com/\"\n        },\n        {\n          \"backgroundColor\": \"#CCC4BCFF\",\n          \"content\": {\n            \"_type\": \"StyledText\",\n            \"size\": 18,\n            \"text\": \"No, thanks!\",\n            \"color\": \"#FFFFFFFF\"\n          }\n        }\n      ]\n    }\n  }\n}\n```\n"
  },
  {
    "path": "Format/Format-Changelog.md",
    "content": "# Facebook In-App Notifications Format Changelog\n\n## 1.0\n\nInitial Release"
  },
  {
    "path": "LICENSE",
    "content": "Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n\nFor Facebook In-App Notifications Framework software\n\nYou are hereby granted a non-exclusive, worldwide, royalty-free license to use,\ncopy, modify, and distribute this software in source code or binary form for use\nin connection with the web services and APIs provided by Facebook.\n\nAs with any software that integrates with the Facebook platform, your use of\nthis software is subject to the Facebook Developer Principles and Policies\n[http://developers.facebook.com/policy/]. This copyright notice shall be\nincluded in all copies or substantial portions of the software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "LICENSE-specification",
    "content": "Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n\nFor In-App Notifications Format specification in Format/\n\nCreative Commons Attribution 4.0 International Public License\n\nBy exercising the Licensed Rights (defined below), You accept and agree\nto be bound by the terms and conditions of this Creative Commons\nAttribution 4.0 International Public License (\"Public License\"). To the\nextent this Public License may be interpreted as a contract, You are\ngranted the Licensed Rights in consideration of Your acceptance of\nthese terms and conditions, and the Licensor grants You such rights in\nconsideration of benefits the Licensor receives from making the\nLicensed Material available under these terms and conditions.\n\n\nSection 1 -- Definitions.\n\n  a. Adapted Material means material subject to Copyright and Similar\n     Rights that is derived from or based upon the Licensed Material\n     and in which the Licensed Material is translated, altered,\n     arranged, transformed, or otherwise modified in a manner requiring\n     permission under the Copyright and Similar Rights held by the\n     Licensor. For purposes of this Public License, where the Licensed\n     Material is a musical work, performance, or sound recording,\n     Adapted Material is always produced where the Licensed Material is\n     synched in timed relation with a moving image.\n\n  b. Adapter's License means the license You apply to Your Copyright\n     and Similar Rights in Your contributions to Adapted Material in\n     accordance with the terms and conditions of this Public License.\n\n  c. Copyright and Similar Rights means copyright and/or similar rights\n     closely related to copyright including, without limitation,\n     performance, broadcast, sound recording, and Sui Generis Database\n     Rights, without regard to how the rights are labeled or\n     categorized. For purposes of this Public License, the rights\n     specified in Section 2(b)(1)-(2) are not Copyright and Similar\n     Rights.\n\n  d. Effective Technological Measures means those measures that, in the\n     absence of proper authority, may not be circumvented under laws\n     fulfilling obligations under Article 11 of the WIPO Copyright\n     Treaty adopted on December 20, 1996, and/or similar international\n     agreements.\n\n  e. Exceptions and Limitations means fair use, fair dealing, and/or\n     any other exception or limitation to Copyright and Similar Rights\n     that applies to Your use of the Licensed Material.\n\n  f. Licensed Material means the artistic or literary work, database,\n     or other material to which the Licensor applied this Public\n     License.\n\n  g. Licensed Rights means the rights granted to You subject to the\n     terms and conditions of this Public License, which are limited to\n     all Copyright and Similar Rights that apply to Your use of the\n     Licensed Material and that the Licensor has authority to license.\n\n  h. Licensor means the individual(s) or entity(ies) granting rights\n     under this Public License.\n\n  i. Share means to provide material to the public by any means or\n     process that requires permission under the Licensed Rights, such\n     as reproduction, public display, public performance, distribution,\n     dissemination, communication, or importation, and to make material\n     available to the public including in ways that members of the\n     public may access the material from a place and at a time\n     individually chosen by them.\n\n  j. Sui Generis Database Rights means rights other than copyright\n     resulting from Directive 96/9/EC of the European Parliament and of\n     the Council of 11 March 1996 on the legal protection of databases,\n     as amended and/or succeeded, as well as other essentially\n     equivalent rights anywhere in the world.\n\n  k. You means the individual or entity exercising the Licensed Rights\n     under this Public License. Your has a corresponding meaning.\n\n\nSection 2 -- Scope.\n\n  a. License grant.\n\n       1. Subject to the terms and conditions of this Public License,\n          the Licensor hereby grants You a worldwide, royalty-free,\n          non-sublicensable, non-exclusive, irrevocable license to\n          exercise the Licensed Rights in the Licensed Material to:\n\n            a. reproduce and Share the Licensed Material, in whole or\n               in part; and\n\n            b. produce, reproduce, and Share Adapted Material.\n\n       2. Exceptions and Limitations. For the avoidance of doubt, where\n          Exceptions and Limitations apply to Your use, this Public\n          License does not apply, and You do not need to comply with\n          its terms and conditions.\n\n       3. Term. The term of this Public License is specified in Section\n          6(a).\n\n       4. Media and formats; technical modifications allowed. The\n          Licensor authorizes You to exercise the Licensed Rights in\n          all media and formats whether now known or hereafter created,\n          and to make technical modifications necessary to do so. The\n          Licensor waives and/or agrees not to assert any right or\n          authority to forbid You from making technical modifications\n          necessary to exercise the Licensed Rights, including\n          technical modifications necessary to circumvent Effective\n          Technological Measures. For purposes of this Public License,\n          simply making modifications authorized by this Section 2(a)\n          (4) never produces Adapted Material.\n\n       5. Downstream recipients.\n\n            a. Offer from the Licensor -- Licensed Material. Every\n               recipient of the Licensed Material automatically\n               receives an offer from the Licensor to exercise the\n               Licensed Rights under the terms and conditions of this\n               Public License.\n\n            b. No downstream restrictions. You may not offer or impose\n               any additional or different terms or conditions on, or\n               apply any Effective Technological Measures to, the\n               Licensed Material if doing so restricts exercise of the\n               Licensed Rights by any recipient of the Licensed\n               Material.\n\n       6. No endorsement. Nothing in this Public License constitutes or\n          may be construed as permission to assert or imply that You\n          are, or that Your use of the Licensed Material is, connected\n          with, or sponsored, endorsed, or granted official status by,\n          the Licensor or others designated to receive attribution as\n          provided in Section 3(a)(1)(A)(i).\n\n  b. Other rights.\n\n       1. Moral rights, such as the right of integrity, are not\n          licensed under this Public License, nor are publicity,\n          privacy, and/or other similar personality rights; however, to\n          the extent possible, the Licensor waives and/or agrees not to\n          assert any such rights held by the Licensor to the limited\n          extent necessary to allow You to exercise the Licensed\n          Rights, but not otherwise.\n\n       2. Patent and trademark rights are not licensed under this\n          Public License.\n\n       3. To the extent possible, the Licensor waives any right to\n          collect royalties from You for the exercise of the Licensed\n          Rights, whether directly or through a collecting society\n          under any voluntary or waivable statutory or compulsory\n          licensing scheme. In all other cases the Licensor expressly\n          reserves any right to collect such royalties.\n\n\nSection 3 -- License Conditions.\n\nYour exercise of the Licensed Rights is expressly made subject to the\nfollowing conditions.\n\n  a. Attribution.\n\n       1. If You Share the Licensed Material (including in modified\n          form), You must:\n\n            a. retain the following if it is supplied by the Licensor\n               with the Licensed Material:\n\n                 i. identification of the creator(s) of the Licensed\n                    Material and any others designated to receive\n                    attribution, in any reasonable manner requested by\n                    the Licensor (including by pseudonym if\n                    designated);\n\n                ii. a copyright notice;\n\n               iii. a notice that refers to this Public License;\n\n                iv. a notice that refers to the disclaimer of\n                    warranties;\n\n                 v. a URI or hyperlink to the Licensed Material to the\n                    extent reasonably practicable;\n\n            b. indicate if You modified the Licensed Material and\n               retain an indication of any previous modifications; and\n\n            c. indicate the Licensed Material is licensed under this\n               Public License, and include the text of, or the URI or\n               hyperlink to, this Public License.\n\n       2. You may satisfy the conditions in Section 3(a)(1) in any\n          reasonable manner based on the medium, means, and context in\n          which You Share the Licensed Material. For example, it may be\n          reasonable to satisfy the conditions by providing a URI or\n          hyperlink to a resource that includes the required\n          information.\n\n       3. If requested by the Licensor, You must remove any of the\n          information required by Section 3(a)(1)(A) to the extent\n          reasonably practicable.\n\n       4. If You Share Adapted Material You produce, the Adapter's\n          License You apply must not prevent recipients of the Adapted\n          Material from complying with this Public License.\n\n\nSection 4 -- Sui Generis Database Rights.\n\nWhere the Licensed Rights include Sui Generis Database Rights that\napply to Your use of the Licensed Material:\n\n  a. for the avoidance of doubt, Section 2(a)(1) grants You the right\n     to extract, reuse, reproduce, and Share all or a substantial\n     portion of the contents of the database;\n\n  b. if You include all or a substantial portion of the database\n     contents in a database in which You have Sui Generis Database\n     Rights, then the database in which You have Sui Generis Database\n     Rights (but not its individual contents) is Adapted Material; and\n\n  c. You must comply with the conditions in Section 3(a) if You Share\n     all or a substantial portion of the contents of the database.\n\nFor the avoidance of doubt, this Section 4 supplements and does not\nreplace Your obligations under this Public License where the Licensed\nRights include other Copyright and Similar Rights.\n\n\nSection 5 -- Disclaimer of Warranties and Limitation of Liability.\n\n  a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE\n     EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS\n     AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF\n     ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,\n     IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,\n     WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR\n     PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,\n     ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT\n     KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT\n     ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.\n\n  b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE\n     TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,\n     NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,\n     INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,\n     COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR\n     USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN\n     ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR\n     DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR\n     IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.\n\n  c. The disclaimer of warranties and limitation of liability provided\n     above shall be interpreted in a manner that, to the extent\n     possible, most closely approximates an absolute disclaimer and\n     waiver of all liability.\n\n\nSection 6 -- Term and Termination.\n\n  a. This Public License applies for the term of the Copyright and\n     Similar Rights licensed here. However, if You fail to comply with\n     this Public License, then Your rights under this Public License\n     terminate automatically.\n\n  b. Where Your right to use the Licensed Material has terminated under\n     Section 6(a), it reinstates:\n\n       1. automatically as of the date the violation is cured, provided\n          it is cured within 30 days of Your discovery of the\n          violation; or\n\n       2. upon express reinstatement by the Licensor.\n\n     For the avoidance of doubt, this Section 6(b) does not affect any\n     right the Licensor may have to seek remedies for Your violations\n     of this Public License.\n\n  c. For the avoidance of doubt, the Licensor may also offer the\n     Licensed Material under separate terms or conditions or stop\n     distributing the Licensed Material at any time; however, doing so\n     will not terminate this Public License.\n\n  d. Sections 1, 5, 6, 7, and 8 survive termination of this Public\n     License.\n\n\nSection 7 -- Other Terms and Conditions.\n\n  a. The Licensor shall not be bound by any additional or different\n     terms or conditions communicated by You unless expressly agreed.\n\n  b. Any arrangements, understandings, or agreements regarding the\n     Licensed Material not stated herein are separate from and\n     independent of the terms and conditions of this Public License.\n\n\nSection 8 -- Interpretation.\n\n  a. For the avoidance of doubt, this Public License does not, and\n     shall not be interpreted to, reduce, limit, restrict, or impose\n     conditions on any use of the Licensed Material that could lawfully\n     be made without permission under this Public License.\n\n  b. To the extent possible, if any provision of this Public License is\n     deemed unenforceable, it shall be automatically reformed to the\n     minimum extent necessary to make it enforceable. If the provision\n     cannot be reformed, it shall be severed from this Public License\n     without affecting the enforceability of the remaining terms and\n     conditions.\n\n  c. No term or condition of this Public License will be waived and no\n     failure to comply consented to unless expressly agreed to by the\n     Licensor.\n\n  d. Nothing in this Public License constitutes or may be interpreted\n     as a limitation upon, or waiver of, any privileges and immunities\n     that apply to the Licensor or You, including from the legal\n     processes of any jurisdiction or authority.\n"
  },
  {
    "path": "README.md",
    "content": "![FBNotifications logo](.github/FBNotifications-Logo.png?raw=true)\n\n![Platforms][platforms-svg]\n[![Build Status][build-status-svg]][build-status-link]\n\nFacebook In-App Notifications enables you to create rich and customizable in-app notifications and deliver them via push notifications, based on the actions people take in your app. You can use text, photos, animated GIFs, buttons or extend the open format to suit your needs.\n\n## Getting Started on iOS\n\n[![Podspec][podspec-svg]][podspec-link]\n[![Carthage compatible][carthage-svg]](carthage-link)\n\nTo get started on iOS, install the framework using one of these options:\n\n- **[CocoaPods](https://cocoapods.org)**\n\n Add the following line to your Podfile:\n ```ruby\n pod 'FBNotifications'\n ```\n Run `pod install`, and you should now have the latest framework installed.\n\n- **[Carthage](https://github.com/carthage/carthage)**\n\n Add the following line to your Cartfile:\n ```\n github \"facebook/FBNotifications\"\n ```\n Run `carthage update`, and you should now have the latest version of the framework in your Carthage folder.\n\nAfter you've installed the framework, you would need to add the following to your application delegate to present the notification:\n\nUsing *Objective-C*:\n\n```objc\n/// Present In-App Notification from remote notification (if present).\n- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(nonnull void (^)(UIBackgroundFetchResult))completionHandler {\n  FBNotificationsManager *notificationsManager = [FBNotificationsManager sharedManager];\n  [notificationsManager presentPushCardForRemoteNotificationPayload:userInfo\n                                                 fromViewController:nil\n                                                         completion:^(FBNCardViewController * _Nullable viewController, NSError * _Nullable error) {\n                                                           if (error) {\n                                                             completionHandler(UIBackgroundFetchResultFailed);\n                                                           } else {\n                                                             completionHandler(UIBackgroundFetchResultNewData);\n                                                           }\n                                                         }];\n}\n```\n\nUsing *Swift*:\n```swift\n/// Present In-App Notification from remote notification (if present).\nfunc application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {\n  FBNotificationsManager.sharedManager().presentPushCardForRemoteNotificationPayload(userInfo, fromViewController: nil) { viewController, error in\n    if let _ error = error {\n      completionHandler(.Failed)\n    } else {\n      completionHandler(.NewData)\n    }\n  }\n}\n```\n\n## Getting Started on Android\n\n[![Maven Central][maven-svg]][maven-link]\n\nTo get started on Android, add the following to your gradle dependencies:\n\n```gradle\ncompile 'com.facebook.android:notifications:1.+'\n```\n\nAfter you've added the dependency, you'll have to [set up an FCM listener service](https://firebase.google.com/docs/cloud-messaging/android/client), and add the following to your service:\n\n```java\n@Override\npublic void onMessageReceived(RemoteMessage remoteMessage) {\n    Bundle data = new Bundle();\n    for (Map.Entry<String, String> entry : remoteMessage.getData().entrySet()) {\n      data.putString(entry.getKey(), entry.getValue());\n    }\n  \n    NotificationsManager.presentNotification(\n        this,\n        data,\n        new Intent(getApplicationContext(), MainActivity.class)\n    );\n}\n```\n\nThen when all the content for the notification is ready - it will automatically present the notification to the end user with a pending intent to present a card on open.\nTo hand-off the necessary data from the intent - you need to handle the notification in the `onCreate` function of your Main Activity:\n\n```java\npublic class MainActivity extends AppCompatActivity {\n  @Override\n  protected void onCreate(Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n    NotificationsManager.presentCardFromNotification(this);\n  }\n}\n```\n\nFor more help on getting started, take a look at our [Facebook Push Campaigns Documentation](https://developers.facebook.com/docs/push-campaigns).\n\n## In-App Notifications Format\n\nIn-app notifications are powered by a custom format that has an open specification available in this repository.\nThe format describes all the possible values and combinations of content that can be rendered by the framework.\n\nWe are open to accepting contributions to the format and the format is constantly evolving.\nAny version of the framework is compatible with any previous version of the format in the same major version scope.\n\nFor example:\n  - Framework `1.0.0` **is** compatible with format version `1.0`\n  - Framework `1.0.0` **is not** compatible with format version `1.5`\n  - Framework `1.5.0` **is** compatible with format version `1.5`\n  - Framework `1.5.1` **is** compatible with format version `1.5`\n  - Framework `2.0.0` **is not** compatible with format version `1.0`, or `1.5`\n\n## Contributing\n\nWe want to make contributing to this project as easy and transparent as possible. Please refer to the [Contribution Guidelines](https://github.com/facebook/FBNotifications/blob/master/CONTRIBUTING.md).\n\n## License\n\nSee the `LICENSE` file for source code.\nSee the `LICENSE-specification` file for In-App Notifications format specification.\n\n [platforms-svg]: https://img.shields.io/badge/platform-iOS%20%7C%20Android-lightgrey.svg\n\n [build-status-svg]: https://img.shields.io/travis/facebook/FBNotifications/master.svg\n [build-status-link]: https://travis-ci.org/facebook/FBNotifications/branches\n\n [podspec-svg]: https://img.shields.io/cocoapods/v/FBNotifications.svg\n [podspec-link]: https://cocoapods.org/pods/FBNotifications\n\n [carthage-svg]: https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat\n [carthage-link]: https://github.com/carthage/carthage\n\n [maven-svg]: https://maven-badges.herokuapp.com/maven-central/com.facebook.android/notifications/badge.svg?style=flat\n [maven-link]: https://maven-badges.herokuapp.com/maven-central/com.facebook.android/notifications\n"
  },
  {
    "path": "iOS/.gitignore",
    "content": "## OS X\n.DS_Store\n\n## Build generated\nbuild/\nDerivedData\n\n## Various settings\n*.pbxuser\n!default.pbxuser\n*.mode1v3\n!default.mode1v3\n*.mode2v3\n!default.mode2v3\n*.perspectivev3\n!default.perspectivev3\nxcuserdata\n\n## Other\n*.xccheckout\n*.moved-aside\n*.xcuserstate\n*.xcscmblueprint\n\n## Obj-C/Swift specific\n*.hmap\n*.ipa\n\n## Dependency Managers\nPods/\nCarthage/Build\n\n## AppCode\n.idea/\n"
  },
  {
    "path": "iOS/FBNotifications/Configurations/FBNotifications-iOS-Dynamic.xcconfig",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#include \"Shared/Platform/iOS.xcconfig\"\n#include \"Shared/Product/Framework.xcconfig\"\n\nPRODUCT_NAME = FBNotifications\nPRODUCT_BUNDLE_IDENTIFIER = com.facebook.notifications.ios\n\nIPHONEOS_DEPLOYMENT_TARGET = 8.0\n\nMACH_O_TYPE = mh_dylib\nDYLIB_INSTALL_NAME_BASE = @rpath\n\nDEFINES_MODULE = YES\n\nINFOPLIST_FILE = $(PROJECT_DIR)/FBNotifications/Resources/Info.plist\n\nOTHER_CFLAGS[sdk=iphoneos9.*] = $(inherited) -fembed-bitcode\n"
  },
  {
    "path": "iOS/FBNotifications/Configurations/FBNotifications-iOS.xcconfig",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#include \"Shared/Platform/iOS.xcconfig\"\n#include \"Shared/Product/Framework.xcconfig\"\n\nPRODUCT_NAME = FBNotifications\nPRODUCT_BUNDLE_IDENTIFIER = com.facebook.notifications.ios\n\nIPHONEOS_DEPLOYMENT_TARGET = 8.0\n\nMACH_O_TYPE = staticlib\nDEFINES_MODULE = YES\n\nINFOPLIST_FILE = $(PROJECT_DIR)/FBNotifications/Resources/Info.plist\n\nOTHER_CFLAGS[sdk=iphoneos9.*] = $(inherited) -fembed-bitcode\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/FBNCardViewController.h",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import <Foundation/Foundation.h>\n#import <UIKit/UIKit.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class FBNCardViewController;\n\n/**\n The `FBNCardViewControllerDelegate` defines methods for delegate of `FBNCardViewController`.\n */\n@protocol FBNCardViewControllerDelegate <NSObject>\n\n@optional\n\n/**\n Called when a view controller is about to dismiss and open a URL.\n\n @param controller The view controller that called this method.\n @param url        URL that will be open after the view controller is dismissed.\n */\n- (void)pushCardViewController:(FBNCardViewController *)controller willDismissWithOpenURL:(NSURL *)url;\n\n/**\n Called when a view controller is about to dismiss without opening any URL.\n\n @param controller The view controller that called this method.\n */\n- (void)pushCardViewControllerWillDismiss:(FBNCardViewController *)controller;\n\n@end\n\n/**\n `FBNCardViewController` is the main entry point for presenting a card that represents In-App Notification from a payload.\n This class encapsulates the display and layout of the entire push card and is intended to be presented full screen.\n \n It is invalid to initialize this class yourself, but it's intended to be used from `FBNotificationsManager`.\n*/\n@interface FBNCardViewController : UIViewController\n\n/**\n The delegate of the card view controller.\n */\n@property (nonatomic, weak) id<FBNCardViewControllerDelegate> delegate;\n\n///--------------------------------------\n#pragma mark - Unavailable Methods\n///--------------------------------------\n\n/**\n Allocates memory and initializes a new instance into it.\n\n @warning This method is unavaialble. Please use `FBNotificationsManager` to create the view controller.\n */\n+ (instancetype)new NS_UNAVAILABLE;\n\n/**\n Initializes a new instance.\n\n @warning This method is unavaialble. Please use `FBNotificationsManager` to create the view controller.\n */\n- (instancetype)init NS_UNAVAILABLE;\n\n/**\n Returns an object initiailized from data in a given unarchiver.\n\n @param decoder The unarchiver object.\n \n @warning This method is unavaialble. Please use `FBNotificationsManager` to create the view controller.\n */\n- (nullable instancetype)initWithCoder:(NSCoder *)decoder NS_UNAVAILABLE;\n\n/**\n Returns a newly initialized view controller with the nib file in the specified bundle.\n\n @param nibNameOrNil   The name of the nib file to associate with the view controller or `nil`.\n @param nibBundleOrNil he bundle in which to search for the nib file or `nil`.\n \n @warning This method is unavaialble. Please use `FBNotificationsManager` to create the view controller.\n */\n- (instancetype)initWithNibName:(nullable NSString *)nibNameOrNil bundle:(nullable NSBundle *)nibBundleOrNil NS_UNAVAILABLE;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/FBNCardViewController.m",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import \"FBNCardViewController.h\"\n#import \"FBNCardViewController_Internal.h\"\n\n#import \"FBNAssetsController.h\"\n#import \"FBNAssetContentCache.h\"\n#import \"FBNCardDisplayOptions.h\"\n#import \"FBNCardHeroViewController.h\"\n#import \"FBNCardBodyViewController.h\"\n#import \"FBNCardActionsViewController.h\"\n#import \"FBNCardDismissButton.h\"\n#import \"FBNCardViewUtilities.h\"\n#import \"FBNCardConfiguration.h\"\n#import \"FBNCardHeroConfiguration.h\"\n#import \"FBNCardBodyConfiguration.h\"\n#import \"FBNCardActionsConfiguration.h\"\n#import \"FBNCardActionConfiguration.h\"\n#import \"FBNCardAppEventsLogger.h\"\n#import \"FBNCardColor.h\"\n\n@interface FBNCardViewController () <FBNCardActionsViewControllerDelegate>\n\n@property (nullable, nonatomic, copy, readonly) NSString *campaignIdentifier;\n@property (nonatomic, strong, readonly) FBNAssetsController *assetsController;\n\n@property (nonatomic, strong, readonly) FBNCardDisplayOptions *cardDisplayOptions;\n@property (nullable, nonatomic, strong) FBNCardConfiguration *configuration;\n\n@property (nonatomic, strong) UIView *contentView;\n@property (nullable, nonatomic, strong) UIActivityIndicatorView *loadingIndicatorView;\n@property (nullable, nonatomic, strong) FBNCardHeroViewController *heroViewController;\n@property (nullable, nonatomic, strong) FBNCardBodyViewController *bodyViewController;\n@property (nullable, nonatomic, strong) FBNCardActionsViewController *actionsViewController;\n@property (nullable, nonatomic, strong) FBNCardDismissButton *dismissButton;\n\n@end\n\n@implementation FBNCardViewController\n\n///--------------------------------------\n#pragma mark - Init\n///--------------------------------------\n\n- (instancetype)initWithPushCardPayload:(FBNCardPayload *)payload\n                     campaignIdentifier:(nullable NSString *)campaignIdentifier\n                       assetsController:(FBNAssetsController *)assetsController {\n    self = [super initWithNibName:nil bundle:nil];\n    if (!self) return self;\n\n    _payload = [payload copy];\n    _cardDisplayOptions = [FBNCardDisplayOptions displayOptionsFromDictionary:payload];\n    _campaignIdentifier = [campaignIdentifier copy];\n    _assetsController = assetsController;\n\n    [self _reloadConfiguration];\n\n    self.modalPresentationStyle = UIModalPresentationOverFullScreen;\n    self.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;\n\n    return self;\n}\n\n- (void)dealloc {\n    [self.dismissButton removeTarget:nil action:nil forControlEvents:UIControlEventAllEvents];\n    [[NSNotificationCenter defaultCenter] removeObserver:self];\n}\n\n///--------------------------------------\n#pragma mark - View\n///--------------------------------------\n\n- (void)viewDidAppear:(BOOL)animated {\n    [super viewDidAppear:animated];\n\n    if ([UIApplication sharedApplication].applicationState != UIApplicationStateBackground) {\n        [self _logPushOpen];\n    } else {\n        [[NSNotificationCenter defaultCenter] addObserver:self\n                                                 selector:@selector(_applicationWillEnterForeground)\n                                                     name:UIApplicationWillEnterForegroundNotification\n                                                   object:nil];\n    }\n}\n\n///--------------------------------------\n#pragma mark - Configuration\n///--------------------------------------\n\n- (void)_reloadConfiguration {\n    if ([self.assetsController hasCachedContentForCardPayload:self.payload]) {\n        [FBNCardConfiguration loadFromDictionary:self.payload\n                              withDisplayOptions:self.cardDisplayOptions\n                                assetsController:self.assetsController\n                                      completion:^(FBNCardConfiguration * _Nullable configuration) {\n                                          dispatch_block_t reloadBlock = ^{\n                                              self.configuration = configuration;\n                                              if ([self isViewLoaded]) {\n                                                  [self _reloadSubviews];\n                                              }\n                                          };\n                                          if ([NSThread isMainThread]) {\n                                              reloadBlock();\n                                          } else {\n                                              dispatch_async(dispatch_get_main_queue(), reloadBlock);\n                                          }\n                                      }];\n    } else {\n        __weak typeof(self) wself = self;\n        [self.assetsController cacheAssetContentForCardPayload:self.payload completion:^{\n            [wself _reloadConfiguration];\n        }];\n    }\n}\n\n///--------------------------------------\n#pragma mark - Subviews\n///--------------------------------------\n\n- (void)_reloadSubviews {\n    self.view.backgroundColor = self.cardDisplayOptions.backdropColor;\n\n    self.contentView = [[UIView alloc] initWithFrame:CGRectZero];\n    self.contentView.layer.cornerRadius = self.cardDisplayOptions.cornerRadius;\n    self.contentView.clipsToBounds = YES;\n    [self.view addSubview:self.contentView];\n\n    if (self.configuration) {\n        [self.loadingIndicatorView stopAnimating];\n        [self.loadingIndicatorView removeFromSuperview];\n        self.loadingIndicatorView = nil;\n\n        [self _reloadContentViews];\n    } else {\n        FBNCardContrastColor contrastColor = FBNCardContrastColorForColor(self.view.backgroundColor);\n        UIActivityIndicatorViewStyle indicatorViewStyle = (contrastColor == FBNCardContrastColorBlack ?\n                                                           UIActivityIndicatorViewStyleGray :\n                                                           UIActivityIndicatorViewStyleWhite);\n        self.loadingIndicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:indicatorViewStyle];\n        [self.view addSubview:self.loadingIndicatorView];\n        [self.loadingIndicatorView startAnimating];\n    }\n}\n\n- (void)_reloadContentViews {\n    if (self.configuration.heroConfiguration) {\n        self.heroViewController = [[FBNCardHeroViewController alloc] initWithAssetsController:self.assetsController\n                                                                                configuration:self.configuration.heroConfiguration\n                                                                                 contentInset:self.cardDisplayOptions.contentInset];\n        [self addChildViewController:self.heroViewController];\n        [self.contentView addSubview:self.heroViewController.view];\n        [self.heroViewController didMoveToParentViewController:self];\n    }\n    if (self.configuration.bodyConfiguration) {\n        self.bodyViewController = [[FBNCardBodyViewController alloc] initWithAssetsController:self.assetsController\n                                                                                configuration:self.configuration.bodyConfiguration\n                                                                                 contentInset:self.cardDisplayOptions.contentInset];\n        [self addChildViewController:self.bodyViewController];\n        [self.contentView addSubview:self.bodyViewController.view];\n        [self.bodyViewController didMoveToParentViewController:self];\n    }\n    if (self.configuration.actionsConfiguration) {\n        self.actionsViewController = [[FBNCardActionsViewController alloc] initWithAssetsController:self.assetsController\n                                                                                      configuration:self.configuration.actionsConfiguration];\n        self.actionsViewController.delegate = self;\n        [self addChildViewController:self.actionsViewController];\n        switch (self.configuration.actionsConfiguration.style) {\n            case FBNCardActionsStyleAttached:\n                [self.contentView addSubview:self.actionsViewController.view];\n                break;\n            case FBNCardActionsStyleDetached:\n                [self.view addSubview:self.actionsViewController.view];\n                break;\n            default:break;\n        }\n        [self.actionsViewController didMoveToParentViewController:self];\n    }\n    [self _reloadDismissButton];\n}\n\n- (void)_reloadDismissButton {\n    BOOL showsDismissButton = YES;\n    for (FBNCardActionConfiguration *action in self.configuration.actionsConfiguration.actions) {\n        if (!action.actionURL) {\n            showsDismissButton = NO;\n            break;\n        }\n    }\n    if (showsDismissButton) {\n        self.dismissButton = [[FBNCardDismissButton alloc] initWithFrame:CGRectZero];\n        self.dismissButton.imageColor = self.cardDisplayOptions.dismissButtonColor;\n        [self.dismissButton addTarget:self action:@selector(_dismissButtonAction) forControlEvents:UIControlEventTouchUpInside];\n        [self.view addSubview:self.dismissButton];\n    }\n}\n\n///--------------------------------------\n#pragma mark - UIViewController\n///--------------------------------------\n\n- (void)loadView {\n    [super loadView];\n\n    self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;\n}\n\n- (void)viewDidLoad {\n    [super viewDidLoad];\n\n    [self _reloadSubviews];\n}\n\n- (void)viewWillLayoutSubviews {\n    [super viewWillLayoutSubviews];\n\n    CGRect bounds = self.view.bounds;\n    if (self.cardDisplayOptions.size == FBNCardSizeLarge) {\n        bounds.size.height -= self.topLayoutGuide.length;\n        bounds.origin.y += self.topLayoutGuide.length;\n    }\n\n    CGSize availableSize = FBNCardLayoutSizeThatFits(self.cardDisplayOptions.size, bounds.size);\n\n    const CGSize bodySize = CGSizeMake(availableSize.width,\n                                       [self.bodyViewController contentSizeThatFitsParentContainerSize:availableSize].height);\n    availableSize.height -= bodySize.height;\n\n    const CGSize actionsSize = CGSizeMake(availableSize.width,\n                                          [self.actionsViewController contentSizeThatFitsParentContainerSize:availableSize].height);\n    availableSize.height -= actionsSize.height;\n\n    CGSize heroSize = availableSize;\n    if (self.configuration.heroConfiguration.height == FBNCardHeroHeightUnspecified) {\n        heroSize.height = [self.heroViewController contentSizeThatFitsParentContainerSize:availableSize].height;\n    } else {\n        heroSize.height *= self.configuration.heroConfiguration.height;\n    }\n    heroSize = FBNSizeAdjustToScreenScale(heroSize, NSRoundUp);\n\n    CGSize contentSize = CGSizeMake(availableSize.width, bodySize.height + heroSize.height);\n\n    const CGRect heroFrame = FBNRectMakeWithOriginSize(CGPointZero, heroSize);\n    const CGRect bodyFrame = FBNRectMakeWithOriginSize(CGPointMake(CGRectGetMinX(heroFrame), CGRectGetMaxY(heroFrame)), bodySize);\n    CGRect actionsFrame = FBNRectMakeWithOriginSize(CGPointZero, actionsSize);\n    CGRect contentFrame = CGRectZero;\n    switch (self.configuration.actionsConfiguration.style) {\n        case FBNCardActionsStyleAttached: {\n            actionsFrame.origin = CGPointMake(CGRectGetMinX(heroFrame), CGRectGetMaxY(bodyFrame));\n            contentSize.height += actionsSize.height;\n            contentFrame = FBNRectMakeWithSizeCenteredInRect(contentSize, bounds);\n        }\n            break;\n        case FBNCardActionsStyleDetached: {\n            CGPoint contentOrigin = FBNRectMakeWithSizeCenteredInRect(CGSizeMake(contentSize.width, contentSize.height + actionsSize.height),\n                                                                     bounds).origin;\n            contentFrame = FBNRectMakeWithOriginSize(contentOrigin, contentSize);\n            actionsFrame.origin = CGPointMake(CGRectGetMinX(contentFrame), CGRectGetMaxY(contentFrame));\n        }\n            break;\n        default:break;\n    }\n    CGRect dismissButtonFrame = FBNRectMakeWithOriginSize(CGPointZero, [self.dismissButton sizeThatFits:bounds.size]);\n    dismissButtonFrame.origin.x = CGRectGetMaxX(contentFrame) - CGRectGetWidth(dismissButtonFrame) - self.cardDisplayOptions.contentInset;\n    dismissButtonFrame.origin.y = CGRectGetMinY(contentFrame) + self.cardDisplayOptions.contentInset;\n\n    self.contentView.frame = contentFrame;\n    self.heroViewController.view.frame = heroFrame;\n    self.bodyViewController.view.frame = bodyFrame;\n    self.actionsViewController.view.frame = actionsFrame;\n    self.dismissButton.frame = dismissButtonFrame;\n    self.loadingIndicatorView.center = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds));\n}\n\n///--------------------------------------\n#pragma mark - Application State Changes\n///--------------------------------------\n\n- (void)_applicationWillEnterForeground {\n    [self _logPushOpen];\n    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationWillEnterForegroundNotification object:nil];\n}\n\n///--------------------------------------\n#pragma mark - Logging Events\n///--------------------------------------\n\n- (void)_logPushOpen {\n    [FBNCardAppEventsLogger logCardOpenWithCampaignIdentifier:self.campaignIdentifier];\n}\n\n///--------------------------------------\n#pragma mark - Dismiss\n///--------------------------------------\n\n- (void)_dismissFromButtonAction:(FBNCardButtonAction)action withOpenURL:(nullable NSURL *)url {\n    [FBNCardAppEventsLogger logButtonAction:action forCardWithCampaignIdentifier:self.campaignIdentifier];\n\n    id<FBNCardViewControllerDelegate> delegate = self.delegate;\n    if (url) {\n        if ([delegate respondsToSelector:@selector(pushCardViewController:willDismissWithOpenURL:)]) {\n            [delegate pushCardViewController:self willDismissWithOpenURL:url];\n        }\n        [[UIApplication sharedApplication] openURL:url];\n    } else {\n        if ([delegate respondsToSelector:@selector(pushCardViewControllerWillDismiss:)]) {\n            [delegate pushCardViewControllerWillDismiss:self];\n        }\n    }\n    [self.assetsController clearAssetContentCacheForCardPayload:self.payload];\n\n    [self dismissViewControllerAnimated:YES completion:nil];\n}\n\n///--------------------------------------\n#pragma mark - FBNCardActionsViewControllerDelegate\n///--------------------------------------\n\n- (void)actionsViewController:(FBNCardActionsViewController *)viewController\n       didPerformButtonAction:(FBNCardButtonAction)action\n                  withOpenURL:(nullable NSURL *)url {\n    [self _dismissFromButtonAction:action withOpenURL:url];\n}\n\n///--------------------------------------\n#pragma mark - Dismiss Button\n///--------------------------------------\n\n- (void)_dismissButtonAction {\n    [self _dismissFromButtonAction:FBNCardButtonActionDismiss withOpenURL:nil];\n}\n\n@end\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/FBNConstants.h",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import <Foundation/Foundation.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\n/**\n Error domain used for all of the errors in FBNotifications framework.\n */\nextern NSString *FBNotificationsErrorDomain;\n\ntypedef NS_ENUM(NSUInteger, FBNotificationsErrorCode) {\n    /**\n     Error code indicating that notification payload is invalid.\n     */\n    FBNotificationsErrorInvalidPayload = 1,\n};\n\n/**\n String that represents a highest supported card format by the framework.\n */\nextern NSString *FBNotificationsCardFormatVersionString;\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/FBNConstants.m",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import \"FBNConstants.h\"\n\nNSString *FBNotificationsErrorDomain = @\"FBNotificationsErrorDomain\";\n\nNSString *FBNotificationsCardFormatVersionString = @\"1.0\";\n\n\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/FBNotifications.h",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import <FBNotifications/FBNotificationsManager.h>\n#import <FBNotifications/FBNConstants.h>\n#import <FBNotifications/FBNCardViewController.h>\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/FBNotificationsManager.h",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import <Foundation/Foundation.h>\n#import <UIKit/UIKit.h>\n\n#import <FBNotifications/FBNCardViewController.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\n/**\n Block type used as a completion for content preparation from remote notification payload.\n\n @param payload Payload for which content was fetched.\n @param error   An instance of `NSError` that represents the error if it happened, otherwise - `nil`.\n */\ntypedef void(^FBNCardContentPreparationCompletion)(NSDictionary *_Nullable payload, NSError *_Nullable error);\n\n/**\n Block type used as a completion for card view controller presentation from remote notification payload.\n\n @param viewController A card view controller that was presented.\n @param error          An instance of `NSError` that represents the error if it happened, otherwise - `nil`.\n */\ntypedef void(^FBNCardPresentationCompletion)(FBNCardViewController *_Nullable viewController, NSError *_Nullable error);\n\n/**\n Block type used as a completion for local notification creation from remote notification payload.\n\n @param notification Newly created notification if the operation succeded, otherwise - `nil`.\n @param error        An instance of `NSError` that represents the error if it happened, otherwise - `nil`.\n */\ntypedef void(^FBNLocalNotificationCreationCompletion)(UILocalNotification *_Nullable notification, NSError *_Nullable error);\n\n\n/**\n `FBNotificationsManager` is a primary interface for interacting with FBNotifications.framework.\n */\n@interface FBNotificationsManager : NSObject\n\n///--------------------------------------\n#pragma mark - Creating a Card Manager\n///--------------------------------------\n\n/**\n Returns a shared notifications manager for the current process.\n\n @return Shared notifications manager.\n */\n+ (instancetype)sharedManager;\n\n/**\n Initializes a new instance.\n\n @warning This method is unavaialble. Please use `sharedManager`.\n */\n- (instancetype)init NS_UNAVAILABLE;\n\n/**\n Allocates memory and initializes a new instance into it.\n\n @warning This method is unavaialble. Please use `sharedManager`.\n */\n+ (instancetype)new NS_UNAVAILABLE;\n\n///--------------------------------------\n#pragma mark - Present from Remote Notification\n///--------------------------------------\n\n/**\n Fetch push card content from a remote notification payload and cache it for later use.\n If the payload doesn't contain a push card - completion block is going to be called with an error.\n\n @param payload    Remote notification payload.\n @param completion Completion block that will be called when content fetch is done or there was an error.\n */\n- (void)preparePushCardContentForRemoteNotificationPayload:(NSDictionary *)payload\n                                                completion:(nullable FBNCardContentPreparationCompletion)completion;\n\n/**\n Presents a push card from a remote notification if it contains one.\n If content is not fully available for a given push card, a loading indicator will be shown instead of a card.\n\n @param payload        Remote notification payload.\n @param viewController View controller to present a push card from (optional).\n @param completion     Optional completion block that will be called when a card is visible or there was an error.\n */\n- (void)presentPushCardForRemoteNotificationPayload:(NSDictionary *)payload\n                                 fromViewController:(nullable UIViewController *)viewController\n                                         completion:(nullable FBNCardPresentationCompletion)completion;\n\n/**\n Returns a `BOOL` value that designated whether a push notification payload is a valid push card payload.\n\n @param payload Push notification payload.\n\n @return `YES` if payload is a valid push card payload, otherwise - `NO`.\n */\n- (BOOL)canPresentPushCardFromRemoteNotificationPayload:(nullable NSDictionary *)payload;\n\n///--------------------------------------\n#pragma mark - Present from Local Notification\n///--------------------------------------\n\n/**\n Creates a local notification from a remote notification payload (if present).\n The completion will be called when all content is cached for the in app notification or if there was an error.\n\n @param payload Remote notification payload, usually acquired via `application:didReceiveRemoteNotification:`.\n @param completion A block that will be called after the content is ready for presentation or if there was an error.\n */\n- (void)createLocalNotificationFromRemoteNotificationPayload:(NSDictionary *)payload\n                                                  completion:(FBNLocalNotificationCreationCompletion)completion;\n\n/**\n Presents a push card from a local notification if it contains one.\n\n @param notification   A local notification.\n @param viewController View controller to present a push card from (optional).\n @param completion     Optional completion block that will be called when a card is visible or there was an error.\n */\n- (void)presentPushCardForLocalNotification:(UILocalNotification *)notification\n                         fromViewController:(nullable UIViewController *)viewController\n                                 completion:(nullable FBNCardPresentationCompletion)completion;\n\n/**\n Returns a boolean value that indicates whether a push card can be presented from a local notification.\n\n @param notification Local notification to check.\n\n @return `YES` if push card can be presented, otherwise - `NO`.\n */\n- (BOOL)canPresentPushCardFromLocalNotification:(UILocalNotification *)notification;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/FBNotificationsManager.m",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import \"FBNotificationsManager.h\"\n\n#import \"FBNConstants.h\"\n#import \"FBNCardError.h\"\n#import \"FBNAssetContentCache.h\"\n#import \"FBNCardViewUtilities.h\"\n#import \"FBNCardViewController_Internal.h\"\n#import \"FBNCardPayload.h\"\n#import \"FBNCardAppEventsLogger.h\"\n#import \"FBNAssetsController.h\"\n#import \"FBNColorAsset.h\"\n#import \"FBNColorAssetController.h\"\n#import \"FBNImageAsset.h\"\n#import \"FBNImageAssetController.h\"\n#import \"FBNGIFAsset.h\"\n#import \"FBNGIFAssetController.h\"\n\n@interface FBNotificationsManager ()\n\n@property (nonnull, nonatomic, strong, readonly) FBNAssetsController *assetsController;\n\n@property (nullable, nonatomic, weak) FBNCardViewController *currentCardViewController;\n\n@end\n\n@implementation FBNotificationsManager\n\n///--------------------------------------\n#pragma mark - Creating a Card Manager\n///--------------------------------------\n\n- (instancetype)init {\n    self = [super init];\n    if (!self) return self;\n\n    _assetsController = [self _defaultConfigurationAssetsController];\n\n    return self;\n}\n\n+ (instancetype)sharedManager {\n    static FBNotificationsManager *manager;\n    static dispatch_once_t onceToken;\n    dispatch_once(&onceToken, ^{\n        manager = [[self alloc] init];\n    });\n    return manager;\n}\n\n///--------------------------------------\n#pragma mark - Assets Controller\n///--------------------------------------\n\n- (FBNAssetsController *)_defaultConfigurationAssetsController {\n    FBNAssetsController *controller = [[FBNAssetsController alloc] init];\n    [controller registerAssetController:[[FBNColorAssetController alloc] init] forAssetType:FBNColorAssetType];\n    [controller registerAssetController:[[FBNImageAssetController alloc] init] forAssetType:FBNImageAssetType];\n    [controller registerAssetController:[[FBNGIFAssetController alloc] init] forAssetType:FBNGIFAssetType];\n    return controller;\n}\n\n///--------------------------------------\n#pragma mark - Present from Remote Notification\n///--------------------------------------\n\n- (void)preparePushCardContentForRemoteNotificationPayload:(NSDictionary *)payload\n                                                completion:(nullable FBNCardContentPreparationCompletion)completion {\n    if (![self canPresentPushCardFromRemoteNotificationPayload:payload]) {\n        if (completion) {\n            completion(nil, [FBNCardError invalidRemoteNotificationPayloadError]);\n        }\n        return;\n    }\n    [self.assetsController cacheAssetContentForCardPayload:payload completion:^{\n        if (completion) {\n            completion(payload, nil);\n        }\n    }];\n}\n\n- (void)presentPushCardForRemoteNotificationPayload:(NSDictionary *)payload\n                                 fromViewController:(nullable UIViewController *)viewController\n                                         completion:(nullable FBNCardPresentationCompletion)completion {\n    if (![self canPresentPushCardFromRemoteNotificationPayload:payload]) {\n        if (completion) {\n            completion(nil, [FBNCardError invalidRemoteNotificationPayloadError]);\n        }\n        return;\n    }\n\n    FBNCardPayload *cardPayload = FBNCardPayloadFromRemoteNotificationPayload(payload);\n    NSString *campaignIdentifier = [FBNCardAppEventsLogger campaignIdentifierFromRemoteNotificationPayload:payload];\n\n    FBNCardViewController *oldCardViewController = self.currentCardViewController;\n    // Has the same payload and is visible on screen, meaning that we don't need to re-present it.\n    if ([oldCardViewController.payload isEqual:cardPayload] &&\n        oldCardViewController.presentingViewController != nil &&\n        !oldCardViewController.isBeingDismissed) {\n        if (completion) {\n            completion(oldCardViewController, nil);\n        }\n        return;\n    }\n\n    // Dismiss the old one.\n    [oldCardViewController dismissViewControllerAnimated:NO completion:nil];\n\n    // Create and present the new one.\n    FBNCardViewController *cardViewController = [[FBNCardViewController alloc] initWithPushCardPayload:cardPayload\n                                                                                    campaignIdentifier:campaignIdentifier\n                                                                                      assetsController:self.assetsController];\n    viewController = viewController ?: FBNApplicationTopMostViewController();\n    BOOL animated = (oldCardViewController == nil);\n    [viewController presentViewController:cardViewController animated:animated completion:^{\n        if (completion) {\n            completion(cardViewController, nil);\n        }\n    }];\n    // Save the new one into a weak property.\n    self.currentCardViewController = cardViewController;\n}\n\n- (BOOL)canPresentPushCardFromRemoteNotificationPayload:(nullable NSDictionary *)payload {\n    FBNCardPayload *cardPayload = FBNCardPayloadFromRemoteNotificationPayload(payload);\n    return (cardPayload != nil && FBNCardPayloadIsCompatibleWithCurrentVersion(cardPayload, FBNotificationsCardFormatVersionString));\n}\n\n///--------------------------------------\n#pragma mark - Present via Local Notification\n///--------------------------------------\n\n- (void)createLocalNotificationFromRemoteNotificationPayload:(NSDictionary *)payload\n                                                  completion:(FBNLocalNotificationCreationCompletion)completion {\n    if (![self canPresentPushCardFromRemoteNotificationPayload:payload]) {\n        NSError *error = [FBNCardError invalidRemoteNotificationPayloadError];\n        completion(nil, error);\n        return;\n    }\n\n    FBNCardPayload *cardPayload = FBNCardPayloadFromRemoteNotificationPayload(payload);\n    [self.assetsController cacheAssetContentForCardPayload:cardPayload completion:^{\n        UILocalNotification *notification = [self _localNotificationFromPayload:cardPayload];\n        notification.userInfo = payload;\n        completion(notification, nil);\n    }];\n}\n\n- (void)presentPushCardForLocalNotification:(UILocalNotification *)notification\n                         fromViewController:(nullable UIViewController *)viewController\n                                 completion:(nullable FBNCardPresentationCompletion)completion {\n    [[UIApplication sharedApplication] cancelLocalNotification:notification];\n    [self presentPushCardForRemoteNotificationPayload:notification.userInfo\n                                   fromViewController:viewController\n                                           completion:completion];\n}\n\n- (BOOL)canPresentPushCardFromLocalNotification:(UILocalNotification *)notification {\n    return [self canPresentPushCardFromRemoteNotificationPayload:notification.userInfo];\n}\n\n- (nullable UILocalNotification *)_localNotificationFromPayload:(NSDictionary<NSString *, id> *)payload {\n    UILocalNotification *notification = [[UILocalNotification alloc] init];\n    notification.alertTitle = payload[@\"alert\"][@\"title\"];\n    notification.alertBody = payload[@\"alert\"][@\"body\"];\n    return notification;\n}\n\n@end\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/AppEvents/FBNCardAppEventsLogger.h",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import <Foundation/Foundation.h>\n\n#import \"FBNCardButtonAction.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface FBNCardAppEventsLogger : NSObject\n\n+ (nullable NSString *)campaignIdentifierFromRemoteNotificationPayload:(NSDictionary *)payload;\n\n+ (void)logCardOpenWithCampaignIdentifier:(nullable NSString *)identifier;\n+ (void)logButtonAction:(FBNCardButtonAction)action forCardWithCampaignIdentifier:(nullable NSString *)identifier;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/AppEvents/FBNCardAppEventsLogger.m",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import \"FBNCardAppEventsLogger.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface FBSDKAppEvents : NSObject\n\n+ (void)logEvent:(NSString *)eventName parameters:(nullable NSDictionary<NSString *, NSString *> *)parameters;\n\n@end\n\n@implementation FBNCardAppEventsLogger\n\n///--------------------------------------\n#pragma mark - Public\n///--------------------------------------\n\n+ (nullable NSString *)campaignIdentifierFromRemoteNotificationPayload:(NSDictionary *)payload {\n    return payload[@\"fb_push_payload\"][@\"campaign\"];\n}\n\n+ (void)logCardOpenWithCampaignIdentifier:(nullable NSString *)identifier {\n    if (!identifier) {\n        return;\n    }\n    [self _logAppEventWithName:@\"fb_mobile_push_opened\" campaignIdentifier:identifier];\n}\n\n+ (void)logButtonAction:(FBNCardButtonAction)action forCardWithCampaignIdentifier:(nullable NSString *)identifier {\n    NSString *eventName = [self _appEventNameForButtonAction:action];\n    [self _logAppEventWithName:eventName campaignIdentifier:identifier];\n}\n\n///--------------------------------------\n#pragma mark - Private\n///--------------------------------------\n\n+ (void)_logAppEventWithName:(NSString *)name campaignIdentifier:(NSString *)identifier {\n    if (!identifier) {\n        return;\n    }\n\n    Class loggerClass = NSClassFromString(@\"FBSDKAppEvents\");\n    if (loggerClass && [loggerClass respondsToSelector:@selector(logEvent:parameters:)]) {\n        [loggerClass logEvent:name\n                   parameters:@{ @\"fb_push_campaign\" : identifier }];\n    }\n}\n\n+ (nullable NSString *)_appEventNameForButtonAction:(FBNCardButtonAction)action {\n    switch (action) {\n        case FBNCardButtonActionPrimary:\n            return @\"fb_mobile_push_card_action_primary\";\n        case FBNCardButtonActionSecondary:\n            return @\"fb_mobile_push_card_action_secondary\";\n        case FBNCardButtonActionDismiss:\n            return @\"fb_mobile_push_card_action_dismiss\";\n        default:break;\n    }\n    return nil;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Asset/Cache/FBNAssetContentCache.h",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import <Foundation/Foundation.h>\n\n#import \"FBNCardPayload.h\"\n\n@class FBNAssetsController;\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface FBNAssetContentCache : NSObject\n\n- (void)cacheContentForURLs:(NSSet<NSURL *> *)urls completion:(dispatch_block_t)completion;\n- (void)clearContentForURLs:(nullable NSSet<NSURL *> *)urls;\n\n- (nullable NSData *)cachedDataForContentURL:(NSURL *)url;\n\n- (BOOL)hasCachedContentForURLs:(nullable NSSet<NSURL *> *)urls;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Asset/Cache/FBNAssetContentCache.m",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import \"FBNAssetContentCache.h\"\n\n#import <UIKit/UIKit.h>\n\n#import \"FBNAssetsController.h\"\n#import \"FBNCardHash.h\"\n#import \"FBNAssetContentCacheOperation.h\"\n\n@interface FBNAssetContentCache () <NSURLSessionDownloadDelegate>\n\n@property (nonatomic, strong, readonly) NSURLSession *session;\n\n@property (nonatomic, copy, readonly) NSMutableDictionary<NSString *, NSMutableSet<FBNAssetContentCacheOperation *> *> *cacheOperations;\n@property (nonatomic, copy) NSMutableSet<NSString *> *cachedKeys;\n@property (nonatomic, strong, readonly) dispatch_queue_t synchronizationQueue;\n\n@property (nonatomic, assign) UIBackgroundTaskIdentifier currentBackgroundTask;\n\n@end\n\n@implementation FBNAssetContentCache\n\n///--------------------------------------\n#pragma mark - Init\n///--------------------------------------\n\n- (instancetype)init {\n    self = [super init];\n    if (!self) return self;\n\n    NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];\n    _session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];\n\n    _cacheOperations = [NSMutableDictionary dictionary];\n    _synchronizationQueue = dispatch_queue_create(\"com.facebook.cards.cache.sync\", DISPATCH_QUEUE_SERIAL);\n\n    _currentBackgroundTask = UIBackgroundTaskInvalid;\n\n    return self;\n}\n\n///--------------------------------------\n#pragma mark - Cache\n///--------------------------------------\n\n- (void)cacheContentForURLs:(NSSet<NSURL *> *)urls completion:(dispatch_block_t)completion {\n    [self _beginBackgroundTask];\n\n    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{\n        FBNAssetContentCacheOperation *operation = [[FBNAssetContentCacheOperation alloc] initWithContentURLs:urls completion:completion];\n        [self _startDownloadTasksForCacheOperation:operation];\n    });\n}\n\n- (void)clearContentForURLs:(nullable NSSet<NSURL *> *)urls {\n    if (!urls.count) {\n        return;\n    }\n\n    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{\n        for (NSURL *url in urls) {\n            NSString *cacheKey = [self _cacheKeyForContentURL:url];\n            [[NSFileManager defaultManager] removeItemAtPath:[self _cacheFilePathForContentWithCacheKey:cacheKey] error:nil];\n            dispatch_async(_synchronizationQueue, ^{\n                [self.cachedKeys removeObject:cacheKey];\n            });\n        }\n    });\n}\n\n///--------------------------------------\n#pragma mark - Getters\n///--------------------------------------\n\n- (NSData *)cachedDataForContentURL:(NSURL *)url {\n    NSString *cacheKey = [self _cacheKeyForContentURL:url];\n    return [NSData dataWithContentsOfFile:[self _cacheFilePathForContentWithCacheKey:cacheKey]\n                                  options:NSDataReadingMappedIfSafe\n                                    error:nil];\n}\n\n- (BOOL)hasCachedContentForURLs:(nullable NSSet<NSURL *> *)urls {\n    for (NSURL *url in urls) {\n        NSString *cacheKey = [self _cacheKeyForContentURL:url];\n        if (![self _hasCachedDataForContentWithCacheKey:cacheKey]) {\n            return NO;\n        }\n    }\n    return YES;\n}\n\n- (BOOL)_hasCachedDataForContentWithCacheKey:(NSString *)key {\n    return [self.cachedKeys containsObject:key];\n}\n\n- (NSString *)_cacheFilesFolderPath {\n    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);\n    return [paths.firstObject stringByAppendingPathComponent:@\"FBNotifications\"];\n}\n\n- (NSString *)_cacheFilePathForContentWithCacheKey:(NSString *)key {\n    return [[self _cacheFilesFolderPath] stringByAppendingPathComponent:key];\n}\n\n///--------------------------------------\n#pragma mark - Private\n///--------------------------------------\n\n///--------------------------------------\n#pragma mark - Accessors\n///--------------------------------------\n\n- (NSMutableSet *)cachedKeys {\n    if (!_cachedKeys) {\n        NSArray *existingFiles = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:[self _cacheFilesFolderPath] error:nil];\n        _cachedKeys = [NSMutableSet setWithArray:existingFiles];\n    }\n    return _cachedKeys;\n}\n\n///--------------------------------------\n#pragma mark - Hash\n///--------------------------------------\n\n- (NSString *)_cacheKeyForContentURL:(NSURL *)url {\n    return FBMD5HashFromString(url.absoluteString);\n}\n\n///--------------------------------------\n#pragma mark - Content\n///--------------------------------------\n\n- (void)_startDownloadTasksForCacheOperation:(FBNAssetContentCacheOperation *)operation {\n    dispatch_async(_synchronizationQueue, ^{\n        NSUInteger scheduledCount = 0;\n        NSSet *cacheURLs = [operation.pendingCacheURLs copy];\n        for (NSURL *url in cacheURLs) {\n            NSString *cacheKey = [self _cacheKeyForContentURL:url];\n            if ([self _hasCachedDataForContentWithCacheKey:cacheKey]) {\n                [operation.pendingCacheURLs removeObject:url];\n                continue;\n            }\n\n            NSMutableSet<FBNAssetContentCacheOperation *> *cacheOperations = self.cacheOperations[cacheKey];\n            if (cacheOperations) {\n                [cacheOperations addObject:operation];\n            } else {\n                cacheOperations = [NSMutableSet setWithObject:operation];\n                self.cacheOperations[cacheKey] = cacheOperations;\n\n                [[self.session downloadTaskWithURL:url] resume];\n            }\n\n            scheduledCount++;\n        }\n\n        BOOL endBackgroundTask = (self.cacheOperations.count == 0);\n        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{\n            if (scheduledCount == 0 && operation.completion) {\n                dispatch_async(dispatch_get_main_queue(), operation.completion);\n            }\n\n            if (endBackgroundTask) {\n                [self _endBackgroundTask];\n            }\n        });\n    });\n}\n\n- (void)_didDownloadContentWithCacheKey:(NSString *)cacheKey toURL:(NSURL *)url {\n    NSString *cacheFolderPath = [self _cacheFilesFolderPath];\n    NSFileManager *fileManager = [NSFileManager defaultManager];\n    if (![fileManager fileExistsAtPath:cacheFolderPath]) {\n        [fileManager createDirectoryAtPath:cacheFolderPath withIntermediateDirectories:YES attributes:nil error:nil];\n    }\n\n    NSString *targetPath = [self _cacheFilePathForContentWithCacheKey:cacheKey];\n    [fileManager moveItemAtPath:url.path toPath:targetPath error:nil]; // TODO: Track Error\n}\n\n- (void)_didFinishDownloadTaskWithCacheKey:(NSString *)cacheKey fromURL:(NSURL *)url {\n    dispatch_async(_synchronizationQueue, ^{\n        [self.cachedKeys addObject:cacheKey];\n\n        NSSet<FBNAssetContentCacheOperation *> *operations = self.cacheOperations[cacheKey];\n        NSMutableSet<FBNAssetContentCacheOperation *> *finishedOperations = [NSMutableSet set];\n        for (FBNAssetContentCacheOperation *operation in operations) {\n            [operation.pendingCacheURLs removeObject:url];\n            if (operation.pendingCacheURLs.count == 0) {\n                [finishedOperations addObject:operation];\n            }\n        }\n        [self.cacheOperations removeObjectForKey:cacheKey];\n\n        BOOL endBackgroundTask = (self.cacheOperations.count == 0);\n        dispatch_async(dispatch_get_main_queue(), ^{\n            for (FBNAssetContentCacheOperation *operation in finishedOperations) {\n                if (operation.completion) {\n                    operation.completion();\n                }\n            }\n            if (endBackgroundTask) {\n                [self _endBackgroundTask];\n            }\n        });\n    });\n}\n\n///--------------------------------------\n#pragma mark - NSURLSessionDownloadDelegate\n///--------------------------------------\n\n- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location {\n    NSString *cacheKey = [self _cacheKeyForContentURL:downloadTask.originalRequest.URL];\n    [self _didDownloadContentWithCacheKey:cacheKey toURL:location];\n}\n\n- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {\n    NSURL *url = task.originalRequest.URL;\n    NSString *cacheKey = [self _cacheKeyForContentURL:url];\n    [self _didFinishDownloadTaskWithCacheKey:cacheKey fromURL:url];\n}\n\n///--------------------------------------\n#pragma mark - Background Task\n///--------------------------------------\n\n- (void)_beginBackgroundTask {\n    if (self.currentBackgroundTask == UIBackgroundTaskInvalid) {\n        self.currentBackgroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{\n            [self _endBackgroundTask];\n        }];\n    }\n}\n\n- (void)_endBackgroundTask {\n    if (self.currentBackgroundTask != UIBackgroundTaskInvalid) {\n        UIBackgroundTaskIdentifier task = self.currentBackgroundTask;\n        self.currentBackgroundTask = UIBackgroundTaskInvalid;\n        [[UIApplication sharedApplication] endBackgroundTask:task];\n    }\n}\n\n@end\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Asset/Cache/FBNAssetContentCacheOperation.h",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import <Foundation/Foundation.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\ntypedef NSString FBNAssetContentCacheOperationId;\n\n@interface FBNAssetContentCacheOperation : NSObject\n\n@property (nonatomic, copy, readonly) NSMutableSet<NSURL *> *pendingCacheURLs;\n@property (nonatomic, copy, readonly) dispatch_block_t completion;\n\n- (instancetype)initWithContentURLs:(NSSet<NSURL *> *)urls completion:(dispatch_block_t)completion;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Asset/Cache/FBNAssetContentCacheOperation.m",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import \"FBNAssetContentCacheOperation.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation FBNAssetContentCacheOperation\n\n- (instancetype)initWithContentURLs:(NSSet<NSURL *> *)urls completion:(dispatch_block_t)completion {\n    self = [super init];\n    if (!self) return self;\n\n    _pendingCacheURLs = [urls mutableCopy];\n    _completion = completion;\n\n    return self;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Asset/Color/FBNColorAsset.h",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import <UIKit/UIKit.h>\n\n#import \"FBNAsset.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\nextern NSString *const FBNColorAssetType;\n\n@interface FBNColorAsset : NSObject <FBNAsset>\n\n@property (nonatomic, strong, readonly) UIColor *color;\n\n- (instancetype)initWithRGBAHex:(NSString *)hexColor;\n- (instancetype)init NS_UNAVAILABLE;\n+ (instancetype)new NS_UNAVAILABLE;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Asset/Color/FBNColorAsset.m",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import \"FBNColorAsset.h\"\n\n#import \"FBNCardColor.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\nNSString *const FBNColorAssetType = @\"Color\";\n\n@implementation FBNColorAsset\n\n///--------------------------------------\n#pragma mark - Init\n///--------------------------------------\n\n- (instancetype)initWithRGBAHex:(NSString *)hexColor {\n    self = [super init];\n    if (!self) return self;\n\n    _color = FBNCardColorFromRGBAHex(hexColor);\n\n    return self;\n}\n\n///--------------------------------------\n#pragma mark - FBNColorAsset\n///--------------------------------------\n\n- (NSString *)type {\n    return FBNColorAssetType;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Asset/Color/FBNColorAssetController.h",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import <Foundation/Foundation.h>\n\n#import \"FBNAssetController.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface FBNColorAssetController : NSObject <FBNAssetController>\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Asset/Color/FBNColorAssetController.m",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import \"FBNColorAssetController.h\"\n\n#import <UIKit/UIKit.h>\n\n#import \"FBNColorAsset.h\"\n#import \"FBNColorAssetViewController.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation FBNColorAssetController\n\n///--------------------------------------\n#pragma mark - FBNAssetController\n///--------------------------------------\n\n- (void)loadAssetFromDictionary:(NSDictionary *)dictionary\n                   contentCache:(nonnull FBNAssetContentCache *)cache\n                     completion:(void (^)(id <FBNAsset> _Nullable asset))completion\n{\n    if (![self isValidAssetDictionary:dictionary]) {\n        return;\n    }\n\n    NSString *rgbaHex = dictionary[@\"rgbaHex\"];\n    completion([[FBNColorAsset alloc] initWithRGBAHex:rgbaHex]);\n}\n\n- (nullable NSSet<NSURL *> *)cacheURLsForAssetDictionary:(NSDictionary *)dictionary {\n    return nil;\n}\n\n- (BOOL)isValidAssetDictionary:(NSDictionary *)dictionary {\n    if (![dictionary isKindOfClass:[NSDictionary class]] ||\n        ![dictionary[@\"_type\"] isEqualToString:@\"Color\"] ||\n        ![dictionary[@\"rgbaHex\"] isKindOfClass:[NSString class]]) {\n        return NO;\n    }\n    return YES;\n}\n\n- (nullable UIViewController<FBNContentSizeProvider> *)viewControllerForAsset:(id<FBNAsset>)asset {\n    FBNColorAsset *colorAsset = (FBNColorAsset *)asset;\n    return [[FBNColorAssetViewController alloc] initWithAsset:colorAsset];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Asset/Color/FBNColorAssetViewController.h",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import <UIKit/UIKit.h>\n\n#import \"FBNContentSizeProvider.h\"\n\n@class FBNColorAsset;\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface FBNColorAssetViewController : UIViewController <FBNContentSizeProvider>\n\n- (instancetype)initWithAsset:(FBNColorAsset *)asset;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Asset/Color/FBNColorAssetViewController.m",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import \"FBNColorAssetViewController.h\"\n\n#import \"FBNColorAsset.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface FBNColorAssetViewController ()\n\n@property (nonatomic, strong, readonly) FBNColorAsset *asset;\n\n@end\n\n@implementation FBNColorAssetViewController\n\n///--------------------------------------\n#pragma mark - Init\n///--------------------------------------\n\n- (instancetype)initWithAsset:(FBNColorAsset *)asset {\n    self = [super initWithNibName:nil bundle:nil];\n    if (!self) return self;\n\n    _asset = asset;\n\n    return self;\n}\n\n///--------------------------------------\n#pragma mark - View\n///--------------------------------------\n\n- (void)loadView {\n    [super loadView];\n    self.view.backgroundColor = self.asset.color;\n}\n\n///--------------------------------------\n#pragma mark - FBNContentSizeProvider\n///--------------------------------------\n\n- (CGSize)contentSizeThatFitsParentContainerSize:(CGSize)fitSize {\n    return CGSizeZero;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Asset/Common/FBNAsset.h",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import <Foundation/Foundation.h>\n#import <UIKit/UIKit.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\n@protocol FBNAsset <NSObject>\n\n@property (nonatomic, copy, readonly) NSString *type;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Asset/Common/FBNAssetController.h",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import <UIKit/UIKit.h>\n\n#import \"FBNContentSizeProvider.h\"\n\n@protocol FBNAsset;\n@class FBNAssetContentCache;\n\nNS_ASSUME_NONNULL_BEGIN\n\n@protocol FBNAssetController <NSObject>\n\n- (void)loadAssetFromDictionary:(NSDictionary *)dictionary\n                   contentCache:(nonnull FBNAssetContentCache *)cache\n                     completion:(void (^)(id <FBNAsset> _Nullable asset))completion;\n\n- (nullable NSSet<NSURL *> *)cacheURLsForAssetDictionary:(NSDictionary *)dictionary;\n- (BOOL)isValidAssetDictionary:(NSDictionary *)dictionary;\n\n- (nullable UIViewController<FBNContentSizeProvider> *)viewControllerForAsset:(id<FBNAsset>)asset;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Asset/FBNAssetsController.h",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import <UIKit/UIKit.h>\n\n#import \"FBNCardPayload.h\"\n\n@protocol FBNAsset;\n@protocol FBNAssetController;\n@class FBNAssetContentCache;\n@protocol FBNContentSizeProvider;\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface FBNAssetsController : NSObject\n\n///--------------------------------------\n#pragma mark - Asset Controllers\n///--------------------------------------\n\n- (void)registerAssetController:(id<FBNAssetController>)controller forAssetType:(NSString *)type;\n- (nullable id<FBNAssetController>)assetControllerForAssetType:(NSString *)type;\n\n///--------------------------------------\n#pragma mark - Assets\n///--------------------------------------\n\n- (void)loadAssetFromDictionary:(NSDictionary *)dictionary completion:(nonnull void (^)(id<FBNAsset> _Nullable asset))completion;\n- (nullable UIViewController <FBNContentSizeProvider> *)viewControllerForAsset:(id<FBNAsset>)asset;\n\n///--------------------------------------\n#pragma mark - Cache\n///--------------------------------------\n\n- (void)cacheAssetContentForCardPayload:(FBNCardPayload *)payload completion:(dispatch_block_t)completion;\n- (void)clearAssetContentCacheForCardPayload:(FBNCardPayload *)payload;\n- (BOOL)hasCachedContentForCardPayload:(FBNCardPayload *)payload;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Asset/FBNAssetsController.m",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import \"FBNAssetsController.h\"\n\n#import \"FBNAsset.h\"\n#import \"FBNAssetContentCache.h\"\n#import \"FBNAssetController.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface FBNAssetsController ()\n\n@property (nonatomic, strong, readonly) NSMutableDictionary<NSString *, id<FBNAssetController>> *assetControllers;\n@property (nonatomic, strong, readonly) FBNAssetContentCache *contentCache;\n\n@end\n\n@implementation FBNAssetsController\n\n///--------------------------------------\n#pragma mark - Init\n///--------------------------------------\n\n- (instancetype)init {\n    self = [super init];\n    if (!self) return self;\n\n    _assetControllers = [NSMutableDictionary dictionary];\n    _contentCache = [[FBNAssetContentCache alloc] init];\n\n    return self;\n}\n\n///--------------------------------------\n#pragma mark - Asset Controllers\n///--------------------------------------\n\n- (void)registerAssetController:(id<FBNAssetController>)controller forAssetType:(NSString *)type {\n    NSAssert(!_assetControllers[type], @\"Trying to register asset controller for already registered type %@\", type);\n    self.assetControllers[type] = controller;\n}\n\n- (nullable id<FBNAssetController>)assetControllerForAssetType:(NSString *)type {\n    return self.assetControllers[type];\n}\n\n///--------------------------------------\n#pragma mark - Assets\n///--------------------------------------\n\n- (void)loadAssetFromDictionary:(NSDictionary *)dictionary completion:(nonnull void (^)(id<FBNAsset> _Nullable asset))completion {\n    NSString *type = [self _assetTypeFromDictionary:dictionary];\n    if (!type) {\n        completion(nil);\n        return;\n    }\n\n    id<FBNAssetController> controller = [self assetControllerForAssetType:type];\n    [controller loadAssetFromDictionary:dictionary contentCache:self.contentCache completion:completion];\n}\n\n- (nullable UIViewController <FBNContentSizeProvider> *)viewControllerForAsset:(id<FBNAsset>)asset {\n    id<FBNAssetController> controller = [self assetControllerForAssetType:asset.type];\n    return [controller viewControllerForAsset:asset];\n}\n\n- (nullable NSString *)_assetTypeFromDictionary:(NSDictionary *)dictionary {\n    return dictionary[@\"_type\"];\n}\n\n- (nullable NSSet<NSURL *> *)_assetContentURLsFromAssetDictionary:(NSDictionary *)dictionary {\n    NSString *type = [self _assetTypeFromDictionary:dictionary];\n    if (!type) {\n        return nil;\n    }\n    id<FBNAssetController> controller = [self assetControllerForAssetType:type];\n    return [controller cacheURLsForAssetDictionary:dictionary];\n}\n\n///--------------------------------------\n#pragma mark - Cache\n///--------------------------------------\n\n- (void)cacheAssetContentForCardPayload:(FBNCardPayload *)payload completion:(dispatch_block_t)completion {\n    NSSet *urls = [self _assetContentURLsFromCardPayload:payload];\n    if (!urls.count) {\n        completion();\n        return;\n    }\n    [self.contentCache cacheContentForURLs:urls completion:completion];\n}\n\n- (void)clearAssetContentCacheForCardPayload:(FBNCardPayload *)payload {\n    NSSet *urls = [self _assetContentURLsFromCardPayload:payload];\n    [self.contentCache clearContentForURLs:urls];\n}\n\n- (BOOL)hasCachedContentForCardPayload:(FBNCardPayload *)payload {\n    NSSet<NSURL *> *urls = [self _assetContentURLsFromCardPayload:payload];\n    return [self.contentCache hasCachedContentForURLs:urls];\n}\n\n- (nullable NSSet<NSURL *> *)_assetContentURLsFromCardPayload:(FBNCardPayload *)payload {\n    return [self _assetContentURLsFromCollection:payload];\n}\n\n- (nullable NSSet<NSURL *> *)_assetContentURLsFromCollection:(id)collection {\n    NSMutableSet<NSURL *> *contentURLs = [NSMutableSet set];\n    void (^block)(NSMutableSet<NSURL *> *, id) = ^(NSMutableSet<NSURL *> *urls, id obj){\n        NSSet *assetURLs = nil;\n        if ([obj isKindOfClass:[NSDictionary class]]) {\n            assetURLs = [self _assetContentURLsFromAssetDictionary:obj];\n            if (assetURLs) {\n                [urls unionSet:assetURLs];\n                return;\n            }\n        }\n        assetURLs = [self _assetContentURLsFromCollection:obj];\n        if (assetURLs) {\n            [urls unionSet:assetURLs];\n        }\n    };\n\n    if ([collection isKindOfClass:[NSDictionary class]]) {\n        [collection enumerateKeysAndObjectsUsingBlock:^(NSString *_, id obj, BOOL *__) {\n            block(contentURLs, obj);\n        }];\n    } else if ([collection isKindOfClass:[NSArray class]]) {\n        for (id obj in collection) {\n            block(contentURLs, obj);\n        }\n    }\n    return [contentURLs copy];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Asset/GIF/FBNGIFAsset.h",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import <UIKit/UIKit.h>\n\n#import \"FBNAsset.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\nextern NSString *const FBNGIFAssetType;\n\n@interface FBNGIFAsset : NSObject <FBNAsset>\n\n@property (nonatomic, strong, readonly) UIImage *image;\n\n- (instancetype)initWithImage:(UIImage *)image;\n- (instancetype)init NS_UNAVAILABLE;\n+ (instancetype)new NS_UNAVAILABLE;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Asset/GIF/FBNGIFAsset.m",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import \"FBNGIFAsset.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\nNSString *const FBNGIFAssetType = @\"GIF\";\n\n@implementation FBNGIFAsset\n\n///--------------------------------------\n#pragma mark - Init\n///--------------------------------------\n\n- (instancetype)initWithImage:(UIImage *)image {\n    self = [super init];\n    if (!self) return self;\n\n    _image = image;\n\n    return self;\n}\n\n///--------------------------------------\n#pragma mark - FBNAsset\n///--------------------------------------\n\n- (NSString *)type {\n    return FBNGIFAssetType;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Asset/GIF/FBNGIFAssetController.h",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import <Foundation/Foundation.h>\n\n#import \"FBNAssetController.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface FBNGIFAssetController : NSObject <FBNAssetController>\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Asset/GIF/FBNGIFAssetController.m",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import \"FBNGIFAssetController.h\"\n\n#import \"FBNGIFAsset.h\"\n#import \"FBNIGIFAssetViewController.h\"\n#import \"FBNAssetContentCache.h\"\n#import \"FBNAnimatedImage.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation FBNGIFAssetController\n\n///--------------------------------------\n#pragma mark - FBNAssetController\n///--------------------------------------\n\n- (void)loadAssetFromDictionary:(NSDictionary *)dictionary\n                   contentCache:(nonnull FBNAssetContentCache *)cache\n                     completion:(void (^)(id <FBNAsset> _Nullable asset))completion {\n    if (![self isValidAssetDictionary:dictionary]) {\n        completion(nil);\n        return;\n    }\n\n    NSURL *url = [NSURL URLWithString:dictionary[@\"url\"]];\n    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{\n        NSData *data = [cache cachedDataForContentURL:url];\n        UIImage *image = FBNAnimatedImageFromData(data);\n        FBNGIFAsset *asset = [[FBNGIFAsset alloc] initWithImage:image];\n        completion(asset);\n    });\n}\n\n- (nullable NSSet<NSURL *> *)cacheURLsForAssetDictionary:(NSDictionary *)dictionary {\n    if (![self isValidAssetDictionary:dictionary]) {\n        return nil;\n    }\n\n    NSURL *url = [NSURL URLWithString:dictionary[@\"url\"]];\n    return (url ? [NSSet setWithObject:url] : nil);\n}\n\n- (BOOL)isValidAssetDictionary:(NSDictionary *)dictionary {\n    if (![dictionary isKindOfClass:[NSDictionary class]] ||\n        ![dictionary[@\"_type\"] isEqualToString:FBNGIFAssetType] ||\n        ![dictionary[@\"url\"] isKindOfClass:[NSString class]]) {\n        return NO;\n    }\n    return YES;\n}\n\n- (nullable UIViewController<FBNContentSizeProvider> *)viewControllerForAsset:(id<FBNAsset>)asset {\n    FBNGIFAsset *gifAsset = (FBNGIFAsset *)asset;\n    return [[FBNGIFAssetViewController alloc] initWithAsset:gifAsset];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Asset/GIF/FBNIGIFAssetViewController.h",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import <UIKit/UIKit.h>\n\n#import \"FBNContentSizeProvider.h\"\n\n@class FBNGIFAsset;\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface FBNGIFAssetViewController : UIViewController <FBNContentSizeProvider>\n\n- (instancetype)initWithAsset:(FBNGIFAsset *)asset;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Asset/GIF/FBNIGIFAssetViewController.m",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import \"FBNIGIFAssetViewController.h\"\n\n#import \"FBNGIFAsset.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface FBNGIFAssetViewController ()\n\n@property (nonatomic, strong, readonly) FBNGIFAsset *asset;\n\n@end\n\n@implementation FBNGIFAssetViewController\n\n///--------------------------------------\n#pragma mark - Init\n///--------------------------------------\n\n- (instancetype)initWithAsset:(FBNGIFAsset *)asset {\n    self = [super initWithNibName:nil bundle:nil];\n    if (!self) return self;\n\n    _asset = asset;\n\n    return self;\n}\n\n///--------------------------------------\n#pragma mark - View\n///--------------------------------------\n\n- (void)loadView {\n    //TODO: (nlutsenko) This should be implemented with a custom view, so we can support gifs with custom delays.\n    UIImageView *view = [[UIImageView alloc] initWithImage:self.asset.image];\n    view.contentMode = UIViewContentModeScaleAspectFill;\n    self.view = view;\n}\n\n///--------------------------------------\n#pragma mark - FBNContentSizeProvider\n///--------------------------------------\n\n- (CGSize)contentSizeThatFitsParentContainerSize:(CGSize)fitSize {\n    if ([self isViewLoaded]) {\n        return [self.view sizeThatFits:fitSize];\n    }\n    return self.asset.image.size;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Asset/Image/FBNImageAsset.h",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import <UIKit/UIKit.h>\n\n#import \"FBNAsset.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\nextern NSString *const FBNImageAssetType;\n\n@interface FBNImageAsset : NSObject <FBNAsset>\n\n@property (nonatomic, strong, readonly) UIImage *image;\n\n- (instancetype)initWithImage:(UIImage *)image;\n- (instancetype)init NS_UNAVAILABLE;\n+ (instancetype)new NS_UNAVAILABLE;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Asset/Image/FBNImageAsset.m",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import \"FBNImageAsset.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\nNSString *const FBNImageAssetType = @\"Image\";\n\n@implementation FBNImageAsset\n\n///--------------------------------------\n#pragma mark - Init\n///--------------------------------------\n\n- (instancetype)initWithImage:(UIImage *)image {\n    self = [super init];\n    if (!self) return self;\n    if (!image) return nil;\n\n    _image = image;\n\n    return self;\n}\n\n///--------------------------------------\n#pragma mark - FBNAsset\n///--------------------------------------\n\n- (NSString *)type {\n    return FBNImageAssetType;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Asset/Image/FBNImageAssetController.h",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import <Foundation/Foundation.h>\n\n#import \"FBNAssetController.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface FBNImageAssetController : NSObject <FBNAssetController>\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Asset/Image/FBNImageAssetController.m",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import \"FBNImageAssetController.h\"\n\n#import \"FBNImageAsset.h\"\n#import \"FBNImageAssetViewController.h\"\n#import \"FBNAssetContentCache.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation FBNImageAssetController\n\n///--------------------------------------\n#pragma mark - FBNAssetController\n///--------------------------------------\n\n- (void)loadAssetFromDictionary:(NSDictionary *)dictionary\n                   contentCache:(nonnull FBNAssetContentCache *)cache\n                     completion:(void (^)(id <FBNAsset> _Nullable asset))completion {\n    if (![self isValidAssetDictionary:dictionary]) {\n        completion(nil);\n        return;\n    }\n\n    NSURL *url = [NSURL URLWithString:dictionary[@\"url\"]];\n    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{\n        NSData *data = [cache cachedDataForContentURL:url];\n        UIImage *image = [[UIImage alloc] initWithData:data];\n        FBNImageAsset *asset = [[FBNImageAsset alloc] initWithImage:image];\n        completion(asset);\n    });\n}\n\n- (nullable NSSet<NSURL *> *)cacheURLsForAssetDictionary:(NSDictionary *)dictionary {\n    if (![self isValidAssetDictionary:dictionary]) {\n        return nil;\n    }\n\n    NSURL *url = [NSURL URLWithString:dictionary[@\"url\"]];\n    return (url ? [NSSet setWithObject:url] : nil);\n}\n\n- (BOOL)isValidAssetDictionary:(NSDictionary *)dictionary {\n    if (![dictionary isKindOfClass:[NSDictionary class]] ||\n        ![dictionary[@\"_type\"] isEqualToString:FBNImageAssetType] ||\n        ![dictionary[@\"url\"] isKindOfClass:[NSString class]]) {\n        return NO;\n    }\n    return YES;\n}\n\n- (nullable UIViewController<FBNContentSizeProvider> *)viewControllerForAsset:(id<FBNAsset>)asset {\n    FBNImageAsset *imageAsset = (FBNImageAsset *)asset;\n    return [[FBNImageAssetViewController alloc] initWithAsset:imageAsset];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Asset/Image/FBNImageAssetViewController.h",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import <UIKit/UIKit.h>\n\n#import \"FBNContentSizeProvider.h\"\n\n@class FBNImageAsset;\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface FBNImageAssetViewController : UIViewController <FBNContentSizeProvider>\n\n- (instancetype)initWithAsset:(FBNImageAsset *)asset;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Asset/Image/FBNImageAssetViewController.m",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import \"FBNImageAssetViewController.h\"\n\n#import \"FBNImageAsset.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface FBNImageAssetViewController ()\n\n@property (nonatomic, strong, readonly) FBNImageAsset *asset;\n\n@end\n\n@implementation FBNImageAssetViewController\n\n///--------------------------------------\n#pragma mark - Init\n///--------------------------------------\n\n- (instancetype)initWithAsset:(FBNImageAsset *)asset {\n    self = [super initWithNibName:nil bundle:nil];\n    if (!self) return self;\n\n    _asset = asset;\n\n    return self;\n}\n\n///--------------------------------------\n#pragma mark - View\n///--------------------------------------\n\n- (void)loadView {\n    UIImageView *view = [[UIImageView alloc] initWithImage:self.asset.image];\n    view.contentMode = UIViewContentModeScaleAspectFill;\n    self.view = view;\n}\n\n///--------------------------------------\n#pragma mark - FBNContentSizeProvider\n///--------------------------------------\n\n- (CGSize)contentSizeThatFitsParentContainerSize:(CGSize)fitSize {\n    if ([self isViewLoaded]) {\n        return [self.view sizeThatFits:fitSize];\n    }\n    return self.asset.image.size;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/FBNCardViewController_Internal.h",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import <FBNotifications/FBNCardViewController.h>\n\n#import \"FBNCardPayload.h\"\n\n@class FBNAssetsController;\n@class FBNAssetContentCache;\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface FBNCardViewController ()\n\n@property (nonatomic, copy, readonly) FBNCardPayload *payload;\n\n///--------------------------------------\n#pragma mark - Init\n///--------------------------------------\n\n- (instancetype)initWithPushCardPayload:(FBNCardPayload *)payload\n                     campaignIdentifier:(nullable NSString *)campaignIdentifier\n                       assetsController:(FBNAssetsController *)assetsController NS_DESIGNATED_INITIALIZER;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Models/Actions/FBNCardActionConfiguration.h",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import <Foundation/Foundation.h>\n#import <UIKit/UIKit.h>\n\n@class FBNCardTextContent;\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface FBNCardActionConfiguration : NSObject\n\n///--------------------------------------\n#pragma mark - Properties\n///--------------------------------------\n\n@property (nullable, nonatomic, strong, readonly) UIColor *backgroundColor;\n@property (nullable, nonatomic, strong, readonly) UIColor *borderColor;\n@property (nonatomic, assign, readonly) CGFloat borderWidth;\n\n@property (nullable, nonatomic, strong, readonly) FBNCardTextContent *content;\n\n@property (nullable, nonatomic, strong, readonly) NSURL *actionURL;\n\n///--------------------------------------\n#pragma mark - Init\n///--------------------------------------\n\n- (instancetype)init NS_UNAVAILABLE;\n+ (instancetype)new NS_UNAVAILABLE;\n\n+ (nullable instancetype)configurationFromDictionary:(nullable NSDictionary<NSString *, id> *)dictionary;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Models/Actions/FBNCardActionConfiguration.m",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import \"FBNCardActionConfiguration.h\"\n\n#import \"FBNCardColor.h\"\n#import \"FBNCardTextContent.h\"\n#import \"FBNCardViewUtilities.h\"\n\n@implementation FBNCardActionConfiguration\n\n///--------------------------------------\n#pragma mark - Init\n///--------------------------------------\n\n- (instancetype)initFromDictionary:(NSDictionary<NSString *, id> *)dictionary {\n    self = [super init];\n    if (!self) return self;\n\n    _backgroundColor = FBNCardColorFromRGBAHex(dictionary[@\"backgroundColor\"]);\n    _borderColor = FBNCardColorFromRGBAHex(dictionary[@\"borderColor\"]);\n    _borderWidth = FBNCGFloatFromNumber(dictionary[@\"borderWidth\"]);\n\n    _content = [FBNCardTextContent contentFromDictionary:dictionary[@\"content\"]];\n\n    _actionURL = [NSURL URLWithString:dictionary[@\"url\"]];\n\n    return self;\n}\n\n+ (nullable instancetype)configurationFromDictionary:(nullable NSDictionary<NSString *, id> *)dictionary {\n    if (!dictionary) {\n        return nil;\n    }\n    return [[self alloc] initFromDictionary:dictionary];\n}\n\n@end\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Models/Actions/FBNCardActionsConfiguration.h",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import <Foundation/Foundation.h>\n#import <UIKit/UIKit.h>\n\n#import \"FBNCardActionsStyle.h\"\n\n@class FBNAssetsController;\n@class FBNCardActionConfiguration;\n@protocol FBNAsset;\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface FBNCardActionsConfiguration : NSObject\n\n///--------------------------------------\n#pragma mark - Properties\n///--------------------------------------\n\n@property (nonatomic, assign, readonly) FBNCardActionsStyle style;\n@property (nonatomic, assign, readonly) FBNCardActionsLayoutStyle layoutStyle;\n\n@property (nullable, nonatomic, strong, readonly) id<FBNAsset> background;\n\n@property (nonatomic, assign, readonly) CGFloat height;\n@property (nonatomic, assign, readonly) CGFloat topInset;\n@property (nonatomic, assign, readonly) CGFloat contentInset;\n@property (nonatomic, assign, readonly) CGFloat cornerRadius;\n\n@property (nullable, nonatomic, copy, readonly) NSArray<FBNCardActionConfiguration *> *actions;\n\n///--------------------------------------\n#pragma mark - Init\n///--------------------------------------\n\n- (instancetype)init NS_UNAVAILABLE;\n+ (instancetype)new NS_UNAVAILABLE;\n\n+ (void)loadFromDictionary:(nullable NSDictionary<NSString *, id> *)dictionary\n          assetsController:(FBNAssetsController *)controller\n                completion:(void (^)(FBNCardActionsConfiguration *_Nullable configuration))completion;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Models/Actions/FBNCardActionsConfiguration.m",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import \"FBNCardActionsConfiguration.h\"\n\n#import \"FBNAssetsController.h\"\n#import \"FBNCardActionConfiguration.h\"\n#import \"FBNCardViewUtilities.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation FBNCardActionsConfiguration\n\n///--------------------------------------\n#pragma mark - Init\n///--------------------------------------\n\n- (instancetype)initFromDictionary:(NSDictionary<NSString *, id> *)dictionary\n                    withBackground:(nullable id<FBNAsset>)background {\n    self = [super init];\n    if (!self) return self;\n\n    _style = FBNCardActionsStyleFromString(dictionary[@\"style\"]);\n    _layoutStyle = FBNCardActionsLayoutStyleFromString(dictionary[@\"layoutStyle\"]);\n\n    _background = background;\n\n    NSNumber *height = dictionary[@\"height\"] ?: @(44.0); // Defaults to 44.0\n    _height = FBNCGFloatFromNumber(height);\n    _topInset = FBNCGFloatFromNumber(dictionary[@\"topInset\"]); // Default to 0\n    _contentInset = FBNCGFloatFromNumber(dictionary[@\"contentInset\"]); // Defaults to 0\n    _cornerRadius = FBNCGFloatFromNumber(dictionary[@\"cornerRadius\"]); // Defaults to 0\n\n    NSArray<NSDictionary *> *rawActions = dictionary[@\"actions\"];\n    NSMutableArray<FBNCardActionConfiguration *> *actions = [NSMutableArray arrayWithCapacity:rawActions.count];\n    for (NSDictionary *rawAction in rawActions) {\n        FBNCardActionConfiguration *action = [FBNCardActionConfiguration configurationFromDictionary:rawAction];\n        [actions addObject:action];\n    }\n    _actions = [actions copy];\n\n    return self;\n}\n\n+ (void)loadFromDictionary:(nullable NSDictionary<NSString *,id> *)dictionary\n          assetsController:(FBNAssetsController *)controller\n                completion:(void (^)(FBNCardActionsConfiguration * _Nullable configuration))completion {\n    if (!dictionary) {\n        completion(nil);\n        return;\n    }\n    [controller loadAssetFromDictionary:dictionary[@\"background\"] completion:^(id<FBNAsset> _Nullable asset) {\n        FBNCardActionsConfiguration *configuration = [[self alloc] initFromDictionary:dictionary withBackground:asset];\n        completion(configuration);\n    }];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Models/Actions/FBNCardActionsStyle.h",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import <UIKit/UIKit.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\n///--------------------------------------\n#pragma mark - Style\n///--------------------------------------\n\ntypedef NS_ENUM(NSUInteger, FBNCardActionsStyle) {\n    FBNCardActionsStyleAttached,\n    FBNCardActionsStyleDetached,\n};\n\nextern FBNCardActionsStyle FBNCardActionsStyleFromString(NSString *_Nullable string);\n\n///--------------------------------------\n#pragma mark - LayoutStyle\n///--------------------------------------\n\ntypedef NS_ENUM(NSUInteger, FBNCardActionsLayoutStyle) {\n    FBNCardActionsLayoutStyleVertical,\n    FBNCardActionsLayoutStyleHorizontal,\n};\n\nextern FBNCardActionsLayoutStyle FBNCardActionsLayoutStyleFromString(NSString *_Nullable string);\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Models/Actions/FBNCardActionsStyle.m",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import \"FBNCardActionsStyle.h\"\n\nFBNCardActionsStyle FBNCardActionsStyleFromString(NSString *_Nullable string) {\n    if ([string isEqualToString:@\"attached\"]) {\n        return FBNCardActionsStyleAttached;\n    } else if ([string isEqualToString:@\"detached\"]) {\n        return FBNCardActionsStyleDetached;\n    }\n    return FBNCardActionsStyleAttached;\n}\n\nextern FBNCardActionsLayoutStyle FBNCardActionsLayoutStyleFromString(NSString *_Nullable string) {\n    if ([string isEqualToString:@\"vertical\"]) {\n        return FBNCardActionsLayoutStyleVertical;\n    } else if ([string isEqualToString:@\"horizontal\"]) {\n        return FBNCardActionsLayoutStyleHorizontal;\n    }\n    return FBNCardActionsLayoutStyleVertical;\n}\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Models/Actions/FBNCardButtonAction.h",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#ifndef FBNCardButtonAction_h\n#define FBNCardButtonAction_h\n\ntypedef NS_ENUM(NSUInteger, FBNCardButtonAction) {\n    FBNCardButtonActionPrimary = 1,\n    FBNCardButtonActionSecondary,\n    FBNCardButtonActionDismiss\n};\n\n#endif /* FBNCardButtonAction_h */\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Models/Body/FBNCardBodyConfiguration.h",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import <Foundation/Foundation.h>\n#import <UIKit/UIKit.h>\n\n#import \"FBNAsset.h\"\n#import \"FBNCardTextContent.h\"\n\n@class FBNAssetsController;\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface FBNCardBodyConfiguration : NSObject\n\n///--------------------------------------\n#pragma mark - Properties\n///--------------------------------------\n\n@property (nullable, nonatomic, strong, readonly) id<FBNAsset> background;\n@property (nullable, nonatomic, strong, readonly) FBNCardTextContent *content;\n\n///--------------------------------------\n#pragma mark - Init\n///--------------------------------------\n\n+ (void)loadFromDictionary:(nullable NSDictionary<NSString *,id> *)dictionary\n          assetsController:(FBNAssetsController *)controller\n                completion:(void (^)(FBNCardBodyConfiguration *_Nullable configuration))completion;\n\n- (instancetype)init NS_UNAVAILABLE;\n+ (instancetype)new NS_UNAVAILABLE;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Models/Body/FBNCardBodyConfiguration.m",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import \"FBNCardBodyConfiguration.h\"\n\n#import \"FBNAssetsController.h\"\n#import \"FBNCardTextContent.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation FBNCardBodyConfiguration\n\n///--------------------------------------\n#pragma mark - Init\n///--------------------------------------\n\n- (instancetype)initFromDictionary:(NSDictionary<NSString *, id> *)dictionary\n                    withBackground:(nullable id<FBNAsset>)background {\n    self = [super init];\n    if (!self) return self;\n\n    _background = background;\n    _content = [FBNCardTextContent contentFromDictionary:dictionary[@\"content\"]];\n\n    return self;\n}\n\n+ (void)loadFromDictionary:(nullable NSDictionary<NSString *,id> *)dictionary\n          assetsController:(FBNAssetsController *)controller\n                completion:(void (^)(FBNCardBodyConfiguration *_Nullable configuration))completion {\n    if (!dictionary) {\n        completion(nil);\n        return;\n    }\n    [controller loadAssetFromDictionary:dictionary[@\"background\"] completion:^(id<FBNAsset> _Nullable asset) {\n        FBNCardBodyConfiguration *configuration = [[self alloc] initFromDictionary:dictionary withBackground:asset];\n        completion(configuration);\n    }];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Models/Card/FBNCardConfiguration.h",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import <Foundation/Foundation.h>\n\n#import \"FBNCardSize.h\"\n\n@class FBNAssetsController;\n@class FBNCardDisplayOptions;\n@class FBNCardHeroConfiguration;\n@class FBNCardBodyConfiguration;\n@class FBNCardActionsConfiguration;\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface FBNCardConfiguration : NSObject\n\n@property (nonatomic, strong, readonly) FBNCardDisplayOptions *displayOptions;\n@property (nullable, nonatomic, strong, readonly) FBNCardHeroConfiguration *heroConfiguration;\n@property (nullable, nonatomic, strong, readonly) FBNCardBodyConfiguration *bodyConfiguration;\n@property (nullable, nonatomic, strong, readonly) FBNCardActionsConfiguration *actionsConfiguration;\n\n+ (void)loadFromDictionary:(NSDictionary *)dictionary\n        withDisplayOptions:(FBNCardDisplayOptions *)displayOptions\n          assetsController:(FBNAssetsController *)controller\n                completion:(void (^)(FBNCardConfiguration * _Nullable configuration))completion;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Models/Card/FBNCardConfiguration.m",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import \"FBNCardConfiguration.h\"\n\n#import \"FBNAssetsController.h\"\n#import \"FBNCardHeroConfiguration.h\"\n#import \"FBNCardBodyConfiguration.h\"\n#import \"FBNCardActionsConfiguration.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation FBNCardConfiguration\n\n///--------------------------------------\n#pragma mark - Init\n///--------------------------------------\n\n- (instancetype)initFromDictionary:(NSDictionary *)dictionary\n                withDisplayOptions:(FBNCardDisplayOptions *)displayOptions\n                 heroConfiguration:(FBNCardHeroConfiguration *)heroConfiguration\n                 bodyConfiguration:(FBNCardBodyConfiguration *)bodyConfiguration\n              actionsConfiguration:(FBNCardActionsConfiguration *)actionsConfiguration {\n    self = [super init];\n    if (!self) return self;\n\n    _displayOptions = displayOptions;\n    _heroConfiguration = heroConfiguration;\n    _bodyConfiguration = bodyConfiguration;\n    _actionsConfiguration = actionsConfiguration;\n\n    return self;\n}\n\n+ (void)loadFromDictionary:(NSDictionary *)dictionary\n        withDisplayOptions:(FBNCardDisplayOptions *)displayOptions\n          assetsController:(FBNAssetsController *)controller\n                completion:(void (^)(FBNCardConfiguration * _Nullable configuration))completion {\n    dispatch_group_t group = dispatch_group_create();\n\n    dispatch_group_enter(group);\n    __block FBNCardHeroConfiguration *heroConfiguration = nil;\n    [FBNCardHeroConfiguration loadFromDictionary:dictionary[@\"hero\"]\n                                assetsController:controller\n                                      completion:^(FBNCardHeroConfiguration * _Nullable configuration) {\n                                          heroConfiguration = configuration;\n                                          dispatch_group_leave(group);\n                                      }];\n\n\n    dispatch_group_enter(group);\n    __block FBNCardBodyConfiguration *bodyConfiguration = nil;\n    [FBNCardBodyConfiguration loadFromDictionary:dictionary[@\"body\"]\n                                assetsController:controller\n                                      completion:^(FBNCardBodyConfiguration * _Nullable configuration) {\n                                          bodyConfiguration = configuration;\n                                          dispatch_group_leave(group);\n                                      }];\n\n    dispatch_group_enter(group);\n    __block FBNCardActionsConfiguration *actionsConfiguration = nil;\n    [FBNCardActionsConfiguration loadFromDictionary:dictionary[@\"actions\"]\n                                   assetsController:controller\n                                         completion:^(FBNCardActionsConfiguration * _Nullable configuration) {\n                                             actionsConfiguration = configuration;\n                                             dispatch_group_leave(group);\n                                         }];\n\n\n    dispatch_group_notify(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{\n        FBNCardConfiguration *configuration = [[FBNCardConfiguration alloc] initFromDictionary:dictionary\n                                                                            withDisplayOptions:displayOptions\n                                                                             heroConfiguration:heroConfiguration\n                                                                             bodyConfiguration:bodyConfiguration\n                                                                          actionsConfiguration:actionsConfiguration];\n        completion(configuration);\n    });\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Models/Card/FBNCardDisplayOptions.h",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import <Foundation/Foundation.h>\n#import <UIKit/UIKit.h>\n\n#import \"FBNCardSize.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface FBNCardDisplayOptions : NSObject\n\n@property (nonatomic, assign, readonly) FBNCardSize size;\n@property (nonatomic, assign, readonly) CGFloat cornerRadius;\n@property (nonatomic, assign, readonly) CGFloat contentInset;\n\n@property (nullable, nonatomic, strong, readonly) UIColor *backdropColor;\n@property (nonatomic, strong, readonly) UIColor *dismissButtonColor;\n\n+ (instancetype)displayOptionsFromDictionary:(NSDictionary *)dictionary;\n- (instancetype)init NS_UNAVAILABLE;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Models/Card/FBNCardDisplayOptions.m",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import \"FBNCardDisplayOptions.h\"\n\n#import \"FBNCardColor.h\"\n#import \"FBNCardViewUtilities.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation FBNCardDisplayOptions\n\n- (instancetype)initFromDictionary:(NSDictionary *)dictionary {\n    self = [super init];\n    if (!self) return nil;\n\n    _size = FBNCardSizeFromString(dictionary[@\"size\"]);\n    _cornerRadius = FBNCGFloatFromNumber(dictionary[@\"cornerRadius\"]); // Defaults to 0\n    _contentInset = FBNCGFloatFromNumber(dictionary[@\"contentInset\"] ?: @(10.0)); // Defaults to 10.0\n\n    _backdropColor = FBNCardColorFromRGBAHex(dictionary[@\"backdropColor\"]);\n    _dismissButtonColor = FBNCardColorFromRGBAHex(dictionary[@\"dismissColor\"]) ?: [UIColor blackColor];\n\n    return self;\n}\n\n+ (instancetype)displayOptionsFromDictionary:(NSDictionary *)dictionary {\n    return [[self alloc] initFromDictionary:dictionary];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Models/Card/FBNCardSize.h",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import <Foundation/Foundation.h>\n#import <UIKit/UIKit.h>\n\ntypedef NS_ENUM(NSUInteger, FBNCardSize) {\n    FBNCardSizeInvalid,\n    FBNCardSizeSmall,\n    FBNCardSizeMedium,\n    FBNCardSizeLarge,\n};\n\nNS_ASSUME_NONNULL_BEGIN\n\nextern FBNCardSize FBNCardSizeFromString(NSString *_Nullable string);\nextern CGSize FBNCardLayoutSizeThatFits(FBNCardSize cardSize, CGSize size);\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Models/Card/FBNCardSize.m",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import \"FBNCardSize.h\"\n#import \"FBNCardViewUtilities.h\"\n\nFBNCardSize FBNCardSizeFromString(NSString *_Nullable string) {\n    if ([string isEqualToString:@\"small\"]) {\n        return FBNCardSizeSmall;\n    } else if ([string isEqualToString:@\"medium\"]) {\n        return FBNCardSizeMedium;\n    } else if ([string isEqualToString:@\"large\"]) {\n        return FBNCardSizeLarge;\n    }\n    return FBNCardSizeInvalid;\n}\n\nCGSize FBNCardLayoutSizeThatFits(FBNCardSize cardSize, CGSize size) {\n    const CGSize maxSize = CGSizeMake(400, 700);\n    CGSize layoutSize = FBNSizeMin(maxSize, size);\n    switch (cardSize) {\n        case FBNCardSizeInvalid:\n            return CGSizeZero;\n        case FBNCardSizeSmall: {\n            layoutSize.width *= 0.75;\n            layoutSize.height *= 0.7;\n        }\n            break;\n        case FBNCardSizeMedium: {\n            layoutSize.width *= 0.83;\n            layoutSize.height *= 0.9;\n        }\n            break;\n        case FBNCardSizeLarge:\n        default:\n            break;\n    }\n    return FBNSizeAdjustToScreenScale(layoutSize, NSRoundPlain);\n}\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Models/Components/FBNAnimatedImage.h",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import <UIKIt/UIKit.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\nextern UIImage *FBNAnimatedImageFromData(NSData *data);\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Models/Components/FBNAnimatedImage.m",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import \"FBNAnimatedImage.h\"\n\n#import <ImageIO/ImageIO.h>\n#import <MobileCoreServices/MobileCoreServices.h>\n\nextern BOOL FBNImageSourceContainsAnimatedGIF(CGImageSourceRef source);\nextern UIImage *FBNAnimatedImageFromImageSource(CGImageSourceRef source);\nextern NSTimeInterval FBNImageSourceGetGIFFrameDelay(CGImageSourceRef imageSource, NSUInteger index);\n\n///--------------------------------------\n#pragma mark - Public\n///--------------------------------------\n\nUIImage *FBNAnimatedImageFromData(NSData *data) {\n    if (!data) {\n        return nil;\n    }\n\n    CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)(data), NULL);\n\n    UIImage *image = nil;\n    if (FBNImageSourceContainsAnimatedGIF(source)) {\n        image = FBNAnimatedImageFromImageSource(source);\n    } else {\n        image = [UIImage imageWithData:data];\n    }\n\n    if (source) {\n        CFRelease(source);\n    }\n\n    return image;\n}\n\n///--------------------------------------\n#pragma mark - Private\n///--------------------------------------\n\nBOOL FBNImageSourceContainsAnimatedGIF(CGImageSourceRef source) {\n    return (source && UTTypeConformsTo(CGImageSourceGetType(source), kUTTypeGIF) && CGImageSourceGetCount(source) > 1);\n}\n\nUIImage *FBNAnimatedImageFromImageSource(CGImageSourceRef source) {\n    CFRetain(source);\n    NSUInteger numberOfFrames = CGImageSourceGetCount(source);\n    NSMutableArray<UIImage *> *images = [NSMutableArray arrayWithCapacity:numberOfFrames];\n    NSTimeInterval duration = 0.0;\n    for (NSUInteger i = 0; i < numberOfFrames; ++i) {\n        CGImageRef image = CGImageSourceCreateImageAtIndex(source, i, NULL);\n        if (image) {\n            UIImage *frameImage = [UIImage imageWithCGImage:image scale:1.0 orientation:UIImageOrientationUp];\n            [images addObject:frameImage];\n            CFRelease(image);\n        } else {\n            continue;\n        }\n\n        duration += FBNImageSourceGetGIFFrameDelay(source, i);\n    }\n    CFRelease(source);\n\n    return [UIImage animatedImageWithImages:images duration:duration];\n}\n\nNSTimeInterval FBNImageSourceGetGIFFrameDelay(CGImageSourceRef source, NSUInteger index) {\n    NSTimeInterval frameDelay = 0;\n    CFDictionaryRef imageProperties = CGImageSourceCopyPropertiesAtIndex(source, index, NULL);\n    if (!imageProperties) {\n        return frameDelay;\n    }\n\n    CFDictionaryRef gifProperties = nil;\n    if (CFDictionaryGetValueIfPresent(imageProperties, kCGImagePropertyGIFDictionary, (const void **)&gifProperties)) {\n        const void *durationValue = nil;\n        if (CFDictionaryGetValueIfPresent(gifProperties, kCGImagePropertyGIFUnclampedDelayTime, &durationValue)) {\n            frameDelay = [(__bridge NSNumber *)durationValue doubleValue];\n            if (frameDelay <= 0) {\n                if (CFDictionaryGetValueIfPresent(gifProperties, kCGImagePropertyGIFDelayTime, &durationValue)) {\n                    frameDelay = [(__bridge NSNumber *)durationValue doubleValue];\n                }\n            }\n        }\n    }\n    CFRelease(imageProperties);\n\n    return frameDelay;\n}\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Models/Components/FBNCardBackground.h",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import <Foundation/Foundation.h>\n#import <UIKit/UIKit.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\nextern UIImage *_Nullable FBNCardBackgroundImageWithColor(UIColor *color);\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Models/Components/FBNCardBackground.m",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import \"FBNCardBackground.h\"\n#import \"FBNCardViewUtilities.h\"\n\nUIImage *_Nullable FBNCardBackgroundImageWithColor(UIColor *color) {\n    CGSize size = CGSizeMake(1, 1);\n\n    UIGraphicsBeginImageContext(size);\n    CGContextRef context = UIGraphicsGetCurrentContext();\n\n    CGContextSetFillColorWithColor(context, color.CGColor);\n    CGContextFillRect(context, FBNRectMakeWithOriginSize(CGPointZero, size));\n\n    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();\n    UIGraphicsEndImageContext();\n\n    return image;\n}\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Models/Components/FBNCardColor.h",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import <Foundation/Foundation.h>\n#import <UIKit/UIKit.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\nextern UIColor *_Nullable FBNCardColorFromRGBAHex(NSString *string);\n\ntypedef NS_ENUM(uint8_t, FBNCardContrastColor) {\n    FBNCardContrastColorWhite,\n    FBNCardContrastColorBlack\n};\n\nextern FBNCardContrastColor FBNCardContrastColorForColor(UIColor *color);\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Models/Components/FBNCardColor.m",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import \"FBNCardColor.h\"\n\nUIColor *_Nullable FBNCardColorFromRGBAHex(NSString *string) {\n    if (![string isKindOfClass:[NSString class]]) {\n        return nil;\n    }\n\n    NSString *hexString = [string substringFromIndex:1];\n\n    unsigned long long hexValue = 0;\n    [[NSScanner scannerWithString:hexString] scanHexLongLong:&hexValue];\n\n    CGFloat divisor = 255.0;\n    CGFloat red   = ((hexValue & 0xFF000000) >> 24) / divisor;\n    CGFloat green = ((hexValue & 0x00FF0000) >> 16) / divisor;\n    CGFloat blue  = ((hexValue & 0x0000FF00) >> 8)  / divisor;\n    CGFloat alpha = (hexValue & 0x000000FF)         / divisor;\n    return [UIColor colorWithRed:red green:green blue:blue alpha:alpha];\n}\n\nFBNCardContrastColor FBNCardContrastColorForColor(UIColor *color) {\n    CGFloat red = 0.0, green = 0.0, blue = 0.0;\n    [color getRed:&red green:&green blue:&blue alpha:NULL];\n    CGFloat perceptiveLuminance = (red * 255 * 299 + green * 255 * 587 + blue * 255 * 114) / 1000.0f;\n    return (perceptiveLuminance >= 128 ? FBNCardContrastColorBlack : FBNCardContrastColorWhite);\n}\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Models/Components/FBNCardFont.h",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import <UIKit/UIKit.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\nextern NSString *const FBNCardFontNameSystemRegular;\nextern NSString *const FBNCardFontNameSystemLight;\nextern NSString *const FBNCardFontNameSystemItalic;\nextern NSString *const FBNCardFontNameSystemBold;\nextern NSString *const FBNCardFontNameSystemBoldItalic;\n\nextern UIFont *FBNCardFontWithNameSize(NSString *_Nullable fontName, CGFloat size);\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Models/Components/FBNCardFont.m",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import \"FBNCardFont.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\nNSString *const FBNCardFontNameSystemRegular = @\"system-regular\";\nNSString *const FBNCardFontNameSystemLight = @\"system-light\";\nNSString *const FBNCardFontNameSystemItalic = @\"system-italic\";\nNSString *const FBNCardFontNameSystemBold = @\"system-bold\";\nNSString *const FBNCardFontNameSystemBoldItalic = @\"system-bolditalic\";\n\nUIFont *FBNCardFontWithNameSize(NSString *_Nullable fontName, CGFloat size) {\n    // Make sure we do case-insensitive comparison.\n    fontName = fontName.lowercaseString;\n\n    UIFont *systemFont = [UIFont systemFontOfSize:size];\n    UIFontDescriptor *fontDescriptor = nil;\n    if ([fontName isEqualToString:FBNCardFontNameSystemLight]) {\n        fontDescriptor = [UIFontDescriptor fontDescriptorWithFontAttributes:@{ UIFontDescriptorFamilyAttribute: systemFont.familyName,\n                                                                               UIFontDescriptorFaceAttribute : @\"Light\" }];\n    } else if ([fontName isEqualToString:FBNCardFontNameSystemItalic]) {\n        fontDescriptor = [systemFont.fontDescriptor fontDescriptorWithSymbolicTraits:UIFontDescriptorTraitItalic];\n    } else if ([fontName isEqualToString:FBNCardFontNameSystemBold]) {\n        fontDescriptor = [systemFont.fontDescriptor fontDescriptorWithSymbolicTraits:UIFontDescriptorTraitBold];\n    } else if ([fontName isEqualToString:FBNCardFontNameSystemBoldItalic]) {\n        fontDescriptor = [systemFont.fontDescriptor fontDescriptorWithSymbolicTraits:(UIFontDescriptorTraitBold | UIFontDescriptorTraitItalic)];\n    } else {\n        fontDescriptor = systemFont.fontDescriptor;\n    }\n    return [UIFont fontWithDescriptor:fontDescriptor size:size];\n}\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Models/Components/FBNCardTextAlignment.h",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import <Foundation/Foundation.h>\n#import <UIKit/UIKit.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\nextern NSTextAlignment FBNCardTextAlignmentFromString(NSString *_Nullable string);\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Models/Components/FBNCardTextAlignment.m",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import \"FBNCardTextAlignment.h\"\n\nNSTextAlignment FBNCardTextAlignmentFromString(NSString *_Nullable string) {\n    if ([string isEqualToString:@\"left\"]) {\n        return NSTextAlignmentLeft;\n    } else if ([string isEqualToString:@\"right\"]) {\n        return NSTextAlignmentRight;\n    } else if ([string isEqualToString:@\"center\"]) {\n        return NSTextAlignmentCenter;\n    }\n    return NSTextAlignmentCenter;\n}\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Models/Components/FBNCardTextContent.h",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import <Foundation/Foundation.h>\n#import <UIKit/UIKit.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\ntypedef NS_ENUM(NSUInteger, FBNCardContentVerticalAlignment) {\n    FBNCardContentVerticalAlignmentTop,\n    FBNCardContentVerticalAlignmentCenter,\n    FBNCardContentVerticalAlignmentBottom\n};\n\nextern FBNCardContentVerticalAlignment FBNCardContentVerticalAlignmentFromString(NSString *_Nullable string);\n\n@interface FBNCardTextContent : NSObject\n\n///--------------------------------------\n#pragma mark - Properties\n///--------------------------------------\n\n@property (nonatomic, strong, readonly) UIFont *font;\n@property (nonatomic, strong, readonly) UIColor *textColor;\n@property (nonatomic, assign, readonly) NSTextAlignment textAlignment;\n\n@property (nullable, nonatomic, copy, readonly) NSAttributedString *attributedText;\n\n///--------------------------------------\n#pragma mark - Init\n///--------------------------------------\n\n- (instancetype)init NS_UNAVAILABLE;\n+ (instancetype)new NS_UNAVAILABLE;\n\n+ (nullable instancetype)contentFromDictionary:(nullable NSDictionary<NSString *, id> *)dictionary;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Models/Components/FBNCardTextContent.m",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import \"FBNCardTextContent.h\"\n\n#import \"FBNCardColor.h\"\n#import \"FBNCardTextAlignment.h\"\n#import \"FBNCardViewUtilities.h\"\n#import \"FBNCardFont.h\"\n\nFBNCardContentVerticalAlignment FBNCardContentVerticalAlignmentFromString(NSString *_Nullable string) {\n    if ([string isEqualToString:@\"top\"]) {\n        return FBNCardContentVerticalAlignmentTop;\n    } else if ([string isEqualToString:@\"center\"]) {\n        return FBNCardContentVerticalAlignmentCenter;\n    } else if ([string isEqualToString:@\"bottom\"]) {\n        return FBNCardContentVerticalAlignmentBottom;\n    }\n    return FBNCardContentVerticalAlignmentCenter;\n}\n\n@implementation FBNCardTextContent\n\n///--------------------------------------\n#pragma mark - Init\n///--------------------------------------\n\n- (instancetype)initFromDictionary:(NSDictionary<NSString *, id> *)dictionary {\n    self = [super init];\n    if (!self) return self;\n\n    NSString *fontName = dictionary[@\"font\"];\n    NSNumber *fontSize = dictionary[@\"size\"] ?: @([UIFont systemFontSize]);\n    _font = FBNCardFontWithNameSize(fontName, FBNCGFloatFromNumber(fontSize));\n    _textColor = FBNCardColorFromRGBAHex(dictionary[@\"color\"]) ?: [UIColor blackColor]; // Defaults to Black\n    _textAlignment = FBNCardTextAlignmentFromString(dictionary[@\"align\"]);\n\n    NSMutableParagraphStyle *paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];\n    paragraphStyle.alignment = _textAlignment;\n    NSDictionary<NSString *, id> *attributes = @{ NSFontAttributeName : self.font,\n                                                  NSForegroundColorAttributeName : self.textColor,\n                                                  NSParagraphStyleAttributeName : paragraphStyle };\n    \n    _attributedText = [[NSAttributedString alloc] initWithString:dictionary[@\"text\"] attributes:attributes];\n\n    return self;\n}\n\n+ (nullable instancetype)contentFromDictionary:(nullable NSDictionary<NSString *, id> *)dictionary {\n    if (!dictionary) {\n        return nil;\n    }\n    return [[self alloc] initFromDictionary:dictionary];\n}\n\n@end\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Models/Hero/FBNCardHeroConfiguration.h",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import <Foundation/Foundation.h>\n#import <UIKit/UIKit.h>\n\n#import \"FBNCardTextContent.h\"\n#import \"FBNAsset.h\"\n\n@class FBNAssetsController;\n@class FBNAssetContentCache;\n\nNS_ASSUME_NONNULL_BEGIN\n\nextern const CGFloat FBNCardHeroHeightUnspecified;\n\n@interface FBNCardHeroConfiguration : NSObject\n\n///--------------------------------------\n#pragma mark - Properties\n///--------------------------------------\n\n@property (nonatomic, assign, readonly) CGFloat height;\n@property (nullable, nonatomic, strong, readonly) id<FBNAsset> background;\n\n@property (nullable, nonatomic, strong, readonly) FBNCardTextContent *content;\n@property (nonatomic, assign, readonly) FBNCardContentVerticalAlignment contentVerticalAlignment;\n\n///--------------------------------------\n#pragma mark - Init\n///--------------------------------------\n\n+ (void)loadFromDictionary:(nullable NSDictionary<NSString *,id> *)dictionary\n          assetsController:(FBNAssetsController *)controller\n                completion:(void (^)(FBNCardHeroConfiguration *_Nullable configuration))completion;\n\n- (instancetype)init NS_UNAVAILABLE;\n+ (instancetype)new NS_UNAVAILABLE;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Models/Hero/FBNCardHeroConfiguration.m",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import \"FBNCardHeroConfiguration.h\"\n\n#import \"FBNAssetContentCache.h\"\n#import \"FBNAssetsController.h\"\n#import \"FBNCardViewUtilities.h\"\n\nconst CGFloat FBNCardHeroHeightUnspecified = CGFLOAT_MAX;\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation FBNCardHeroConfiguration\n\n///--------------------------------------\n#pragma mark - Init\n///--------------------------------------\n\n- (instancetype)initFromDictionary:(NSDictionary<NSString *, id> *)dictionary\n                    withBackground:(nullable id <FBNAsset>)background {\n    self = [super init];\n    if (!self) return self;\n\n    NSNumber *height = dictionary[@\"height\"] ?: @(FBNCardHeroHeightUnspecified);\n    _height = FBNCGFloatFromNumber(height);\n    _background = background;\n\n    _content = [FBNCardTextContent contentFromDictionary:dictionary[@\"content\"]];\n    _contentVerticalAlignment = FBNCardContentVerticalAlignmentFromString(dictionary[@\"contentAlign\"]);\n\n    return self;\n}\n\n+ (void)loadFromDictionary:(nullable NSDictionary<NSString *,id> *)dictionary\n          assetsController:(FBNAssetsController *)controller\n                completion:(void (^)(FBNCardHeroConfiguration * _Nullable))completion {\n    if (!dictionary) {\n        completion(nil);\n        return;\n    }\n    [controller loadAssetFromDictionary:dictionary[@\"background\"] completion:^(id<FBNAsset> _Nullable asset) {\n        FBNCardHeroConfiguration *configuration = [[self alloc] initFromDictionary:dictionary withBackground:asset];\n        completion(configuration);\n    }];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Utilities/FBNCardError.h",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import <Foundation/Foundation.h>\n\n@interface FBNCardError : NSError\n\n+ (instancetype)invalidRemoteNotificationPayloadError;\n\n@end\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Utilities/FBNCardError.m",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import \"FBNCardError.h\"\n\n#import \"FBNConstants.h\"\n\n@implementation FBNCardError\n\n+ (instancetype)invalidRemoteNotificationPayloadError {\n    return [self errorWithDomain:FBNotificationsErrorDomain\n                            code:FBNotificationsErrorInvalidPayload\n                        userInfo:@{ NSLocalizedDescriptionKey : @\"Invalid remote notification payload for presenting push card.\" }];\n}\n\n@end\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Utilities/FBNCardHash.h",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import <Foundation/Foundation.h>\n\nextern NSString *FBMD5HashFromData(NSData *data);\nextern NSString *FBMD5HashFromString(NSString *string);\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Utilities/FBNCardHash.m",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import \"FBNCardHash.h\"\n\n#import <CommonCrypto/CommonDigest.h>\n\nNSString *FBMD5HashFromData(NSData *data) {\n    unsigned char md[CC_MD5_DIGEST_LENGTH];\n\n    // NOTE: `__block` variables of a struct type seem to be bugged. The compiler emits instructions to read\n    // from the stack past where they're supposed to exist. This fixes that, by only using a traditional pointer.\n    CC_MD5_CTX ctx_val = { 0 };\n    CC_MD5_CTX *ctx_ptr = &ctx_val;\n    CC_MD5_Init(ctx_ptr);\n    [data enumerateByteRangesUsingBlock:^(const void *bytes, NSRange byteRange, BOOL *stop) {\n        CC_MD5_Update(ctx_ptr , bytes, (CC_LONG)byteRange.length);\n    }];\n    CC_MD5_Final(md, ctx_ptr);\n\n    NSString *string = [NSString stringWithFormat:@\"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\",\n                        md[0], md[1],\n                        md[2], md[3],\n                        md[4], md[5],\n                        md[6], md[7],\n                        md[8], md[9],\n                        md[10], md[11],\n                        md[12], md[13],\n                        md[14], md[15]];\n    return string;\n}\n\nNSString *FBMD5HashFromString(NSString *string) {\n    return FBMD5HashFromData([string dataUsingEncoding:NSUTF8StringEncoding]);\n}\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Utilities/FBNCardPayload.h",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import <Foundation/Foundation.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\ntypedef NSDictionary<NSString *, id> FBNCardPayload;\n\nextern FBNCardPayload *_Nullable FBNCardPayloadFromRemoteNotificationPayload(NSDictionary *payload);\nextern BOOL FBNCardPayloadIsCompatibleWithCurrentVersion(FBNCardPayload *payload, NSString *frameworkVersion);\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Utilities/FBNCardPayload.m",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import \"FBNCardPayload.h\"\n\n///--------------------------------------\n#pragma mark - Version\n///--------------------------------------\n\ntypedef struct {\n    uint32_t major;\n    uint32_t minor;\n    uint32_t patch;\n} FBNCardPayloadVersion;\n\nstatic const FBNCardPayloadVersion FBNCardPayloadVersionInvalid = { .major = -1, .minor = -1, .patch = -1 };\n\nBOOL FBNCardPayloadVersionIsValid(FBNCardPayloadVersion version) {\n    return (version.major != FBNCardPayloadVersionInvalid.major &&\n            version.minor != FBNCardPayloadVersionInvalid.minor &&\n            version.patch != FBNCardPayloadVersionInvalid.patch);\n}\n\nFBNCardPayloadVersion FBNCardPayloadVersionFromString(NSString *string) {\n    FBNCardPayloadVersion version = {0, 0, 0};\n    int tokens = sscanf([string UTF8String], \"%u.%u.%u\", &version.major, &version.minor, &version.patch);\n    if (tokens < 2) {\n        return FBNCardPayloadVersionInvalid;\n    }\n    return version;\n}\n\n///--------------------------------------\n#pragma mark - Public\n///--------------------------------------\n\nFBNCardPayload *_Nullable FBNCardPayloadFromRemoteNotificationPayload(NSDictionary *payload) {\n    return payload[@\"fb_push_card\"];\n}\n\nBOOL FBNCardPayloadIsCompatibleWithCurrentVersion(FBNCardPayload *payload, NSString *frameworkVersionString) {\n    FBNCardPayloadVersion payloadVersion = FBNCardPayloadVersionFromString(payload[@\"version\"]);\n    FBNCardPayloadVersion frameworkVersion = FBNCardPayloadVersionFromString(frameworkVersionString);\n\n    // Check for both versions to be valid\n    if (!FBNCardPayloadVersionIsValid(payloadVersion) ||\n        !FBNCardPayloadVersionIsValid(frameworkVersion)) {\n        return NO;\n    }\n    // Not forward/backward compatible on major\n    if (payloadVersion.major != frameworkVersion.major) {\n        return NO;\n    }\n    // Not forward compatible on minor\n    if (payloadVersion.minor > frameworkVersion.minor) {\n        return NO;\n    }\n    // Don't care about patch\n    return YES;\n}\n\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Utilities/FBNCardViewUtilities.h",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import <UIKit/UIKit.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\n///--------------------------------------\n#pragma mark - CGFloat\n///--------------------------------------\n\nextern CGFloat FBNCGFloatFromNumber(NSNumber *_Nullable number);\nextern CGFloat FBNCGFloatRound(CGFloat number, NSRoundingMode roundingMode);\n\n///--------------------------------------\n#pragma mark - CGRect\n///--------------------------------------\n\nextern CGRect FBNRectMakeWithOriginSize(CGPoint origin, CGSize size);\nextern CGRect FBNRectMakeWithSizeCenteredInRect(CGSize size, CGRect rect);\n\n///--------------------------------------\n#pragma mark - CGSize\n///--------------------------------------\n\nextern CGSize FBNSizeMin(CGSize size1, CGSize size2);\nextern CGSize FBNSizeMax(CGSize size1, CGSize size2);\nextern CGFloat FBNAspectFillScaleThatFits(CGSize size, CGSize fitSize);\n\n///--------------------------------------\n#pragma mark - Screen Scaling\n///--------------------------------------\n\nextern CGRect FBNRectAdjustToScreenScale(CGRect rect, NSRoundingMode roundingMode);\nextern CGSize FBNSizeAdjustToScreenScale(CGSize size, NSRoundingMode roundingMode);\nextern CGFloat FBNFloatAdjustToScreenScale(CGFloat value, NSRoundingMode roundingMode);\n\n///--------------------------------------\n#pragma mark - Top Most View Controller\n///--------------------------------------\n\nextern UIViewController *_Nullable FBNApplicationTopMostViewController();\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Utilities/FBNCardViewUtilities.m",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#include \"FBNCardViewUtilities.h\"\n\n///--------------------------------------\n#pragma mark - CGFloat\n///--------------------------------------\n\nCGFloat FBNCGFloatFromNumber(NSNumber *_Nullable number) {\n#if CGFLOAT_IS_DOUBLE\n    return number.doubleValue;\n#else\n    return number.floatValue;\n#endif\n}\n\nCGFloat FBNCGFloatRound(CGFloat number, NSRoundingMode roundingMode) {\n    switch (roundingMode) {\n        case NSRoundPlain:\n        case NSRoundBankers:\n#if CGFLOAT_IS_DOUBLE\n            number = round(number);\n#else\n            number = roundf(number);\n#endif\n        case NSRoundDown:\n#if CGFLOAT_IS_DOUBLE\n            number = floor(number);\n#else\n            number = floorf(number);\n#endif\n        case NSRoundUp:\n#if CGFLOAT_IS_DOUBLE\n            number = ceil(number);\n#else\n            number = ceilf(number);\n#endif\n        default: break;\n    }\n    return number;\n}\n\n///--------------------------------------\n#pragma mark - CGRect\n///--------------------------------------\n\nCGRect FBNRectMakeWithOriginSize(CGPoint origin, CGSize size) {\n    return CGRectMake(origin.x, origin.y, size.width, size.height);\n}\n\nCGRect FBNRectMakeWithSizeCenteredInRect(CGSize size, CGRect rect) {\n    CGPoint center = CGPointMake(CGRectGetMidX(rect), CGRectGetMidY(rect));\n    CGPoint origin = CGPointMake(center.x - size.width / 2.0f, center.y - size.height / 2.0f);\n    rect = FBNRectMakeWithOriginSize(origin, size);\n    return FBNRectAdjustToScreenScale(rect, NSRoundPlain);\n}\n\n///--------------------------------------\n#pragma mark - CGSize\n///--------------------------------------\n\nCGSize FBNSizeMin(CGSize size1, CGSize size2) {\n    CGSize size = CGSizeZero;\n    size.width = (float)fmin(size1.width, size2.width);\n    size.height = (float)fmin(size1.height, size2.height);\n    return size;\n}\n\nCGSize FBNSizeMax(CGSize size1, CGSize size2) {\n    CGSize size = CGSizeZero;\n    size.width = (float)fmax(size1.width, size2.width);\n    size.height = (float)fmax(size1.height, size2.height);\n    return size;\n}\n\nCGFloat FBNAspectFillScaleThatFits(CGSize size, CGSize fitSize) {\n    return MIN(fitSize.width / size.width, fitSize.height / size.height);\n}\n\n///--------------------------------------\n#pragma mark - Screen Scaling\n///--------------------------------------\n\nCGRect FBNRectAdjustToScreenScale(CGRect rect, NSRoundingMode roundingMode) {\n    rect.origin.x = FBNFloatAdjustToScreenScale(rect.origin.x, roundingMode);\n    rect.origin.y = FBNFloatAdjustToScreenScale(rect.origin.y, roundingMode);\n    rect.size = FBNSizeAdjustToScreenScale(rect.size, roundingMode);\n    return rect;\n}\n\nCGSize FBNSizeAdjustToScreenScale(CGSize size, NSRoundingMode roundingMode) {\n    size.width = FBNFloatAdjustToScreenScale(size.width, roundingMode);\n    size.height = FBNFloatAdjustToScreenScale(size.height, roundingMode);\n    return size;\n}\n\nCGFloat FBNFloatAdjustToScreenScale(CGFloat value, NSRoundingMode roundingMode) {\n    const CGFloat scale = [UIScreen mainScreen].scale;\n    value = value * scale;\n    value = FBNCGFloatRound(value, roundingMode);\n    value /= scale;\n    return value;\n}\n\nUIViewController *_Nullable FBNApplicationTopMostViewController() {\n    UIWindow *keyWindow = [UIApplication sharedApplication].keyWindow;\n    UIViewController *viewController = keyWindow.rootViewController;\n    while (viewController.presentedViewController && !viewController.presentedViewController.isBeingDismissed) {\n        viewController = viewController.presentedViewController;\n    }\n    return viewController;\n}\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Utilities/FBNContentSizeProvider.h",
    "content": "//\n//  FBNContentSizeProvider.h\n//  FBNotifications\n//\n//  Created by Nikita Lutsenko on 5/20/16.\n//  Copyright © 2016 Facebook Inc. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n#import <UIKit/UIKit.h>\n\n@protocol FBNContentSizeProvider <NSObject>\n\n- (CGSize)contentSizeThatFitsParentContainerSize:(CGSize)fitSize;\n\n@end\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Views/Components/FBNCardDismissButton.h",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As withany software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import <UIKit/UIKit.h>\n\n@interface FBNCardDismissButton : UIButton\n\n@property (nonatomic, strong) UIColor *imageColor;\n\n@end\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Views/Components/FBNCardDismissButton.m",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import \"FBNCardDismissButton.h\"\n\n#import \"FBNCardViewUtilities.h\"\n\nstatic const CGFloat FBNCardDismissButtonEdgeLength = 16.0;\nstatic const CGFloat FBNCardDismissButtonLineWidth = 2.0;\n\n@implementation FBNCardDismissButton\n\n///--------------------------------------\n#pragma mark - Accessors\n///--------------------------------------\n\n- (void)setImageColor:(UIColor *)imageColor {\n    if (self.imageColor != imageColor) {\n        _imageColor = imageColor;\n        [self setImage:[[self class] _imageWithColor:imageColor] forState:UIControlStateNormal];\n    }\n}\n\n///--------------------------------------\n#pragma mark - UIView\n///--------------------------------------\n\n- (CGSize)sizeThatFits:(CGSize)boundingSize {\n    CGSize size = CGSizeZero;\n    size.width = MIN(FBNCardDismissButtonEdgeLength, boundingSize.width);\n    size.height = MIN(FBNCardDismissButtonEdgeLength, boundingSize.height);\n    return size;\n}\n\n- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {\n    CGFloat edgeInset = CGRectGetWidth(self.bounds) - 44.0f;\n    CGRect bigBounds = CGRectInset(self.bounds, edgeInset, edgeInset);\n    return CGRectContainsPoint(bigBounds, point);\n}\n\n///--------------------------------------\n#pragma mark - Default\n///--------------------------------------\n\n+ (UIImage *)_imageWithColor:(UIColor *)color {\n    CGRect imageRect = FBNRectMakeWithOriginSize(CGPointZero, CGSizeMake(FBNCardDismissButtonEdgeLength, FBNCardDismissButtonEdgeLength));\n\n    UIGraphicsBeginImageContextWithOptions(imageRect.size, NO, 0.0f);\n\n    [color setStroke];\n\n    UIBezierPath *path = [UIBezierPath bezierPath];\n\n    [path moveToPoint:CGPointZero];\n    [path addLineToPoint:CGPointMake(CGRectGetMaxX(imageRect), CGRectGetMaxY(imageRect))];\n\n    [path moveToPoint:CGPointMake(CGRectGetMaxX(imageRect), CGRectGetMinY(imageRect))];\n    [path addLineToPoint:CGPointMake(CGRectGetMinX(imageRect), CGRectGetMaxY(imageRect))];\n\n    path.lineWidth = FBNCardDismissButtonLineWidth;\n\n    [path stroke];\n\n    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();\n    UIGraphicsEndImageContext();\n\n    return image;\n}\n\n@end\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Views/Components/FBNCardLabel.h",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import <UIKit/UIKit.h>\n\n@class FBNCardTextContent;\n\n@interface FBNCardLabel : UILabel\n\n+ (instancetype)labelFromTextContent:(FBNCardTextContent *)content;\n\n@end\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Views/Components/FBNCardLabel.m",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import \"FBNCardLabel.h\"\n\n#import \"FBNCardTextContent.h\"\n#import \"FBNCardViewUtilities.h\"\n\n@implementation FBNCardLabel\n\n///--------------------------------------\n#pragma mark - Init\n///--------------------------------------\n\n+ (instancetype)labelFromTextContent:(FBNCardTextContent *)content {\n    FBNCardLabel *label = [[self alloc] initWithFrame:CGRectZero];\n    label.textColor = content.textColor;\n    label.textAlignment = content.textAlignment;\n    label.attributedText = content.attributedText;\n    label.numberOfLines = 0;\n    label.lineBreakMode = NSLineBreakByWordWrapping;\n    return label;\n}\n\n///--------------------------------------\n#pragma mark - UIView\n///--------------------------------------\n\n- (CGSize)sizeThatFits:(CGSize)size {\n    // This is required to accommodate for UILabel behavior, where it returns size bigger than the fit size.\n    return FBNSizeMin([super sizeThatFits:size], size);\n}\n\n@end\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Views/FBNCardActionButton.h",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import <UIKit/UIKit.h>\n\n#import \"FBNCardButtonAction.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class FBNCardActionConfiguration;\n\n@interface FBNCardActionButton : UIButton\n\n@property (nonatomic, strong, readonly) FBNCardActionConfiguration *configuration;\n@property (nonatomic, assign, readonly) FBNCardButtonAction action;\n\n+ (instancetype)buttonFromConfiguration:(FBNCardActionConfiguration *)configuration\n                       withCornerRadius:(CGFloat)cornerRadius\n                                 action:(FBNCardButtonAction)action;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Views/FBNCardActionButton.m",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import \"FBNCardActionButton.h\"\n\n#import \"FBNCardActionConfiguration.h\"\n#import \"FBNCardBackground.h\"\n#import \"FBNCardTextContent.h\"\n\n@implementation FBNCardActionButton\n\n- (instancetype)initWithConfiguration:(FBNCardActionConfiguration *)configuration\n                         cornerRadius:(CGFloat)cornerRadius\n                               action:(FBNCardButtonAction)action {\n    self = [super initWithFrame:CGRectZero];\n    if (!self) return self;\n\n    _configuration = configuration;\n    _action = action;\n\n    self.clipsToBounds = YES;\n    self.layer.cornerRadius = cornerRadius;\n\n    [self setAttributedTitle:configuration.content.attributedText forState:UIControlStateNormal];\n\n    if (configuration.backgroundColor) {\n        [self setBackgroundImage:FBNCardBackgroundImageWithColor(configuration.backgroundColor) forState:UIControlStateNormal];\n    }\n    if (configuration.borderColor) {\n        self.layer.borderColor = configuration.borderColor.CGColor;\n        self.layer.borderWidth = configuration.borderWidth;\n    }\n\n    return self;\n}\n\n+ (instancetype)buttonFromConfiguration:(FBNCardActionConfiguration *)configuration\n                       withCornerRadius:(CGFloat)cornerRadius\n                                 action:(FBNCardButtonAction)action {\n    return [[self alloc] initWithConfiguration:configuration cornerRadius:cornerRadius action:action];\n}\n\n@end\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Views/FBNCardActionsViewController.h",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import <UIKit/UIKit.h>\n\n#import \"FBNContentSizeProvider.h\"\n#import \"FBNCardButtonAction.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class FBNAssetsController;\n@class FBNCardActionsConfiguration;\n@class FBNCardActionsViewController;\n\n@protocol FBNCardActionsViewControllerDelegate <NSObject>\n\n- (void)actionsViewController:(FBNCardActionsViewController *)viewController\n       didPerformButtonAction:(FBNCardButtonAction)action\n                  withOpenURL:(nullable NSURL *)url;\n\n@end\n\n@interface FBNCardActionsViewController : UIViewController <FBNContentSizeProvider>\n\n@property (nonatomic, weak) id<FBNCardActionsViewControllerDelegate> delegate;\n\n- (instancetype)initWithAssetsController:(FBNAssetsController *)assetsController\n                           configuration:(FBNCardActionsConfiguration *)configuration;\n\n@end\n\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Views/FBNCardActionsViewController.m",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import \"FBNCardActionsViewController.h\"\n\n#import \"FBNAssetsController.h\"\n#import \"FBNCardActionsConfiguration.h\"\n#import \"FBNCardActionConfiguration.h\"\n#import \"FBNCardActionButton.h\"\n#import \"FBNCardViewUtilities.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface FBNCardActionsViewController ()\n\n@property (nonatomic, strong, readonly) FBNAssetsController *assetsController;\n@property (nonatomic, strong, readonly) FBNCardActionsConfiguration *configuration;\n\n@property (nullable, nonatomic, strong) UIViewController <FBNContentSizeProvider> *backgroundViewController;\n@property (nullable, nonatomic, copy) NSArray<FBNCardActionButton *> *actionButtons;\n\n@end\n\n@implementation FBNCardActionsViewController\n\n///--------------------------------------\n#pragma mark - Init/Dealloc\n///--------------------------------------\n\n- (instancetype)initWithAssetsController:(FBNAssetsController *)assetsController\n                           configuration:(FBNCardActionsConfiguration *)configuration {\n    self = [super init];\n    if (!self) return self;\n\n    _assetsController = assetsController;\n    _configuration = configuration;\n\n    return self;\n}\n\n- (void)dealloc {\n    for (FBNCardActionButton *button in self.actionButtons) {\n        [button removeTarget:nil action:NULL forControlEvents:UIControlEventAllEvents];\n    }\n}\n\n///--------------------------------------\n#pragma mark - View\n///--------------------------------------\n\n- (void)viewDidLoad {\n    [super viewDidLoad];\n\n    id<FBNAsset> background = self.configuration.background;\n    if (background) {\n        self.backgroundViewController = [self.assetsController viewControllerForAsset:background];\n        [self addChildViewController:self.backgroundViewController];\n        [self.view addSubview:self.backgroundViewController.view];\n        [self.backgroundViewController didMoveToParentViewController:self];\n    }\n\n    self.actionButtons = [[self class] _actionButtonsFromConfiguration:self.configuration];\n    for (FBNCardActionButton *button in self.actionButtons) {\n        [button addTarget:self action:@selector(_buttonAction:) forControlEvents:UIControlEventTouchUpInside];\n        [self.view addSubview:button];\n    }\n}\n\n///--------------------------------------\n#pragma mark - Layout\n///--------------------------------------\n\n- (void)viewDidLayoutSubviews {\n    [super viewDidLayoutSubviews];\n\n    const CGRect bounds = self.view.bounds;\n\n    self.backgroundViewController.view.frame = bounds;\n\n    CGSize buttonSize = { .width = 0.0f, .height = self.configuration.height };\n    switch (self.configuration.layoutStyle) {\n        case FBNCardActionsLayoutStyleHorizontal: {\n            if (self.configuration.style == FBNCardActionsStyleAttached) {\n                buttonSize.width = CGRectGetWidth(bounds) - self.configuration.contentInset * (self.actionButtons.count + 1); // Left + Right + Inter-button\n            } else {\n                buttonSize.width = CGRectGetWidth(bounds) - self.configuration.contentInset * (self.actionButtons.count - 1); // Inter-button only\n            }\n            buttonSize.width /= self.actionButtons.count;\n        } break;\n        case FBNCardActionsLayoutStyleVertical: {\n            if (self.configuration.style == FBNCardActionsStyleAttached) {\n                buttonSize.width = CGRectGetWidth(bounds) - (self.configuration.contentInset * 2); // Left + Right\n            } else {\n                buttonSize.width = CGRectGetWidth(bounds);\n            }\n        } break;\n        default:break;\n    }\n\n    CGPoint buttonOrigin = { .x = 0.0f, .y = self.configuration.topInset };\n    CGRect buttonFrame = FBNRectAdjustToScreenScale(FBNRectMakeWithOriginSize(buttonOrigin, buttonSize), NSRoundUp);\n\n    if (self.configuration.style == FBNCardActionsStyleAttached) {\n        buttonFrame.origin.x = self.configuration.contentInset;\n    }\n\n    for (FBNCardActionButton *button in self.actionButtons) {\n        button.frame = FBNRectAdjustToScreenScale(buttonFrame, NSRoundUp);\n\n        switch (self.configuration.layoutStyle) {\n            case FBNCardActionsLayoutStyleHorizontal: {\n                buttonFrame.origin.x = CGRectGetMaxX(buttonFrame) + self.configuration.contentInset; // Previous button + Inset\n            } break;\n            case FBNCardActionsLayoutStyleVertical: {\n                buttonFrame.origin.y = CGRectGetMaxY(buttonFrame) + self.configuration.contentInset; // Previous button + Inset\n            } break;\n            default:break;\n        }\n    }\n}\n\n///--------------------------------------\n#pragma mark - FBNContentSizeProvider\n///--------------------------------------\n\n- (CGSize)contentSizeThatFitsParentContainerSize:(CGSize)fitSize {\n    CGSize size = CGSizeMake(fitSize.width, self.configuration.topInset);\n    switch (self.configuration.layoutStyle) {\n        case FBNCardActionsLayoutStyleVertical: {\n            size.height += self.configuration.height * self.actionButtons.count; // All the buttons\n            size.height += self.configuration.contentInset * self.actionButtons.count; // Inter-button + Bottom\n        } break;\n        case FBNCardActionsLayoutStyleHorizontal: {\n            size.height += self.configuration.height; // Single button\n            size.height += self.configuration.contentInset; // Bottom inset\n        } break;\n        default: break;\n    }\n    return FBNSizeAdjustToScreenScale(size, NSRoundUp);\n}\n\n///--------------------------------------\n#pragma mark - Buttons\n///--------------------------------------\n\n+ (NSArray<FBNCardActionButton *> *)_actionButtonsFromConfiguration:(FBNCardActionsConfiguration *)configuration {\n    NSMutableArray<FBNCardActionButton *> *actionButtons = [NSMutableArray arrayWithCapacity:configuration.actions.count];\n    FBNCardButtonAction buttonAction = FBNCardButtonActionPrimary;\n    for (FBNCardActionConfiguration *actionConfiguration in configuration.actions) {\n        FBNCardActionButton *button = nil;\n        if (actionConfiguration.actionURL != nil) {\n            button = [FBNCardActionButton buttonFromConfiguration:actionConfiguration\n                                                 withCornerRadius:configuration.cornerRadius\n                                                           action:buttonAction];\n            if (buttonAction == FBNCardButtonActionPrimary) {\n                buttonAction = FBNCardButtonActionSecondary;\n            }\n        } else {\n            button = [FBNCardActionButton buttonFromConfiguration:actionConfiguration\n                                                 withCornerRadius:configuration.cornerRadius\n                                                           action:FBNCardButtonActionDismiss];\n        }\n        [actionButtons addObject:button];\n    }\n    return actionButtons;\n}\n\n- (void)_buttonAction:(FBNCardActionButton *)button {\n    [self.delegate actionsViewController:self didPerformButtonAction:button.action withOpenURL:button.configuration.actionURL];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Views/FBNCardBodyViewController.h",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import <UIKit/UIKit.h>\n\n#import \"FBNContentSizeProvider.h\"\n\n@class FBNAssetsController;\n@class FBNCardBodyConfiguration;\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface FBNCardBodyViewController : UIViewController <FBNContentSizeProvider>\n\n- (instancetype)initWithAssetsController:(FBNAssetsController *)controller\n                           configuration:(FBNCardBodyConfiguration *)configuration\n                            contentInset:(CGFloat)contentInset;\n\n- (instancetype)initWithCoder:(NSCoder *)aDecoder NS_UNAVAILABLE;\n- (instancetype)initWithNibName:(nullable NSString *)nibNameOrNil bundle:(nullable NSBundle *)nibBundleOrNil NS_UNAVAILABLE;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Views/FBNCardBodyViewController.m",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import \"FBNCardBodyViewController.h\"\n\n#import \"FBNAssetsController.h\"\n#import \"FBNCardBodyConfiguration.h\"\n#import \"FBNCardTextContent.h\"\n#import \"FBNCardLabel.h\"\n#import \"FBNCardViewUtilities.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface FBNCardBodyViewController ()\n\n@property (nonatomic, strong, readonly) FBNAssetsController *assetsController;\n@property (nonatomic, strong, readonly) FBNCardBodyConfiguration *configuration;\n@property (nonatomic, assign, readonly) CGFloat contentInset;\n\n@property (nullable, nonatomic, strong) UIViewController <FBNContentSizeProvider> *backgroundViewController;\n@property (nullable, nonatomic, strong) UILabel *textLabel;\n\n@end\n\n@implementation FBNCardBodyViewController\n\n///--------------------------------------\n#pragma mark - Init\n///--------------------------------------\n\n- (instancetype)initWithAssetsController:(FBNAssetsController *)controller\n                           configuration:(FBNCardBodyConfiguration *)configuration\n                            contentInset:(CGFloat)contentInset {\n    self = [super init];\n    if (!self) return self;\n\n    _assetsController = controller;\n    _configuration = configuration;\n    _contentInset = contentInset;\n\n    return self;\n}\n\n///--------------------------------------\n#pragma mark - View\n///--------------------------------------\n\n- (void)loadView {\n    [super loadView];\n\n    self.view.clipsToBounds = YES;\n}\n\n- (void)viewDidLoad {\n    [super viewDidLoad];\n\n\n    id<FBNAsset> background = self.configuration.background;\n    if (background) {\n        self.backgroundViewController = [self.assetsController viewControllerForAsset:background];\n        [self addChildViewController:self.backgroundViewController];\n        [self.view addSubview:self.backgroundViewController.view];\n        [self.backgroundViewController didMoveToParentViewController:self];\n    }\n\n    if (self.configuration.content) {\n        self.textLabel = [FBNCardLabel labelFromTextContent:self.configuration.content];\n        [self.view addSubview:self.textLabel];\n    }\n}\n\n///--------------------------------------\n#pragma mark - Layout\n///--------------------------------------\n\n- (void)viewDidLayoutSubviews {\n    [super viewDidLayoutSubviews];\n\n    const CGRect bounds = self.view.bounds;\n\n    self.backgroundViewController.view.frame = bounds;\n\n    CGRect contentBounds = CGRectInset(bounds, self.contentInset, self.contentInset);\n    self.textLabel.frame = FBNRectAdjustToScreenScale(FBNRectMakeWithSizeCenteredInRect(contentBounds.size, bounds), NSRoundUp);\n    self.textLabel.frame = CGRectIntegral(self.textLabel.frame);\n}\n\n///--------------------------------------\n#pragma mark - FBNContentSizeProvider\n///--------------------------------------\n\n- (CGSize)contentSizeThatFitsParentContainerSize:(CGSize)fitSize {\n    fitSize.width -= self.contentInset * 2;\n    fitSize.height -= self.contentInset * 2;\n\n    CGSize size = [self.textLabel sizeThatFits:fitSize];\n    size.width += self.contentInset * 2;\n    size.height += self.contentInset * 2;\n    return FBNSizeAdjustToScreenScale(size, NSRoundUp);\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Views/FBNCardHeroViewController.h",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import <UIKit/UIKit.h>\n\n#import \"FBNContentSizeProvider.h\"\n\n@class FBNAssetsController;\n@class FBNCardHeroConfiguration;\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface FBNCardHeroViewController : UIViewController <FBNContentSizeProvider>\n\n- (instancetype)initWithAssetsController:(FBNAssetsController *)assetsController\n                           configuration:(FBNCardHeroConfiguration *)configuration\n                            contentInset:(CGFloat)contentInset NS_DESIGNATED_INITIALIZER;\n\n- (instancetype)initWithCoder:(NSCoder *)aDecoder NS_UNAVAILABLE;\n- (instancetype)initWithNibName:(nullable NSString *)nibNameOrNil bundle:(nullable NSBundle *)nibBundleOrNil NS_UNAVAILABLE;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Internal/Views/FBNCardHeroViewController.m",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import \"FBNCardHeroViewController.h\"\n\n#import \"FBNAssetsController.h\"\n#import \"FBNCardHeroConfiguration.h\"\n#import \"FBNCardViewUtilities.h\"\n#import \"FBNCardLabel.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface FBNCardHeroViewController ()\n\n@property (nonatomic, strong, readonly) FBNAssetsController *assetsController;\n@property (nonatomic, strong, readonly) FBNCardHeroConfiguration *configuration;\n@property (nonatomic, assign, readonly) CGFloat contentInset;\n\n@property (nullable, nonatomic, strong) UIViewController <FBNContentSizeProvider> *backgroundViewController;\n@property (nullable, nonatomic, strong) UILabel *textLabel;\n\n@end\n\n@implementation FBNCardHeroViewController\n\n///--------------------------------------\n#pragma mark - Init\n///--------------------------------------\n\n- (instancetype)initWithAssetsController:(FBNAssetsController *)assetsController\n                           configuration:(FBNCardHeroConfiguration *)configuration\n                            contentInset:(CGFloat)contentInset {\n    self = [super initWithNibName:nil bundle:nil];\n    if (!self) return self;\n\n    _assetsController = assetsController;\n    _configuration = configuration;\n    _contentInset = contentInset;\n\n    return self;\n}\n\n///--------------------------------------\n#pragma mark - Layout\n///--------------------------------------\n\n- (void)loadView {\n    [super loadView];\n\n    self.view.clipsToBounds = YES;\n}\n\n- (void)viewDidLoad {\n    [super viewDidLoad];\n\n    id<FBNAsset> background = self.configuration.background;\n    if (background) {\n        self.backgroundViewController = [self.assetsController viewControllerForAsset:background];\n        [self addChildViewController:self.backgroundViewController];\n        [self.view addSubview:self.backgroundViewController.view];\n        [self.backgroundViewController didMoveToParentViewController:self];\n    }\n\n    if (self.configuration.content) {\n        self.textLabel = [FBNCardLabel labelFromTextContent:self.configuration.content];\n        [self.view addSubview:self.textLabel];\n    }\n}\n\n- (void)viewWillLayoutSubviews {\n    [super viewWillLayoutSubviews];\n\n    const CGRect bounds = self.view.bounds;\n\n    self.backgroundViewController.view.frame = bounds;\n\n    CGRect contentBounds = CGRectInset(bounds, self.contentInset, self.contentInset);\n\n    const CGSize textLabelSize = CGSizeMake(CGRectGetWidth(contentBounds), [self.textLabel sizeThatFits:contentBounds.size].height);\n    CGRect textLabelFrame = CGRectZero;\n    switch (self.configuration.contentVerticalAlignment) {\n        case FBNCardContentVerticalAlignmentTop: {\n            textLabelFrame = FBNRectMakeWithOriginSize(CGPointMake(self.contentInset, self.contentInset), textLabelSize);\n        } break;\n        case FBNCardContentVerticalAlignmentCenter: {\n            textLabelFrame = FBNRectMakeWithSizeCenteredInRect(textLabelSize, contentBounds);\n        } break;\n        case FBNCardContentVerticalAlignmentBottom: {\n            CGPoint origin = CGPointMake(self.contentInset, CGRectGetMaxY(contentBounds) - textLabelSize.height);\n            textLabelFrame = FBNRectMakeWithOriginSize(origin, textLabelSize);\n        } break;\n        default:break;\n    }\n\n    self.textLabel.frame = textLabelFrame;\n}\n\n///--------------------------------------\n#pragma mark - FBNContentSizeProvider\n///--------------------------------------\n\n- (CGSize)contentSizeThatFitsParentContainerSize:(CGSize)fitSize {\n    CGSize labelFitSize = fitSize;\n    labelFitSize.width -= self.contentInset * 2;\n    labelFitSize.height -= self.contentInset * 2;\n\n    CGSize textSize = [self.textLabel sizeThatFits:labelFitSize];\n    if (self.textLabel.text.length > 0) {\n        textSize.width += self.contentInset * 2;\n        textSize.height += self.contentInset * 2;\n    }\n\n    CGSize imageSize = [self.backgroundViewController contentSizeThatFitsParentContainerSize:fitSize];\n    if (imageSize.width != 0 && imageSize.height != 0) {\n        CGFloat imageScale = FBNAspectFillScaleThatFits(imageSize, fitSize);\n        imageSize.width *= imageScale;\n        imageSize.height *= imageScale;\n    }\n\n    CGSize size = FBNSizeMax(textSize, imageSize);\n    return FBNSizeAdjustToScreenScale(size, NSRoundUp);\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications/Resources/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>FMWK</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0.1</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>1.0.1</string>\n\t<key>NSPrincipalClass</key>\n\t<string></string>\n</dict>\n</plist>\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t0699F2131CF038750076241D /* FBNColorAssetViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 0699F2111CF038750076241D /* FBNColorAssetViewController.h */; };\n\t\t0699F2141CF038750076241D /* FBNColorAssetViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 0699F2111CF038750076241D /* FBNColorAssetViewController.h */; };\n\t\t0699F2151CF038750076241D /* FBNColorAssetViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0699F2121CF038750076241D /* FBNColorAssetViewController.m */; };\n\t\t0699F2161CF038750076241D /* FBNColorAssetViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0699F2121CF038750076241D /* FBNColorAssetViewController.m */; };\n\t\t0699F21F1CF039A30076241D /* FBNImageAssetViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 0699F21D1CF039A30076241D /* FBNImageAssetViewController.h */; };\n\t\t0699F2201CF039A30076241D /* FBNImageAssetViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 0699F21D1CF039A30076241D /* FBNImageAssetViewController.h */; };\n\t\t0699F2211CF039A30076241D /* FBNImageAssetViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0699F21E1CF039A30076241D /* FBNImageAssetViewController.m */; };\n\t\t0699F2221CF039A30076241D /* FBNImageAssetViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0699F21E1CF039A30076241D /* FBNImageAssetViewController.m */; };\n\t\t0699F2251CF03A9A0076241D /* FBNIGIFAssetViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 0699F2231CF03A9A0076241D /* FBNIGIFAssetViewController.h */; };\n\t\t0699F2261CF03A9A0076241D /* FBNIGIFAssetViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 0699F2231CF03A9A0076241D /* FBNIGIFAssetViewController.h */; };\n\t\t0699F2271CF03A9A0076241D /* FBNIGIFAssetViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0699F2241CF03A9A0076241D /* FBNIGIFAssetViewController.m */; };\n\t\t0699F2281CF03A9A0076241D /* FBNIGIFAssetViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0699F2241CF03A9A0076241D /* FBNIGIFAssetViewController.m */; };\n\t\t06DCCB081CF02F4600E2A0AF /* FBNContentSizeProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = 06DCCB071CF02F4600E2A0AF /* FBNContentSizeProvider.h */; };\n\t\t06DCCB091CF02F4600E2A0AF /* FBNContentSizeProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = 06DCCB071CF02F4600E2A0AF /* FBNContentSizeProvider.h */; };\n\t\t811E17161CB75034009AAE22 /* FBNCardActionConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 81A494BE1CA9CB1B00201C4B /* FBNCardActionConfiguration.m */; };\n\t\t811E17171CB75034009AAE22 /* FBNConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 815BAE791C59653600D79E1A /* FBNConstants.m */; };\n\t\t811E17181CB75034009AAE22 /* FBNCardViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 815BAE7D1C59653600D79E1A /* FBNCardViewController.m */; };\n\t\t811E17191CB75034009AAE22 /* FBNCardDismissButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 815BAEAF1C59653600D79E1A /* FBNCardDismissButton.m */; };\n\t\t811E171A1CB75034009AAE22 /* FBNCardTextAlignment.m in Sources */ = {isa = PBXBuildFile; fileRef = 81A494D61CA9CB1B00201C4B /* FBNCardTextAlignment.m */; };\n\t\t811E171B1CB75034009AAE22 /* FBNColorAsset.m in Sources */ = {isa = PBXBuildFile; fileRef = 81EF49DE1C6C098B0074B2B4 /* FBNColorAsset.m */; };\n\t\t811E171C1CB75034009AAE22 /* FBNCardTextContent.m in Sources */ = {isa = PBXBuildFile; fileRef = 81A494D81CA9CB1B00201C4B /* FBNCardTextContent.m */; };\n\t\t811E171D1CB75034009AAE22 /* FBNCardPayload.m in Sources */ = {isa = PBXBuildFile; fileRef = 815BAEA91C59653600D79E1A /* FBNCardPayload.m */; };\n\t\t811E171E1CB75034009AAE22 /* FBNImageAssetController.m in Sources */ = {isa = PBXBuildFile; fileRef = 81EF4A311C6C159B0074B2B4 /* FBNImageAssetController.m */; };\n\t\t811E171F1CB75034009AAE22 /* FBNCardError.m in Sources */ = {isa = PBXBuildFile; fileRef = 815BAEA51C59653600D79E1A /* FBNCardError.m */; };\n\t\t811E17201CB75034009AAE22 /* FBNCardBodyConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 81A494C51CA9CB1B00201C4B /* FBNCardBodyConfiguration.m */; };\n\t\t811E17211CB75034009AAE22 /* FBNCardActionsStyle.m in Sources */ = {isa = PBXBuildFile; fileRef = 81A494C21CA9CB1B00201C4B /* FBNCardActionsStyle.m */; };\n\t\t811E17221CB75034009AAE22 /* FBNAssetContentCacheOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 81EF4A641C6C273F0074B2B4 /* FBNAssetContentCacheOperation.m */; };\n\t\t811E17231CB75034009AAE22 /* FBNAnimatedImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 81A494CD1CA9CB1B00201C4B /* FBNAnimatedImage.m */; };\n\t\t811E17241CB75034009AAE22 /* FBNCardActionsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 815BAEB61C59653600D79E1A /* FBNCardActionsViewController.m */; };\n\t\t811E17251CB75034009AAE22 /* FBNCardSize.m in Sources */ = {isa = PBXBuildFile; fileRef = 81A495071CA9CC2900201C4B /* FBNCardSize.m */; };\n\t\t811E17261CB75034009AAE22 /* FBNCardHeroViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 815BAEBA1C59653600D79E1A /* FBNCardHeroViewController.m */; };\n\t\t811E17271CB75034009AAE22 /* FBNCardAppEventsLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 815BAE821C59653600D79E1A /* FBNCardAppEventsLogger.m */; };\n\t\t811E17281CB75034009AAE22 /* FBNCardActionButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 815BAEB31C59653600D79E1A /* FBNCardActionButton.m */; };\n\t\t811E17291CB75034009AAE22 /* FBNCardLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = 815BAEB11C59653600D79E1A /* FBNCardLabel.m */; };\n\t\t811E172A1CB75034009AAE22 /* FBNCardHeroConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 81A494DB1CA9CB1B00201C4B /* FBNCardHeroConfiguration.m */; };\n\t\t811E172B1CB75034009AAE22 /* FBNCardViewUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 815BAEAB1C59653600D79E1A /* FBNCardViewUtilities.m */; };\n\t\t811E172C1CB75034009AAE22 /* FBNCardBodyViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 815BAEB81C59653600D79E1A /* FBNCardBodyViewController.m */; };\n\t\t811E172D1CB75034009AAE22 /* FBNCardConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 81A494C81CA9CB1B00201C4B /* FBNCardConfiguration.m */; };\n\t\t811E172E1CB75034009AAE22 /* FBNImageAsset.m in Sources */ = {isa = PBXBuildFile; fileRef = 81EF49E71C6C098B0074B2B4 /* FBNImageAsset.m */; };\n\t\t811E172F1CB75034009AAE22 /* FBNGIFAsset.m in Sources */ = {isa = PBXBuildFile; fileRef = 81EF49E41C6C098B0074B2B4 /* FBNGIFAsset.m */; };\n\t\t811E17301CB75034009AAE22 /* FBNCardBackground.m in Sources */ = {isa = PBXBuildFile; fileRef = 81A494CF1CA9CB1B00201C4B /* FBNCardBackground.m */; };\n\t\t811E17311CB75034009AAE22 /* FBNColorAssetController.m in Sources */ = {isa = PBXBuildFile; fileRef = 81EF4A161C6C0CF40074B2B4 /* FBNColorAssetController.m */; };\n\t\t811E17321CB75034009AAE22 /* FBNAssetsController.m in Sources */ = {isa = PBXBuildFile; fileRef = 81EF4A051C6C0A420074B2B4 /* FBNAssetsController.m */; };\n\t\t811E17331CB75034009AAE22 /* FBNCardHash.m in Sources */ = {isa = PBXBuildFile; fileRef = 815BAEA71C59653600D79E1A /* FBNCardHash.m */; };\n\t\t811E17341CB75034009AAE22 /* FBNCardActionsConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 81A494C01CA9CB1B00201C4B /* FBNCardActionsConfiguration.m */; };\n\t\t811E17351CB75034009AAE22 /* FBNCardColor.m in Sources */ = {isa = PBXBuildFile; fileRef = 81A494D11CA9CB1B00201C4B /* FBNCardColor.m */; };\n\t\t811E17361CB75034009AAE22 /* FBNGIFAssetController.m in Sources */ = {isa = PBXBuildFile; fileRef = 81EF4A3D1C6C18F30074B2B4 /* FBNGIFAssetController.m */; };\n\t\t811E17371CB75034009AAE22 /* FBNAssetContentCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 81EF4A621C6C273F0074B2B4 /* FBNAssetContentCache.m */; };\n\t\t811E17381CB75034009AAE22 /* FBNotificationsManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 815BAE7B1C59653600D79E1A /* FBNotificationsManager.m */; };\n\t\t811E173B1CB75034009AAE22 /* FBNAssetsController.h in Headers */ = {isa = PBXBuildFile; fileRef = 81EF4A041C6C0A420074B2B4 /* FBNAssetsController.h */; };\n\t\t811E173C1CB75034009AAE22 /* FBNColorAssetController.h in Headers */ = {isa = PBXBuildFile; fileRef = 81EF4A151C6C0CF40074B2B4 /* FBNColorAssetController.h */; };\n\t\t811E173D1CB75034009AAE22 /* FBNCardLabel.h in Headers */ = {isa = PBXBuildFile; fileRef = 815BAEB01C59653600D79E1A /* FBNCardLabel.h */; };\n\t\t811E173E1CB75034009AAE22 /* FBNGIFAsset.h in Headers */ = {isa = PBXBuildFile; fileRef = 81EF49E31C6C098B0074B2B4 /* FBNGIFAsset.h */; };\n\t\t811E173F1CB75034009AAE22 /* FBNAssetContentCacheOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 81EF4A631C6C273F0074B2B4 /* FBNAssetContentCacheOperation.h */; };\n\t\t811E17401CB75034009AAE22 /* FBNCardTextAlignment.h in Headers */ = {isa = PBXBuildFile; fileRef = 81A494D51CA9CB1B00201C4B /* FBNCardTextAlignment.h */; };\n\t\t811E17411CB75034009AAE22 /* FBNAssetContentCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 81EF4A611C6C273F0074B2B4 /* FBNAssetContentCache.h */; };\n\t\t811E17421CB75034009AAE22 /* FBNCardBodyConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 81A494C41CA9CB1B00201C4B /* FBNCardBodyConfiguration.h */; };\n\t\t811E17431CB75034009AAE22 /* FBNCardHeroConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 81A494DA1CA9CB1B00201C4B /* FBNCardHeroConfiguration.h */; };\n\t\t811E17441CB75034009AAE22 /* FBNCardHeroViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 815BAEB91C59653600D79E1A /* FBNCardHeroViewController.h */; };\n\t\t811E17451CB75034009AAE22 /* FBNImageAssetController.h in Headers */ = {isa = PBXBuildFile; fileRef = 81EF4A301C6C159B0074B2B4 /* FBNImageAssetController.h */; };\n\t\t811E17461CB75034009AAE22 /* FBNGIFAssetController.h in Headers */ = {isa = PBXBuildFile; fileRef = 81EF4A3C1C6C18F30074B2B4 /* FBNGIFAssetController.h */; };\n\t\t811E17471CB75034009AAE22 /* FBNCardActionsStyle.h in Headers */ = {isa = PBXBuildFile; fileRef = 81A494C11CA9CB1B00201C4B /* FBNCardActionsStyle.h */; };\n\t\t811E17481CB75034009AAE22 /* FBNCardHash.h in Headers */ = {isa = PBXBuildFile; fileRef = 815BAEA61C59653600D79E1A /* FBNCardHash.h */; };\n\t\t811E17491CB75034009AAE22 /* FBNCardActionButton.h in Headers */ = {isa = PBXBuildFile; fileRef = 815BAEB21C59653600D79E1A /* FBNCardActionButton.h */; };\n\t\t811E174A1CB75034009AAE22 /* FBNCardPayload.h in Headers */ = {isa = PBXBuildFile; fileRef = 815BAEA81C59653600D79E1A /* FBNCardPayload.h */; };\n\t\t811E174B1CB75034009AAE22 /* FBNCardAppEventsLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 815BAE811C59653600D79E1A /* FBNCardAppEventsLogger.h */; };\n\t\t811E174C1CB75034009AAE22 /* FBNConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = 815BAE781C59653600D79E1A /* FBNConstants.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t811E174D1CB75034009AAE22 /* FBNCardViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 815BAE7C1C59653600D79E1A /* FBNCardViewController.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t811E174E1CB75034009AAE22 /* FBNCardSize.h in Headers */ = {isa = PBXBuildFile; fileRef = 81A495061CA9CC2900201C4B /* FBNCardSize.h */; };\n\t\t811E174F1CB75034009AAE22 /* FBNotifications.h in Headers */ = {isa = PBXBuildFile; fileRef = 815BAE771C59653600D79E1A /* FBNotifications.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t811E17501CB75034009AAE22 /* FBNCardViewUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 815BAEAA1C59653600D79E1A /* FBNCardViewUtilities.h */; };\n\t\t811E17511CB75034009AAE22 /* FBNImageAsset.h in Headers */ = {isa = PBXBuildFile; fileRef = 81EF49E61C6C098B0074B2B4 /* FBNImageAsset.h */; };\n\t\t811E17521CB75034009AAE22 /* FBNCardViewController_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 81D632BD1CB3AA6A000921B1 /* FBNCardViewController_Internal.h */; };\n\t\t811E17531CB75034009AAE22 /* FBNotificationsManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 815BAE7A1C59653600D79E1A /* FBNotificationsManager.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t811E17541CB75034009AAE22 /* FBNCardBackground.h in Headers */ = {isa = PBXBuildFile; fileRef = 81A494CE1CA9CB1B00201C4B /* FBNCardBackground.h */; };\n\t\t811E17551CB75034009AAE22 /* FBNColorAsset.h in Headers */ = {isa = PBXBuildFile; fileRef = 81EF49DD1C6C098B0074B2B4 /* FBNColorAsset.h */; };\n\t\t811E17561CB75034009AAE22 /* FBNCardTextContent.h in Headers */ = {isa = PBXBuildFile; fileRef = 81A494D71CA9CB1B00201C4B /* FBNCardTextContent.h */; };\n\t\t811E17571CB75034009AAE22 /* FBNCardButtonAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 81A4950C1CA9CD2D00201C4B /* FBNCardButtonAction.h */; };\n\t\t811E17581CB75034009AAE22 /* FBNCardBodyViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 815BAEB71C59653600D79E1A /* FBNCardBodyViewController.h */; };\n\t\t811E17591CB75034009AAE22 /* FBNCardActionsConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 81A494BF1CA9CB1B00201C4B /* FBNCardActionsConfiguration.h */; };\n\t\t811E175A1CB75034009AAE22 /* FBNAnimatedImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 81A494CC1CA9CB1B00201C4B /* FBNAnimatedImage.h */; };\n\t\t811E175B1CB75034009AAE22 /* FBNAsset.h in Headers */ = {isa = PBXBuildFile; fileRef = 81EF49E01C6C098B0074B2B4 /* FBNAsset.h */; };\n\t\t811E175C1CB75034009AAE22 /* FBNCardError.h in Headers */ = {isa = PBXBuildFile; fileRef = 815BAEA41C59653600D79E1A /* FBNCardError.h */; };\n\t\t811E175D1CB75034009AAE22 /* FBNCardConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 81A494C71CA9CB1B00201C4B /* FBNCardConfiguration.h */; };\n\t\t811E175E1CB75034009AAE22 /* FBNCardDismissButton.h in Headers */ = {isa = PBXBuildFile; fileRef = 815BAEAE1C59653600D79E1A /* FBNCardDismissButton.h */; };\n\t\t811E175F1CB75034009AAE22 /* FBNCardActionsViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 815BAEB51C59653600D79E1A /* FBNCardActionsViewController.h */; };\n\t\t811E17601CB75034009AAE22 /* FBNCardActionConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 81A494BD1CA9CB1B00201C4B /* FBNCardActionConfiguration.h */; };\n\t\t811E17611CB75034009AAE22 /* FBNAssetController.h in Headers */ = {isa = PBXBuildFile; fileRef = 81EF49F61C6C09C20074B2B4 /* FBNAssetController.h */; };\n\t\t811E17621CB75034009AAE22 /* FBNCardColor.h in Headers */ = {isa = PBXBuildFile; fileRef = 81A494D01CA9CB1B00201C4B /* FBNCardColor.h */; };\n\t\t811E17731CB750D2009AAE22 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 811E17721CB750D2009AAE22 /* UIKit.framework */; };\n\t\t811E17761CB750D5009AAE22 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 811E17751CB750D5009AAE22 /* CoreGraphics.framework */; };\n\t\t811E17791CB750DA009AAE22 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 811E17781CB750DA009AAE22 /* MobileCoreServices.framework */; };\n\t\t811E177C1CB750DE009AAE22 /* ImageIO.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 811E177B1CB750DE009AAE22 /* ImageIO.framework */; };\n\t\t811E17931CB844AD009AAE22 /* FBNCardFont.h in Headers */ = {isa = PBXBuildFile; fileRef = 811E17911CB844AD009AAE22 /* FBNCardFont.h */; };\n\t\t811E17941CB844AD009AAE22 /* FBNCardFont.m in Sources */ = {isa = PBXBuildFile; fileRef = 811E17921CB844AD009AAE22 /* FBNCardFont.m */; };\n\t\t815BAEBE1C59653600D79E1A /* FBNotifications.h in Headers */ = {isa = PBXBuildFile; fileRef = 815BAE771C59653600D79E1A /* FBNotifications.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t815BAEBF1C59653600D79E1A /* FBNConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = 815BAE781C59653600D79E1A /* FBNConstants.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t815BAEC01C59653600D79E1A /* FBNConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 815BAE791C59653600D79E1A /* FBNConstants.m */; };\n\t\t815BAEC11C59653600D79E1A /* FBNotificationsManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 815BAE7A1C59653600D79E1A /* FBNotificationsManager.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t815BAEC21C59653600D79E1A /* FBNotificationsManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 815BAE7B1C59653600D79E1A /* FBNotificationsManager.m */; };\n\t\t815BAEC31C59653600D79E1A /* FBNCardViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 815BAE7C1C59653600D79E1A /* FBNCardViewController.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t815BAEC41C59653600D79E1A /* FBNCardViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 815BAE7D1C59653600D79E1A /* FBNCardViewController.m */; };\n\t\t815BAEC61C59653600D79E1A /* FBNCardAppEventsLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 815BAE811C59653600D79E1A /* FBNCardAppEventsLogger.h */; };\n\t\t815BAEC71C59653600D79E1A /* FBNCardAppEventsLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 815BAE821C59653600D79E1A /* FBNCardAppEventsLogger.m */; };\n\t\t815BAEE51C59653600D79E1A /* FBNCardError.h in Headers */ = {isa = PBXBuildFile; fileRef = 815BAEA41C59653600D79E1A /* FBNCardError.h */; };\n\t\t815BAEE61C59653600D79E1A /* FBNCardError.m in Sources */ = {isa = PBXBuildFile; fileRef = 815BAEA51C59653600D79E1A /* FBNCardError.m */; };\n\t\t815BAEE71C59653600D79E1A /* FBNCardHash.h in Headers */ = {isa = PBXBuildFile; fileRef = 815BAEA61C59653600D79E1A /* FBNCardHash.h */; };\n\t\t815BAEE81C59653600D79E1A /* FBNCardHash.m in Sources */ = {isa = PBXBuildFile; fileRef = 815BAEA71C59653600D79E1A /* FBNCardHash.m */; };\n\t\t815BAEE91C59653600D79E1A /* FBNCardPayload.h in Headers */ = {isa = PBXBuildFile; fileRef = 815BAEA81C59653600D79E1A /* FBNCardPayload.h */; };\n\t\t815BAEEA1C59653600D79E1A /* FBNCardPayload.m in Sources */ = {isa = PBXBuildFile; fileRef = 815BAEA91C59653600D79E1A /* FBNCardPayload.m */; };\n\t\t815BAEEB1C59653600D79E1A /* FBNCardViewUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 815BAEAA1C59653600D79E1A /* FBNCardViewUtilities.h */; };\n\t\t815BAEEC1C59653600D79E1A /* FBNCardViewUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 815BAEAB1C59653600D79E1A /* FBNCardViewUtilities.m */; };\n\t\t815BAEED1C59653600D79E1A /* FBNCardDismissButton.h in Headers */ = {isa = PBXBuildFile; fileRef = 815BAEAE1C59653600D79E1A /* FBNCardDismissButton.h */; };\n\t\t815BAEEE1C59653600D79E1A /* FBNCardDismissButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 815BAEAF1C59653600D79E1A /* FBNCardDismissButton.m */; };\n\t\t815BAEEF1C59653600D79E1A /* FBNCardLabel.h in Headers */ = {isa = PBXBuildFile; fileRef = 815BAEB01C59653600D79E1A /* FBNCardLabel.h */; };\n\t\t815BAEF01C59653600D79E1A /* FBNCardLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = 815BAEB11C59653600D79E1A /* FBNCardLabel.m */; };\n\t\t815BAEF11C59653600D79E1A /* FBNCardActionButton.h in Headers */ = {isa = PBXBuildFile; fileRef = 815BAEB21C59653600D79E1A /* FBNCardActionButton.h */; };\n\t\t815BAEF21C59653600D79E1A /* FBNCardActionButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 815BAEB31C59653600D79E1A /* FBNCardActionButton.m */; };\n\t\t815BAEF41C59653600D79E1A /* FBNCardActionsViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 815BAEB51C59653600D79E1A /* FBNCardActionsViewController.h */; };\n\t\t815BAEF51C59653600D79E1A /* FBNCardActionsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 815BAEB61C59653600D79E1A /* FBNCardActionsViewController.m */; };\n\t\t815BAEF61C59653600D79E1A /* FBNCardBodyViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 815BAEB71C59653600D79E1A /* FBNCardBodyViewController.h */; };\n\t\t815BAEF71C59653600D79E1A /* FBNCardBodyViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 815BAEB81C59653600D79E1A /* FBNCardBodyViewController.m */; };\n\t\t815BAEF81C59653600D79E1A /* FBNCardHeroViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 815BAEB91C59653600D79E1A /* FBNCardHeroViewController.h */; };\n\t\t815BAEF91C59653600D79E1A /* FBNCardHeroViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 815BAEBA1C59653600D79E1A /* FBNCardHeroViewController.m */; };\n\t\t816A91ED1CB865A900A5DA85 /* FBNCardFont.m in Sources */ = {isa = PBXBuildFile; fileRef = 811E17921CB844AD009AAE22 /* FBNCardFont.m */; };\n\t\t816A91EF1CB865AC00A5DA85 /* FBNCardFont.h in Headers */ = {isa = PBXBuildFile; fileRef = 811E17911CB844AD009AAE22 /* FBNCardFont.h */; };\n\t\t81A494DC1CA9CB1B00201C4B /* FBNCardActionConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 81A494BD1CA9CB1B00201C4B /* FBNCardActionConfiguration.h */; };\n\t\t81A494DD1CA9CB1B00201C4B /* FBNCardActionConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 81A494BE1CA9CB1B00201C4B /* FBNCardActionConfiguration.m */; };\n\t\t81A494DE1CA9CB1B00201C4B /* FBNCardActionsConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 81A494BF1CA9CB1B00201C4B /* FBNCardActionsConfiguration.h */; };\n\t\t81A494DF1CA9CB1B00201C4B /* FBNCardActionsConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 81A494C01CA9CB1B00201C4B /* FBNCardActionsConfiguration.m */; };\n\t\t81A494E01CA9CB1B00201C4B /* FBNCardActionsStyle.h in Headers */ = {isa = PBXBuildFile; fileRef = 81A494C11CA9CB1B00201C4B /* FBNCardActionsStyle.h */; };\n\t\t81A494E11CA9CB1B00201C4B /* FBNCardActionsStyle.m in Sources */ = {isa = PBXBuildFile; fileRef = 81A494C21CA9CB1B00201C4B /* FBNCardActionsStyle.m */; };\n\t\t81A494E21CA9CB1B00201C4B /* FBNCardBodyConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 81A494C41CA9CB1B00201C4B /* FBNCardBodyConfiguration.h */; };\n\t\t81A494E31CA9CB1B00201C4B /* FBNCardBodyConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 81A494C51CA9CB1B00201C4B /* FBNCardBodyConfiguration.m */; };\n\t\t81A494E41CA9CB1B00201C4B /* FBNCardConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 81A494C71CA9CB1B00201C4B /* FBNCardConfiguration.h */; };\n\t\t81A494E51CA9CB1B00201C4B /* FBNCardConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 81A494C81CA9CB1B00201C4B /* FBNCardConfiguration.m */; };\n\t\t81A494E81CA9CB1B00201C4B /* FBNAnimatedImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 81A494CC1CA9CB1B00201C4B /* FBNAnimatedImage.h */; };\n\t\t81A494E91CA9CB1B00201C4B /* FBNAnimatedImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 81A494CD1CA9CB1B00201C4B /* FBNAnimatedImage.m */; };\n\t\t81A494EA1CA9CB1B00201C4B /* FBNCardBackground.h in Headers */ = {isa = PBXBuildFile; fileRef = 81A494CE1CA9CB1B00201C4B /* FBNCardBackground.h */; };\n\t\t81A494EB1CA9CB1B00201C4B /* FBNCardBackground.m in Sources */ = {isa = PBXBuildFile; fileRef = 81A494CF1CA9CB1B00201C4B /* FBNCardBackground.m */; };\n\t\t81A494EC1CA9CB1B00201C4B /* FBNCardColor.h in Headers */ = {isa = PBXBuildFile; fileRef = 81A494D01CA9CB1B00201C4B /* FBNCardColor.h */; };\n\t\t81A494ED1CA9CB1B00201C4B /* FBNCardColor.m in Sources */ = {isa = PBXBuildFile; fileRef = 81A494D11CA9CB1B00201C4B /* FBNCardColor.m */; };\n\t\t81A494F11CA9CB1B00201C4B /* FBNCardTextAlignment.h in Headers */ = {isa = PBXBuildFile; fileRef = 81A494D51CA9CB1B00201C4B /* FBNCardTextAlignment.h */; };\n\t\t81A494F21CA9CB1B00201C4B /* FBNCardTextAlignment.m in Sources */ = {isa = PBXBuildFile; fileRef = 81A494D61CA9CB1B00201C4B /* FBNCardTextAlignment.m */; };\n\t\t81A494F31CA9CB1B00201C4B /* FBNCardTextContent.h in Headers */ = {isa = PBXBuildFile; fileRef = 81A494D71CA9CB1B00201C4B /* FBNCardTextContent.h */; };\n\t\t81A494F41CA9CB1B00201C4B /* FBNCardTextContent.m in Sources */ = {isa = PBXBuildFile; fileRef = 81A494D81CA9CB1B00201C4B /* FBNCardTextContent.m */; };\n\t\t81A494F51CA9CB1B00201C4B /* FBNCardHeroConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 81A494DA1CA9CB1B00201C4B /* FBNCardHeroConfiguration.h */; };\n\t\t81A494F61CA9CB1B00201C4B /* FBNCardHeroConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 81A494DB1CA9CB1B00201C4B /* FBNCardHeroConfiguration.m */; };\n\t\t81A495081CA9CC2900201C4B /* FBNCardSize.h in Headers */ = {isa = PBXBuildFile; fileRef = 81A495061CA9CC2900201C4B /* FBNCardSize.h */; };\n\t\t81A495091CA9CC2900201C4B /* FBNCardSize.m in Sources */ = {isa = PBXBuildFile; fileRef = 81A495071CA9CC2900201C4B /* FBNCardSize.m */; };\n\t\t81A4950D1CA9CD2D00201C4B /* FBNCardButtonAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 81A4950C1CA9CD2D00201C4B /* FBNCardButtonAction.h */; };\n\t\t81C0361E1CE6A47300D11CF8 /* FBNCardDisplayOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 81C0361C1CE6A47300D11CF8 /* FBNCardDisplayOptions.h */; };\n\t\t81C0361F1CE6A47300D11CF8 /* FBNCardDisplayOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 81C0361C1CE6A47300D11CF8 /* FBNCardDisplayOptions.h */; };\n\t\t81C036201CE6A47300D11CF8 /* FBNCardDisplayOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 81C0361D1CE6A47300D11CF8 /* FBNCardDisplayOptions.m */; };\n\t\t81C036211CE6A47300D11CF8 /* FBNCardDisplayOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 81C0361D1CE6A47300D11CF8 /* FBNCardDisplayOptions.m */; };\n\t\t81D632BE1CB3AA6A000921B1 /* FBNCardViewController_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 81D632BD1CB3AA6A000921B1 /* FBNCardViewController_Internal.h */; };\n\t\t81EF49E81C6C098B0074B2B4 /* FBNColorAsset.h in Headers */ = {isa = PBXBuildFile; fileRef = 81EF49DD1C6C098B0074B2B4 /* FBNColorAsset.h */; };\n\t\t81EF49E91C6C098B0074B2B4 /* FBNColorAsset.m in Sources */ = {isa = PBXBuildFile; fileRef = 81EF49DE1C6C098B0074B2B4 /* FBNColorAsset.m */; };\n\t\t81EF49EA1C6C098B0074B2B4 /* FBNAsset.h in Headers */ = {isa = PBXBuildFile; fileRef = 81EF49E01C6C098B0074B2B4 /* FBNAsset.h */; };\n\t\t81EF49EC1C6C098B0074B2B4 /* FBNGIFAsset.h in Headers */ = {isa = PBXBuildFile; fileRef = 81EF49E31C6C098B0074B2B4 /* FBNGIFAsset.h */; };\n\t\t81EF49ED1C6C098B0074B2B4 /* FBNGIFAsset.m in Sources */ = {isa = PBXBuildFile; fileRef = 81EF49E41C6C098B0074B2B4 /* FBNGIFAsset.m */; };\n\t\t81EF49EE1C6C098B0074B2B4 /* FBNImageAsset.h in Headers */ = {isa = PBXBuildFile; fileRef = 81EF49E61C6C098B0074B2B4 /* FBNImageAsset.h */; };\n\t\t81EF49EF1C6C098B0074B2B4 /* FBNImageAsset.m in Sources */ = {isa = PBXBuildFile; fileRef = 81EF49E71C6C098B0074B2B4 /* FBNImageAsset.m */; };\n\t\t81EF49F81C6C09C20074B2B4 /* FBNAssetController.h in Headers */ = {isa = PBXBuildFile; fileRef = 81EF49F61C6C09C20074B2B4 /* FBNAssetController.h */; };\n\t\t81EF4A061C6C0A420074B2B4 /* FBNAssetsController.h in Headers */ = {isa = PBXBuildFile; fileRef = 81EF4A041C6C0A420074B2B4 /* FBNAssetsController.h */; };\n\t\t81EF4A071C6C0A420074B2B4 /* FBNAssetsController.m in Sources */ = {isa = PBXBuildFile; fileRef = 81EF4A051C6C0A420074B2B4 /* FBNAssetsController.m */; };\n\t\t81EF4A171C6C0CF40074B2B4 /* FBNColorAssetController.h in Headers */ = {isa = PBXBuildFile; fileRef = 81EF4A151C6C0CF40074B2B4 /* FBNColorAssetController.h */; };\n\t\t81EF4A181C6C0CF40074B2B4 /* FBNColorAssetController.m in Sources */ = {isa = PBXBuildFile; fileRef = 81EF4A161C6C0CF40074B2B4 /* FBNColorAssetController.m */; };\n\t\t81EF4A321C6C159B0074B2B4 /* FBNImageAssetController.h in Headers */ = {isa = PBXBuildFile; fileRef = 81EF4A301C6C159B0074B2B4 /* FBNImageAssetController.h */; };\n\t\t81EF4A331C6C159B0074B2B4 /* FBNImageAssetController.m in Sources */ = {isa = PBXBuildFile; fileRef = 81EF4A311C6C159B0074B2B4 /* FBNImageAssetController.m */; };\n\t\t81EF4A3E1C6C18F30074B2B4 /* FBNGIFAssetController.h in Headers */ = {isa = PBXBuildFile; fileRef = 81EF4A3C1C6C18F30074B2B4 /* FBNGIFAssetController.h */; };\n\t\t81EF4A3F1C6C18F30074B2B4 /* FBNGIFAssetController.m in Sources */ = {isa = PBXBuildFile; fileRef = 81EF4A3D1C6C18F30074B2B4 /* FBNGIFAssetController.m */; };\n\t\t81EF4A651C6C273F0074B2B4 /* FBNAssetContentCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 81EF4A611C6C273F0074B2B4 /* FBNAssetContentCache.h */; };\n\t\t81EF4A661C6C273F0074B2B4 /* FBNAssetContentCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 81EF4A621C6C273F0074B2B4 /* FBNAssetContentCache.m */; };\n\t\t81EF4A671C6C273F0074B2B4 /* FBNAssetContentCacheOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 81EF4A631C6C273F0074B2B4 /* FBNAssetContentCacheOperation.h */; };\n\t\t81EF4A681C6C273F0074B2B4 /* FBNAssetContentCacheOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 81EF4A641C6C273F0074B2B4 /* FBNAssetContentCacheOperation.m */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\t0699F2111CF038750076241D /* FBNColorAssetViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBNColorAssetViewController.h; sourceTree = \"<group>\"; };\n\t\t0699F2121CF038750076241D /* FBNColorAssetViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBNColorAssetViewController.m; sourceTree = \"<group>\"; };\n\t\t0699F21D1CF039A30076241D /* FBNImageAssetViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBNImageAssetViewController.h; sourceTree = \"<group>\"; };\n\t\t0699F21E1CF039A30076241D /* FBNImageAssetViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBNImageAssetViewController.m; sourceTree = \"<group>\"; };\n\t\t0699F2231CF03A9A0076241D /* FBNIGIFAssetViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBNIGIFAssetViewController.h; sourceTree = \"<group>\"; };\n\t\t0699F2241CF03A9A0076241D /* FBNIGIFAssetViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBNIGIFAssetViewController.m; sourceTree = \"<group>\"; };\n\t\t06DCCB071CF02F4600E2A0AF /* FBNContentSizeProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBNContentSizeProvider.h; sourceTree = \"<group>\"; };\n\t\t811E17671CB75034009AAE22 /* FBNotifications.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = FBNotifications.framework; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t811E176C1CB7506A009AAE22 /* FBNotifications-iOS-Dynamic.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = \"FBNotifications-iOS-Dynamic.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t811E17721CB750D2009AAE22 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.3.sdk/System/Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; };\n\t\t811E17751CB750D5009AAE22 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.3.sdk/System/Library/Frameworks/CoreGraphics.framework; sourceTree = DEVELOPER_DIR; };\n\t\t811E17781CB750DA009AAE22 /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.3.sdk/System/Library/Frameworks/MobileCoreServices.framework; sourceTree = DEVELOPER_DIR; };\n\t\t811E177B1CB750DE009AAE22 /* ImageIO.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ImageIO.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.3.sdk/System/Library/Frameworks/ImageIO.framework; sourceTree = DEVELOPER_DIR; };\n\t\t811E17911CB844AD009AAE22 /* FBNCardFont.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBNCardFont.h; sourceTree = \"<group>\"; };\n\t\t811E17921CB844AD009AAE22 /* FBNCardFont.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBNCardFont.m; sourceTree = \"<group>\"; };\n\t\t812B7CC41C587CDB00F79BC1 /* FBNotifications-iOS.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = \"FBNotifications-iOS.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t812B7CC61C587CDB00F79BC1 /* Common.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Common.xcconfig; sourceTree = \"<group>\"; };\n\t\t812B7CC81C587CDB00F79BC1 /* iOS.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = iOS.xcconfig; sourceTree = \"<group>\"; };\n\t\t812B7CC91C587CDB00F79BC1 /* OSX.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = OSX.xcconfig; sourceTree = \"<group>\"; };\n\t\t812B7CCA1C587CDB00F79BC1 /* tvOS.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = tvOS.xcconfig; sourceTree = \"<group>\"; };\n\t\t812B7CCB1C587CDB00F79BC1 /* watchOS.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = watchOS.xcconfig; sourceTree = \"<group>\"; };\n\t\t812B7CCD1C587CDB00F79BC1 /* Application.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Application.xcconfig; sourceTree = \"<group>\"; };\n\t\t812B7CCE1C587CDB00F79BC1 /* Framework.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Framework.xcconfig; sourceTree = \"<group>\"; };\n\t\t812B7CCF1C587CDB00F79BC1 /* UnitTest.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = UnitTest.xcconfig; sourceTree = \"<group>\"; };\n\t\t812B7CD11C587CDB00F79BC1 /* Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = \"<group>\"; };\n\t\t812B7CD21C587CDB00F79BC1 /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = \"<group>\"; };\n\t\t812B7CD31C587CDB00F79BC1 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = \"<group>\"; };\n\t\t815BAE771C59653600D79E1A /* FBNotifications.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBNotifications.h; sourceTree = \"<group>\"; };\n\t\t815BAE781C59653600D79E1A /* FBNConstants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBNConstants.h; sourceTree = \"<group>\"; };\n\t\t815BAE791C59653600D79E1A /* FBNConstants.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBNConstants.m; sourceTree = \"<group>\"; };\n\t\t815BAE7A1C59653600D79E1A /* FBNotificationsManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBNotificationsManager.h; sourceTree = \"<group>\"; };\n\t\t815BAE7B1C59653600D79E1A /* FBNotificationsManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBNotificationsManager.m; sourceTree = \"<group>\"; };\n\t\t815BAE7C1C59653600D79E1A /* FBNCardViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBNCardViewController.h; sourceTree = \"<group>\"; };\n\t\t815BAE7D1C59653600D79E1A /* FBNCardViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBNCardViewController.m; sourceTree = \"<group>\"; };\n\t\t815BAE811C59653600D79E1A /* FBNCardAppEventsLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBNCardAppEventsLogger.h; sourceTree = \"<group>\"; };\n\t\t815BAE821C59653600D79E1A /* FBNCardAppEventsLogger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBNCardAppEventsLogger.m; sourceTree = \"<group>\"; };\n\t\t815BAEA41C59653600D79E1A /* FBNCardError.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBNCardError.h; sourceTree = \"<group>\"; };\n\t\t815BAEA51C59653600D79E1A /* FBNCardError.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBNCardError.m; sourceTree = \"<group>\"; };\n\t\t815BAEA61C59653600D79E1A /* FBNCardHash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBNCardHash.h; sourceTree = \"<group>\"; };\n\t\t815BAEA71C59653600D79E1A /* FBNCardHash.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBNCardHash.m; sourceTree = \"<group>\"; };\n\t\t815BAEA81C59653600D79E1A /* FBNCardPayload.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBNCardPayload.h; sourceTree = \"<group>\"; };\n\t\t815BAEA91C59653600D79E1A /* FBNCardPayload.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBNCardPayload.m; sourceTree = \"<group>\"; };\n\t\t815BAEAA1C59653600D79E1A /* FBNCardViewUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBNCardViewUtilities.h; sourceTree = \"<group>\"; };\n\t\t815BAEAB1C59653600D79E1A /* FBNCardViewUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBNCardViewUtilities.m; sourceTree = \"<group>\"; };\n\t\t815BAEAE1C59653600D79E1A /* FBNCardDismissButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBNCardDismissButton.h; sourceTree = \"<group>\"; };\n\t\t815BAEAF1C59653600D79E1A /* FBNCardDismissButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBNCardDismissButton.m; sourceTree = \"<group>\"; };\n\t\t815BAEB01C59653600D79E1A /* FBNCardLabel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBNCardLabel.h; sourceTree = \"<group>\"; };\n\t\t815BAEB11C59653600D79E1A /* FBNCardLabel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBNCardLabel.m; sourceTree = \"<group>\"; };\n\t\t815BAEB21C59653600D79E1A /* FBNCardActionButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBNCardActionButton.h; sourceTree = \"<group>\"; };\n\t\t815BAEB31C59653600D79E1A /* FBNCardActionButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBNCardActionButton.m; sourceTree = \"<group>\"; };\n\t\t815BAEB51C59653600D79E1A /* FBNCardActionsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBNCardActionsViewController.h; sourceTree = \"<group>\"; };\n\t\t815BAEB61C59653600D79E1A /* FBNCardActionsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBNCardActionsViewController.m; sourceTree = \"<group>\"; };\n\t\t815BAEB71C59653600D79E1A /* FBNCardBodyViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBNCardBodyViewController.h; sourceTree = \"<group>\"; };\n\t\t815BAEB81C59653600D79E1A /* FBNCardBodyViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBNCardBodyViewController.m; sourceTree = \"<group>\"; };\n\t\t815BAEB91C59653600D79E1A /* FBNCardHeroViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBNCardHeroViewController.h; sourceTree = \"<group>\"; };\n\t\t815BAEBA1C59653600D79E1A /* FBNCardHeroViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBNCardHeroViewController.m; sourceTree = \"<group>\"; };\n\t\t815BAEBD1C59653600D79E1A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t81A494BD1CA9CB1B00201C4B /* FBNCardActionConfiguration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBNCardActionConfiguration.h; sourceTree = \"<group>\"; };\n\t\t81A494BE1CA9CB1B00201C4B /* FBNCardActionConfiguration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBNCardActionConfiguration.m; sourceTree = \"<group>\"; };\n\t\t81A494BF1CA9CB1B00201C4B /* FBNCardActionsConfiguration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBNCardActionsConfiguration.h; sourceTree = \"<group>\"; };\n\t\t81A494C01CA9CB1B00201C4B /* FBNCardActionsConfiguration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBNCardActionsConfiguration.m; sourceTree = \"<group>\"; };\n\t\t81A494C11CA9CB1B00201C4B /* FBNCardActionsStyle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBNCardActionsStyle.h; sourceTree = \"<group>\"; };\n\t\t81A494C21CA9CB1B00201C4B /* FBNCardActionsStyle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBNCardActionsStyle.m; sourceTree = \"<group>\"; };\n\t\t81A494C41CA9CB1B00201C4B /* FBNCardBodyConfiguration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBNCardBodyConfiguration.h; sourceTree = \"<group>\"; };\n\t\t81A494C51CA9CB1B00201C4B /* FBNCardBodyConfiguration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBNCardBodyConfiguration.m; sourceTree = \"<group>\"; };\n\t\t81A494C71CA9CB1B00201C4B /* FBNCardConfiguration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBNCardConfiguration.h; sourceTree = \"<group>\"; };\n\t\t81A494C81CA9CB1B00201C4B /* FBNCardConfiguration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBNCardConfiguration.m; sourceTree = \"<group>\"; };\n\t\t81A494CC1CA9CB1B00201C4B /* FBNAnimatedImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBNAnimatedImage.h; sourceTree = \"<group>\"; };\n\t\t81A494CD1CA9CB1B00201C4B /* FBNAnimatedImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBNAnimatedImage.m; sourceTree = \"<group>\"; };\n\t\t81A494CE1CA9CB1B00201C4B /* FBNCardBackground.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBNCardBackground.h; sourceTree = \"<group>\"; };\n\t\t81A494CF1CA9CB1B00201C4B /* FBNCardBackground.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBNCardBackground.m; sourceTree = \"<group>\"; };\n\t\t81A494D01CA9CB1B00201C4B /* FBNCardColor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBNCardColor.h; sourceTree = \"<group>\"; };\n\t\t81A494D11CA9CB1B00201C4B /* FBNCardColor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBNCardColor.m; sourceTree = \"<group>\"; };\n\t\t81A494D51CA9CB1B00201C4B /* FBNCardTextAlignment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBNCardTextAlignment.h; sourceTree = \"<group>\"; };\n\t\t81A494D61CA9CB1B00201C4B /* FBNCardTextAlignment.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBNCardTextAlignment.m; sourceTree = \"<group>\"; };\n\t\t81A494D71CA9CB1B00201C4B /* FBNCardTextContent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBNCardTextContent.h; sourceTree = \"<group>\"; };\n\t\t81A494D81CA9CB1B00201C4B /* FBNCardTextContent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBNCardTextContent.m; sourceTree = \"<group>\"; };\n\t\t81A494DA1CA9CB1B00201C4B /* FBNCardHeroConfiguration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBNCardHeroConfiguration.h; sourceTree = \"<group>\"; };\n\t\t81A494DB1CA9CB1B00201C4B /* FBNCardHeroConfiguration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBNCardHeroConfiguration.m; sourceTree = \"<group>\"; };\n\t\t81A495061CA9CC2900201C4B /* FBNCardSize.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBNCardSize.h; sourceTree = \"<group>\"; };\n\t\t81A495071CA9CC2900201C4B /* FBNCardSize.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBNCardSize.m; sourceTree = \"<group>\"; };\n\t\t81A4950C1CA9CD2D00201C4B /* FBNCardButtonAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBNCardButtonAction.h; sourceTree = \"<group>\"; };\n\t\t81C0361C1CE6A47300D11CF8 /* FBNCardDisplayOptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBNCardDisplayOptions.h; sourceTree = \"<group>\"; };\n\t\t81C0361D1CE6A47300D11CF8 /* FBNCardDisplayOptions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBNCardDisplayOptions.m; sourceTree = \"<group>\"; };\n\t\t81D632BD1CB3AA6A000921B1 /* FBNCardViewController_Internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FBNCardViewController_Internal.h; path = Internal/FBNCardViewController_Internal.h; sourceTree = \"<group>\"; };\n\t\t81EF49DD1C6C098B0074B2B4 /* FBNColorAsset.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBNColorAsset.h; sourceTree = \"<group>\"; };\n\t\t81EF49DE1C6C098B0074B2B4 /* FBNColorAsset.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBNColorAsset.m; sourceTree = \"<group>\"; };\n\t\t81EF49E01C6C098B0074B2B4 /* FBNAsset.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBNAsset.h; sourceTree = \"<group>\"; };\n\t\t81EF49E31C6C098B0074B2B4 /* FBNGIFAsset.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBNGIFAsset.h; sourceTree = \"<group>\"; };\n\t\t81EF49E41C6C098B0074B2B4 /* FBNGIFAsset.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBNGIFAsset.m; sourceTree = \"<group>\"; };\n\t\t81EF49E61C6C098B0074B2B4 /* FBNImageAsset.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBNImageAsset.h; sourceTree = \"<group>\"; };\n\t\t81EF49E71C6C098B0074B2B4 /* FBNImageAsset.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBNImageAsset.m; sourceTree = \"<group>\"; };\n\t\t81EF49F61C6C09C20074B2B4 /* FBNAssetController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBNAssetController.h; sourceTree = \"<group>\"; };\n\t\t81EF4A041C6C0A420074B2B4 /* FBNAssetsController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBNAssetsController.h; sourceTree = \"<group>\"; };\n\t\t81EF4A051C6C0A420074B2B4 /* FBNAssetsController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBNAssetsController.m; sourceTree = \"<group>\"; };\n\t\t81EF4A151C6C0CF40074B2B4 /* FBNColorAssetController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBNColorAssetController.h; sourceTree = \"<group>\"; };\n\t\t81EF4A161C6C0CF40074B2B4 /* FBNColorAssetController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBNColorAssetController.m; sourceTree = \"<group>\"; };\n\t\t81EF4A301C6C159B0074B2B4 /* FBNImageAssetController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBNImageAssetController.h; sourceTree = \"<group>\"; };\n\t\t81EF4A311C6C159B0074B2B4 /* FBNImageAssetController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBNImageAssetController.m; sourceTree = \"<group>\"; };\n\t\t81EF4A3C1C6C18F30074B2B4 /* FBNGIFAssetController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBNGIFAssetController.h; sourceTree = \"<group>\"; };\n\t\t81EF4A3D1C6C18F30074B2B4 /* FBNGIFAssetController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBNGIFAssetController.m; sourceTree = \"<group>\"; };\n\t\t81EF4A611C6C273F0074B2B4 /* FBNAssetContentCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBNAssetContentCache.h; sourceTree = \"<group>\"; };\n\t\t81EF4A621C6C273F0074B2B4 /* FBNAssetContentCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBNAssetContentCache.m; sourceTree = \"<group>\"; };\n\t\t81EF4A631C6C273F0074B2B4 /* FBNAssetContentCacheOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBNAssetContentCacheOperation.h; sourceTree = \"<group>\"; };\n\t\t81EF4A641C6C273F0074B2B4 /* FBNAssetContentCacheOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBNAssetContentCacheOperation.m; sourceTree = \"<group>\"; };\n\t\t81F0B10A1C4ED4FE00160CCD /* FBNotifications.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = FBNotifications.framework; sourceTree = BUILT_PRODUCTS_DIR; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t811E17391CB75034009AAE22 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t811E177C1CB750DE009AAE22 /* ImageIO.framework in Frameworks */,\n\t\t\t\t811E17791CB750DA009AAE22 /* MobileCoreServices.framework in Frameworks */,\n\t\t\t\t811E17761CB750D5009AAE22 /* CoreGraphics.framework in Frameworks */,\n\t\t\t\t811E17731CB750D2009AAE22 /* UIKit.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t81F0B1061C4ED4FE00160CCD /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t811E177E1CB750E6009AAE22 /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t811E177B1CB750DE009AAE22 /* ImageIO.framework */,\n\t\t\t\t811E17781CB750DA009AAE22 /* MobileCoreServices.framework */,\n\t\t\t\t811E17751CB750D5009AAE22 /* CoreGraphics.framework */,\n\t\t\t\t811E17721CB750D2009AAE22 /* UIKit.framework */,\n\t\t\t);\n\t\t\tname = Frameworks;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t812B7CC31C587CDB00F79BC1 /* Configurations */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t812B7CC41C587CDB00F79BC1 /* FBNotifications-iOS.xcconfig */,\n\t\t\t\t811E176C1CB7506A009AAE22 /* FBNotifications-iOS-Dynamic.xcconfig */,\n\t\t\t\t812B7CC51C587CDB00F79BC1 /* Shared */,\n\t\t\t);\n\t\t\tpath = Configurations;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t812B7CC51C587CDB00F79BC1 /* Shared */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t812B7CC61C587CDB00F79BC1 /* Common.xcconfig */,\n\t\t\t\t812B7CC71C587CDB00F79BC1 /* Platform */,\n\t\t\t\t812B7CCC1C587CDB00F79BC1 /* Product */,\n\t\t\t\t812B7CD01C587CDB00F79BC1 /* Project */,\n\t\t\t\t812B7CD31C587CDB00F79BC1 /* Warnings.xcconfig */,\n\t\t\t);\n\t\t\tpath = Shared;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t812B7CC71C587CDB00F79BC1 /* Platform */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t812B7CC81C587CDB00F79BC1 /* iOS.xcconfig */,\n\t\t\t\t812B7CC91C587CDB00F79BC1 /* OSX.xcconfig */,\n\t\t\t\t812B7CCA1C587CDB00F79BC1 /* tvOS.xcconfig */,\n\t\t\t\t812B7CCB1C587CDB00F79BC1 /* watchOS.xcconfig */,\n\t\t\t);\n\t\t\tpath = Platform;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t812B7CCC1C587CDB00F79BC1 /* Product */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t812B7CCD1C587CDB00F79BC1 /* Application.xcconfig */,\n\t\t\t\t812B7CCE1C587CDB00F79BC1 /* Framework.xcconfig */,\n\t\t\t\t812B7CCF1C587CDB00F79BC1 /* UnitTest.xcconfig */,\n\t\t\t);\n\t\t\tpath = Product;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t812B7CD01C587CDB00F79BC1 /* Project */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t812B7CD11C587CDB00F79BC1 /* Debug.xcconfig */,\n\t\t\t\t812B7CD21C587CDB00F79BC1 /* Release.xcconfig */,\n\t\t\t);\n\t\t\tpath = Project;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t815BAE761C59653600D79E1A /* FBNotifications */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t815BAE771C59653600D79E1A /* FBNotifications.h */,\n\t\t\t\t815BAE7A1C59653600D79E1A /* FBNotificationsManager.h */,\n\t\t\t\t815BAE7B1C59653600D79E1A /* FBNotificationsManager.m */,\n\t\t\t\t815BAE781C59653600D79E1A /* FBNConstants.h */,\n\t\t\t\t815BAE791C59653600D79E1A /* FBNConstants.m */,\n\t\t\t\t815BAE7C1C59653600D79E1A /* FBNCardViewController.h */,\n\t\t\t\t81D632BD1CB3AA6A000921B1 /* FBNCardViewController_Internal.h */,\n\t\t\t\t815BAE7D1C59653600D79E1A /* FBNCardViewController.m */,\n\t\t\t\t815BAE7F1C59653600D79E1A /* Internal */,\n\t\t\t\t815BAEBC1C59653600D79E1A /* Resources */,\n\t\t\t);\n\t\t\tpath = FBNotifications;\n\t\t\tsourceTree = SOURCE_ROOT;\n\t\t};\n\t\t815BAE7F1C59653600D79E1A /* Internal */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t81EF49DB1C6C098B0074B2B4 /* Asset */,\n\t\t\t\t815BAE801C59653600D79E1A /* AppEvents */,\n\t\t\t\t81A494BB1CA9CB1B00201C4B /* Models */,\n\t\t\t\t815BAEA31C59653600D79E1A /* Utilities */,\n\t\t\t\t815BAEAC1C59653600D79E1A /* Views */,\n\t\t\t);\n\t\t\tpath = Internal;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t815BAE801C59653600D79E1A /* AppEvents */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t815BAE811C59653600D79E1A /* FBNCardAppEventsLogger.h */,\n\t\t\t\t815BAE821C59653600D79E1A /* FBNCardAppEventsLogger.m */,\n\t\t\t);\n\t\t\tpath = AppEvents;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t815BAEA31C59653600D79E1A /* Utilities */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t815BAEA41C59653600D79E1A /* FBNCardError.h */,\n\t\t\t\t815BAEA51C59653600D79E1A /* FBNCardError.m */,\n\t\t\t\t815BAEA61C59653600D79E1A /* FBNCardHash.h */,\n\t\t\t\t815BAEA71C59653600D79E1A /* FBNCardHash.m */,\n\t\t\t\t815BAEA81C59653600D79E1A /* FBNCardPayload.h */,\n\t\t\t\t815BAEA91C59653600D79E1A /* FBNCardPayload.m */,\n\t\t\t\t815BAEAA1C59653600D79E1A /* FBNCardViewUtilities.h */,\n\t\t\t\t815BAEAB1C59653600D79E1A /* FBNCardViewUtilities.m */,\n\t\t\t\t06DCCB071CF02F4600E2A0AF /* FBNContentSizeProvider.h */,\n\t\t\t);\n\t\t\tpath = Utilities;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t815BAEAC1C59653600D79E1A /* Views */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t815BAEB71C59653600D79E1A /* FBNCardBodyViewController.h */,\n\t\t\t\t815BAEB81C59653600D79E1A /* FBNCardBodyViewController.m */,\n\t\t\t\t815BAEB91C59653600D79E1A /* FBNCardHeroViewController.h */,\n\t\t\t\t815BAEBA1C59653600D79E1A /* FBNCardHeroViewController.m */,\n\t\t\t\t815BAEB51C59653600D79E1A /* FBNCardActionsViewController.h */,\n\t\t\t\t815BAEB61C59653600D79E1A /* FBNCardActionsViewController.m */,\n\t\t\t\t815BAEB21C59653600D79E1A /* FBNCardActionButton.h */,\n\t\t\t\t815BAEB31C59653600D79E1A /* FBNCardActionButton.m */,\n\t\t\t\t815BAEAD1C59653600D79E1A /* Components */,\n\t\t\t);\n\t\t\tpath = Views;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t815BAEAD1C59653600D79E1A /* Components */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t815BAEAE1C59653600D79E1A /* FBNCardDismissButton.h */,\n\t\t\t\t815BAEAF1C59653600D79E1A /* FBNCardDismissButton.m */,\n\t\t\t\t815BAEB01C59653600D79E1A /* FBNCardLabel.h */,\n\t\t\t\t815BAEB11C59653600D79E1A /* FBNCardLabel.m */,\n\t\t\t);\n\t\t\tpath = Components;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t815BAEBC1C59653600D79E1A /* Resources */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t815BAEBD1C59653600D79E1A /* Info.plist */,\n\t\t\t);\n\t\t\tpath = Resources;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t81A494BB1CA9CB1B00201C4B /* Models */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t81A494C61CA9CB1B00201C4B /* Card */,\n\t\t\t\t81A494D91CA9CB1B00201C4B /* Hero */,\n\t\t\t\t81A494BC1CA9CB1B00201C4B /* Actions */,\n\t\t\t\t81A494C31CA9CB1B00201C4B /* Body */,\n\t\t\t\t81A494CB1CA9CB1B00201C4B /* Components */,\n\t\t\t);\n\t\t\tpath = Models;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t81A494BC1CA9CB1B00201C4B /* Actions */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t81A494BF1CA9CB1B00201C4B /* FBNCardActionsConfiguration.h */,\n\t\t\t\t81A494C01CA9CB1B00201C4B /* FBNCardActionsConfiguration.m */,\n\t\t\t\t81A494BD1CA9CB1B00201C4B /* FBNCardActionConfiguration.h */,\n\t\t\t\t81A494BE1CA9CB1B00201C4B /* FBNCardActionConfiguration.m */,\n\t\t\t\t81A494C11CA9CB1B00201C4B /* FBNCardActionsStyle.h */,\n\t\t\t\t81A494C21CA9CB1B00201C4B /* FBNCardActionsStyle.m */,\n\t\t\t\t81A4950C1CA9CD2D00201C4B /* FBNCardButtonAction.h */,\n\t\t\t);\n\t\t\tpath = Actions;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t81A494C31CA9CB1B00201C4B /* Body */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t81A494C41CA9CB1B00201C4B /* FBNCardBodyConfiguration.h */,\n\t\t\t\t81A494C51CA9CB1B00201C4B /* FBNCardBodyConfiguration.m */,\n\t\t\t);\n\t\t\tpath = Body;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t81A494C61CA9CB1B00201C4B /* Card */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t81A494C71CA9CB1B00201C4B /* FBNCardConfiguration.h */,\n\t\t\t\t81A494C81CA9CB1B00201C4B /* FBNCardConfiguration.m */,\n\t\t\t\t81A495061CA9CC2900201C4B /* FBNCardSize.h */,\n\t\t\t\t81A495071CA9CC2900201C4B /* FBNCardSize.m */,\n\t\t\t\t81C0361C1CE6A47300D11CF8 /* FBNCardDisplayOptions.h */,\n\t\t\t\t81C0361D1CE6A47300D11CF8 /* FBNCardDisplayOptions.m */,\n\t\t\t);\n\t\t\tpath = Card;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t81A494CB1CA9CB1B00201C4B /* Components */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t81A494CC1CA9CB1B00201C4B /* FBNAnimatedImage.h */,\n\t\t\t\t81A494CD1CA9CB1B00201C4B /* FBNAnimatedImage.m */,\n\t\t\t\t81A494CE1CA9CB1B00201C4B /* FBNCardBackground.h */,\n\t\t\t\t81A494CF1CA9CB1B00201C4B /* FBNCardBackground.m */,\n\t\t\t\t81A494D01CA9CB1B00201C4B /* FBNCardColor.h */,\n\t\t\t\t81A494D11CA9CB1B00201C4B /* FBNCardColor.m */,\n\t\t\t\t81A494D51CA9CB1B00201C4B /* FBNCardTextAlignment.h */,\n\t\t\t\t81A494D61CA9CB1B00201C4B /* FBNCardTextAlignment.m */,\n\t\t\t\t81A494D71CA9CB1B00201C4B /* FBNCardTextContent.h */,\n\t\t\t\t81A494D81CA9CB1B00201C4B /* FBNCardTextContent.m */,\n\t\t\t\t811E17911CB844AD009AAE22 /* FBNCardFont.h */,\n\t\t\t\t811E17921CB844AD009AAE22 /* FBNCardFont.m */,\n\t\t\t);\n\t\t\tpath = Components;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t81A494D91CA9CB1B00201C4B /* Hero */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t81A494DA1CA9CB1B00201C4B /* FBNCardHeroConfiguration.h */,\n\t\t\t\t81A494DB1CA9CB1B00201C4B /* FBNCardHeroConfiguration.m */,\n\t\t\t);\n\t\t\tpath = Hero;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t81EF49DB1C6C098B0074B2B4 /* Asset */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t81EF4A041C6C0A420074B2B4 /* FBNAssetsController.h */,\n\t\t\t\t81EF4A051C6C0A420074B2B4 /* FBNAssetsController.m */,\n\t\t\t\t81EF49DF1C6C098B0074B2B4 /* Common */,\n\t\t\t\t81EF49DC1C6C098B0074B2B4 /* Color */,\n\t\t\t\t81EF49E51C6C098B0074B2B4 /* Image */,\n\t\t\t\t81EF49E21C6C098B0074B2B4 /* GIF */,\n\t\t\t\t81EF4A601C6C273F0074B2B4 /* Cache */,\n\t\t\t);\n\t\t\tpath = Asset;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t81EF49DC1C6C098B0074B2B4 /* Color */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t81EF49DD1C6C098B0074B2B4 /* FBNColorAsset.h */,\n\t\t\t\t81EF49DE1C6C098B0074B2B4 /* FBNColorAsset.m */,\n\t\t\t\t0699F2111CF038750076241D /* FBNColorAssetViewController.h */,\n\t\t\t\t0699F2121CF038750076241D /* FBNColorAssetViewController.m */,\n\t\t\t\t81EF4A151C6C0CF40074B2B4 /* FBNColorAssetController.h */,\n\t\t\t\t81EF4A161C6C0CF40074B2B4 /* FBNColorAssetController.m */,\n\t\t\t);\n\t\t\tpath = Color;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t81EF49DF1C6C098B0074B2B4 /* Common */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t81EF49E01C6C098B0074B2B4 /* FBNAsset.h */,\n\t\t\t\t81EF49F61C6C09C20074B2B4 /* FBNAssetController.h */,\n\t\t\t);\n\t\t\tpath = Common;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t81EF49E21C6C098B0074B2B4 /* GIF */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t81EF49E31C6C098B0074B2B4 /* FBNGIFAsset.h */,\n\t\t\t\t81EF49E41C6C098B0074B2B4 /* FBNGIFAsset.m */,\n\t\t\t\t0699F2231CF03A9A0076241D /* FBNIGIFAssetViewController.h */,\n\t\t\t\t0699F2241CF03A9A0076241D /* FBNIGIFAssetViewController.m */,\n\t\t\t\t81EF4A3C1C6C18F30074B2B4 /* FBNGIFAssetController.h */,\n\t\t\t\t81EF4A3D1C6C18F30074B2B4 /* FBNGIFAssetController.m */,\n\t\t\t);\n\t\t\tpath = GIF;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t81EF49E51C6C098B0074B2B4 /* Image */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t81EF49E61C6C098B0074B2B4 /* FBNImageAsset.h */,\n\t\t\t\t81EF49E71C6C098B0074B2B4 /* FBNImageAsset.m */,\n\t\t\t\t0699F21D1CF039A30076241D /* FBNImageAssetViewController.h */,\n\t\t\t\t0699F21E1CF039A30076241D /* FBNImageAssetViewController.m */,\n\t\t\t\t81EF4A301C6C159B0074B2B4 /* FBNImageAssetController.h */,\n\t\t\t\t81EF4A311C6C159B0074B2B4 /* FBNImageAssetController.m */,\n\t\t\t);\n\t\t\tpath = Image;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t81EF4A601C6C273F0074B2B4 /* Cache */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t81EF4A611C6C273F0074B2B4 /* FBNAssetContentCache.h */,\n\t\t\t\t81EF4A621C6C273F0074B2B4 /* FBNAssetContentCache.m */,\n\t\t\t\t81EF4A631C6C273F0074B2B4 /* FBNAssetContentCacheOperation.h */,\n\t\t\t\t81EF4A641C6C273F0074B2B4 /* FBNAssetContentCacheOperation.m */,\n\t\t\t);\n\t\t\tpath = Cache;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t81F0B1001C4ED4FE00160CCD = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t812B7CC31C587CDB00F79BC1 /* Configurations */,\n\t\t\t\t815BAE761C59653600D79E1A /* FBNotifications */,\n\t\t\t\t81F0B10B1C4ED4FE00160CCD /* Products */,\n\t\t\t\t811E177E1CB750E6009AAE22 /* Frameworks */,\n\t\t\t);\n\t\t\tindentWidth = 4;\n\t\t\tsourceTree = \"<group>\";\n\t\t\ttabWidth = 4;\n\t\t};\n\t\t81F0B10B1C4ED4FE00160CCD /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t81F0B10A1C4ED4FE00160CCD /* FBNotifications.framework */,\n\t\t\t\t811E17671CB75034009AAE22 /* FBNotifications.framework */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXHeadersBuildPhase section */\n\t\t811E173A1CB75034009AAE22 /* Headers */ = {\n\t\t\tisa = PBXHeadersBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t811E173B1CB75034009AAE22 /* FBNAssetsController.h in Headers */,\n\t\t\t\t811E173C1CB75034009AAE22 /* FBNColorAssetController.h in Headers */,\n\t\t\t\t811E173D1CB75034009AAE22 /* FBNCardLabel.h in Headers */,\n\t\t\t\t811E173E1CB75034009AAE22 /* FBNGIFAsset.h in Headers */,\n\t\t\t\t811E173F1CB75034009AAE22 /* FBNAssetContentCacheOperation.h in Headers */,\n\t\t\t\t811E17401CB75034009AAE22 /* FBNCardTextAlignment.h in Headers */,\n\t\t\t\t811E17411CB75034009AAE22 /* FBNAssetContentCache.h in Headers */,\n\t\t\t\t811E17421CB75034009AAE22 /* FBNCardBodyConfiguration.h in Headers */,\n\t\t\t\t811E17431CB75034009AAE22 /* FBNCardHeroConfiguration.h in Headers */,\n\t\t\t\t811E17441CB75034009AAE22 /* FBNCardHeroViewController.h in Headers */,\n\t\t\t\t811E17451CB75034009AAE22 /* FBNImageAssetController.h in Headers */,\n\t\t\t\t0699F2201CF039A30076241D /* FBNImageAssetViewController.h in Headers */,\n\t\t\t\t811E17461CB75034009AAE22 /* FBNGIFAssetController.h in Headers */,\n\t\t\t\t811E17471CB75034009AAE22 /* FBNCardActionsStyle.h in Headers */,\n\t\t\t\t811E17481CB75034009AAE22 /* FBNCardHash.h in Headers */,\n\t\t\t\t811E17491CB75034009AAE22 /* FBNCardActionButton.h in Headers */,\n\t\t\t\t811E174A1CB75034009AAE22 /* FBNCardPayload.h in Headers */,\n\t\t\t\t811E174B1CB75034009AAE22 /* FBNCardAppEventsLogger.h in Headers */,\n\t\t\t\t811E174C1CB75034009AAE22 /* FBNConstants.h in Headers */,\n\t\t\t\t811E174D1CB75034009AAE22 /* FBNCardViewController.h in Headers */,\n\t\t\t\t811E174E1CB75034009AAE22 /* FBNCardSize.h in Headers */,\n\t\t\t\t811E174F1CB75034009AAE22 /* FBNotifications.h in Headers */,\n\t\t\t\t811E17501CB75034009AAE22 /* FBNCardViewUtilities.h in Headers */,\n\t\t\t\t0699F2261CF03A9A0076241D /* FBNIGIFAssetViewController.h in Headers */,\n\t\t\t\t811E17511CB75034009AAE22 /* FBNImageAsset.h in Headers */,\n\t\t\t\t811E17521CB75034009AAE22 /* FBNCardViewController_Internal.h in Headers */,\n\t\t\t\t811E17531CB75034009AAE22 /* FBNotificationsManager.h in Headers */,\n\t\t\t\t811E17541CB75034009AAE22 /* FBNCardBackground.h in Headers */,\n\t\t\t\t811E17551CB75034009AAE22 /* FBNColorAsset.h in Headers */,\n\t\t\t\t811E17561CB75034009AAE22 /* FBNCardTextContent.h in Headers */,\n\t\t\t\t811E17571CB75034009AAE22 /* FBNCardButtonAction.h in Headers */,\n\t\t\t\t811E17581CB75034009AAE22 /* FBNCardBodyViewController.h in Headers */,\n\t\t\t\t81C0361F1CE6A47300D11CF8 /* FBNCardDisplayOptions.h in Headers */,\n\t\t\t\t06DCCB091CF02F4600E2A0AF /* FBNContentSizeProvider.h in Headers */,\n\t\t\t\t811E17591CB75034009AAE22 /* FBNCardActionsConfiguration.h in Headers */,\n\t\t\t\t811E175A1CB75034009AAE22 /* FBNAnimatedImage.h in Headers */,\n\t\t\t\t816A91EF1CB865AC00A5DA85 /* FBNCardFont.h in Headers */,\n\t\t\t\t811E175B1CB75034009AAE22 /* FBNAsset.h in Headers */,\n\t\t\t\t811E175C1CB75034009AAE22 /* FBNCardError.h in Headers */,\n\t\t\t\t811E175D1CB75034009AAE22 /* FBNCardConfiguration.h in Headers */,\n\t\t\t\t0699F2141CF038750076241D /* FBNColorAssetViewController.h in Headers */,\n\t\t\t\t811E175E1CB75034009AAE22 /* FBNCardDismissButton.h in Headers */,\n\t\t\t\t811E175F1CB75034009AAE22 /* FBNCardActionsViewController.h in Headers */,\n\t\t\t\t811E17601CB75034009AAE22 /* FBNCardActionConfiguration.h in Headers */,\n\t\t\t\t811E17611CB75034009AAE22 /* FBNAssetController.h in Headers */,\n\t\t\t\t811E17621CB75034009AAE22 /* FBNCardColor.h in Headers */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t81F0B1071C4ED4FE00160CCD /* Headers */ = {\n\t\t\tisa = PBXHeadersBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t81EF4A061C6C0A420074B2B4 /* FBNAssetsController.h in Headers */,\n\t\t\t\t81EF4A171C6C0CF40074B2B4 /* FBNColorAssetController.h in Headers */,\n\t\t\t\t815BAEEF1C59653600D79E1A /* FBNCardLabel.h in Headers */,\n\t\t\t\t81EF49EC1C6C098B0074B2B4 /* FBNGIFAsset.h in Headers */,\n\t\t\t\t81EF4A671C6C273F0074B2B4 /* FBNAssetContentCacheOperation.h in Headers */,\n\t\t\t\t81A494F11CA9CB1B00201C4B /* FBNCardTextAlignment.h in Headers */,\n\t\t\t\t81EF4A651C6C273F0074B2B4 /* FBNAssetContentCache.h in Headers */,\n\t\t\t\t81A494E21CA9CB1B00201C4B /* FBNCardBodyConfiguration.h in Headers */,\n\t\t\t\t81A494F51CA9CB1B00201C4B /* FBNCardHeroConfiguration.h in Headers */,\n\t\t\t\t815BAEF81C59653600D79E1A /* FBNCardHeroViewController.h in Headers */,\n\t\t\t\t81EF4A321C6C159B0074B2B4 /* FBNImageAssetController.h in Headers */,\n\t\t\t\t0699F21F1CF039A30076241D /* FBNImageAssetViewController.h in Headers */,\n\t\t\t\t81EF4A3E1C6C18F30074B2B4 /* FBNGIFAssetController.h in Headers */,\n\t\t\t\t81A494E01CA9CB1B00201C4B /* FBNCardActionsStyle.h in Headers */,\n\t\t\t\t815BAEE71C59653600D79E1A /* FBNCardHash.h in Headers */,\n\t\t\t\t815BAEF11C59653600D79E1A /* FBNCardActionButton.h in Headers */,\n\t\t\t\t815BAEE91C59653600D79E1A /* FBNCardPayload.h in Headers */,\n\t\t\t\t815BAEC61C59653600D79E1A /* FBNCardAppEventsLogger.h in Headers */,\n\t\t\t\t815BAEBF1C59653600D79E1A /* FBNConstants.h in Headers */,\n\t\t\t\t815BAEC31C59653600D79E1A /* FBNCardViewController.h in Headers */,\n\t\t\t\t81A495081CA9CC2900201C4B /* FBNCardSize.h in Headers */,\n\t\t\t\t815BAEBE1C59653600D79E1A /* FBNotifications.h in Headers */,\n\t\t\t\t815BAEEB1C59653600D79E1A /* FBNCardViewUtilities.h in Headers */,\n\t\t\t\t0699F2251CF03A9A0076241D /* FBNIGIFAssetViewController.h in Headers */,\n\t\t\t\t81EF49EE1C6C098B0074B2B4 /* FBNImageAsset.h in Headers */,\n\t\t\t\t81D632BE1CB3AA6A000921B1 /* FBNCardViewController_Internal.h in Headers */,\n\t\t\t\t815BAEC11C59653600D79E1A /* FBNotificationsManager.h in Headers */,\n\t\t\t\t81A494EA1CA9CB1B00201C4B /* FBNCardBackground.h in Headers */,\n\t\t\t\t81EF49E81C6C098B0074B2B4 /* FBNColorAsset.h in Headers */,\n\t\t\t\t81A494F31CA9CB1B00201C4B /* FBNCardTextContent.h in Headers */,\n\t\t\t\t81A4950D1CA9CD2D00201C4B /* FBNCardButtonAction.h in Headers */,\n\t\t\t\t815BAEF61C59653600D79E1A /* FBNCardBodyViewController.h in Headers */,\n\t\t\t\t81C0361E1CE6A47300D11CF8 /* FBNCardDisplayOptions.h in Headers */,\n\t\t\t\t06DCCB081CF02F4600E2A0AF /* FBNContentSizeProvider.h in Headers */,\n\t\t\t\t81A494DE1CA9CB1B00201C4B /* FBNCardActionsConfiguration.h in Headers */,\n\t\t\t\t81A494E81CA9CB1B00201C4B /* FBNAnimatedImage.h in Headers */,\n\t\t\t\t811E17931CB844AD009AAE22 /* FBNCardFont.h in Headers */,\n\t\t\t\t81EF49EA1C6C098B0074B2B4 /* FBNAsset.h in Headers */,\n\t\t\t\t815BAEE51C59653600D79E1A /* FBNCardError.h in Headers */,\n\t\t\t\t81A494E41CA9CB1B00201C4B /* FBNCardConfiguration.h in Headers */,\n\t\t\t\t0699F2131CF038750076241D /* FBNColorAssetViewController.h in Headers */,\n\t\t\t\t815BAEED1C59653600D79E1A /* FBNCardDismissButton.h in Headers */,\n\t\t\t\t815BAEF41C59653600D79E1A /* FBNCardActionsViewController.h in Headers */,\n\t\t\t\t81A494DC1CA9CB1B00201C4B /* FBNCardActionConfiguration.h in Headers */,\n\t\t\t\t81EF49F81C6C09C20074B2B4 /* FBNAssetController.h in Headers */,\n\t\t\t\t81A494EC1CA9CB1B00201C4B /* FBNCardColor.h in Headers */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXHeadersBuildPhase section */\n\n/* Begin PBXNativeTarget section */\n\t\t811E17141CB75034009AAE22 /* FBNotifications-iOS-Dynamic */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 811E17641CB75034009AAE22 /* Build configuration list for PBXNativeTarget \"FBNotifications-iOS-Dynamic\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t811E17151CB75034009AAE22 /* Sources */,\n\t\t\t\t811E17391CB75034009AAE22 /* Frameworks */,\n\t\t\t\t811E173A1CB75034009AAE22 /* Headers */,\n\t\t\t\t811E17631CB75034009AAE22 /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = \"FBNotifications-iOS-Dynamic\";\n\t\t\tproductName = FBPushCards;\n\t\t\tproductReference = 811E17671CB75034009AAE22 /* FBNotifications.framework */;\n\t\t\tproductType = \"com.apple.product-type.framework\";\n\t\t};\n\t\t81F0B1091C4ED4FE00160CCD /* FBNotifications-iOS */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 81F0B1121C4ED4FE00160CCD /* Build configuration list for PBXNativeTarget \"FBNotifications-iOS\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t81F0B1051C4ED4FE00160CCD /* Sources */,\n\t\t\t\t81F0B1061C4ED4FE00160CCD /* Frameworks */,\n\t\t\t\t81F0B1071C4ED4FE00160CCD /* Headers */,\n\t\t\t\t81F0B1081C4ED4FE00160CCD /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = \"FBNotifications-iOS\";\n\t\t\tproductName = FBPushCards;\n\t\t\tproductReference = 81F0B10A1C4ED4FE00160CCD /* FBNotifications.framework */;\n\t\t\tproductType = \"com.apple.product-type.framework\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t81F0B1011C4ED4FE00160CCD /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastUpgradeCheck = 0730;\n\t\t\t\tORGANIZATIONNAME = \"Facebook Inc\";\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t81F0B1091C4ED4FE00160CCD = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 7.3;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 81F0B1041C4ED4FE00160CCD /* Build configuration list for PBXProject \"FBNotifications\" */;\n\t\t\tcompatibilityVersion = \"Xcode 3.2\";\n\t\t\tdevelopmentRegion = English;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t);\n\t\t\tmainGroup = 81F0B1001C4ED4FE00160CCD;\n\t\t\tproductRefGroup = 81F0B10B1C4ED4FE00160CCD /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t81F0B1091C4ED4FE00160CCD /* FBNotifications-iOS */,\n\t\t\t\t811E17141CB75034009AAE22 /* FBNotifications-iOS-Dynamic */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t811E17631CB75034009AAE22 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t81F0B1081C4ED4FE00160CCD /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t811E17151CB75034009AAE22 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t811E17161CB75034009AAE22 /* FBNCardActionConfiguration.m in Sources */,\n\t\t\t\t811E17171CB75034009AAE22 /* FBNConstants.m in Sources */,\n\t\t\t\t811E17181CB75034009AAE22 /* FBNCardViewController.m in Sources */,\n\t\t\t\t811E17191CB75034009AAE22 /* FBNCardDismissButton.m in Sources */,\n\t\t\t\t811E171A1CB75034009AAE22 /* FBNCardTextAlignment.m in Sources */,\n\t\t\t\t811E171B1CB75034009AAE22 /* FBNColorAsset.m in Sources */,\n\t\t\t\t811E171C1CB75034009AAE22 /* FBNCardTextContent.m in Sources */,\n\t\t\t\t811E171D1CB75034009AAE22 /* FBNCardPayload.m in Sources */,\n\t\t\t\t811E171E1CB75034009AAE22 /* FBNImageAssetController.m in Sources */,\n\t\t\t\t811E171F1CB75034009AAE22 /* FBNCardError.m in Sources */,\n\t\t\t\t81C036211CE6A47300D11CF8 /* FBNCardDisplayOptions.m in Sources */,\n\t\t\t\t811E17201CB75034009AAE22 /* FBNCardBodyConfiguration.m in Sources */,\n\t\t\t\t0699F2281CF03A9A0076241D /* FBNIGIFAssetViewController.m in Sources */,\n\t\t\t\t811E17211CB75034009AAE22 /* FBNCardActionsStyle.m in Sources */,\n\t\t\t\t811E17221CB75034009AAE22 /* FBNAssetContentCacheOperation.m in Sources */,\n\t\t\t\t811E17231CB75034009AAE22 /* FBNAnimatedImage.m in Sources */,\n\t\t\t\t811E17241CB75034009AAE22 /* FBNCardActionsViewController.m in Sources */,\n\t\t\t\t811E17251CB75034009AAE22 /* FBNCardSize.m in Sources */,\n\t\t\t\t811E17261CB75034009AAE22 /* FBNCardHeroViewController.m in Sources */,\n\t\t\t\t0699F2221CF039A30076241D /* FBNImageAssetViewController.m in Sources */,\n\t\t\t\t811E17271CB75034009AAE22 /* FBNCardAppEventsLogger.m in Sources */,\n\t\t\t\t811E17281CB75034009AAE22 /* FBNCardActionButton.m in Sources */,\n\t\t\t\t811E17291CB75034009AAE22 /* FBNCardLabel.m in Sources */,\n\t\t\t\t811E172A1CB75034009AAE22 /* FBNCardHeroConfiguration.m in Sources */,\n\t\t\t\t811E172B1CB75034009AAE22 /* FBNCardViewUtilities.m in Sources */,\n\t\t\t\t811E172C1CB75034009AAE22 /* FBNCardBodyViewController.m in Sources */,\n\t\t\t\t816A91ED1CB865A900A5DA85 /* FBNCardFont.m in Sources */,\n\t\t\t\t811E172D1CB75034009AAE22 /* FBNCardConfiguration.m in Sources */,\n\t\t\t\t811E172E1CB75034009AAE22 /* FBNImageAsset.m in Sources */,\n\t\t\t\t811E172F1CB75034009AAE22 /* FBNGIFAsset.m in Sources */,\n\t\t\t\t811E17301CB75034009AAE22 /* FBNCardBackground.m in Sources */,\n\t\t\t\t811E17311CB75034009AAE22 /* FBNColorAssetController.m in Sources */,\n\t\t\t\t811E17321CB75034009AAE22 /* FBNAssetsController.m in Sources */,\n\t\t\t\t811E17331CB75034009AAE22 /* FBNCardHash.m in Sources */,\n\t\t\t\t0699F2161CF038750076241D /* FBNColorAssetViewController.m in Sources */,\n\t\t\t\t811E17341CB75034009AAE22 /* FBNCardActionsConfiguration.m in Sources */,\n\t\t\t\t811E17351CB75034009AAE22 /* FBNCardColor.m in Sources */,\n\t\t\t\t811E17361CB75034009AAE22 /* FBNGIFAssetController.m in Sources */,\n\t\t\t\t811E17371CB75034009AAE22 /* FBNAssetContentCache.m in Sources */,\n\t\t\t\t811E17381CB75034009AAE22 /* FBNotificationsManager.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t81F0B1051C4ED4FE00160CCD /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t81A494DD1CA9CB1B00201C4B /* FBNCardActionConfiguration.m in Sources */,\n\t\t\t\t815BAEC01C59653600D79E1A /* FBNConstants.m in Sources */,\n\t\t\t\t815BAEC41C59653600D79E1A /* FBNCardViewController.m in Sources */,\n\t\t\t\t815BAEEE1C59653600D79E1A /* FBNCardDismissButton.m in Sources */,\n\t\t\t\t81A494F21CA9CB1B00201C4B /* FBNCardTextAlignment.m in Sources */,\n\t\t\t\t81EF49E91C6C098B0074B2B4 /* FBNColorAsset.m in Sources */,\n\t\t\t\t81A494F41CA9CB1B00201C4B /* FBNCardTextContent.m in Sources */,\n\t\t\t\t815BAEEA1C59653600D79E1A /* FBNCardPayload.m in Sources */,\n\t\t\t\t81EF4A331C6C159B0074B2B4 /* FBNImageAssetController.m in Sources */,\n\t\t\t\t815BAEE61C59653600D79E1A /* FBNCardError.m in Sources */,\n\t\t\t\t81C036201CE6A47300D11CF8 /* FBNCardDisplayOptions.m in Sources */,\n\t\t\t\t81A494E31CA9CB1B00201C4B /* FBNCardBodyConfiguration.m in Sources */,\n\t\t\t\t0699F2271CF03A9A0076241D /* FBNIGIFAssetViewController.m in Sources */,\n\t\t\t\t81A494E11CA9CB1B00201C4B /* FBNCardActionsStyle.m in Sources */,\n\t\t\t\t81EF4A681C6C273F0074B2B4 /* FBNAssetContentCacheOperation.m in Sources */,\n\t\t\t\t81A494E91CA9CB1B00201C4B /* FBNAnimatedImage.m in Sources */,\n\t\t\t\t815BAEF51C59653600D79E1A /* FBNCardActionsViewController.m in Sources */,\n\t\t\t\t81A495091CA9CC2900201C4B /* FBNCardSize.m in Sources */,\n\t\t\t\t815BAEF91C59653600D79E1A /* FBNCardHeroViewController.m in Sources */,\n\t\t\t\t0699F2211CF039A30076241D /* FBNImageAssetViewController.m in Sources */,\n\t\t\t\t815BAEC71C59653600D79E1A /* FBNCardAppEventsLogger.m in Sources */,\n\t\t\t\t815BAEF21C59653600D79E1A /* FBNCardActionButton.m in Sources */,\n\t\t\t\t815BAEF01C59653600D79E1A /* FBNCardLabel.m in Sources */,\n\t\t\t\t81A494F61CA9CB1B00201C4B /* FBNCardHeroConfiguration.m in Sources */,\n\t\t\t\t815BAEEC1C59653600D79E1A /* FBNCardViewUtilities.m in Sources */,\n\t\t\t\t815BAEF71C59653600D79E1A /* FBNCardBodyViewController.m in Sources */,\n\t\t\t\t811E17941CB844AD009AAE22 /* FBNCardFont.m in Sources */,\n\t\t\t\t81A494E51CA9CB1B00201C4B /* FBNCardConfiguration.m in Sources */,\n\t\t\t\t81EF49EF1C6C098B0074B2B4 /* FBNImageAsset.m in Sources */,\n\t\t\t\t81EF49ED1C6C098B0074B2B4 /* FBNGIFAsset.m in Sources */,\n\t\t\t\t81A494EB1CA9CB1B00201C4B /* FBNCardBackground.m in Sources */,\n\t\t\t\t81EF4A181C6C0CF40074B2B4 /* FBNColorAssetController.m in Sources */,\n\t\t\t\t81EF4A071C6C0A420074B2B4 /* FBNAssetsController.m in Sources */,\n\t\t\t\t815BAEE81C59653600D79E1A /* FBNCardHash.m in Sources */,\n\t\t\t\t0699F2151CF038750076241D /* FBNColorAssetViewController.m in Sources */,\n\t\t\t\t81A494DF1CA9CB1B00201C4B /* FBNCardActionsConfiguration.m in Sources */,\n\t\t\t\t81A494ED1CA9CB1B00201C4B /* FBNCardColor.m in Sources */,\n\t\t\t\t81EF4A3F1C6C18F30074B2B4 /* FBNGIFAssetController.m in Sources */,\n\t\t\t\t81EF4A661C6C273F0074B2B4 /* FBNAssetContentCache.m in Sources */,\n\t\t\t\t815BAEC21C59653600D79E1A /* FBNotificationsManager.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin XCBuildConfiguration section */\n\t\t811E17651CB75034009AAE22 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 811E176C1CB7506A009AAE22 /* FBNotifications-iOS-Dynamic.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t811E17661CB75034009AAE22 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 811E176C1CB7506A009AAE22 /* FBNotifications-iOS-Dynamic.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t81F0B1101C4ED4FE00160CCD /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 812B7CD11C587CDB00F79BC1 /* Debug.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t81F0B1111C4ED4FE00160CCD /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 812B7CD21C587CDB00F79BC1 /* Release.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t81F0B1131C4ED4FE00160CCD /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 812B7CC41C587CDB00F79BC1 /* FBNotifications-iOS.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tDEFINES_MODULE = YES;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks @loader_path/Frameworks\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t81F0B1141C4ED4FE00160CCD /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 812B7CC41C587CDB00F79BC1 /* FBNotifications-iOS.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tDEFINES_MODULE = YES;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks @loader_path/Frameworks\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t811E17641CB75034009AAE22 /* Build configuration list for PBXNativeTarget \"FBNotifications-iOS-Dynamic\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t811E17651CB75034009AAE22 /* Debug */,\n\t\t\t\t811E17661CB75034009AAE22 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t81F0B1041C4ED4FE00160CCD /* Build configuration list for PBXProject \"FBNotifications\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t81F0B1101C4ED4FE00160CCD /* Debug */,\n\t\t\t\t81F0B1111C4ED4FE00160CCD /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t81F0B1121C4ED4FE00160CCD /* Build configuration list for PBXNativeTarget \"FBNotifications-iOS\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t81F0B1131C4ED4FE00160CCD /* Debug */,\n\t\t\t\t81F0B1141C4ED4FE00160CCD /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = 81F0B1011C4ED4FE00160CCD /* Project object */;\n}\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications.xcodeproj/xcshareddata/xcschemes/FBNotifications-iOS-Dynamic.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"0730\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"811E17141CB75034009AAE22\"\n               BuildableName = \"FBNotifications.framework\"\n               BlueprintName = \"FBNotifications-iOS-Dynamic\"\n               ReferencedContainer = \"container:FBNotifications.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <Testables>\n      </Testables>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"811E17141CB75034009AAE22\"\n            BuildableName = \"FBNotifications.framework\"\n            BlueprintName = \"FBNotifications-iOS-Dynamic\"\n            ReferencedContainer = \"container:FBNotifications.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"811E17141CB75034009AAE22\"\n            BuildableName = \"FBNotifications.framework\"\n            BlueprintName = \"FBNotifications-iOS-Dynamic\"\n            ReferencedContainer = \"container:FBNotifications.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "iOS/FBNotifications/FBNotifications.xcodeproj/xcshareddata/xcschemes/FBNotifications-iOS.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"0730\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"81F0B1091C4ED4FE00160CCD\"\n               BuildableName = \"FBNotifications.framework\"\n               BlueprintName = \"FBNotifications-iOS\"\n               ReferencedContainer = \"container:FBNotifications.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <Testables>\n      </Testables>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"81F0B1091C4ED4FE00160CCD\"\n            BuildableName = \"FBNotifications.framework\"\n            BlueprintName = \"FBNotifications-iOS\"\n            ReferencedContainer = \"container:FBNotifications.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"81F0B1091C4ED4FE00160CCD\"\n            BuildableName = \"FBNotifications.framework\"\n            BlueprintName = \"FBNotifications-iOS\"\n            ReferencedContainer = \"container:FBNotifications.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "iOS/FBNotifications.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"group:FBNotifications/FBNotifications.xcodeproj\">\n   </FileRef>\n   <FileRef\n      location = \"group:FBNotificationsExample/FBNotificationsExample.xcodeproj\">\n   </FileRef>\n</Workspace>\n"
  },
  {
    "path": "iOS/FBNotificationsExample/.gitignore",
    "content": "*.framework"
  },
  {
    "path": "iOS/FBNotificationsExample/FBNotificationsExample/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "iOS/FBNotificationsExample/FBNotificationsExample/Resources/Base.lproj/LaunchScreen.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"9532\" systemVersion=\"15D21\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" useTraitCollections=\"YES\" initialViewController=\"01J-lp-oVM\">\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"9530\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"EHf-IW-A2E\">\n            <objects>\n                <viewController id=\"01J-lp-oVM\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"Llm-lL-Icb\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"xb3-aO-Qok\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"Ze5-6b-2t3\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"600\" height=\"600\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"calibratedWhite\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"iYj-Kq-Ea1\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"53\" y=\"375\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "iOS/FBNotificationsExample/FBNotificationsExample/Resources/Base.lproj/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"9532\" systemVersion=\"15D21\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" initialViewController=\"BYZ-38-t0r\">\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"9530\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"tne-QT-ifu\">\n            <objects>\n                <viewController id=\"BYZ-38-t0r\" customClass=\"ViewController\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"y3c-jy-aDJ\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"wfy-db-euE\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"8bC-Xf-vdC\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"600\" height=\"600\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"calibratedWhite\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"dkx-z0-nzr\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "iOS/FBNotificationsExample/FBNotificationsExample/Resources/Examples/example1.json",
    "content": "{\n  \"fb_push_card\": {\n    \"version\" : \"1.0\",\n    \"dismissColor\": \"#334D5CFF\",\n    \"size\": \"small\",\n    \"cornerRadius\": 12.0,\n    \"contentInset\" : 10,\n    \"backdropColor\": \"#000000CC\",\n    \"hero\": {\n      \"background\": {\n        \"_type\": \"Color\",\n        \"rgbaHex\": \"#FFFFFFFF\"\n      },\n      \"content\": {\n        \"_type\": \"StyledText\",\n        \"size\": 17,\n        \"text\": \"There are item(s) in your cart\",\n        \"align\": \"left\",\n        \"color\": \"#334D5CFF\"\n      },\n      \"contentAlign\" : \"bottom\"\n    },\n    \"body\": {\n      \"background\": {\n        \"_type\": \"Color\",\n        \"rgbaHex\": \"#FFFFFFFF\"\n      },\n      \"content\": {\n        \"_type\": \"StyledText\",\n        \"size\": 15,\n        \"text\": \"Oops! It seems like you left some item(s) in your cart. You can remove them or checkout.\",\n        \"align\": \"left\",\n        \"color\": \"#334D5CFF\"\n      }\n    },\n    \"alert\" : {\n      \"title\": \"Oops!\",\n      \"body\" : \"There are item(s) in your cart!\"\n    },\n    \"actions\": {\n      \"style\": \"attached\",\n      \"layoutStyle\" : \"vertical\",\n      \"background\": {\n        \"_type\": \"Color\",\n        \"rgbaHex\": \"#FFFFFFFF\"\n      },\n      \"contentInset\" : 10,\n      \"cornerRadius\" : 8,\n      \"actions\": [\n        {\n          \"backgroundColor\": \"#61B6E5FF\",\n          \"content\": {\n            \"_type\": \"StyledText\",\n            \"size\": 18,\n            \"text\": \"GO TO CART\",\n            \"color\": \"#FFFFFFFF\"\n          },\n          \"url\": \"https://parse.com/\"\n        }\n      ]\n    }\n  }\n}\n"
  },
  {
    "path": "iOS/FBNotificationsExample/FBNotificationsExample/Resources/Examples/example2.json",
    "content": "{\n  \"fb_push_payload\" : {\n    \"campaign\" : \"2\"\n  },\n  \"fb_push_card\": {\n    \"version\": \"1.0\",\n    \"size\": \"medium\",\n    \"cornerRadius\": 12,\n    \"contentInset\" : 16,\n    \"backdropColor\": \"#334D5CF5\",\n    \"hero\": {\n      \"background\": {\n        \"_type\": \"Color\",\n        \"rgbaHex\": \"#50CCB4FF\"\n      },\n      \"content\": {\n        \"_type\": \"StyledText\",\n        \"size\": 24,\n        \"text\": \"Introducing Messaging!\",\n        \"font\": \"system-bold\",\n        \"align\": \"center\",\n        \"color\": \"#FFFFFFFF\"\n      }\n    },\n    \"body\": {\n      \"background\": {\n        \"_type\": \"Color\",\n        \"rgbaHex\": \"#FFFFFFFF\"\n      },\n      \"content\": {\n        \"_type\": \"StyledText\",\n        \"size\": 16,\n        \"text\": \"The AnyApp team is proud to launch our in app messaging feature! Give it a try today and message your friends.\",\n        \"align\": \"left\",\n        \"font\": \"system-light\",\n        \"color\": \"#334D5CFF\"\n      }\n    },\n    \"alert\" : {\n      \"body\" : \"Introducing Messaging!\"\n    },\n    \"actions\": {\n      \"style\": \"attached\",\n      \"layoutStyle\" : \"horizontal\",\n      \"actionsHeight\" : 60.0,\n      \"actions\": [\n        {\n          \"backgroundColor\": \"#C6D9E0FF\",\n          \"title\": \"Not Now\",\n          \"content\": {\n            \"_type\": \"StyledText\",\n            \"size\": 18,\n            \"text\": \"Not Now\",\n            \"color\": \"#FFFFFFFF\"\n          }\n        },\n        {\n          \"backgroundColor\": \"#9167EFFF\",\n          \"content\": {\n            \"_type\": \"StyledText\",\n            \"size\": 18,\n            \"text\": \"Try It\",\n            \"color\": \"#FFFFFFFF\"\n          },\n          \"url\": \"https://messenger.com\"\n        }\n      ]\n    }\n  }\n}\n"
  },
  {
    "path": "iOS/FBNotificationsExample/FBNotificationsExample/Resources/Examples/example3.json",
    "content": "{\n  \"fb_push_payload\" : {\n    \"campaign\" : \"3\"\n  },\n  \"fb_push_card\": {\n    \"version\": \"1.0\",\n    \"size\": \"medium\",\n    \"cornerRadius\": 16,\n    \"contentInset\" : 16,\n    \"backdropColor\": \"#332D2DF0\",\n    \"hero\": {\n      \"background\": {\n        \"_type\": \"GIF\",\n        \"url\": \"https://s3.amazonaws.com/f.cl.ly/items/3S3a3I0a0l2w3M2v2h30/fall.gif\"\n      }\n    },\n    \"body\": {\n      \"background\": {\n        \"_type\": \"Color\",\n        \"rgbaHex\": \"#FFFFFFFF\"\n      },\n      \"content\": {\n        \"_type\": \"StyledText\",\n        \"size\": 14,\n        \"text\": \"September 22nd marks the first day of fall and the release of our new fall clothing line. We’re celebrating with a 20% off sale!\",\n        \"align\": \"left\",\n        \"color\": \"#33251FFF\"\n      }\n    },\n    \"alert\" : {\n      \"title\": \"New Clothing Line\",\n      \"body\" : \"20% fall sale!\"\n    },\n    \"actions\": {\n      \"style\": \"attached\",\n      \"layoutStyle\" : \"horizontal\", \n      \"contentInset\" : 16.0,\n      \"cornerRadius\" : 6,\n      \"background\": {\n        \"_type\": \"Color\",\n        \"rgbaHex\": \"#FFFFFFFF\"\n      },\n      \"actions\": [\n        {\n          \"backgroundColor\": \"#690200FF\",\n          \"content\": {\n            \"_type\": \"StyledText\",\n            \"size\": 18,\n            \"text\": \"Yes, please!\",\n            \"color\": \"#FFFFFFFF\"\n          },\n          \"url\": \"https://parse.com/\"\n        },\n        {\n          \"backgroundColor\": \"#CCC4BCFF\",\n          \"content\": {\n            \"_type\": \"StyledText\",\n            \"size\": 18,\n            \"text\": \"No, thanks!\",\n            \"color\": \"#FFFFFFFF\"\n          }\n        }\n      ]\n    }\n  }\n}\n"
  },
  {
    "path": "iOS/FBNotificationsExample/FBNotificationsExample/Resources/Examples/example4.json",
    "content": "{\n  \"fb_push_payload\" : {\n    \"campaign\" : \"4\"\n  },\n  \"fb_push_card\": {\n    \"version\": \"1.0\",\n    \"size\": \"medium\",\n    \"cornerRadius\": 20,\n    \"backdropColor\": \"#332D2DF0\",\n    \"dismissColor\": \"#000000FF\",\n    \"hero\": {\n      \"background\": {\n        \"_type\": \"Image\",\n        \"url\": \"https://s3.amazonaws.com/f.cl.ly/items/3n2d2G3V3w2h261x0r0i/pizzzza.png\"\n      }\n    },\n    \"alert\" : {\n      \"title\": \"Yum!\",\n      \"body\" : \"Bob's now delivers!\"\n    },\n    \"actions\": {\n      \"style\": \"detached\",\n      \"layoutStyle\" : \"horizontal\",   \n      \"topInset\": 20,\n      \"cornerRadius\": 20,\n      \"actions\": [\n        {\n          \"borderColor\": \"#FFC84DFF\",\n          \"borderWidth\" : 2,\n          \"content\": {\n            \"_type\": \"StyledText\",\n            \"size\": 18,\n            \"text\": \"Deliver Me Pizzza\",\n            \"color\": \"#FFC84DFF\"\n          },\n          \"url\": \"https://facebook.com/\"\n        }\n      ]\n    }\n  }\n}\n"
  },
  {
    "path": "iOS/FBNotificationsExample/FBNotificationsExample/Resources/Examples/example5.json",
    "content": "{\n  \"fb_push_payload\" : {\n    \"campaign\" : \"5\"\n  },\n  \"fb_push_card\": {\n    \"version\": \"1.0\",\n    \"size\": \"large\",\n    \"contentInset\" : 20,\n    \"backdropColor\": \"#FFF9F8F5\",\n    \"hero\": {\n      \"background\": {\n        \"_type\": \"Image\",\n        \"url\": \"https://s3.amazonaws.com/f.cl.ly/items/2s0J0S1a0B2G1n0b421R/PirateBooty.png\"\n      }\n    },\n    \"alert\" : {\n      \"title\": \"Yarr!\",\n      \"body\" : \"Get the free pirate expansion!\"\n    },\n    \"actions\": {\n      \"style\": \"attached\",\n      \"layoutStyle\" : \"vertical\", \n      \"contentInset\" : 10.0,\n      \"height\" : 50,\n      \"cornerRadius\" : 8,\n      \"actions\": [\n        {\n          \"backgroundColor\": \"#EF5B5BFF\",\n          \"content\": {\n            \"_type\": \"StyledText\",\n            \"size\": 18,\n            \"text\": \"Get the free pirate expansion\",\n            \"color\": \"#FFFFFFFF\"\n          },\n          \"url\": \"http://worth1000.s3.amazonaws.com/submissions/384000/384447_858b_625x1000.jpg\"\n        },\n        {\n          \"backgroundColor\": \"#00000000\",\n          \"content\": {\n            \"_type\": \"StyledText\",\n            \"size\": 14,\n            \"text\": \"Nah, I don't like free\",\n            \"color\": \"#EF5B5BFF\"\n          }\n        }\n      ]\n    }\n  }\n}\n"
  },
  {
    "path": "iOS/FBNotificationsExample/FBNotificationsExample/Resources/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>UIBackgroundModes</key>\n\t<array>\n\t\t<string>remote-notification</string>\n\t</array>\n\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</string>\n\t<key>UIMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>UIRequiredDeviceCapabilities</key>\n\t<array>\n\t\t<string>armv7</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "iOS/FBNotificationsExample/FBNotificationsExample/Source/AppDelegate.h",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import <UIKit/UIKit.h>\n\n@interface AppDelegate : UIResponder <UIApplicationDelegate>\n\n@property (strong, nonatomic) UIWindow *window;\n\n@end\n\n"
  },
  {
    "path": "iOS/FBNotificationsExample/FBNotificationsExample/Source/AppDelegate.m",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import \"AppDelegate.h\"\n\n#import <FBNotifications/FBNotifications.h>\n\n@interface AppDelegate ()\n\n@end\n\n@implementation AppDelegate\n\n- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(nullable NSDictionary *)launchOptions {\n    UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert categories:nil];\n    [[UIApplication sharedApplication] registerUserNotificationSettings:settings];\n\n    [[UIApplication sharedApplication] registerForRemoteNotifications];\n\n    return YES;\n}\n\n- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {\n    // TODO: Integrate with FBSDKCoreKit\n}\n\n- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(nonnull void (^)(UIBackgroundFetchResult))completionHandler {\n    FBNotificationsManager *notificationsManager = [FBNotificationsManager sharedManager];\n    if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground) {\n        [notificationsManager preparePushCardContentForRemoteNotificationPayload:userInfo\n                                                                      completion:^(NSDictionary * _Nullable payload, NSError * _Nullable error) {\n                                                                          if (error) {\n                                                                              completionHandler(UIBackgroundFetchResultFailed);\n                                                                          } else {\n                                                                              completionHandler(UIBackgroundFetchResultNewData);\n                                                                          }\n                                                                      }];\n    } else {\n        [notificationsManager presentPushCardForRemoteNotificationPayload:userInfo\n                                                       fromViewController:nil\n                                                               completion:^(FBNCardViewController * _Nullable viewController, NSError * _Nullable error) {\n                                                                   if (error) {\n                                                                       completionHandler(UIBackgroundFetchResultFailed);\n                                                                   } else {\n                                                                       completionHandler(UIBackgroundFetchResultNewData);\n                                                                   }\n                                                               }];\n    }\n}\n\n@end\n"
  },
  {
    "path": "iOS/FBNotificationsExample/FBNotificationsExample/Source/ViewController.h",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import <UIKit/UIKit.h>\n\n@interface ViewController : UIViewController\n\n\n@end\n\n"
  },
  {
    "path": "iOS/FBNotificationsExample/FBNotificationsExample/Source/ViewController.m",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import \"ViewController.h\"\n\n#import <FBNotifications/FBNotifications.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\nstatic const CGFloat FBNotificationsExampleButtonHeight = 44.0;\n\n@interface ViewController ()\n\n@property (nonatomic, copy, readonly) NSArray<NSString *> *examplePaths;\n@property (nullable, nonatomic, copy) NSArray<UIButton *> *buttons;\n\n@end\n\n@implementation ViewController\n\n@synthesize examplePaths = _examplePaths;\n\n///--------------------------------------\n#pragma mark - View\n///--------------------------------------\n\n- (void)viewDidLoad {\n    [super viewDidLoad];\n\n    self.buttons = [self _buttonsArrayWithCount:self.examplePaths.count];\n}\n\n- (void)viewDidLayoutSubviews {\n    [super viewDidLayoutSubviews];\n\n    const CGRect bounds = self.view.bounds;\n\n    CGFloat buttonsHeight = FBNotificationsExampleButtonHeight * self.buttons.count;\n    CGFloat buttonY = CGRectGetMidY(bounds) - buttonsHeight / 2.0;\n    for (UIButton *button in self.buttons) {\n        CGRect buttonFrame = CGRectZero;\n        buttonFrame.size.width = [button sizeThatFits:bounds.size].width;\n        buttonFrame.size.height = FBNotificationsExampleButtonHeight;\n        buttonFrame.origin.x = CGRectGetMidX(bounds) - CGRectGetMidX(buttonFrame);\n        buttonFrame.origin.y = buttonY;\n        button.frame = buttonFrame;\n\n        buttonY = CGRectGetMaxY(buttonFrame);\n    }\n}\n\n///--------------------------------------\n#pragma mark - Buttons\n///--------------------------------------\n\n- (void)_buttonAction:(UIButton *)button {\n    NSUInteger buttonIndex = [self.buttons indexOfObject:button];\n    if (buttonIndex == NSNotFound) {\n        return;\n    }\n\n    NSString *path = self.examplePaths[buttonIndex];\n    NSData *data = [NSData dataWithContentsOfFile:path];\n    NSDictionary *payload = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];\n    if (!payload) {\n        return;\n    }\n\n    //\n    // Here is the most interesting part of this example.\n    // We have 1 of 2 choices here - present the card immediately from the payload\n    // or schedule a local notification and mimic the remote notification.\n    //\n    // We use the present immediately from remote to simply showcase what you can do with cards,\n    // but the generic proper one should actually go through remote notification methods.\n    //\n    // Please note: Card presentation is not queued, so you can schedule presentation of more than a single card on a view controller.\n    // Not queuing them and not waiting for animation to finish leads to undefined behavior, so please write a simple queue on top.\n\n    //\n    // Approach #1: Present immediately, as if you would get it from remote notification.\n    [[FBNotificationsManager sharedManager] presentPushCardForRemoteNotificationPayload:payload\n                                                                     fromViewController:self\n                                                                             completion:nil];\n    //\n    // Approach #2: Mimic presentation via remote notification, by simply invoking a method.\n//    UIApplication *application = [UIApplication sharedApplication];\n//    [application.delegate application:application\n//         didReceiveRemoteNotification:payload\n//               fetchCompletionHandler:^(UIBackgroundFetchResult result) {}];\n}\n\n- (void)setButtons:(nullable NSArray<UIButton *> *)buttons {\n    if (self.buttons != buttons) {\n        [self.buttons makeObjectsPerformSelector:@selector(removeFromSuperview)];\n        _buttons = buttons;\n        for (UIButton *button in buttons) {\n            [self.view addSubview:button];\n        }\n        [self.view setNeedsLayout];\n    }\n}\n\n- (NSArray<UIButton *> *)_buttonsArrayWithCount:(NSUInteger)count {\n    NSMutableArray *buttons = [NSMutableArray array];\n    while (buttons.count != count) {\n        UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];\n        [button setTitle:[NSString stringWithFormat:@\"Show Example #%lu\", (unsigned long)buttons.count + 1] forState:UIControlStateNormal];\n        [button addTarget:self action:@selector(_buttonAction:) forControlEvents:UIControlEventTouchUpInside];\n        [buttons addObject:button];\n    }\n    return buttons;\n}\n\n///--------------------------------------\n#pragma mark - Examples\n///--------------------------------------\n\n- (NSArray<NSString *> *)examplePaths {\n    if (!_examplePaths) {\n        NSBundle *bundle = [NSBundle mainBundle];\n        NSMutableArray *array = [NSMutableArray array];\n        [array addObject:[bundle pathForResource:@\"example1\" ofType:@\"json\"]];\n        [array addObject:[bundle pathForResource:@\"example2\" ofType:@\"json\"]];\n        [array addObject:[bundle pathForResource:@\"example3\" ofType:@\"json\"]];\n        [array addObject:[bundle pathForResource:@\"example4\" ofType:@\"json\"]];\n        [array addObject:[bundle pathForResource:@\"example5\" ofType:@\"json\"]];\n        _examplePaths = [array copy];\n    }\n    return _examplePaths;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "iOS/FBNotificationsExample/FBNotificationsExample/Source/main.m",
    "content": "// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n//\n// You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n// copy, modify, and distribute this software in source code or binary form for use\n// in connection with the web services and APIs provided by Facebook.\n//\n// As with any software that integrates with the Facebook platform, your use of\n// this software is subject to the Facebook Developer Principles and Policies\n// [http://developers.facebook.com/policy/]. This copyright notice shall be\n// included in all copies or substantial portions of the software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n#import <UIKit/UIKit.h>\n#import \"AppDelegate.h\"\n\nint main(int argc, char * argv[]) {\n    @autoreleasepool {\n        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));\n    }\n}\n"
  },
  {
    "path": "iOS/FBNotificationsExample/FBNotificationsExample.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t06AF90D51CF049B400D656F8 /* FBNotifications.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 06AF90D41CF049AB00D656F8 /* FBNotifications.framework */; };\n\t\t06AF90D61CF049B400D656F8 /* FBNotifications.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 06AF90D41CF049AB00D656F8 /* FBNotifications.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };\n\t\t8106E5671C750D1700950AAA /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8106E5661C750D1700950AAA /* MobileCoreServices.framework */; };\n\t\t8106E56C1C750D2000950AAA /* ImageIO.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8106E56B1C750D2000950AAA /* ImageIO.framework */; };\n\t\t8106E5911C750D7400950AAA /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8106E57F1C750D7400950AAA /* Assets.xcassets */; };\n\t\t8106E5921C750D7400950AAA /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8106E5801C750D7400950AAA /* LaunchScreen.storyboard */; };\n\t\t8106E5931C750D7400950AAA /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8106E5821C750D7400950AAA /* Main.storyboard */; };\n\t\t8106E5941C750D7400950AAA /* example1.json in Resources */ = {isa = PBXBuildFile; fileRef = 8106E5851C750D7400950AAA /* example1.json */; };\n\t\t8106E5951C750D7400950AAA /* example2.json in Resources */ = {isa = PBXBuildFile; fileRef = 8106E5861C750D7400950AAA /* example2.json */; };\n\t\t8106E5961C750D7400950AAA /* example3.json in Resources */ = {isa = PBXBuildFile; fileRef = 8106E5871C750D7400950AAA /* example3.json */; };\n\t\t8106E5971C750D7400950AAA /* example4.json in Resources */ = {isa = PBXBuildFile; fileRef = 8106E5881C750D7400950AAA /* example4.json */; };\n\t\t8106E5981C750D7400950AAA /* example5.json in Resources */ = {isa = PBXBuildFile; fileRef = 8106E5891C750D7400950AAA /* example5.json */; };\n\t\t8106E59A1C750D7400950AAA /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 8106E58D1C750D7400950AAA /* AppDelegate.m */; };\n\t\t8106E59B1C750D7400950AAA /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 8106E58E1C750D7400950AAA /* main.m */; };\n\t\t8106E59C1C750D7400950AAA /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8106E5901C750D7400950AAA /* ViewController.m */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXContainerItemProxy section */\n\t\t06AF90D11CF049AB00D656F8 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 06AF90CC1CF049AB00D656F8 /* FBNotifications.xcodeproj */;\n\t\t\tproxyType = 2;\n\t\t\tremoteGlobalIDString = 81F0B10A1C4ED4FE00160CCD;\n\t\t\tremoteInfo = \"FBNotifications-iOS\";\n\t\t};\n\t\t06AF90D31CF049AB00D656F8 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 06AF90CC1CF049AB00D656F8 /* FBNotifications.xcodeproj */;\n\t\t\tproxyType = 2;\n\t\t\tremoteGlobalIDString = 811E17671CB75034009AAE22;\n\t\t\tremoteInfo = \"FBNotifications-iOS-Dynamic\";\n\t\t};\n\t\t06AF90D71CF049B400D656F8 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 06AF90CC1CF049AB00D656F8 /* FBNotifications.xcodeproj */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 811E17141CB75034009AAE22;\n\t\t\tremoteInfo = \"FBNotifications-iOS-Dynamic\";\n\t\t};\n/* End PBXContainerItemProxy section */\n\n/* Begin PBXCopyFilesBuildPhase section */\n\t\t06AF90D91CF049B400D656F8 /* Embed Frameworks */ = {\n\t\t\tisa = PBXCopyFilesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tdstPath = \"\";\n\t\t\tdstSubfolderSpec = 10;\n\t\t\tfiles = (\n\t\t\t\t06AF90D61CF049B400D656F8 /* FBNotifications.framework in Embed Frameworks */,\n\t\t\t);\n\t\t\tname = \"Embed Frameworks\";\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXCopyFilesBuildPhase section */\n\n/* Begin PBXFileReference section */\n\t\t06AF90CC1CF049AB00D656F8 /* FBNotifications.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = \"wrapper.pb-project\"; name = FBNotifications.xcodeproj; path = ../FBNotifications/FBNotifications.xcodeproj; sourceTree = \"<group>\"; };\n\t\t8106E53C1C750B7700950AAA /* FBNotificationsExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = FBNotificationsExample.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t8106E5661C750D1700950AAA /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; };\n\t\t8106E56B1C750D2000950AAA /* ImageIO.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ImageIO.framework; path = System/Library/Frameworks/ImageIO.framework; sourceTree = SDKROOT; };\n\t\t8106E57F1C750D7400950AAA /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\t8106E5811C750D7400950AAA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = \"<group>\"; };\n\t\t8106E5831C750D7400950AAA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = \"<group>\"; };\n\t\t8106E5851C750D7400950AAA /* example1.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = example1.json; sourceTree = \"<group>\"; };\n\t\t8106E5861C750D7400950AAA /* example2.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = example2.json; sourceTree = \"<group>\"; };\n\t\t8106E5871C750D7400950AAA /* example3.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = example3.json; sourceTree = \"<group>\"; };\n\t\t8106E5881C750D7400950AAA /* example4.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = example4.json; sourceTree = \"<group>\"; };\n\t\t8106E5891C750D7400950AAA /* example5.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = example5.json; sourceTree = \"<group>\"; };\n\t\t8106E58A1C750D7400950AAA /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t8106E58C1C750D7400950AAA /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = \"<group>\"; };\n\t\t8106E58D1C750D7400950AAA /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = \"<group>\"; };\n\t\t8106E58E1C750D7400950AAA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = \"<group>\"; };\n\t\t8106E58F1C750D7400950AAA /* ViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = \"<group>\"; };\n\t\t8106E5901C750D7400950AAA /* ViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t8106E5391C750B7700950AAA /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t8106E56C1C750D2000950AAA /* ImageIO.framework in Frameworks */,\n\t\t\t\t06AF90D51CF049B400D656F8 /* FBNotifications.framework in Frameworks */,\n\t\t\t\t8106E5671C750D1700950AAA /* MobileCoreServices.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t06AF90CD1CF049AB00D656F8 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t06AF90D21CF049AB00D656F8 /* FBNotifications.framework */,\n\t\t\t\t06AF90D41CF049AB00D656F8 /* FBNotifications.framework */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t8106E5331C750B7700950AAA = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t8106E53E1C750B7700950AAA /* FBNotificationsExample */,\n\t\t\t\t8106E5751C750D2C00950AAA /* Frameworks */,\n\t\t\t\t8106E53D1C750B7700950AAA /* Products */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t8106E53D1C750B7700950AAA /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t8106E53C1C750B7700950AAA /* FBNotificationsExample.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t8106E53E1C750B7700950AAA /* FBNotificationsExample */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t8106E58B1C750D7400950AAA /* Source */,\n\t\t\t\t8106E57E1C750D7400950AAA /* Resources */,\n\t\t\t);\n\t\t\tpath = FBNotificationsExample;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t8106E5751C750D2C00950AAA /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t06AF90CC1CF049AB00D656F8 /* FBNotifications.xcodeproj */,\n\t\t\t\t8106E56B1C750D2000950AAA /* ImageIO.framework */,\n\t\t\t\t8106E5661C750D1700950AAA /* MobileCoreServices.framework */,\n\t\t\t);\n\t\t\tname = Frameworks;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t8106E57E1C750D7400950AAA /* Resources */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t8106E5821C750D7400950AAA /* Main.storyboard */,\n\t\t\t\t8106E5801C750D7400950AAA /* LaunchScreen.storyboard */,\n\t\t\t\t8106E57F1C750D7400950AAA /* Assets.xcassets */,\n\t\t\t\t8106E5841C750D7400950AAA /* Examples */,\n\t\t\t\t8106E58A1C750D7400950AAA /* Info.plist */,\n\t\t\t);\n\t\t\tpath = Resources;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t8106E5841C750D7400950AAA /* Examples */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t8106E5851C750D7400950AAA /* example1.json */,\n\t\t\t\t8106E5861C750D7400950AAA /* example2.json */,\n\t\t\t\t8106E5871C750D7400950AAA /* example3.json */,\n\t\t\t\t8106E5881C750D7400950AAA /* example4.json */,\n\t\t\t\t8106E5891C750D7400950AAA /* example5.json */,\n\t\t\t);\n\t\t\tpath = Examples;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t8106E58B1C750D7400950AAA /* Source */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t8106E58C1C750D7400950AAA /* AppDelegate.h */,\n\t\t\t\t8106E58D1C750D7400950AAA /* AppDelegate.m */,\n\t\t\t\t8106E58F1C750D7400950AAA /* ViewController.h */,\n\t\t\t\t8106E5901C750D7400950AAA /* ViewController.m */,\n\t\t\t\t8106E5A61C750DA300950AAA /* Other */,\n\t\t\t);\n\t\t\tpath = Source;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t8106E5A61C750DA300950AAA /* Other */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t8106E58E1C750D7400950AAA /* main.m */,\n\t\t\t);\n\t\t\tname = Other;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t8106E53B1C750B7700950AAA /* FBNotificationsExample */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 8106E5531C750B7700950AAA /* Build configuration list for PBXNativeTarget \"FBNotificationsExample\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t8106E5381C750B7700950AAA /* Sources */,\n\t\t\t\t8106E5391C750B7700950AAA /* Frameworks */,\n\t\t\t\t8106E53A1C750B7700950AAA /* Resources */,\n\t\t\t\t06AF90D91CF049B400D656F8 /* Embed Frameworks */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\t06AF90D81CF049B400D656F8 /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = FBNotificationsExample;\n\t\t\tproductName = FBNotificationsExample;\n\t\t\tproductReference = 8106E53C1C750B7700950AAA /* FBNotificationsExample.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t8106E5341C750B7700950AAA /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastUpgradeCheck = 0720;\n\t\t\t\tORGANIZATIONNAME = \"Facebook Inc\";\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t8106E53B1C750B7700950AAA = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 7.2.1;\n\t\t\t\t\t\tSystemCapabilities = {\n\t\t\t\t\t\t\tcom.apple.BackgroundModes = {\n\t\t\t\t\t\t\t\tenabled = 1;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\tcom.apple.Push = {\n\t\t\t\t\t\t\t\tenabled = 1;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t};\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 8106E5371C750B7700950AAA /* Build configuration list for PBXProject \"FBNotificationsExample\" */;\n\t\t\tcompatibilityVersion = \"Xcode 3.2\";\n\t\t\tdevelopmentRegion = English;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = 8106E5331C750B7700950AAA;\n\t\t\tproductRefGroup = 8106E53D1C750B7700950AAA /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectReferences = (\n\t\t\t\t{\n\t\t\t\t\tProductGroup = 06AF90CD1CF049AB00D656F8 /* Products */;\n\t\t\t\t\tProjectRef = 06AF90CC1CF049AB00D656F8 /* FBNotifications.xcodeproj */;\n\t\t\t\t},\n\t\t\t);\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t8106E53B1C750B7700950AAA /* FBNotificationsExample */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXReferenceProxy section */\n\t\t06AF90D21CF049AB00D656F8 /* FBNotifications.framework */ = {\n\t\t\tisa = PBXReferenceProxy;\n\t\t\tfileType = wrapper.framework;\n\t\t\tpath = FBNotifications.framework;\n\t\t\tremoteRef = 06AF90D11CF049AB00D656F8 /* PBXContainerItemProxy */;\n\t\t\tsourceTree = BUILT_PRODUCTS_DIR;\n\t\t};\n\t\t06AF90D41CF049AB00D656F8 /* FBNotifications.framework */ = {\n\t\t\tisa = PBXReferenceProxy;\n\t\t\tfileType = wrapper.framework;\n\t\t\tpath = FBNotifications.framework;\n\t\t\tremoteRef = 06AF90D31CF049AB00D656F8 /* PBXContainerItemProxy */;\n\t\t\tsourceTree = BUILT_PRODUCTS_DIR;\n\t\t};\n/* End PBXReferenceProxy section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t8106E53A1C750B7700950AAA /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t8106E5961C750D7400950AAA /* example3.json in Resources */,\n\t\t\t\t8106E5911C750D7400950AAA /* Assets.xcassets in Resources */,\n\t\t\t\t8106E5951C750D7400950AAA /* example2.json in Resources */,\n\t\t\t\t8106E5941C750D7400950AAA /* example1.json in Resources */,\n\t\t\t\t8106E5931C750D7400950AAA /* Main.storyboard in Resources */,\n\t\t\t\t8106E5971C750D7400950AAA /* example4.json in Resources */,\n\t\t\t\t8106E5981C750D7400950AAA /* example5.json in Resources */,\n\t\t\t\t8106E5921C750D7400950AAA /* LaunchScreen.storyboard in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t8106E5381C750B7700950AAA /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t8106E59C1C750D7400950AAA /* ViewController.m in Sources */,\n\t\t\t\t8106E59B1C750D7400950AAA /* main.m in Sources */,\n\t\t\t\t8106E59A1C750D7400950AAA /* AppDelegate.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXTargetDependency section */\n\t\t06AF90D81CF049B400D656F8 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\tname = \"FBNotifications-iOS-Dynamic\";\n\t\t\ttargetProxy = 06AF90D71CF049B400D656F8 /* PBXContainerItemProxy */;\n\t\t};\n/* End PBXTargetDependency section */\n\n/* Begin PBXVariantGroup section */\n\t\t8106E5801C750D7400950AAA /* LaunchScreen.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t8106E5811C750D7400950AAA /* Base */,\n\t\t\t);\n\t\t\tname = LaunchScreen.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t8106E5821C750D7400950AAA /* Main.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t8106E5831C750D7400950AAA /* Base */,\n\t\t\t);\n\t\t\tname = Main.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\t8106E5511C750B7700950AAA /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 9.2;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t8106E5521C750B7700950AAA /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 9.2;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t8106E5541C750B7700950AAA /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = (\n\t\t\t\t\t\"$(PROJECT_DIR)\",\n\t\t\t\t\t\"$(BUILT_PRODUCTS_DIR)\",\n\t\t\t\t);\n\t\t\t\tINFOPLIST_FILE = FBNotificationsExample/Resources/Info.plist;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 8.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.facebook.FBNotificationsExample;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t8106E5551C750B7700950AAA /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = (\n\t\t\t\t\t\"$(PROJECT_DIR)\",\n\t\t\t\t\t\"$(BUILT_PRODUCTS_DIR)\",\n\t\t\t\t);\n\t\t\t\tINFOPLIST_FILE = FBNotificationsExample/Resources/Info.plist;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 8.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.facebook.FBNotificationsExample;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t8106E5371C750B7700950AAA /* Build configuration list for PBXProject \"FBNotificationsExample\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t8106E5511C750B7700950AAA /* Debug */,\n\t\t\t\t8106E5521C750B7700950AAA /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t8106E5531C750B7700950AAA /* Build configuration list for PBXNativeTarget \"FBNotificationsExample\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t8106E5541C750B7700950AAA /* Debug */,\n\t\t\t\t8106E5551C750B7700950AAA /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = 8106E5341C750B7700950AAA /* Project object */;\n}\n"
  },
  {
    "path": "iOS/FBNotificationsExample/FBNotificationsExample.xcodeproj/xcshareddata/xcschemes/FBNotificationsExample.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"0730\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"8106E53B1C750B7700950AAA\"\n               BuildableName = \"FBNotificationsExample.app\"\n               BlueprintName = \"FBNotificationsExample\"\n               ReferencedContainer = \"container:FBNotificationsExample.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <Testables>\n      </Testables>\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"8106E53B1C750B7700950AAA\"\n            BuildableName = \"FBNotificationsExample.app\"\n            BlueprintName = \"FBNotificationsExample\"\n            ReferencedContainer = \"container:FBNotificationsExample.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"8106E53B1C750B7700950AAA\"\n            BuildableName = \"FBNotificationsExample.app\"\n            BlueprintName = \"FBNotificationsExample\"\n            ReferencedContainer = \"container:FBNotificationsExample.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"8106E53B1C750B7700950AAA\"\n            BuildableName = \"FBNotificationsExample.app\"\n            BlueprintName = \"FBNotificationsExample\"\n            ReferencedContainer = \"container:FBNotificationsExample.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "iOS/Rakefile",
    "content": "# Copyright (c) 2016-present, Facebook, Inc. All rights reserved.\n#\n# You are hereby granted a non-exclusive, worldwide, royalty-free license to use,\n# copy, modify, and distribute this software in source code or binary form for use\n# in connection with the web services and APIs provided by Facebook.\n#\n# As with any software that integrates with the Facebook platform, your use of\n# this software is subject to the Facebook Developer Principles and Policies\n# [http://developers.facebook.com/policy/]. This copyright notice shall be\n# included in all copies or substantial portions of the software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\nrequire_relative 'Vendor/xctoolchain/Scripts/xctask/build_task'\nrequire_relative 'Vendor/xctoolchain/Scripts/xctask/build_framework_task'\n\nscript_folder = File.expand_path(File.dirname(__FILE__))\nframework_source_folder = File.join(script_folder, 'FBNotifications')\nbuild_folder = File.join(script_folder, 'build')\nrelease_folder = File.join(build_folder, 'release')\n\nnamespace :build do\n\n  desc 'Build Frameworks'\n  task :frameworks do |_, _|\n    task = XCTask::BuildFrameworkTask.new do |t|\n      t.directory = framework_source_folder\n      t.build_directory = build_folder\n      t.framework_type = XCTask::FrameworkType::IOS\n      t.framework_name = 'FBNotifications.framework'\n\n      t.project = 'FBNotifications.xcodeproj'\n      t.scheme = 'FBNotifications-iOS'\n      t.configuration = 'Release'\n    end\n    result = task.execute\n    unless result\n      puts 'Failed to build iOS Framework.'\n      exit(1)\n    end\n  end\nend\n\nnamespace :package do\n  \n  framework_path = File.join(build_folder, 'FBNotifications.framework')\n  \n  task :prepare do\n    `rm -rf #{build_folder} && mkdir -p #{build_folder}`\n  end\n  \n  desc 'Package Frameworks for Release'\n  task :frameworks => :prepare do |_, _|\n    Rake::Task['build:frameworks'].invoke\n    make_package(release_folder, [framework_path], 'FBNotifications-iOS.zip')\n  end\n  \n  desc 'Package Sample for Release'\n  task :sample => :frameworks do |_, _|\n    sample_folder = File.join(script_folder, 'FBNotificationsExample')\n    `git clean -xfd #{sample_folder}`\n    cp_r(framework_path, sample_folder)\n    \n    make_package(release_folder, [sample_folder], 'FBNotifications-iOS-Sample.zip')\n  end\n  \n  def make_package(target_path, items, archive_name)\n    temp_folder = File.join(target_path, 'tmp')\n    `mkdir -p #{temp_folder}`\n\n    item_list = ''\n    items.each do |item|\n      `cp -R #{item} #{temp_folder}`\n\n      file_name = File.basename(item)\n      item_list << \" #{file_name}\"\n    end\n\n    archive_path = File.join(target_path, archive_name)\n    `cd #{temp_folder}; zip -r --symlinks #{archive_path} #{item_list}`\n    `rm -rf #{temp_folder}`\n    puts \"Release archive created: #{File.join(target_path, archive_name)}\"\n  end\nend\n\n"
  }
]