[
  {
    "path": ".buckconfig",
    "content": "\n[android]\n  target = Google Inc.:Google APIs:23\n\n[maven_repositories]\n  central = https://repo1.maven.org/maven2\n"
  },
  {
    "path": ".flowconfig",
    "content": "[ignore]\n\n# We fork some components by platform.\n.*/*.web.js\n.*/*.android.js\n\n# Some modules have their own node_modules with overlap\n.*/node_modules/node-haste/.*\n\n# Ugh\n.*/node_modules/babel.*\n.*/node_modules/babylon.*\n.*/node_modules/invariant.*\n\n# Ignore react and fbjs where there are overlaps, but don't ignore\n# anything that react-native relies on\n.*/node_modules/fbjs/lib/Map.js\n.*/node_modules/fbjs/lib/ErrorUtils.js\n\n# Flow has a built-in definition for the 'react' module which we prefer to use\n# over the currently-untyped source\n.*/node_modules/react/react.js\n.*/node_modules/react/lib/React.js\n.*/node_modules/react/lib/ReactDOM.js\n\n.*/__mocks__/.*\n.*/__tests__/.*\n\n.*/commoner/test/source/widget/share.js\n\n# Ignore commoner tests\n.*/node_modules/commoner/test/.*\n\n# See https://github.com/facebook/flow/issues/442\n.*/react-tools/node_modules/commoner/lib/reader.js\n\n# Ignore jest\n.*/node_modules/jest-cli/.*\n\n# Ignore Website\n.*/website/.*\n\n# Ignore generators\n.*/local-cli/generator.*\n\n# Ignore BUCK generated folders\n.*\\.buckd/\n\n# Ignore RNPM\n.*/local-cli/rnpm/.*\n\n.*/node_modules/is-my-json-valid/test/.*\\.json\n.*/node_modules/iconv-lite/encodings/tables/.*\\.json\n.*/node_modules/y18n/test/.*\\.json\n.*/node_modules/spdx-license-ids/spdx-license-ids.json\n.*/node_modules/spdx-exceptions/index.json\n.*/node_modules/resolve/test/subdirs/node_modules/a/b/c/x.json\n.*/node_modules/resolve/lib/core.json\n.*/node_modules/jsonparse/samplejson/.*\\.json\n.*/node_modules/json5/test/.*\\.json\n.*/node_modules/ua-parser-js/test/.*\\.json\n.*/node_modules/builtin-modules/builtin-modules.json\n.*/node_modules/binary-extensions/binary-extensions.json\n.*/node_modules/url-regex/tlds.json\n.*/node_modules/joi/.*\\.json\n.*/node_modules/isemail/.*\\.json\n.*/node_modules/tr46/.*\\.json\n\n\n[include]\n\n[libs]\nnode_modules/react-native/Libraries/react-native/react-native-interface.js\nnode_modules/react-native/flow\nflow/\n\n[options]\nmodule.system=haste\n\nesproposal.class_static_fields=enable\nesproposal.class_instance_fields=enable\n\nmunge_underscores=true\n\nmodule.name_mapper='^image![a-zA-Z0-9$_-]+$' -> 'GlobalImageStub'\nmodule.name_mapper='^[./a-zA-Z0-9$_-]+\\.\\(bmp\\|gif\\|jpg\\|jpeg\\|png\\|psd\\|svg\\|webp\\|m4v\\|mov\\|mp4\\|mpeg\\|mpg\\|webm\\|aac\\|aiff\\|caf\\|m4a\\|mp3\\|wav\\|html\\|pdf\\)$' -> 'RelativeImageStub'\n\nsuppress_type=$FlowIssue\nsuppress_type=$FlowFixMe\nsuppress_type=$FixMe\n\nsuppress_comment=\\\\(.\\\\|\\n\\\\)*\\\\$FlowFixMe\\\\($\\\\|[^(]\\\\|(\\\\(>=0\\\\.\\\\(2[0-5]\\\\|1[0-9]\\\\|[0-9]\\\\).[0-9]\\\\)? *\\\\(site=[a-z,_]*react_native[a-z,_]*\\\\)?)\\\\)\nsuppress_comment=\\\\(.\\\\|\\n\\\\)*\\\\$FlowIssue\\\\((\\\\(>=0\\\\.\\\\(2[0-5]\\\\|1[0-9]\\\\|[0-9]\\\\).[0-9]\\\\)? *\\\\(site=[a-z,_]*react_native[a-z,_]*\\\\)?)\\\\)?:? #[0-9]+\nsuppress_comment=\\\\(.\\\\|\\n\\\\)*\\\\$FlowFixedInNextDeploy\n\n[version]\n^0.25.0\n"
  },
  {
    "path": ".gitignore",
    "content": "# OSX\n#\n.DS_Store\n\n# Xcode\n#\nbuild/\n*.pbxuser\n!default.pbxuser\n*.mode1v3\n!default.mode1v3\n*.mode2v3\n!default.mode2v3\n*.perspectivev3\n!default.perspectivev3\nxcuserdata\n*.xccheckout\n*.moved-aside\nDerivedData\n*.hmap\n*.ipa\n*.xcuserstate\nproject.xcworkspace\n\n# Android/IJ\n#\n.idea\n.gradle\nlocal.properties\n\n# node.js\n#\nnode_modules/\nnpm-debug.log\n\n# BUCK\nbuck-out/\n\\.buckd/\nandroid/app/libs\nandroid/keystores/debug.keystore\n\n# CUSTOM\n*.keystore\n"
  },
  {
    "path": ".npmignore",
    "content": "# OSX\n#\n.DS_Store\n\n# Xcode\n#\nbuild/\n*.pbxuser\n!default.pbxuser\n*.mode1v3\n!default.mode1v3\n*.mode2v3\n!default.mode2v3\n*.perspectivev3\n!default.perspectivev3\nxcuserdata\n*.xccheckout\n*.moved-aside\nDerivedData\n*.hmap\n*.ipa\n*.xcuserstate\n\n# node.js\n#\nnode_modules/\nnpm-debug.log\n"
  },
  {
    "path": ".watchmanconfig",
    "content": "{}"
  },
  {
    "path": "README.md",
    "content": "HackerWeb\n===\n\nA simply readable Hacker News app for iOS and Android.\n\nRead about the story here: [Building HackerWeb for iOS](http://cheeaun.com/blog/2016/03/building-hackerweb-ios/).\n\nPreview\n---\n\n### iOS\n\n![Preview on iOS](media/hackerweb-preview-ios.gif)\n\n### Android\n\n![Preview on Android](media/hackerweb-preview-android.gif)\n\nDevelopment\n---\n\n### Requirements\n\n- [React Native](https://facebook.github.io/react-native/)\n- [React Native Package Manager](https://github.com/rnpm/rnpm)\n- [Node.js](https://nodejs.org/)\n- [Xcode](https://developer.apple.com/xcode/)\n- [iOS](https://www.apple.com/ios/) **9**\n- Android SDK API **23** (minimum support: 21)\n\n### Getting started\n\n- `npm install` - Install all dependencies\n- `rnpm link` - Linking all native dependencies\n\n### Implementations\n\n- [Alt](http://alt.js.org/) - the Flux thing\n- [htmlparser2](https://github.com/fb55/htmlparser2) - for parsing the comments HTML\n- [url-parse](https://github.com/unshiftio/url-parse) - for extracting domains out of story URLs\n- **iOS**\n  - [react-native-safari-view](https://github.com/naoufal/react-native-safari-view) - the reason why iOS 9 is the minimum requirement\n- **Android**\n  - [react-native-chrome-custom-tabs](https://github.com/dstaley/react-native-chrome-custom-tabs) - same as SafariView for iOS, but for Chrome\n  - [react-native-android-share](https://github.com/haydenth/react-native-android-share) - for sharing\n\n### Components\n\n- `LoadingIndicator` - inspired by [react-native-activity-indicator-ios](https://github.com/pwmckenna/react-native-activity-indicator-ios)\n- `HTMLView` - inspired by [react-native-htmlview](https://github.com/jsdf/react-native-htmlview), [react-native-htmltext](https://github.com/siuying/react-native-htmltext) and [react-native-html-render](https://github.com/soliury/react-native-html-render)\n- [react-native-cache-store](https://github.com/cheeaun/react-native-cache-store) - for local caching\n\nSimilar apps\n---\n\n- [HackerNews-React-Native](https://github.com/iSimar/HackerNews-React-Native)\n- [ReactNativeHackerNews](https://github.com/jsdf/ReactNativeHackerNews)\n\nLicense\n---\n\n[MIT](http://cheeaun.mit-license.org/).\n"
  },
  {
    "path": "actions/LinkActions.js",
    "content": "'use strict';\n\nimport alt from '../alt';\nimport CacheStore from 'react-native-cache-store';\n\nclass LinkActions {\n  getLinks(){\n    return (dispatch) => {\n      CacheStore.get('links')\n        .then((links) => dispatch(links || []))\n        .catch(() => {});\n    };\n  }\n\n  addLink(link){\n    return (dispatch) => {\n      CacheStore.get('links')\n        .then((links) => {\n          links = links || [];\n          if (links.indexOf(link) < 0){\n            dispatch(link);\n            links.unshift(link);\n            CacheStore.set('links', links.slice(0, 100));\n          }\n        })\n        .catch(() => {});\n    };\n  }\n}\n\nexport default alt.createActions(LinkActions);\n"
  },
  {
    "path": "actions/StoryActions.js",
    "content": "'use strict';\n\nimport alt from '../alt';\nimport CacheStore from 'react-native-cache-store';\n\nconst API_HOST = 'https://api.hackerwebapp.com/';\nconst FETCH_TIMEOUT = 20000; // 20 seconds\nfunction fetchTimeout(){\n  return new Promise((resolve, reject) => {\n    setTimeout(() => reject(new Error('Response timeout.')), FETCH_TIMEOUT);\n  })\n};\nconst MAX_RETRIES = 3;\nfunction betterFetch(url, times){\n  times = times || 0;\n  return new Promise((resolve, reject) => {\n    fetch(url)\n      .then((response) => response.json())\n      .then(resolve)\n      .catch((times >= MAX_RETRIES) ? reject : (e) => {\n        setTimeout(() => {\n          betterFetch(url, times+1).then(resolve).catch(reject);\n        }, 500);\n      });\n  });\n};\n\nclass StoryActions {\n  updateStories(stories){\n    return stories;\n  }\n\n  updateMoreStories(stories){\n    return stories;\n  }\n\n  flush(){\n    CacheStore.flush(); // Clears everything\n  }\n\n  fetchStories(){\n    return (dispatch) => {\n      dispatch();\n\n      var request = () => {\n        Promise.race([\n          betterFetch(API_HOST + 'news'),\n          fetchTimeout()\n        ])\n          .then((stories) => {\n            if (!stories || !stories.length) throw new Error('Stories payload is empty');\n            this.updateStories(stories);\n            CacheStore.set('stories', stories, 10); // 10 minutes\n          })\n          .catch(this.storiesFailed);\n\n        // Meanwhile...\n        betterFetch(API_HOST + 'news2')\n          .then((stories) => {\n            if (!stories || !stories.length) return;\n            this.hasMoreStories();\n            CacheStore.set('stories2', stories, 10); // 10 minutes\n          })\n          .catch(() => {});\n      };\n\n      CacheStore.get('stories').then((stories) => {\n        if (stories){\n          this.updateStories(stories);\n        } else {\n          request();\n        }\n      }).catch(request);\n\n      CacheStore.get('stories2').then((stories) => {\n        if (stories) this.hasMoreStories();\n      }).catch(() => {});\n    };\n  }\n\n  hasMoreStories(){\n    return true;\n  }\n\n  fetchMoreStories(){\n    CacheStore.get('stories2').then((stories) => {\n      if (stories) this.updateMoreStories(stories);\n    }).catch(() => {});\n  }\n\n  fetchStoriesIfExpired(){\n    CacheStore.isExpired('stories').then(this.fetchStories).catch(() => {});\n  }\n\n  storiesFailed(error){\n    return error;\n  }\n\n  updateStory(story){\n    return story;\n  }\n\n  fetchStory(id) {\n    return (dispatch) => {\n      dispatch(id);\n      const key = `story-${id}`;\n      var request = () => {\n        Promise.race([\n          betterFetch(API_HOST + 'item/' + id),\n          fetchTimeout()\n        ])\n          .then((story) => {\n            if (!story) throw new Error('Story payload is empty');\n            this.updateStory(story);\n            CacheStore.set(key, story, 5); // 5 minutes\n          })\n          .catch(this.storyFailed);\n      };\n      CacheStore.get(key).then((story) => {\n        if (story){\n          this.updateStory(story);\n        } else {\n          request();\n        }\n      }).catch(request);\n    };\n  }\n\n  storyFailed(error){\n    return error;\n  }\n}\n\nexport default alt.createActions(StoryActions);\n"
  },
  {
    "path": "alt.js",
    "content": "import Alt from 'alt';\nexport default new Alt();\n"
  },
  {
    "path": "android/android.iml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<module external.system.id=\"GRADLE\" type=\"JAVA_MODULE\" version=\"4\">\n  <component name=\"FacetManager\">\n    <facet type=\"android-gradle\" name=\"Android-Gradle\">\n      <configuration>\n        <option name=\"GRADLE_PROJECT_PATH\" value=\":\" />\n      </configuration>\n    </facet>\n    <facet type=\"android\" name=\"Android\">\n      <configuration>\n        <option name=\"ALLOW_USER_CONFIGURATION\" value=\"false\" />\n      </configuration>\n    </facet>\n  </component>\n  <component name=\"NewModuleRootManager\" inherit-compiler-output=\"true\">\n    <exclude-output />\n    <content url=\"file://$MODULE_DIR$\" />\n    <orderEntry type=\"jdk\" jdkName=\"1.8\" jdkType=\"JavaSDK\" />\n    <orderEntry type=\"sourceFolder\" forTests=\"false\" />\n  </component>\n</module>"
  },
  {
    "path": "android/app/BUCK",
    "content": "import re\n\n# To learn about Buck see [Docs](https://buckbuild.com/).\n# To run your application with Buck:\n# - install Buck\n# - `npm start` - to start the packager\n# - `cd android`\n# - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname \"CN=Android Debug,O=Android,C=US`\n# - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck\n# - `buck install -r android/app` - compile, install and run application\n#\n\nlib_deps = []\nfor jarfile in glob(['libs/*.jar']):\n  name = 'jars__' + re.sub(r'^.*/([^/]+)\\.jar$', r'\\1', jarfile)\n  lib_deps.append(':' + name)\n  prebuilt_jar(\n    name = name,\n    binary_jar = jarfile,\n  )\n\nfor aarfile in glob(['libs/*.aar']):\n  name = 'aars__' + re.sub(r'^.*/([^/]+)\\.aar$', r'\\1', aarfile)\n  lib_deps.append(':' + name)\n  android_prebuilt_aar(\n    name = name,\n    aar = aarfile,\n  )\n\nandroid_library(\n  name = 'all-libs',\n  exported_deps = lib_deps\n)\n\nandroid_library(\n  name = 'app-code',\n  srcs = glob([\n    'src/main/java/**/*.java',\n  ]),\n  deps = [\n    ':all-libs',\n    ':build_config',\n    ':res',\n  ],\n)\n\nandroid_build_config(\n  name = 'build_config',\n  package = 'cheeaun.hackerweb',\n)\n\nandroid_resource(\n  name = 'res',\n  res = 'src/main/res',\n  package = 'cheeaun.hackerweb',\n)\n\nandroid_binary(\n  name = 'app',\n  package_type = 'debug',\n  manifest = 'src/main/AndroidManifest.xml',\n  keystore = '//android/keystores:debug',\n  deps = [\n    ':app-code',\n  ],\n)\n"
  },
  {
    "path": "android/app/build.gradle",
    "content": "apply plugin: \"com.android.application\"\n\nimport com.android.build.OutputFile\n\n/**\n * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets\n * and bundleReleaseJsAndAssets).\n * These basically call `react-native bundle` with the correct arguments during the Android build\n * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the\n * bundle directly from the development server. Below you can see all the possible configurations\n * and their defaults. If you decide to add a configuration block, make sure to add it before the\n * `apply from: \"../../node_modules/react-native/react.gradle\"` line.\n *\n * project.ext.react = [\n *   // the name of the generated asset file containing your JS bundle\n *   bundleAssetName: \"index.android.bundle\",\n *\n *   // the entry file for bundle generation\n *   entryFile: \"index.android.js\",\n *\n *   // whether to bundle JS and assets in debug mode\n *   bundleInDebug: false,\n *\n *   // whether to bundle JS and assets in release mode\n *   bundleInRelease: true,\n *\n *   // whether to bundle JS and assets in another build variant (if configured).\n *   // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants\n *   // The configuration property can be in the following formats\n *   //         'bundleIn${productFlavor}${buildType}'\n *   //         'bundleIn${buildType}'\n *   // bundleInFreeDebug: true,\n *   // bundleInPaidRelease: true,\n *   // bundleInBeta: true,\n *\n *   // the root of your project, i.e. where \"package.json\" lives\n *   root: \"../../\",\n *\n *   // where to put the JS bundle asset in debug mode\n *   jsBundleDirDebug: \"$buildDir/intermediates/assets/debug\",\n *\n *   // where to put the JS bundle asset in release mode\n *   jsBundleDirRelease: \"$buildDir/intermediates/assets/release\",\n *\n *   // where to put drawable resources / React Native assets, e.g. the ones you use via\n *   // require('./image.png')), in debug mode\n *   resourcesDirDebug: \"$buildDir/intermediates/res/merged/debug\",\n *\n *   // where to put drawable resources / React Native assets, e.g. the ones you use via\n *   // require('./image.png')), in release mode\n *   resourcesDirRelease: \"$buildDir/intermediates/res/merged/release\",\n *\n *   // by default the gradle tasks are skipped if none of the JS files or assets change; this means\n *   // that we don't look at files in android/ or ios/ to determine whether the tasks are up to\n *   // date; if you have any other folders that you want to ignore for performance reasons (gradle\n *   // indexes the entire tree), add them here. Alternatively, if you have JS files in android/\n *   // for example, you might want to remove it from here.\n *   inputExcludes: [\"android/**\", \"ios/**\"]\n * ]\n */\n\napply from: \"../../node_modules/react-native/react.gradle\"\n\n/**\n * Set this to true to create two separate APKs instead of one:\n *   - An APK that only works on ARM devices\n *   - An APK that only works on x86 devices\n * The advantage is the size of the APK is reduced by about 4MB.\n * Upload all the APKs to the Play Store and people will download\n * the correct one based on the CPU architecture of their device.\n */\ndef enableSeparateBuildPerCPUArchitecture = false\n\n/**\n * Run Proguard to shrink the Java bytecode in release builds.\n */\ndef enableProguardInReleaseBuilds = false\n\nandroid {\n    compileSdkVersion 23\n    buildToolsVersion \"23.0.1\"\n\n    defaultConfig {\n        applicationId \"cheeaun.hackerweb\"\n        minSdkVersion 21\n        targetSdkVersion 23\n        versionCode 3\n        versionName \"1.2\"\n        ndk {\n            abiFilters \"armeabi-v7a\", \"x86\"\n        }\n    }\n    signingConfigs {\n        release {\n            storeFile file(MYAPP_RELEASE_STORE_FILE)\n            storePassword MYAPP_RELEASE_STORE_PASSWORD\n            keyAlias MYAPP_RELEASE_KEY_ALIAS\n            keyPassword MYAPP_RELEASE_KEY_PASSWORD\n        }\n    }\n    splits {\n        abi {\n            reset()\n            enable enableSeparateBuildPerCPUArchitecture\n            universalApk false  // If true, also generate a universal APK\n            include \"armeabi-v7a\", \"x86\"\n        }\n    }\n    buildTypes {\n        release {\n            minifyEnabled enableProguardInReleaseBuilds\n            proguardFiles getDefaultProguardFile(\"proguard-android.txt\"), \"proguard-rules.pro\"\n            signingConfig signingConfigs.release\n        }\n    }\n    // applicationVariants are e.g. debug, release\n    applicationVariants.all { variant ->\n        variant.outputs.each { output ->\n            // For each separate APK per architecture, set a unique version code as described here:\n            // http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits\n            def versionCodes = [\"armeabi-v7a\":1, \"x86\":2]\n            def abi = output.getFilter(OutputFile.ABI)\n            if (abi != null) {  // null for the universal-debug, universal-release variants\n                output.versionCodeOverride =\n                        versionCodes.get(abi) * 1048576 + defaultConfig.versionCode\n            }\n        }\n    }\n}\n\ndependencies {\n    compile fileTree(dir: \"libs\", include: [\"*.jar\"])\n    compile \"com.android.support:appcompat-v7:23.0.1\"\n    compile \"com.facebook.react:react-native:+\"  // From node_modules\n    compile project(':ReactNativeChromeCustomTabs')\n    compile project(':RNAndroidShare')\n}\n\n// Run this once to be able to run the application with BUCK\n// puts all compile dependencies into folder libs for BUCK to use\ntask copyDownloadableDepsToLibs(type: Copy) {\n  from configurations.compile\n  into 'libs'\n}\n"
  },
  {
    "path": "android/app/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 /usr/local/Cellar/android-sdk/24.3.3/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\n# Disabling obfuscation is useful if you collect stack traces from production crashes\n# (unless you are using a system that supports de-obfuscate the stack traces).\n-dontobfuscate\n\n# React Native\n\n# Keep our interfaces so they can be used by other ProGuard rules.\n# See http://sourceforge.net/p/proguard/bugs/466/\n-keep,allowobfuscation @interface com.facebook.proguard.annotations.DoNotStrip\n-keep,allowobfuscation @interface com.facebook.proguard.annotations.KeepGettersAndSetters\n\n# Do not strip any method/class that is annotated with @DoNotStrip\n-keep @com.facebook.proguard.annotations.DoNotStrip class *\n-keepclassmembers class * {\n    @com.facebook.proguard.annotations.DoNotStrip *;\n}\n\n-keepclassmembers @com.facebook.proguard.annotations.KeepGettersAndSetters class * {\n  void set*(***);\n  *** get*();\n}\n\n-keep class * extends com.facebook.react.bridge.JavaScriptModule { *; }\n-keep class * extends com.facebook.react.bridge.NativeModule { *; }\n-keepclassmembers,includedescriptorclasses class * { native <methods>; }\n-keepclassmembers class *  { @com.facebook.react.uimanager.UIProp <fields>; }\n-keepclassmembers class *  { @com.facebook.react.uimanager.annotations.ReactProp <methods>; }\n-keepclassmembers class *  { @com.facebook.react.uimanager.annotations.ReactPropGroup <methods>; }\n\n-dontwarn com.facebook.react.**\n\n# okhttp\n\n-keepattributes Signature\n-keepattributes *Annotation*\n-keep class okhttp3.** { *; }\n-keep interface okhttp3.** { *; }\n-dontwarn okhttp3.**\n\n# okio\n\n-keep class sun.misc.Unsafe { *; }\n-dontwarn java.nio.file.*\n-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement\n-dontwarn okio.**\n"
  },
  {
    "path": "android/app/react.gradle",
    "content": "import org.apache.tools.ant.taskdefs.condition.Os\n\ndef config = project.hasProperty(\"react\") ? project.react : [];\n\ndef bundleAssetName = config.bundleAssetName ?: \"index.android.bundle\"\ndef entryFile = config.entryFile ?: \"index.android.js\"\n\n// because elvis operator\ndef elvisFile(thing) {\n    return thing ? file(thing) : null;\n}\n\ndef reactRoot = elvisFile(config.root) ?: file(\"../../\")\ndef inputExcludes = config.inputExcludes ?: [\"android/**\", \"ios/**\"]\n\nvoid runBefore(String dependentTaskName, Task task) {\n    Task dependentTask = tasks.findByPath(dependentTaskName);\n    if (dependentTask != null) {\n        dependentTask.dependsOn task\n    }\n}\n\ngradle.projectsEvaluated {\n    // Grab all build types and product flavors\n    def buildTypes = android.buildTypes.collect { type -> type.name }\n    def productFlavors = android.productFlavors.collect { flavor -> flavor.name }\n\n    // When no product flavors defined, use empty\n    if (!productFlavors) productFlavors.add('')\n\n    productFlavors.each { productFlavorName ->\n        buildTypes.each { buildTypeName ->\n            // Create variant and target names\n            def targetName = \"${productFlavorName.capitalize()}${buildTypeName.capitalize()}\"\n            def targetPath = productFlavorName ?\n                    \"${productFlavorName}/${buildTypeName}\" :\n                    \"${buildTypeName}\"\n\n            // React js bundle directories\n            def jsBundleDirConfigName = \"jsBundleDir${targetName}\"\n            def jsBundleDir = elvisFile(config.\"$jsBundleDirConfigName\") ?:\n                    file(\"$buildDir/intermediates/assets/${targetPath}\")\n\n            def resourcesDirConfigName = \"resourcesDir${targetName}\"\n            def resourcesDir = elvisFile(config.\"${resourcesDirConfigName}\") ?:\n                    file(\"$buildDir/intermediates/res/merged/${targetPath}\")\n            def jsBundleFile = file(\"$jsBundleDir/$bundleAssetName\")\n\n            // Bundle task name for variant\n            def bundleJsAndAssetsTaskName = \"bundle${targetName}JsAndAssets\"\n\n            def currentBundleTask = tasks.create(\n                    name: bundleJsAndAssetsTaskName,\n                    type: Exec) {\n                group = \"react\"\n                description = \"bundle JS and assets for ${targetName}.\"\n\n                // Create dirs if they are not there (e.g. the \"clean\" task just ran)\n                doFirst {\n                    jsBundleDir.mkdirs()\n                    resourcesDir.mkdirs()\n                }\n\n                // Set up inputs and outputs so gradle can cache the result\n                inputs.files fileTree(dir: reactRoot, excludes: inputExcludes)\n                outputs.dir jsBundleDir\n                outputs.dir resourcesDir\n\n                // Set up the call to the react-native cli\n                workingDir reactRoot\n\n                // Set up dev mode\n                def devEnabled = !targetName.toLowerCase().contains(\"release\")\n                if (Os.isFamily(Os.FAMILY_WINDOWS)) {\n                    commandLine \"cmd\", \"/c\", \"node\", \"node_modules/react-native/local-cli/cli.js\", \"bundle\", \"--platform\", \"android\", \"--dev\", \"${devEnabled}\",\n                            \"--entry-file\", entryFile, \"--bundle-output\", jsBundleFile, \"--assets-dest\", resourcesDir\n                } else {\n                    commandLine \"node\", \"node_modules/react-native/local-cli/cli.js\", \"bundle\", \"--platform\", \"android\", \"--dev\", \"${devEnabled}\",\n                            \"--entry-file\", entryFile, \"--bundle-output\", jsBundleFile, \"--assets-dest\", resourcesDir\n                }\n\n                enabled config.\"bundleIn${targetName}\" ||\n                    config.\"bundleIn${buildTypeName.capitalize()}\" ?:\n                            targetName.toLowerCase().contains(\"release\")\n            }\n\n            // Hook bundle${productFlavor}${buildType}JsAndAssets into the android build process\n            currentBundleTask.dependsOn(\"merge${targetName}Resources\")\n            currentBundleTask.dependsOn(\"merge${targetName}Assets\")\n\n            runBefore(\"processArmeabi-v7a${targetName}Resources\", currentBundleTask)\n            runBefore(\"processX86${targetName}Resources\", currentBundleTask)\n            runBefore(\"processUniversal${targetName}Resources\", currentBundleTask)\n            runBefore(\"process${targetName}Resources\", currentBundleTask)\n        }\n    }\n}\n"
  },
  {
    "path": "android/app/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"cheeaun.hackerweb\">\n\n    <uses-permission android:name=\"android.permission.INTERNET\" />\n\n    <application\n      android:allowBackup=\"true\"\n      android:label=\"@string/app_name\"\n      android:icon=\"@mipmap/ic_launcher\"\n      android:theme=\"@style/AppTheme\">\n      <activity\n        android:name=\".MainActivity\"\n        android:label=\"@string/app_name\"\n        android:configChanges=\"keyboard|keyboardHidden|orientation|screenSize\">\n        <intent-filter>\n            <action android:name=\"android.intent.action.MAIN\" />\n            <category android:name=\"android.intent.category.LAUNCHER\" />\n        </intent-filter>\n        <intent-filter>\n            <action android:name=\"android.intent.action.VIEW\" />\n            <category android:name=\"android.intent.category.DEFAULT\" />\n            <category android:name=\"android.intent.category.BROWSABLE\" />\n            <data android:scheme=\"hackerweb\" android:host=\"item\" />\n        </intent-filter>\n      </activity>\n      <activity android:name=\"com.facebook.react.devsupport.DevSettingsActivity\" />\n    </application>\n\n</manifest>\n"
  },
  {
    "path": "android/app/src/main/java/cheeaun/hackerweb/MainActivity.java",
    "content": "package cheeaun.hackerweb;\n\nimport com.facebook.react.ReactActivity;\nimport com.facebook.react.ReactPackage;\nimport com.facebook.react.shell.MainReactPackage;\n\nimport java.util.Arrays;\nimport java.util.List;\n\nimport com.dstaley.ReactNativeChromeCustomTabs.ChromeCustomTabsPackage;\nimport com.blueprintalpha.rnandroidshare.RNAndroidSharePackage;\n\npublic class MainActivity extends ReactActivity {\n\n    /**\n     * Returns the name of the main component registered from JavaScript.\n     * This is used to schedule rendering of the component.\n     */\n    @Override\n    protected String getMainComponentName() {\n        return \"HackerWeb\";\n    }\n\n    /**\n     * Returns whether dev mode should be enabled.\n     * This enables e.g. the dev menu.\n     */\n    @Override\n    protected boolean getUseDeveloperSupport() {\n        return BuildConfig.DEBUG;\n    }\n\n    /**\n     * A list of packages used by the app. If the app uses additional views\n     * or modules besides the default ones, add more packages here.\n     */\n    @Override\n    protected List<ReactPackage> getPackages() {\n        return Arrays.<ReactPackage>asList(\n            new MainReactPackage(),\n            new ChromeCustomTabsPackage(this),\n            new RNAndroidSharePackage(this)\n        );\n    }\n}\n"
  },
  {
    "path": "android/app/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">HackerWeb</string>\n</resources>\n"
  },
  {
    "path": "android/app/src/main/res/values/styles.xml",
    "content": "<resources>\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.NoActionBar\">\n    </style>\n</resources>\n"
  },
  {
    "path": "android/app/src/main/res/values-v23/styles.xml",
    "content": "<resources>\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.NoActionBar\">\n        <item name=\"android:windowLightStatusBar\">true</item>\n        <item name=\"android:statusBarColor\">#e0e0e0</item>\n    </style>\n</resources>\n"
  },
  {
    "path": "android/build.gradle",
    "content": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n    repositories {\n        jcenter()\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:1.5.0'\n\n        // NOTE: Do not place your application dependencies here; they belong\n        // in the individual module build.gradle files\n    }\n}\n\nallprojects {\n    repositories {\n        mavenLocal()\n        jcenter()\n        maven {\n            // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm\n            url \"$projectDir/../../node_modules/react-native/android\"\n        }\n    }\n}\n"
  },
  {
    "path": "android/gradle/wrapper/gradle-wrapper.properties",
    "content": "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-2.4-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\n\nandroid.useDeprecatedNdk=true\n"
  },
  {
    "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# For Cygwin, ensure paths are in UNIX format before anything is touched.\nif $cygwin ; then\n    [ -n \"$JAVA_HOME\" ] && JAVA_HOME=`cygpath --unix \"$JAVA_HOME\"`\nfi\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\\\"`/\" >&-\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >&-\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\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/settings.gradle",
    "content": "rootProject.name = 'HackerWeb'\n\ninclude ':app'\ninclude ':ReactNativeChromeCustomTabs', ':app'\nproject(':ReactNativeChromeCustomTabs').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-chrome-custom-tabs/android')\ninclude ':RNAndroidShare', ':app'\nproject(':RNAndroidShare').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-android-share')\n"
  },
  {
    "path": "colors.js",
    "content": "import { Platform } from 'react-native';\nconst isIOS = Platform.OS === 'ios';\n\nexport default {\n  linkColor: '#007aff',\n  viewBackgroundColor: isIOS ? '#efeff4' : '#fafafa',\n  userColor: isIOS ? '#bf223f' : '#b71c1c',\n  opColor: '#fff',\n  opBackgroundColor: isIOS ? '#bf223f' : '#b71c1c',\n  insignificantColor: 'rgba(0,0,0,.54)',\n  sectionInsignificantColor: '#6d6d72',\n  separatorColor: isIOS ? '#c8c7cc' : '#ebebeb',\n  blockCodeBackgroundColor: '#eee',\n  progressBarBackgroundColor: '#eee',\n  progressBarColor: '#007aff',\n  sectionBackgroundColor: '#fff',\n  domainColor: isIOS ? '#003d80' : '#0D47A1',\n  defaultButtonThemeColor: isIOS ? '#848484' : '#f5f5f5',\n  primaryTextColor: isIOS ? null : 'rgba(0,0,0,.87)',\n  toolbarBackgroundColor: isIOS ? null: '#f5f5f5',\n  disabledColor: 'rgba(0,0,0,.38)',\n}\n"
  },
  {
    "path": "components/Button.android.js",
    "content": "'use strict';\n\nimport React from 'react';\nimport {\n  StyleSheet,\n  View,\n  Text,\n  TouchableNativeFeedback,\n} from 'react-native';\n\nimport colors from '../colors';\n\nconst styles = StyleSheet.create({\n  button: {\n    borderRadius: 2,\n    backgroundColor: colors.defaultButtonThemeColor,\n    paddingVertical: 11,\n    paddingHorizontal: 16,\n  },\n  text: {\n    textAlign: 'center',\n\n  },\n});\n\nexport default (props) => {\n  return (\n    <TouchableNativeFeedback onPress={props.onPress}>\n      <View style={[props.buttonStyles, styles.button]}>\n        <Text style={styles.text}>{props.children.map((c) => c.toUpperCase ? c.toUpperCase() : c)}</Text>\n      </View>\n    </TouchableNativeFeedback>\n  );\n}\n"
  },
  {
    "path": "components/Button.ios.js",
    "content": "'use strict';\n\nimport React, { Component } from 'react';\nimport {\n  StyleSheet,\n  Text,\n  View,\n  TouchableWithoutFeedback,\n} from 'react-native';\n\nimport colors from '../colors';\n\nconst styles = StyleSheet.create({\n  button: {\n    backgroundColor: '#ffffff',\n    borderRadius: 6,\n    borderColor: colors.defaultButtonThemeColor,\n    borderWidth: StyleSheet.hairlineWidth,\n    paddingVertical: 5,\n    paddingHorizontal: 10,\n  },\n  text: {\n    color: colors.defaultButtonThemeColor,\n    textAlign: 'center',\n  },\n  pressedButton: {\n    backgroundColor: colors.defaultButtonThemeColor,\n  },\n  pressedText: {\n    color: '#ffffff',\n  },\n});\n\nexport default class Button extends Component {\n  constructor(props){\n    super(props);\n    this.state = {\n      pressed: false,\n    };\n  }\n  _onPressIn(){\n    this.setState({\n      pressed: true,\n    });\n  }\n  _onPressOut(){\n    this.setState({\n      pressed: false,\n    });\n  }\n  render(){\n    const {pressed} = this.state;\n    const {onPress, buttonStyles, pressedButtonStyles, textStyles, pressedTextStyles, children} = this.props;\n    return (\n      <TouchableWithoutFeedback onPress={onPress} onPressIn={this._onPressIn.bind(this)} onPressOut={this._onPressOut.bind(this)}>\n        <View style={[buttonStyles, styles.button, pressed && styles.pressedButton, pressed && pressedButtonStyles]}>\n          <Text style={[textStyles, styles.text, pressed && styles.pressedText, pressed && pressedTextStyles]}>\n            {children}\n          </Text>\n        </View>\n      </TouchableWithoutFeedback>\n    );\n  }\n}\n"
  },
  {
    "path": "components/Comment.js",
    "content": "'use strict';\n\nimport React from 'react';\nimport {\n  StyleSheet,\n  View,\n  Text,\n  Image,\n  Platform,\n} from 'react-native';\n\nconst isIOS = Platform.OS === 'ios';\n\nimport HTMLView from '../components/HTMLView';\nimport showBrowser from '../utils/showBrowser';\nimport showActivity from '../utils/showActivity';\nimport colors from '../colors';\n\nconst styles = StyleSheet.create({\n  comment: {\n    padding: isIOS ? 15 : 16,\n    flex: 1,\n    flexDirection: 'row',\n  },\n  subComment: {\n    paddingTop: 0,\n    marginTop: -10\n  },\n  commentInner: {\n    flex: 1,\n    flexDirection: 'column',\n  },\n  commentMetadata: {\n    flex: 1,\n    flexDirection: 'row',\n    marginBottom: 8,\n  },\n  commentUserWrap: {\n    flex: 1,\n    flexWrap: 'wrap',\n    flexDirection: 'row',\n  },\n  commentUser: {\n    fontWeight: '500',\n    color: colors.userColor,\n  },\n  opUserContainer: {\n    backgroundColor: colors.opBackgroundColor,\n    paddingVertical: 2,\n    paddingHorizontal: 4,\n    borderRadius: 2,\n    marginLeft: 5,\n  },\n  opUser: {\n    fontSize: 10,\n    fontWeight: 'bold',\n    color: colors.opColor,\n  },\n  commentDeleted: {\n    flex: 1,\n  },\n  commentTime: {\n    color: colors.insignificantColor,\n  },\n  commentArrowIcon: {\n    width: 8,\n    height: 9,\n    marginRight: 6,\n    marginTop: 4,\n    opacity: isIOS ? 1 : .54,\n  },\n});\n\nexport default (props) => {\n  const {data, op} = props;\n  const {level, user} = data;\n\n  const innerComment = data.deleted ? (\n    <View style={styles.commentMetadata}>\n      <Text style={styles.commentDeleted}>[deleted]</Text>\n      <Text style={styles.commentTime}>{data.time_ago}</Text>\n    </View>\n  ) : (\n    <View>\n      <View style={styles.commentMetadata}>\n        <View style={styles.commentUserWrap}>\n          <View>\n            <Text style={styles.commentUser} onPress={showBrowser.bind(null, `https://news.ycombinator.com/user?id=${encodeURIComponent(user)}`)}>{user}</Text>\n          </View>\n          {op == user && <View style={styles.opUserContainer}><Text style={styles.opUser}>OP</Text></View>}\n        </View>\n        <Text style={styles.commentTime} onPress={showBrowser.bind(null, `https://news.ycombinator.com/item?id=${data.id}`)}>{data.time_ago}</Text>\n      </View>\n      <HTMLView html={data.content} onLinkPress={showBrowser} onLinkLongPress={showActivity}/>\n    </View>\n  );\n\n  return (\n    <View style={[styles.comment, level > 0 && styles.subComment]}>\n      {level > 0 && <Image style={styles.commentArrowIcon} source={require('../images/comment-arrow.png')}/>}\n      <View style={styles.commentInner}>\n        {innerComment}\n      </View>\n    </View>\n  );\n}\n"
  },
  {
    "path": "components/CommentRow.js",
    "content": "'use strict';\n\nimport React, { Component } from 'react';\nimport {\n  StyleSheet,\n  View,\n  LayoutAnimation,\n} from 'react-native';\n\nimport CommentsThread from '../components/CommentsThread';\nimport Comment from '../components/Comment';\nimport Button from '../components/Button';\n\nimport colors from '../colors';\n\nconst styles = StyleSheet.create({\n  comment: {\n    backgroundColor: colors.sectionBackgroundColor,\n  },\n  repliesButton: {\n    marginTop: -7,\n    marginRight: 15,\n    marginBottom: 15,\n    marginLeft: 15,\n  },\n});\n\nexport default class CommentRow extends Component {\n  constructor(props){\n    super(props);\n    this.state = {\n      expanded: false,\n    };\n  }\n  _toggleComments(){\n    LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);\n    this.setState({\n      expanded: !this.state.expanded,\n    });\n  }\n  render(){\n    const {op, comment, hasManyComments} = this.props;\n    const {comments} = comment;\n    const commentsThread = <CommentsThread data={comments} op={op}/>;\n    const hasComments = comments && comments.length;\n    const hasOnlyOneComment = comments.length == 1 && !comments[0].comments.length;\n\n    if (hasManyComments && hasComments && !hasOnlyOneComment){\n      let commentsCount = comment.comments.length;\n      (function dive(comments){\n        comments.forEach(function(c){\n          var len = c.comments.length;\n          commentsCount += len;\n          if (len) dive(c.comments);\n        });\n      })(comment.comments);\n\n      let repliesButton = commentsCount > 0 && <Button onPress={this._toggleComments.bind(this)} buttonStyles={styles.repliesButton}>{commentsCount} {commentsCount == 1 ? 'reply' : 'replies'}</Button>;\n\n      return (\n        <View style={styles.comment}>\n          <Comment data={comment} op={op}/>\n          {repliesButton}\n          {this.state.expanded && commentsThread}\n        </View>\n      );\n    } else {\n      return (\n        <View style={styles.comment}>\n          <Comment data={comment} op={op}/>\n          {commentsThread}\n        </View>\n      );\n    }\n  }\n}\n"
  },
  {
    "path": "components/CommentsThread.js",
    "content": "'use strict';\n\nimport React from 'react';\nimport {\n  StyleSheet,\n  View,\n} from 'react-native';\n\nimport Comment from './Comment';\n\nconst styles = StyleSheet.create({\n  indentedThread: {\n    marginLeft: 14,\n  },\n});\n\nconst CommentsThread = (props) => {\n  const {data, op} = props;\n  if (!data || !data.length) return <View/>;\n  return (\n    <View>\n      {data.map((comment) => {\n        return (\n          <View key={comment.id} style={comment.level > 1 && styles.indentedThread}>\n            <Comment data={comment} op={op}/>\n            <CommentsThread data={comment.comments} op={op}/>\n          </View>\n        );\n      })}\n    </View>\n  );\n}\n\nexport default CommentsThread;\n"
  },
  {
    "path": "components/HTMLView.js",
    "content": "'use strict';\n\nimport React, { Component } from 'react';\nimport {\n  StyleSheet,\n  Text,\n  View,\n  ScrollView,\n  Linking,\n  Platform,\n} from 'react-native';\n\nconst isIOS = Platform.OS === 'ios';\n\nimport PureRenderMixin from 'react-addons-pure-render-mixin';\nimport htmlparser from 'htmlparser2';\n\nimport colors from '../colors';\n\nconst nodeStyles = StyleSheet.create({\n  p: {\n    color: colors.primaryTextColor,\n    marginBottom: 8,\n    lineHeight: isIOS ? null : 20,\n  },\n  pre: {\n    paddingVertical: 10,\n    backgroundColor: colors.blockCodeBackgroundColor,\n    borderRadius: 3,\n    marginBottom: 8,\n  },\n  code: {\n    color: colors.primaryTextColor,\n    fontFamily: isIOS ? 'Menlo' : 'monospace',\n    fontSize: 12,\n  },\n  a: {\n    color: colors.linkColor,\n  },\n  i: {\n    fontStyle: 'italic',\n  },\n});\n\nfunction dom2elements(nodes, opts, parentName){\n  if (!nodes || !nodes.length) return;\n  const {onLinkPress, onLinkLongPress} = opts;\n  return nodes.map((node) => {\n    const {name, type, children} = node;\n    const key = (name || type) + '-' + Math.random();\n    const style = nodeStyles[name];\n    if (type == 'tag'){\n      var elements = dom2elements(children, opts, name);\n      if (!elements) return null;\n      if (name == 'pre'){\n        return (\n          <ScrollView\n            key={key}\n            horizontal={true}\n            automaticallyAdjustContentInsets={false}\n            scrollsToTop={false}\n            style={style}>\n            {elements}\n          </ScrollView>\n        );\n      }\n      if (name == 'a'){\n        const {href} = node.attribs;\n        // Steps to make sure children inside is ACTUALLY text\n        const child = children && children.length == 1 && children[0];\n        const text = child && child.type == 'text' && child.data;\n        return <Text key={key} style={style} onPress={onLinkPress.bind(null, href)} onLongPress={onLinkLongPress.bind(null, href)}>{text || elements}</Text>;\n      }\n      return <Text key={key} style={style}>{elements}</Text>;\n    } else if (type == 'text'){\n      const {data} = node;\n      let text;\n      if (parentName == 'code'){\n        // Trim EOL newline\n        text = data.replace(/\\n$/, '');\n      } else {\n        // Trim ALL newlines, because HTML\n        text = data.replace(/[\\n\\s\\t]+/g, ' ');\n      }\n      return <Text key={key} style={style}>{text}</Text>;\n    }\n  });\n};\n\nfunction processDOM(html, opts, callback){\n  if (typeof opts == 'function'){\n    callback = opts;\n    opts = {};\n  }\n  const handler = new htmlparser.DomHandler((err, dom) => {\n    const elements = dom2elements(dom, opts);\n    callback(elements);\n  });\n  const parser = new htmlparser.Parser(handler, {\n    recognizeSelfClosing: true,\n    lowerCaseAttributeNames: true,\n    lowerCaseTags: true,\n    decodeEntities: true,\n  });\n  // Clean up HTML first\n  if (!html.match(/^<p>/i)) html = '<p>' + html;\n  // Stop <pre> from being wrapped by <p>\n  html = html.replace(/<p>\\s*<pre>/ig, '</p><pre>');\n  if (!html.match(/<\\/pre>\\s*<p>/i)){\n    html = html.replace(/<\\/pre>([^<])/ig, '</pre><p>$1');\n  }\n  parser.write(html);\n  parser.end();\n}\n\nexport default class HTMLView extends Component {\n  constructor(props){\n    super(props);\n    this.state = {\n      elements: null,\n    };\n    this.shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate.bind(this);\n  }\n  componentDidMount(){\n    const {html, onLinkPress, onLinkLongPress} = this.props;\n    if (!html) return null;\n    processDOM(html, {\n      onLinkPress: onLinkPress || Linking.openURL,\n      onLinkLongPress: onLinkLongPress || function(){},\n    }, (elements) => {\n      this.setState({\n        elements: elements,\n      });\n    });\n  }\n  render(){\n    return (\n      <View>{this.state.elements}</View>\n    );\n  }\n}\n"
  },
  {
    "path": "components/LoadingIndicator.js",
    "content": "'use strict';\n\nimport React, { Component } from 'react';\nimport {\n  StyleSheet,\n  Text,\n  View,\n  ActivityIndicatorIOS,\n  ProgressBarAndroid,\n  Platform,\n} from 'react-native';\n\nconst isIOS = Platform.OS === 'ios';\n\nimport colors from '../colors';\n\nconst styles = StyleSheet.create({\n  container: {\n    flexDirection: 'row',\n    alignItems: 'center',\n  },\n  spinner: isIOS ? {\n    width: 30,\n    height: 30,\n  } : {\n    width: 24,\n    height: 24,\n  },\n  text: {\n    opacity: .6,\n  },\n});\n\nexport default class LoadingIndicator extends Component {\n  constructor(props){\n    super(props);\n    this.state = {\n      opacity: 0,\n    };\n  }\n  componentDidMount(){\n    this._timer = setTimeout(() => {\n      this.setState({\n        opacity: 1,\n      });\n    }, 900); // less than 1 second\n  }\n  componentWillUnmount(){\n    clearTimeout(this._timer);\n  }\n  render(){\n    const {opacity} = this.state;\n\n    if (isIOS){\n      return (\n        <View style={[styles.container, {opacity}]}>\n          <ActivityIndicatorIOS animating={true} style={styles.spinner}/>\n          <Text style={styles.text}>Loading&hellip;</Text>\n        </View>\n      );\n    }\n\n    return (\n      <View style={[styles.container, {opacity}]}>\n        <ProgressBarAndroid color={colors.disabledColor} styleAttr=\"Small\" style={styles.spinner} indeterminate={true} />\n      </View>\n    );\n  }\n}\n"
  },
  {
    "path": "components/ProgressBar.js",
    "content": "'use strict';\n\nimport React, { Component } from 'react';\nimport {\n  StyleSheet,\n  View,\n  Animated,\n} from 'react-native';\n\nimport colors from '../colors';\n\nconst styles = StyleSheet.create({\n  bar: {\n    backgroundColor: colors.progressBarBackgroundColor,\n    height: 3,\n    borderRadius: 1.5,\n    overflow: 'hidden',\n  },\n  progress: {\n    backgroundColor: colors.progressBarColor,\n    height: 3,\n  }\n});\n\nexport default class ProgressBar extends Component {\n  constructor(props){\n    super(props);\n    this.state = {\n      progressWidth: new Animated.Value(0),\n    };\n    this._onBarLayout = this._onBarLayout.bind(this);\n  }\n  _onBarLayout(e){\n    const {value, max} = this.props;\n    const width = e.nativeEvent.layout.width;\n    Animated.spring(this.state.progressWidth, {\n      toValue: value/max*width,\n      duration: 300,\n    }).start();\n  }\n  render(){\n    return (\n      <View style={styles.bar} onLayout={this._onBarLayout}>\n        <Animated.View style={[styles.progress, {width: this.state.progressWidth}]}></Animated.View>\n      </View>\n    );\n  }\n}\n"
  },
  {
    "path": "components/StoryRow.js",
    "content": "'use strict';\n\nimport React, { Component } from 'react';\nimport {\n  StyleSheet,\n  View,\n  Text,\n  TouchableOpacity,\n  TouchableHighlight,\n  TouchableNativeFeedback,\n  Image,\n  Platform,\n} from 'react-native';\n\nconst isIOS = Platform.OS === 'ios';\nconst CrossTouchableHighlight = isIOS ? TouchableHighlight : TouchableNativeFeedback;\nconst CrossTouchableOpacity = isIOS ? TouchableOpacity : TouchableNativeFeedback;\n\nimport LinkStore from '../stores/LinkStore';\nimport LinkActions from '../actions/LinkActions';\nimport domainify from '../utils/domainify';\n\nimport colors from '../colors';\n\nconst styles = StyleSheet.create({\n  story: {\n    backgroundColor: colors.sectionBackgroundColor,\n    flexDirection: 'row',\n    alignItems: 'stretch',\n  },\n  storyPosition: {\n    paddingTop: isIOS ? 10 : 16,\n    paddingLeft: 15,\n  },\n  storyPositionNumber: {\n    width: 22,\n    textAlign: 'center',\n    color: colors.insignificantColor,\n    fontSize: 17,\n  },\n  storyInfo: {\n    padding: 10,\n    paddingVertical: isIOS ? 10 : 16,\n    flex: 1,\n  },\n  storyComments: {\n    padding: isIOS ? 10 : 16,\n  },\n  storyDisclosure: {\n    paddingVertical: 15,\n    paddingRight: 15,\n    paddingLeft: 5,\n  },\n  storyTitle: {\n    color: colors.primaryTextColor,\n    fontSize: 17,\n  },\n  storyTitleVisited: {\n    color: colors.insignificantColor,\n  },\n  storyDomain: {\n    fontSize: isIOS ? 13 : 14,\n    color: colors.domainColor,\n  },\n  storyMetadataWrap: {\n    flexWrap: 'wrap',\n    flexDirection: 'row',\n  },\n  storyMetadata: {\n    fontSize: isIOS ? 13 : 14,\n    color: colors.insignificantColor,\n  },\n  commentIcon: {\n    width: isIOS ? 20 : 24,\n    height: isIOS ? 19 : 24,\n    marginHorizontal: isIOS ? 2 : 0,\n    marginTop: 3,\n    marginBottom: 2,\n    opacity: isIOS ? 1 : .54,\n  },\n  disclosureIcon: {\n    width: 8,\n    height: 13,\n    marginLeft: 2,\n    marginTop: 1,\n  },\n});\n\nexport default class StoryRow extends Component {\n  constructor(props){\n    super(props);\n    const {data} = props;\n    const {links} = LinkStore.getState();\n    this.state = {\n      visited: links.indexOf(data.url) >= 0,\n    };\n    this._onLinkChange = this._onLinkChange.bind(this);\n  }\n  componentDidMount(){\n    LinkStore.listen(this._onLinkChange);\n    LinkActions.getLinks();\n  }\n  componentWillUnmount(){\n    LinkStore.unlisten(this._onLinkChange);\n  }\n  _onLinkChange(state){\n    this.setState({\n      visited: state.links.indexOf(this.props.data.url) >= 0,\n    });\n  }\n  render(){\n    const {data, position, onCommentPress, ...touchableProps} = this.props;\n    const {url, type, comments_count, points, time_ago} = data;\n    const externalLink = !/^item/i.test(url);\n    const {visited} = this.state;\n\n    // Turns out that longPress is not common at all in native iOS apps\n    // But I actually like this feature on the browser, thus I'm keeping\n    // this but delay it slightly longer than default 500\n    const delayLongPress = 1000;\n\n    return (\n      <CrossTouchableHighlight {...touchableProps} delayLongPress={delayLongPress}>\n        <View style={styles.story}>\n          <View style={styles.storyPosition}>\n            <Text style={styles.storyPositionNumber}>{position}</Text>\n          </View>\n          <View style={styles.storyInfo}>\n            <Text style={[styles.storyTitle, visited && styles.storyTitleVisited]}>{data.title}</Text>\n            {externalLink && <Text numberOfLines={1} style={styles.storyDomain}>{domainify(url)}</Text>}\n            {(() => {\n              if (type == 'job'){\n                return <Text style={styles.storyMetadata}>{time_ago}</Text>;\n              } else {\n                const commentsText = comments_count>0 && <Text> &middot; {comments_count} comment{comments_count != 1 && 's'}</Text>;\n                return (\n                  <View style={styles.storyMetadataWrap}>\n                    <Text style={styles.storyMetadata}>{points} point{points != 1 && 's'} by {data.user} </Text>\n                    <Text style={styles.storyMetadata}>{time_ago}{commentsText}</Text>\n                  </View>\n                );\n              }\n            })()}\n          </View>\n          {type != 'job' && (() => {\n            if (externalLink){\n              return (\n                <CrossTouchableOpacity onPress={onCommentPress}>\n                  <View style={styles.storyComments}>\n                    <Image style={styles.commentIcon} source={require('../images/comments-icon.png')}/>\n                  </View>\n                </CrossTouchableOpacity>\n              );\n            } else if (isIOS){\n              return (\n                <View style={styles.storyDisclosure}>\n                  <Image style={styles.disclosureIcon} source={require('../images/disclosure-indicator.png')}/>\n                </View>\n              );\n            }\n          })()}\n        </View>\n      </CrossTouchableHighlight>\n    );\n  }\n}\n"
  },
  {
    "path": "index.android.js",
    "content": "'use strict';\n\nimport React, { Component } from 'react';\nimport {\n  AppRegistry,\n  StyleSheet,\n  Navigator,\n  AppState,\n  Text,\n  View,\n  ToolbarAndroid,\n  BackAndroid,\n  Linking,\n} from 'react-native';\n\nimport StoryActions from './actions/StoryActions';\nimport StoriesView from './views/StoriesView';\nimport CommentsView from './views/CommentsView';\nimport AboutView from './views/AboutView';\n\nimport colors from './colors';\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n  },\n  wrapper: {\n    backgroundColor: colors.viewBackgroundColor,\n  },\n  toolbar: {\n    backgroundColor: colors.toolbarBackgroundColor,\n    height: 56,\n    elevation: 2,\n  },\n});\n\nlet _navigator;\n\nBackAndroid.addEventListener('hardwareBackPress', () => {\n  if (_navigator.getCurrentRoutes().length == 1){\n    return false;\n  }\n  _navigator.pop();\n  return true;\n});\n\nclass HackerWeb extends Component {\n  constructor(props){\n    super(props);\n    this.state = {\n      currentAppState: AppState.currentState,\n    };\n    this._handleAppStateChange = this._handleAppStateChange.bind(this);\n  }\n  componentDidMount(){\n    AppState.addEventListener('change', this._handleAppStateChange);\n    Linking.getInitialURL().then((url) => {\n      if (!url) return;\n      const id = (url.match(/item\\?id=([a-z\\d]+)/i) || [,null])[1];\n      if (!id) return;\n      _navigator.push({\n        id: 'Comments',\n        component: CommentsView,\n        wrapperStyle: styles.wrapper,\n        passProps: {\n          data: {id},\n        }\n      });\n    }).catch(() => {});\n  }\n  componentWillUnmount(){\n    AppState.removeEventListener('change', this._handleAppStateChange);\n  }\n  _handleAppStateChange(currentAppState){\n    if (currentAppState == 'active' && this.state.currentAppState != currentAppState){\n      StoryActions.fetchStoriesIfExpired();\n    }\n    this.setState({\n      currentAppState,\n    });\n  }\n  _navigatorRenderScene(route, navigator){\n    _navigator = navigator;\n    switch (route.id){\n      case 'Stories':\n        return <View style={styles.container}>\n          <ToolbarAndroid\n            title=\"HackerWeb\"\n            titleColor={colors.primaryTextColor}\n            style={styles.toolbar}\n            actions={[\n              {\n                title: 'Reload',\n                icon: require('./images/refresh-icon.png'),\n                show: 'always',\n              },\n              { title: 'About' },\n            ]}\n            onActionSelected={(position) => {\n              switch (position){\n                case 0:\n                  StoryActions.fetchStories();\n                  break;\n                case 1:\n                  navigator.push({\n                    id: 'About',\n                  });\n                  break;\n              }\n            }}\n          />\n          <StoriesView navigator={navigator} />\n        </View>;\n      case 'Comments':\n        const { component, title, passProps, rightButtonIcon, onRightButtonPress } = route;\n        const TheComponent = component;\n        return <View style={[styles.container, styles.wrapper]}>\n          <ToolbarAndroid\n            title={title}\n            titleColor={colors.primaryTextColor}\n            style={styles.toolbar}\n            navIcon={require('./images/arrow-back.png')}\n            onIconClicked={navigator.pop}\n            actions={[{\n              title: 'Share',\n              icon: rightButtonIcon,\n              show: 'always'\n            }]}\n            onActionSelected={onRightButtonPress}\n          />\n            <TheComponent navigator={navigator} {...passProps}/>\n          </View>;\n      case 'About':\n        return <View style={[styles.container, styles.wrapper]}>\n          <ToolbarAndroid\n            title=\"About\"\n            titleColor={colors.primaryTextColor}\n            style={styles.toolbar}\n          />\n          <AboutView />\n        </View>;\n    }\n  }\n  render(){\n    return (\n      <Navigator\n        initialRoute={{id: 'Stories'}}\n        renderScene={this._navigatorRenderScene}\n        configureScene={() => Navigator.SceneConfigs.FloatFromBottomAndroid}\n      />\n    );\n  }\n}\n\nAppRegistry.registerComponent('HackerWeb', () => HackerWeb);\n"
  },
  {
    "path": "index.ios.js",
    "content": "'use strict';\n\nimport React, { Component } from 'react';\nimport {\n  AppStateIOS,\n  AppRegistry,\n  StyleSheet,\n  Modal,\n  NavigatorIOS,\n  View,\n  Linking,\n} from 'react-native';\n\nimport StoryActions from './actions/StoryActions';\nimport StoriesView from './views/StoriesView';\nimport AboutView from './views/AboutView';\nimport CommentsView from './views/CommentsView';\n\nimport colors from './colors';\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n  },\n  wrapper: {\n    backgroundColor: colors.viewBackgroundColor,\n  },\n});\n\nclass App extends Component {\n  constructor(props){\n    super(props);\n    this.state = {\n      currentAppState: AppStateIOS.currentState,\n      isAboutVisible: false,\n    };\n    this._reloadCount = 0;\n    this._reloadCountTimeout = null;\n    this._handleAppStateChange = this._handleAppStateChange.bind(this);\n    this._handleOpenURL = this._handleOpenURL.bind(this);\n  }\n  componentDidMount(){\n    AppStateIOS.addEventListener('change', this._handleAppStateChange);\n    Linking.addEventListener('url', this._handleOpenURL);\n  }\n  componentWillUnmount(){\n    AppStateIOS.removeEventListener('change', this._handleAppStateChange);\n    Linking.removeEventListener('url', this._handleOpenURL);\n  }\n  _handleAppStateChange(currentAppState){\n    if (currentAppState == 'active' && this.state.currentAppState != currentAppState){\n      StoryActions.fetchStoriesIfExpired();\n    }\n    this.setState({\n      currentAppState,\n    });\n  }\n  _handleOpenURL(e){\n    const {url} = e;\n    if (!url) return;\n    const id = (url.match(/item\\?id=([a-z\\d]+)/i) || [,null])[1];\n    if (!id) return;\n    this.refs.nav.push({\n      component: CommentsView,\n      wrapperStyle: styles.wrapper,\n      passProps: {\n        data: {id}\n      },\n    });\n  }\n  _showAbout(){\n    this.setState({\n      isAboutVisible: true,\n    });\n  }\n  _hideAbout(){\n    this.setState({\n      isAboutVisible: false,\n    });\n  }\n  render(){\n    const {isAboutVisible} = this.state;\n    return (\n      <View style={styles.container}>\n        <View style={styles.container} pointerEvents={isAboutVisible ? 'none' : 'auto'}>\n          <NavigatorIOS\n            ref=\"nav\"\n            style={styles.container}\n            initialRoute={{\n              title: 'HackerWeb',\n              backButtonTitle: 'News',\n              component: StoriesView,\n              leftButtonTitle: 'About',\n              onLeftButtonPress: this._showAbout.bind(this),\n              rightButtonIcon: require('./images/refresh-icon.png'),\n              onRightButtonPress: () => {\n                // For the compulsive-type of people who likes to press Reload multiple times\n                this._reloadCount++;\n                clearTimeout(this._reloadCountTimeout);\n                if (this._reloadCount >= 3){\n                  StoryActions.flush();\n                  this._reloadCount = 0;\n                } else {\n                  this._reloadCountTimeout = setTimeout(() => this._reloadCount = 0, 3000);\n                }\n                StoryActions.fetchStories();\n              },\n            }}/>\n        </View>\n        <Modal animationType=\"slide\" visible={isAboutVisible}>\n          <NavigatorIOS\n            style={styles.container}\n            initialRoute={{\n              title: 'About',\n              component: AboutView,\n              wrapperStyle: styles.wrapper,\n              leftButtonTitle: 'Close',\n              onLeftButtonPress: this._hideAbout.bind(this),\n            }}/>\n        </Modal>\n      </View>\n    );\n  }\n}\n\nAppRegistry.registerComponent('HackerWeb', () => App);\n"
  },
  {
    "path": "ios/HackerWeb/AppDelegate.h",
    "content": "/**\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#import <UIKit/UIKit.h>\n\n@interface AppDelegate : UIResponder <UIApplicationDelegate>\n\n@property (nonatomic, strong) UIWindow *window;\n\n@end\n"
  },
  {
    "path": "ios/HackerWeb/AppDelegate.m",
    "content": "/**\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#import \"AppDelegate.h\"\n\n#import \"RCTRootView.h\"\n\n#import \"RCTLinkingManager.h\"\n\n@implementation AppDelegate\n\n- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions\n{\n  NSURL *jsCodeLocation;\n\n  /**\n   * Loading JavaScript code - uncomment the one you want.\n   *\n   * OPTION 1\n   * Load from development server. Start the server from the repository root:\n   *\n   * $ npm start\n   *\n   * To run on device, change `localhost` to the IP address of your computer\n   * (you can get this by typing `ifconfig` into the terminal and selecting the\n   * `inet` value under `en0:`) and make sure your computer and iOS device are\n   * on the same Wi-Fi network.\n   */\n\n  jsCodeLocation = [NSURL URLWithString:@\"http://localhost:8081/index.ios.bundle?platform=ios&dev=true\"];\n\n  /**\n   * OPTION 2\n   * Load from pre-bundled file on disk. The static bundle is automatically\n   * generated by the \"Bundle React Native code and images\" build step when\n   * running the project on an actual device or running the project on the\n   * simulator in the \"Release\" build configuration.\n   */\n\n//   jsCodeLocation = [[NSBundle mainBundle] URLForResource:@\"main\" withExtension:@\"jsbundle\"];\n\n  RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation\n                                                      moduleName:@\"HackerWeb\"\n                                               initialProperties:nil\n                                                   launchOptions:launchOptions];\n  rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];\n\n  self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];\n  UIViewController *rootViewController = [UIViewController new];\n  rootViewController.view = rootView;\n  self.window.rootViewController = rootViewController;\n  [self.window makeKeyAndVisible];\n  return YES;\n}\n\n- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url\n  sourceApplication:(NSString *)sourceApplication annotation:(id)annotation\n{\n  return [RCTLinkingManager application:application openURL:url\n                      sourceApplication:sourceApplication annotation:annotation];\n}\n\n@end\n"
  },
  {
    "path": "ios/HackerWeb/Base.lproj/LaunchScreen.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.XIB\" version=\"3.0\" toolsVersion=\"10116\" systemVersion=\"15E65\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" useTraitCollections=\"YES\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"10085\"/>\n    </dependencies>\n    <objects>\n        <placeholder placeholderIdentifier=\"IBFilesOwner\" id=\"-1\" userLabel=\"File's Owner\"/>\n        <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"-2\" customClass=\"UIResponder\"/>\n        <view contentMode=\"scaleToFill\" id=\"iN0-l3-epB\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"480\" height=\"480\"/>\n            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n            <subviews>\n                <imageView userInteractionEnabled=\"NO\" contentMode=\"center\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"app-icon\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"gaw-IF-Rtt\">\n                    <rect key=\"frame\" x=\"200\" y=\"200\" width=\"80\" height=\"80\"/>\n                </imageView>\n            </subviews>\n            <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"calibratedWhite\"/>\n            <constraints>\n                <constraint firstItem=\"gaw-IF-Rtt\" firstAttribute=\"centerY\" secondItem=\"iN0-l3-epB\" secondAttribute=\"centerY\" id=\"KXT-ic-lyF\"/>\n                <constraint firstItem=\"gaw-IF-Rtt\" firstAttribute=\"centerX\" secondItem=\"iN0-l3-epB\" secondAttribute=\"centerX\" id=\"ME9-Yf-SOi\"/>\n            </constraints>\n            <nil key=\"simulatedStatusBarMetrics\"/>\n            <freeformSimulatedSizeMetrics key=\"simulatedDestinationMetrics\"/>\n            <point key=\"canvasLocation\" x=\"548\" y=\"455\"/>\n        </view>\n    </objects>\n    <resources>\n        <image name=\"app-icon\" width=\"80\" height=\"80\"/>\n    </resources>\n</document>\n"
  },
  {
    "path": "ios/HackerWeb/Images.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"size\" : \"29x29\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"58.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"29x29\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"97.png\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"size\" : \"40x40\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"80.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"40x40\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"120.png\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"size\" : \"60x60\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"120-1.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"60x60\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"180.png\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "ios/HackerWeb/Images.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "ios/HackerWeb/Images.xcassets/app-icon.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"app-icon.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"app-icon@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"app-icon@3x.png\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "ios/HackerWeb/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.1</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleURLTypes</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>CFBundleTypeRole</key>\n\t\t\t<string>Editor</string>\n\t\t\t<key>CFBundleURLName</key>\n\t\t\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t\t\t<key>CFBundleURLSchemes</key>\n\t\t\t<array>\n\t\t\t\t<string>hackerweb</string>\n\t\t\t</array>\n\t\t</dict>\n\t</array>\n\t<key>CFBundleVersion</key>\n\t<string>5</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>NSAppTransportSecurity</key>\n\t<dict>\n\t\t<key>NSAllowsArbitraryLoads</key>\n\t\t<true/>\n\t</dict>\n\t<key>NSLocationWhenInUseUsageDescription</key>\n\t<string></string>\n\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</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</array>\n\t<key>UIViewControllerBasedStatusBarAppearance</key>\n\t<false/>\n\t<key>NSLocationWhenInUseUsageDescription</key>\n\t<string></string>\n  <key>NSAppTransportSecurity</key>\n  <dict>\n    <!--See http://ste.vn/2015/06/10/configuring-app-transport-security-ios-9-osx-10-11/ -->\n    <key>NSAllowsArbitraryLoads</key>\n    <true/>\n  </dict>\n</dict>\n</plist>\n"
  },
  {
    "path": "ios/HackerWeb/main.m",
    "content": "/**\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#import <UIKit/UIKit.h>\n\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/HackerWeb.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\t00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */; };\n\t\t00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */; };\n\t\t00C302E81ABCBA2D00DB3ED1 /* libRCTImage.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302C01ABCB91800DB3ED1 /* libRCTImage.a */; };\n\t\t00C302E91ABCBA2D00DB3ED1 /* libRCTNetwork.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */; };\n\t\t00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */; };\n\t\t00E356F31AD99517003FC87E /* HackerWebTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* HackerWebTests.m */; };\n\t\t133E29F31AD74F7200F7D852 /* libRCTLinking.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 78C398B91ACF4ADC00677621 /* libRCTLinking.a */; };\n\t\t139105C61AF99C1200B5F7CC /* libRCTSettings.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */; };\n\t\t139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */; };\n\t\t13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; };\n\t\t13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB11A68108700A75B9A /* LaunchScreen.xib */; };\n\t\t13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };\n\t\t13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };\n\t\t146834051AC3E58100842450 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; };\n\t\t832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; };\n\t\t9B47A38C1C5E057600228361 /* libSafariViewManager.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9B47A3891C5E056200228361 /* libSafariViewManager.a */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXContainerItemProxy section */\n\t\t00C302AB1ABCB8CE00DB3ED1 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */;\n\t\t\tproxyType = 2;\n\t\t\tremoteGlobalIDString = 134814201AA4EA6300B7C361;\n\t\t\tremoteInfo = RCTActionSheet;\n\t\t};\n\t\t00C302B91ABCB90400DB3ED1 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */;\n\t\t\tproxyType = 2;\n\t\t\tremoteGlobalIDString = 134814201AA4EA6300B7C361;\n\t\t\tremoteInfo = RCTGeolocation;\n\t\t};\n\t\t00C302BF1ABCB91800DB3ED1 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */;\n\t\t\tproxyType = 2;\n\t\t\tremoteGlobalIDString = 58B5115D1A9E6B3D00147676;\n\t\t\tremoteInfo = RCTImage;\n\t\t};\n\t\t00C302DB1ABCB9D200DB3ED1 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */;\n\t\t\tproxyType = 2;\n\t\t\tremoteGlobalIDString = 58B511DB1A9E6C8500147676;\n\t\t\tremoteInfo = RCTNetwork;\n\t\t};\n\t\t00C302E31ABCB9EE00DB3ED1 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */;\n\t\t\tproxyType = 2;\n\t\t\tremoteGlobalIDString = 832C81801AAF6DEF007FA2F7;\n\t\t\tremoteInfo = RCTVibration;\n\t\t};\n\t\t00E356F41AD99517003FC87E /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 13B07F861A680F5B00A75B9A;\n\t\t\tremoteInfo = HackerWeb;\n\t\t};\n\t\t139105C01AF99BAD00B5F7CC /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */;\n\t\t\tproxyType = 2;\n\t\t\tremoteGlobalIDString = 134814201AA4EA6300B7C361;\n\t\t\tremoteInfo = RCTSettings;\n\t\t};\n\t\t139FDEF31B06529B00C62182 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */;\n\t\t\tproxyType = 2;\n\t\t\tremoteGlobalIDString = 3C86DF461ADF2C930047B81A;\n\t\t\tremoteInfo = RCTWebSocket;\n\t\t};\n\t\t146834031AC3E56700842450 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;\n\t\t\tproxyType = 2;\n\t\t\tremoteGlobalIDString = 83CBBA2E1A601D0E00E9B192;\n\t\t\tremoteInfo = React;\n\t\t};\n\t\t78C398B81ACF4ADC00677621 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */;\n\t\t\tproxyType = 2;\n\t\t\tremoteGlobalIDString = 134814201AA4EA6300B7C361;\n\t\t\tremoteInfo = RCTLinking;\n\t\t};\n\t\t832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */;\n\t\t\tproxyType = 2;\n\t\t\tremoteGlobalIDString = 58B5119B1A9E6C1200147676;\n\t\t\tremoteInfo = RCTText;\n\t\t};\n\t\t9B47A3881C5E056200228361 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 9B47A3841C5E056200228361 /* SafariViewManager.xcodeproj */;\n\t\t\tproxyType = 2;\n\t\t\tremoteGlobalIDString = 134814201AA4EA6300B7C361;\n\t\t\tremoteInfo = SafariViewManager;\n\t\t};\n/* End PBXContainerItemProxy section */\n\n/* Begin PBXFileReference section */\n\t\t008F07F21AC5B25A0029DE68 /* main.jsbundle */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = main.jsbundle; path = main.jsbundle; sourceTree = \"<group>\"; };\n\t\t00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = \"wrapper.pb-project\"; name = RCTActionSheet.xcodeproj; path = ../node_modules/react-native/Libraries/ActionSheetIOS/RCTActionSheet.xcodeproj; sourceTree = \"<group>\"; };\n\t\t00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = \"wrapper.pb-project\"; name = RCTGeolocation.xcodeproj; path = ../node_modules/react-native/Libraries/Geolocation/RCTGeolocation.xcodeproj; sourceTree = \"<group>\"; };\n\t\t00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = \"wrapper.pb-project\"; name = RCTImage.xcodeproj; path = ../node_modules/react-native/Libraries/Image/RCTImage.xcodeproj; sourceTree = \"<group>\"; };\n\t\t00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = \"wrapper.pb-project\"; name = RCTNetwork.xcodeproj; path = ../node_modules/react-native/Libraries/Network/RCTNetwork.xcodeproj; sourceTree = \"<group>\"; };\n\t\t00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = \"wrapper.pb-project\"; name = RCTVibration.xcodeproj; path = ../node_modules/react-native/Libraries/Vibration/RCTVibration.xcodeproj; sourceTree = \"<group>\"; };\n\t\t00E356EE1AD99517003FC87E /* HackerWebTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = HackerWebTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t00E356F21AD99517003FC87E /* HackerWebTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = HackerWebTests.m; sourceTree = \"<group>\"; };\n\t\t139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = \"wrapper.pb-project\"; name = RCTSettings.xcodeproj; path = ../node_modules/react-native/Libraries/Settings/RCTSettings.xcodeproj; sourceTree = \"<group>\"; };\n\t\t139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = \"wrapper.pb-project\"; name = RCTWebSocket.xcodeproj; path = ../node_modules/react-native/Libraries/WebSocket/RCTWebSocket.xcodeproj; sourceTree = \"<group>\"; };\n\t\t13B07F961A680F5B00A75B9A /* HackerWeb.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HackerWeb.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = HackerWeb/AppDelegate.h; sourceTree = \"<group>\"; };\n\t\t13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = HackerWeb/AppDelegate.m; sourceTree = \"<group>\"; };\n\t\t13B07FB21A68108700A75B9A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = \"<group>\"; };\n\t\t13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = HackerWeb/Images.xcassets; sourceTree = \"<group>\"; };\n\t\t13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = HackerWeb/Info.plist; sourceTree = \"<group>\"; };\n\t\t13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = HackerWeb/main.m; sourceTree = \"<group>\"; };\n\t\t146833FF1AC3E56700842450 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = \"wrapper.pb-project\"; name = React.xcodeproj; path = ../node_modules/react-native/React/React.xcodeproj; sourceTree = \"<group>\"; };\n\t\t78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = \"wrapper.pb-project\"; name = RCTLinking.xcodeproj; path = ../node_modules/react-native/Libraries/LinkingIOS/RCTLinking.xcodeproj; sourceTree = \"<group>\"; };\n\t\t832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = \"wrapper.pb-project\"; name = RCTText.xcodeproj; path = ../node_modules/react-native/Libraries/Text/RCTText.xcodeproj; sourceTree = \"<group>\"; };\n\t\t9B47A3841C5E056200228361 /* SafariViewManager.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = \"wrapper.pb-project\"; name = SafariViewManager.xcodeproj; path = \"../node_modules/react-native-safari-view/SafariViewManager.xcodeproj\"; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t00E356EB1AD99517003FC87E /* 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\t\t13B07F8C1A680F5B00A75B9A /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t9B47A38C1C5E057600228361 /* libSafariViewManager.a in Frameworks */,\n\t\t\t\t146834051AC3E58100842450 /* libReact.a in Frameworks */,\n\t\t\t\t00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */,\n\t\t\t\t00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */,\n\t\t\t\t00C302E81ABCBA2D00DB3ED1 /* libRCTImage.a in Frameworks */,\n\t\t\t\t133E29F31AD74F7200F7D852 /* libRCTLinking.a in Frameworks */,\n\t\t\t\t00C302E91ABCBA2D00DB3ED1 /* libRCTNetwork.a in Frameworks */,\n\t\t\t\t139105C61AF99C1200B5F7CC /* libRCTSettings.a in Frameworks */,\n\t\t\t\t832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */,\n\t\t\t\t00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */,\n\t\t\t\t139FDEF61B0652A700C62182 /* libRCTWebSocket.a 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\t00C302A81ABCB8CE00DB3ED1 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t00C302B61ABCB90400DB3ED1 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t00C302BC1ABCB91800DB3ED1 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t00C302C01ABCB91800DB3ED1 /* libRCTImage.a */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t00C302D41ABCB9D200DB3ED1 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t00C302E01ABCB9EE00DB3ED1 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t00E356EF1AD99517003FC87E /* HackerWebTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t00E356F21AD99517003FC87E /* HackerWebTests.m */,\n\t\t\t\t00E356F01AD99517003FC87E /* Supporting Files */,\n\t\t\t);\n\t\t\tpath = HackerWebTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t00E356F01AD99517003FC87E /* Supporting Files */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t00E356F11AD99517003FC87E /* Info.plist */,\n\t\t\t);\n\t\t\tname = \"Supporting Files\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t139105B71AF99BAD00B5F7CC /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t139105C11AF99BAD00B5F7CC /* libRCTSettings.a */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t139FDEE71B06529A00C62182 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t139FDEF41B06529B00C62182 /* libRCTWebSocket.a */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t13B07FAE1A68108700A75B9A /* HackerWeb */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t008F07F21AC5B25A0029DE68 /* main.jsbundle */,\n\t\t\t\t13B07FAF1A68108700A75B9A /* AppDelegate.h */,\n\t\t\t\t13B07FB01A68108700A75B9A /* AppDelegate.m */,\n\t\t\t\t13B07FB51A68108700A75B9A /* Images.xcassets */,\n\t\t\t\t13B07FB61A68108700A75B9A /* Info.plist */,\n\t\t\t\t13B07FB11A68108700A75B9A /* LaunchScreen.xib */,\n\t\t\t\t13B07FB71A68108700A75B9A /* main.m */,\n\t\t\t);\n\t\t\tname = HackerWeb;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t146834001AC3E56700842450 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t146834041AC3E56700842450 /* libReact.a */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t78C398B11ACF4ADC00677621 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t78C398B91ACF4ADC00677621 /* libRCTLinking.a */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t832341AE1AAA6A7D00B99B32 /* Libraries */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t9B47A3841C5E056200228361 /* SafariViewManager.xcodeproj */,\n\t\t\t\t146833FF1AC3E56700842450 /* React.xcodeproj */,\n\t\t\t\t00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */,\n\t\t\t\t00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */,\n\t\t\t\t00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */,\n\t\t\t\t78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */,\n\t\t\t\t00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */,\n\t\t\t\t139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */,\n\t\t\t\t832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */,\n\t\t\t\t00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */,\n\t\t\t\t139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */,\n\t\t\t);\n\t\t\tname = Libraries;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t832341B11AAA6A8300B99B32 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t832341B51AAA6A8300B99B32 /* libRCTText.a */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t83CBB9F61A601CBA00E9B192 = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t13B07FAE1A68108700A75B9A /* HackerWeb */,\n\t\t\t\t832341AE1AAA6A7D00B99B32 /* Libraries */,\n\t\t\t\t00E356EF1AD99517003FC87E /* HackerWebTests */,\n\t\t\t\t83CBBA001A601CBA00E9B192 /* Products */,\n\t\t\t);\n\t\t\tindentWidth = 2;\n\t\t\tsourceTree = \"<group>\";\n\t\t\ttabWidth = 2;\n\t\t};\n\t\t83CBBA001A601CBA00E9B192 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t13B07F961A680F5B00A75B9A /* HackerWeb.app */,\n\t\t\t\t00E356EE1AD99517003FC87E /* HackerWebTests.xctest */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t9B47A3851C5E056200228361 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t9B47A3891C5E056200228361 /* libSafariViewManager.a */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t00E356ED1AD99517003FC87E /* HackerWebTests */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget \"HackerWebTests\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t00E356EA1AD99517003FC87E /* Sources */,\n\t\t\t\t00E356EB1AD99517003FC87E /* Frameworks */,\n\t\t\t\t00E356EC1AD99517003FC87E /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\t00E356F51AD99517003FC87E /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = HackerWebTests;\n\t\t\tproductName = HackerWebTests;\n\t\t\tproductReference = 00E356EE1AD99517003FC87E /* HackerWebTests.xctest */;\n\t\t\tproductType = \"com.apple.product-type.bundle.unit-test\";\n\t\t};\n\t\t13B07F861A680F5B00A75B9A /* HackerWeb */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget \"HackerWeb\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t13B07F871A680F5B00A75B9A /* Sources */,\n\t\t\t\t13B07F8C1A680F5B00A75B9A /* Frameworks */,\n\t\t\t\t13B07F8E1A680F5B00A75B9A /* Resources */,\n\t\t\t\t00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = HackerWeb;\n\t\t\tproductName = \"Hello World\";\n\t\t\tproductReference = 13B07F961A680F5B00A75B9A /* HackerWeb.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t83CBB9F71A601CBA00E9B192 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastUpgradeCheck = 0610;\n\t\t\t\tORGANIZATIONNAME = Facebook;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t00E356ED1AD99517003FC87E = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 6.2;\n\t\t\t\t\t\tTestTargetID = 13B07F861A680F5B00A75B9A;\n\t\t\t\t\t};\n\t\t\t\t\t13B07F861A680F5B00A75B9A = {\n\t\t\t\t\t\tDevelopmentTeam = 7WDVUPXAPH;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject \"HackerWeb\" */;\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 = 83CBB9F61A601CBA00E9B192;\n\t\t\tproductRefGroup = 83CBBA001A601CBA00E9B192 /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectReferences = (\n\t\t\t\t{\n\t\t\t\t\tProductGroup = 00C302A81ABCB8CE00DB3ED1 /* Products */;\n\t\t\t\t\tProjectRef = 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */;\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tProductGroup = 00C302B61ABCB90400DB3ED1 /* Products */;\n\t\t\t\t\tProjectRef = 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */;\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tProductGroup = 00C302BC1ABCB91800DB3ED1 /* Products */;\n\t\t\t\t\tProjectRef = 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */;\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tProductGroup = 78C398B11ACF4ADC00677621 /* Products */;\n\t\t\t\t\tProjectRef = 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */;\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tProductGroup = 00C302D41ABCB9D200DB3ED1 /* Products */;\n\t\t\t\t\tProjectRef = 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */;\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tProductGroup = 139105B71AF99BAD00B5F7CC /* Products */;\n\t\t\t\t\tProjectRef = 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */;\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tProductGroup = 832341B11AAA6A8300B99B32 /* Products */;\n\t\t\t\t\tProjectRef = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */;\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tProductGroup = 00C302E01ABCB9EE00DB3ED1 /* Products */;\n\t\t\t\t\tProjectRef = 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */;\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tProductGroup = 139FDEE71B06529A00C62182 /* Products */;\n\t\t\t\t\tProjectRef = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */;\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tProductGroup = 146834001AC3E56700842450 /* Products */;\n\t\t\t\t\tProjectRef = 146833FF1AC3E56700842450 /* React.xcodeproj */;\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tProductGroup = 9B47A3851C5E056200228361 /* Products */;\n\t\t\t\t\tProjectRef = 9B47A3841C5E056200228361 /* SafariViewManager.xcodeproj */;\n\t\t\t\t},\n\t\t\t);\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t13B07F861A680F5B00A75B9A /* HackerWeb */,\n\t\t\t\t00E356ED1AD99517003FC87E /* HackerWebTests */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXReferenceProxy section */\n\t\t00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */ = {\n\t\t\tisa = PBXReferenceProxy;\n\t\t\tfileType = archive.ar;\n\t\t\tpath = libRCTActionSheet.a;\n\t\t\tremoteRef = 00C302AB1ABCB8CE00DB3ED1 /* PBXContainerItemProxy */;\n\t\t\tsourceTree = BUILT_PRODUCTS_DIR;\n\t\t};\n\t\t00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */ = {\n\t\t\tisa = PBXReferenceProxy;\n\t\t\tfileType = archive.ar;\n\t\t\tpath = libRCTGeolocation.a;\n\t\t\tremoteRef = 00C302B91ABCB90400DB3ED1 /* PBXContainerItemProxy */;\n\t\t\tsourceTree = BUILT_PRODUCTS_DIR;\n\t\t};\n\t\t00C302C01ABCB91800DB3ED1 /* libRCTImage.a */ = {\n\t\t\tisa = PBXReferenceProxy;\n\t\t\tfileType = archive.ar;\n\t\t\tpath = libRCTImage.a;\n\t\t\tremoteRef = 00C302BF1ABCB91800DB3ED1 /* PBXContainerItemProxy */;\n\t\t\tsourceTree = BUILT_PRODUCTS_DIR;\n\t\t};\n\t\t00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */ = {\n\t\t\tisa = PBXReferenceProxy;\n\t\t\tfileType = archive.ar;\n\t\t\tpath = libRCTNetwork.a;\n\t\t\tremoteRef = 00C302DB1ABCB9D200DB3ED1 /* PBXContainerItemProxy */;\n\t\t\tsourceTree = BUILT_PRODUCTS_DIR;\n\t\t};\n\t\t00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */ = {\n\t\t\tisa = PBXReferenceProxy;\n\t\t\tfileType = archive.ar;\n\t\t\tpath = libRCTVibration.a;\n\t\t\tremoteRef = 00C302E31ABCB9EE00DB3ED1 /* PBXContainerItemProxy */;\n\t\t\tsourceTree = BUILT_PRODUCTS_DIR;\n\t\t};\n\t\t139105C11AF99BAD00B5F7CC /* libRCTSettings.a */ = {\n\t\t\tisa = PBXReferenceProxy;\n\t\t\tfileType = archive.ar;\n\t\t\tpath = libRCTSettings.a;\n\t\t\tremoteRef = 139105C01AF99BAD00B5F7CC /* PBXContainerItemProxy */;\n\t\t\tsourceTree = BUILT_PRODUCTS_DIR;\n\t\t};\n\t\t139FDEF41B06529B00C62182 /* libRCTWebSocket.a */ = {\n\t\t\tisa = PBXReferenceProxy;\n\t\t\tfileType = archive.ar;\n\t\t\tpath = libRCTWebSocket.a;\n\t\t\tremoteRef = 139FDEF31B06529B00C62182 /* PBXContainerItemProxy */;\n\t\t\tsourceTree = BUILT_PRODUCTS_DIR;\n\t\t};\n\t\t146834041AC3E56700842450 /* libReact.a */ = {\n\t\t\tisa = PBXReferenceProxy;\n\t\t\tfileType = archive.ar;\n\t\t\tpath = libReact.a;\n\t\t\tremoteRef = 146834031AC3E56700842450 /* PBXContainerItemProxy */;\n\t\t\tsourceTree = BUILT_PRODUCTS_DIR;\n\t\t};\n\t\t78C398B91ACF4ADC00677621 /* libRCTLinking.a */ = {\n\t\t\tisa = PBXReferenceProxy;\n\t\t\tfileType = archive.ar;\n\t\t\tpath = libRCTLinking.a;\n\t\t\tremoteRef = 78C398B81ACF4ADC00677621 /* PBXContainerItemProxy */;\n\t\t\tsourceTree = BUILT_PRODUCTS_DIR;\n\t\t};\n\t\t832341B51AAA6A8300B99B32 /* libRCTText.a */ = {\n\t\t\tisa = PBXReferenceProxy;\n\t\t\tfileType = archive.ar;\n\t\t\tpath = libRCTText.a;\n\t\t\tremoteRef = 832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */;\n\t\t\tsourceTree = BUILT_PRODUCTS_DIR;\n\t\t};\n\t\t9B47A3891C5E056200228361 /* libSafariViewManager.a */ = {\n\t\t\tisa = PBXReferenceProxy;\n\t\t\tfileType = archive.ar;\n\t\t\tpath = libSafariViewManager.a;\n\t\t\tremoteRef = 9B47A3881C5E056200228361 /* PBXContainerItemProxy */;\n\t\t\tsourceTree = BUILT_PRODUCTS_DIR;\n\t\t};\n/* End PBXReferenceProxy section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t00E356EC1AD99517003FC87E /* 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\t13B07F8E1A680F5B00A75B9A /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */,\n\t\t\t\t13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXShellScriptBuildPhase section */\n\t\t00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t);\n\t\t\tname = \"Bundle React Native code and images\";\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"export NODE_BINARY=node\\n../node_modules/react-native/packager/react-native-xcode.sh\";\n\t\t\tshowEnvVarsInLog = 1;\n\t\t};\n/* End PBXShellScriptBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t00E356EA1AD99517003FC87E /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t00E356F31AD99517003FC87E /* HackerWebTests.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t13B07F871A680F5B00A75B9A /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */,\n\t\t\t\t13B07FC11A68108700A75B9A /* main.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\t00E356F51AD99517003FC87E /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 13B07F861A680F5B00A75B9A /* HackerWeb */;\n\t\t\ttargetProxy = 00E356F41AD99517003FC87E /* PBXContainerItemProxy */;\n\t\t};\n/* End PBXTargetDependency section */\n\n/* Begin PBXVariantGroup section */\n\t\t13B07FB11A68108700A75B9A /* LaunchScreen.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t13B07FB21A68108700A75B9A /* Base */,\n\t\t\t);\n\t\t\tname = LaunchScreen.xib;\n\t\t\tpath = HackerWeb;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\t00E356F61AD99517003FC87E /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tBUNDLE_LOADER = \"$(TEST_HOST)\";\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = (\n\t\t\t\t\t\"$(SDKROOT)/Developer/Library/Frameworks\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\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\tINFOPLIST_FILE = HackerWebTests/Info.plist;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 8.2;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks @loader_path/Frameworks\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tTEST_HOST = \"$(BUILT_PRODUCTS_DIR)/HackerWeb.app/HackerWeb\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t00E356F71AD99517003FC87E /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tBUNDLE_LOADER = \"$(TEST_HOST)\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = (\n\t\t\t\t\t\"$(SDKROOT)/Developer/Library/Frameworks\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tINFOPLIST_FILE = HackerWebTests/Info.plist;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 8.2;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks @loader_path/Frameworks\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tTEST_HOST = \"$(BUILT_PRODUCTS_DIR)/HackerWeb.app/HackerWeb\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t13B07F941A680F5B00A75B9A /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCODE_SIGN_IDENTITY = \"iPhone Developer\";\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tDEAD_CODE_STRIPPING = NO;\n\t\t\t\tHEADER_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,\n\t\t\t\t\t\"$(SRCROOT)/../node_modules/react-native/React/**\",\n\t\t\t\t\t\"$(SRCROOT)/../node_modules/react-native/Libraries/**\",\n\t\t\t\t);\n\t\t\t\tINFOPLIST_FILE = \"HackerWeb/Info.plist\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 9.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n        OTHER_LDFLAGS = (\n          \"-ObjC\",\n          \"-lc++\",\n        );\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = cheeaun.hackerweb;\n\t\t\t\tPRODUCT_NAME = HackerWeb;\n\t\t\t\tPROVISIONING_PROFILE = \"\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t13B07F951A680F5B00A75B9A /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCODE_SIGN_IDENTITY = \"iPhone Developer\";\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tDEAD_CODE_STRIPPING = NO;\n\t\t\t\tHEADER_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,\n\t\t\t\t\t\"$(SRCROOT)/../node_modules/react-native/React/**\",\n\t\t\t\t\t\"$(SRCROOT)/../node_modules/react-native/Libraries/**\",\n\t\t\t\t);\n\t\t\t\tINFOPLIST_FILE = \"HackerWeb/Info.plist\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 9.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n        OTHER_LDFLAGS = (\n          \"-ObjC\",\n          \"-lc++\",\n        );\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = cheeaun.hackerweb;\n\t\t\t\tPRODUCT_NAME = HackerWeb;\n\t\t\t\tPROVISIONING_PROFILE = \"\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t83CBBA201A601CBA00E9B192 /* 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\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\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_SYMBOLS_PRIVATE_EXTERN = NO;\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\tHEADER_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,\n\t\t\t\t\t\"$(SRCROOT)/../node_modules/react-native/React/**\",\n\t\t\t\t);\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 9.0;\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\t83CBBA211A601CBA00E9B192 /* 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 = YES;\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_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\tHEADER_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,\n\t\t\t\t\t\"$(SRCROOT)/../node_modules/react-native/React/**\",\n\t\t\t\t);\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 9.0;\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/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget \"HackerWebTests\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t00E356F61AD99517003FC87E /* Debug */,\n\t\t\t\t00E356F71AD99517003FC87E /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget \"HackerWeb\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t13B07F941A680F5B00A75B9A /* Debug */,\n\t\t\t\t13B07F951A680F5B00A75B9A /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject \"HackerWeb\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t83CBBA201A601CBA00E9B192 /* Debug */,\n\t\t\t\t83CBBA211A601CBA00E9B192 /* 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 = 83CBB9F71A601CBA00E9B192 /* Project object */;\n}\n"
  },
  {
    "path": "ios/HackerWeb.xcodeproj/xcshareddata/xcschemes/HackerWeb.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"0620\"\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 = \"13B07F861A680F5B00A75B9A\"\n               BuildableName = \"HackerWeb.app\"\n               BlueprintName = \"HackerWeb\"\n               ReferencedContainer = \"container:HackerWeb.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"NO\"\n            buildForArchiving = \"NO\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"00E356ED1AD99517003FC87E\"\n               BuildableName = \"HackerWebTests.xctest\"\n               BlueprintName = \"HackerWebTests\"\n               ReferencedContainer = \"container:HackerWeb.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         <TestableReference\n            skipped = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"00E356ED1AD99517003FC87E\"\n               BuildableName = \"HackerWebTests.xctest\"\n               BlueprintName = \"HackerWebTests\"\n               ReferencedContainer = \"container:HackerWeb.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n      </Testables>\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"13B07F861A680F5B00A75B9A\"\n            BuildableName = \"HackerWeb.app\"\n            BlueprintName = \"HackerWeb\"\n            ReferencedContainer = \"container:HackerWeb.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      allowLocationSimulation = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"13B07F861A680F5B00A75B9A\"\n            BuildableName = \"HackerWeb.app\"\n            BlueprintName = \"HackerWeb\"\n            ReferencedContainer = \"container:HackerWeb.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 = \"13B07F861A680F5B00A75B9A\"\n            BuildableName = \"HackerWeb.app\"\n            BlueprintName = \"HackerWeb\"\n            ReferencedContainer = \"container:HackerWeb.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/HackerWebTests/HackerWebTests.m",
    "content": "/**\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n#import <UIKit/UIKit.h>\n#import <XCTest/XCTest.h>\n\n#import \"RCTLog.h\"\n#import \"RCTRootView.h\"\n\n#define TIMEOUT_SECONDS 600\n#define TEXT_TO_LOOK_FOR @\"Welcome to React Native!\"\n\n@interface HackerWebTests : XCTestCase\n\n@end\n\n@implementation HackerWebTests\n\n- (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test\n{\n  if (test(view)) {\n    return YES;\n  }\n  for (UIView *subview in [view subviews]) {\n    if ([self findSubviewInView:subview matching:test]) {\n      return YES;\n    }\n  }\n  return NO;\n}\n\n- (void)testRendersWelcomeScreen\n{\n  UIViewController *vc = [[[[UIApplication sharedApplication] delegate] window] rootViewController];\n  NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS];\n  BOOL foundElement = NO;\n\n  __block NSString *redboxError = nil;\n  RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) {\n    if (level >= RCTLogLevelError) {\n      redboxError = message;\n    }\n  });\n\n  while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) {\n    [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];\n    [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];\n\n    foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) {\n      if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) {\n        return YES;\n      }\n      return NO;\n    }];\n  }\n\n  RCTSetLogFunction(RCTDefaultLogFunction);\n\n  XCTAssertNil(redboxError, @\"RedBox error: %@\", redboxError);\n  XCTAssertTrue(foundElement, @\"Couldn't find element with text '%@' in %d seconds\", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS);\n}\n\n\n@end\n"
  },
  {
    "path": "ios/HackerWebTests/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>org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)</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>BNDL</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</dict>\n</plist>\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"HackerWeb\",\n  \"version\": \"0.0.1\",\n  \"private\": true,\n  \"scripts\": {\n    \"start\": \"node_modules/react-native/packager/packager.sh\"\n  },\n  \"dependencies\": {\n    \"alt\": \"~0.18.4\",\n    \"buffer\": \"~4.6.0\",\n    \"events\": \"~1.1.0\",\n    \"htmlparser2\": \"~3.9.0\",\n    \"react\": \"~15.1.0\",\n    \"react-addons-pure-render-mixin\": \"~15.1.0\",\n    \"react-native\": \"~0.27.2\",\n    \"react-native-android-share\": \"https://github.com/haydenth/react-native-android-share.git\",\n    \"react-native-cache-store\": \"~1.0.2\",\n    \"react-native-chrome-custom-tabs\": \"~0.0.2\",\n    \"react-native-safari-view\": \"~0.4.1\",\n    \"stream\": \"~0.0.2\",\n    \"url-parse\": \"~1.1.1\"\n  }\n}\n"
  },
  {
    "path": "stores/LinkStore.js",
    "content": "'use strict';\n\nimport alt from '../alt';\nimport LinkActions from '../actions/LinkActions';\n\nclass LinkStore {\n  constructor(){\n    this.links = [];\n\n    this.bindListeners({\n      handleGetLinks: LinkActions.GET_LINKS,\n      handleAddLink: LinkActions.ADD_LINK,\n    });\n  }\n\n  handleGetLinks(links){\n    this.links = links;\n  }\n\n  handleAddLink(link){\n    this.links.push(link);\n  }\n}\n\nexport default alt.createStore(LinkStore, 'LinkStore');\n"
  },
  {
    "path": "stores/StoryStore.js",
    "content": "'use strict';\n\nimport alt from '../alt';\nimport StoryActions from '../actions/StoryActions';\n\nclass StoryStore {\n  constructor(){\n    this.stories = [];\n    this.storiesLoading = false;\n    this.storiesError = false;\n    this.story = null;\n    this.storyLoading = false;\n    this.storyError = false;\n    this.hasMoreStories = false;\n\n    this.bindListeners({\n      handleFetchStories: StoryActions.FETCH_STORIES,\n      handleFetchMoreStories: StoryActions.FETCH_MORE_STORIES,\n      handleUpdateStories: StoryActions.UPDATE_STORIES,\n      handleUpdateMoreStories: StoryActions.UPDATE_MORE_STORIES,\n      handleHasMoreStories: StoryActions.HAS_MORE_STORIES,\n      handleStoriesFailed: StoryActions.STORIES_FAILED,\n      handleFetchStory: StoryActions.FETCH_STORY,\n      handleUpdateStory: StoryActions.UPDATE_STORY,\n      handleStoryFailed: StoryActions.STORY_FAILED,\n    });\n  }\n\n  handleFetchStories(){\n    this.storiesLoading = true;\n    this.storiesError = false;\n    this.hasMoreStories = false;\n  }\n\n  handleFetchMoreStories(){\n  }\n\n  handleUpdateStories(stories){\n    this.stories = stories;\n    this.storiesLoading = false;\n    this.storiesError = false;\n  }\n\n  handleHasMoreStories(){\n    this.hasMoreStories = true;\n  }\n\n  handleUpdateMoreStories(stories){\n    this.stories = this.stories.concat(stories);\n  }\n\n  handleStoriesFailed(error){\n    this.storiesLoading = false;\n    this.storiesError = error;\n  }\n\n  handleFetchStory(id){\n    if (this.story && this.story.id != id){\n      this.story = null;\n      this.storyLoading = true;\n    }\n    if (!this.story) this.storyLoading = true;\n    this.storyError = false;\n  }\n\n  handleUpdateStory(story){\n    this.story = story;\n    this.storyLoading = false;\n    this.storyError = false;\n\n    // Update story in stories\n    const stories = this.stories;\n    for (let i=0, l=stories.length; i<l; i++){\n      const s = stories[i];\n      if (s.id == story.id){\n        this.stories[i] = story;\n        break;\n      }\n    }\n  }\n\n  handleStoryFailed(error){\n    this.storyLoading = false;\n    this.storyError = error;\n  }\n}\n\nexport default alt.createStore(StoryStore, 'StoryStore');\n"
  },
  {
    "path": "utils/domainify.js",
    "content": "'use strict';\n\nimport urlparse from 'url-parse';\n\nexport default (url) => {\n  if (!url) return;\n  var link = urlparse(url);\n  var domain = link.hostname.replace(/^www\\./, '');\n  var pathname = link.pathname.replace(/^\\//, '').split('/')[0];\n  var pathnameLen = pathname.length;\n  var firstPath = domain.length <= 25 && pathnameLen > 3 && pathnameLen <= 15 && /^[^0-9][^.]+$/.test(pathname) ? ('/' + pathname) : '';\n  return domain + firstPath;\n};\n"
  },
  {
    "path": "utils/showActivity.android.js",
    "content": "'use strict';\n\nimport AndroidShare from 'react-native-android-share';\n\nexport default (url, message) => {\n  if (!url) return;\n  AndroidShare.openChooserWithOptions({\n    subject: message || url,\n    text: (message ? (message + ' ') : '') + url,\n  }, 'Share via');\n}\n"
  },
  {
    "path": "utils/showActivity.ios.js",
    "content": "'use strict';\n\nimport { ActionSheetIOS } from 'react-native';\n\nexport default (url, message) => {\n  if (!url) return;\n  ActionSheetIOS.showShareActionSheetWithOptions({\n    url: url,\n    message: message || '',\n  }, () => {}, () => {});\n}\n"
  },
  {
    "path": "utils/showBrowser.android.js",
    "content": "'use strict';\n\nimport ChromeCustomTabsClient from 'react-native-chrome-custom-tabs';\nimport LinkActions from '../actions/LinkActions';\n\nexport default (url) => {\n  if (!url) return;\n  ChromeCustomTabsClient.launchCustomTab(url);\n  // Log link visit to History\n  setTimeout(() => LinkActions.addLink(url), 1000);\n}\n"
  },
  {
    "path": "utils/showBrowser.ios.js",
    "content": "'use strict';\n\nimport { Linking, AlertIOS } from 'react-native';\nimport SafariView from 'react-native-safari-view';\nimport LinkActions from '../actions/LinkActions';\n\nexport default (url) => {\n  if (!url) return;\n  SafariView.isAvailable()\n    .then(() => {\n      SafariView.show({\n        url: url,\n      });\n      // Log link visit to History\n      setTimeout(() => LinkActions.addLink(url), 1000);\n    })\n    .catch(() => {\n      Linking.canOpenURL(url, (supported) => {\n        if (!supported){\n          AlertIOS.alert('Can\\'t handle URL: ' + url);\n        } else {\n          Linking.openURL(url);\n          // Log link visit to History\n          setTimeout(() => LinkActions.addLink(url), 1000);\n        }\n      });\n    });\n}\n"
  },
  {
    "path": "views/AboutView.js",
    "content": "'use strict';\n\nimport React from 'react';\nimport {\n  StyleSheet,\n  View,\n  Text,\n  Image,\n  ScrollView,\n  TouchableOpacity,\n  TouchableNativeFeedback,\n  Linking,\n  Platform,\n} from 'react-native';\n\nconst isIOS = Platform.OS === 'ios';\nconst CrossTouchable = isIOS ? TouchableOpacity : TouchableNativeFeedback;\n\n// import SafariView from 'react-native-safari-view';\n\nimport colors from '../colors';\n\nconst hairlineWidth = isIOS ? StyleSheet.hairlineWidth : 1;\nconst styles = StyleSheet.create({\n  aboutContainer: {\n    marginTop: isIOS ? 34 : 0,\n    paddingVertical: isIOS ? 10 : 32,\n    paddingHorizontal: isIOS ? 15 : 16,\n    borderTopWidth: isIOS ? hairlineWidth : 0,\n    borderTopColor: colors.separatorColor,\n    borderBottomWidth: hairlineWidth,\n    borderBottomColor: colors.separatorColor,\n    backgroundColor: colors.sectionBackgroundColor,\n    flexDirection: 'row',\n  },\n  appIcon: {\n    width: 60,\n    height: 60,\n    marginRight: 10,\n    borderColor: colors.separatorColor,\n    borderWidth: hairlineWidth,\n    borderRadius: isIOS ? 14 : 2,\n  },\n  aboutTextContainer: {\n    flex: 1,\n  },\n  aboutHeading: {\n    color: colors.primaryTextColor,\n    fontWeight: '500',\n    fontSize: 17,\n  },\n  aboutDescription: {\n    fontSize: 15,\n    color: colors.insignificantColor,\n  },\n  listContainer: {\n    marginTop: 34,\n    borderTopWidth: hairlineWidth,\n    borderTopColor: colors.separatorColor,\n    borderBottomWidth: hairlineWidth,\n    borderBottomColor: colors.separatorColor,\n    backgroundColor: colors.sectionBackgroundColor,\n  },\n  listItem: {\n    paddingVertical: isIOS ? 13 : 16,\n    paddingHorizontal: isIOS ? 15 : 16,\n  },\n  listItemSeparator: {\n    marginLeft: 15,\n    marginTop: -1,\n    height: hairlineWidth,\n    backgroundColor: colors.separatorColor,\n  },\n  link: {\n    color: colors.linkColor,\n    fontSize: isIOS ? 17 : 16,\n  },\n  disclaimer: {\n    paddingVertical: 27,\n    paddingHorizontal: 15,\n  },\n  disclaimerText: {\n    color: colors.sectionInsignificantColor,\n  }\n});\n\nvar linkPress = function(url){\n  Linking.openURL(url);\n  /* BUG: Once <Modal> is open, SafariView can't work anymore.\n  if (/^mailto:/.test(url)){\n    // Note: won't work in Simulator because there's no Mail there\n    Linking.openURL(url);\n  } else {\n    SafariView.show({\n      url: url\n    });\n  }\n  */\n};\n\nfunction linksContainer(links){\n  return <View style={styles.listContainer}>\n    {links.map((link, i) => {\n      return (\n        <View key={link.text}>\n          <CrossTouchable onPress={linkPress.bind(null, link.url)}>\n            <View style={styles.listItem}>\n              <Text style={styles.link}>{link.text}</Text>\n            </View>\n          </CrossTouchable>\n          {i < links.length-1 && <View style={styles.listItemSeparator}/>}\n        </View>\n      );\n    })}\n  </View>\n};\n\nexport default (props) => {\n  return (\n    <ScrollView>\n      <View style={styles.aboutContainer}>\n        <View>\n          <Image style={styles.appIcon} source={require('../images/app-icon.png')}/>\n        </View>\n        <View style={styles.aboutTextContainer}>\n          <Text style={styles.aboutHeading}>HackerWeb</Text>\n          <Text style={styles.aboutDescription}>A simply readable Hacker News app.</Text>\n        </View>\n      </View>\n      {linksContainer([\n        isIOS ? {\n          text: '🌟 Rate HackerWeb on the App Store',\n          url: 'http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewContentsUserReviews?id=1084209377&pageNumber=0&sortOrdering=2&type=Purple+Software&mt=8'\n        } : {\n          text: '🌟 Rate HackerWeb on Google Play',\n          url: 'https://play.google.com/store/apps/details?id=cheeaun.hackerweb'\n        },\n        { text: '☕️ Buy me a cup of coffee', url: 'https://donorbox.org/support-cheeaun' },\n      ])}\n      {linksContainer([\n        { text: 'HackerWeb homepage', url: 'https://hackerwebapp.com/' },\n        { text: 'Hacker News homepage', url: 'https://news.ycombinator.com/' },\n        { text: 'Hacker News FAQ', url: 'https://news.ycombinator.com/newsfaq.html' },\n        { text: 'HackerWeb on GitHub', url: 'https://github.com/cheeaun/hackerweb-native' },\n        { text: 'Follow @cheeaun', url: 'https://twitter.com/cheeaun' },\n        { text: 'Send Feedback', url: 'mailto:cheeaun+hackerweb@gmail.com?subject=HackerWeb feedback' },\n      ])}\n      <View style={styles.disclaimer}>\n        <Text style={styles.disclaimerText}>Built by Lim Chee Aun.</Text>\n        <Text style={styles.disclaimerText}>Not affiliated with Hacker News or YCombinator.</Text>\n      </View>\n    </ScrollView>\n  );\n}\n"
  },
  {
    "path": "views/CommentsView.js",
    "content": "'use strict';\n\nimport React, { Component } from 'react';\nimport {\n  StyleSheet,\n  ActivityIndicatorIOS,\n  View,\n  Text,\n  TouchableHighlight,\n  TouchableOpacity,\n  TouchableWithoutFeedback,\n  Image,\n  ActionSheetIOS,\n  ListView,\n  LayoutAnimation,\n  Platform,\n} from 'react-native';\n\nconst isIOS = Platform.OS === 'ios';\nconst isAndroid = Platform.OS === 'android';\n\nimport ChromeCustomTabsClient from 'react-native-chrome-custom-tabs';\n\nimport StoryStore from '../stores/StoryStore';\nimport StoryActions from '../actions/StoryActions';\n\nimport CommentRow from '../components/CommentRow';\nimport LoadingIndicator from '../components/LoadingIndicator';\nimport HTMLView from '../components/HTMLView';\nimport ProgressBar from '../components/ProgressBar';\nimport showBrowser from '../utils/showBrowser';\nimport showActivity from '../utils/showActivity';\nimport domainify from '../utils/domainify';\n\nimport colors from '../colors';\n\nconst hairlineWidth = isIOS ? StyleSheet.hairlineWidth : 1;\nconst styles = StyleSheet.create({\n  viewCommentsBlank: {\n    flex: 1,\n    flexDirection: 'row',\n    alignItems: 'center',\n    justifyContent: 'center',\n    padding: 50,\n    backgroundColor: colors.sectionBackgroundColor,\n  },\n  footer: {\n    borderTopColor: colors.separatorColor,\n    borderTopWidth: hairlineWidth,\n    height: 30,\n  },\n  errorContainer: {\n    alignItems: 'center',\n  },\n  errorText: {\n    opacity: .6,\n    textAlign: 'center',\n  },\n  retryText: {\n    color: colors.linkColor,\n    textAlign: 'center',\n  },\n  noCommentsText: {\n    opacity: .6,\n  },\n  externalArrowIcon: {\n    width: isIOS ? 12 : 10,\n    height: isIOS ? 9 : 10,\n    marginLeft: 2,\n    marginRight: 4,\n    opacity: isIOS ? 1 : .54,\n  },\n  storyLink: {\n    backgroundColor: colors.viewBackgroundColor,\n  },\n  storyTitle: {\n    color: colors.primaryTextColor,\n    fontSize: 17,\n  },\n  storySection: {\n    padding: 15,\n  },\n  storyDomain: {\n    fontSize: isIOS ? 13 : 14,\n    color: colors.domainColor,\n  },\n  storyMetadataWrap: {\n    flexWrap: 'wrap',\n    flexDirection: 'row',\n    marginBottom: 2,\n  },\n  storyMetadata: {\n    fontSize: isIOS ? 13 : 14,\n    color: colors.insignificantColor,\n  },\n  storyContent: {\n    backgroundColor: colors.sectionBackgroundColor,\n    padding: isIOS ? 15 : 16,\n    borderTopColor: colors.separatorColor,\n    borderTopWidth: hairlineWidth,\n    borderBottomColor: colors.separatorColor,\n    borderBottomWidth: hairlineWidth,\n    marginBottom: 30,\n  },\n  separator: {\n    backgroundColor: colors.separatorColor,\n    height: hairlineWidth,\n  },\n  externalLink: {\n    flex: 1,\n    flexDirection: 'row',\n    alignItems: 'center',\n    backgroundColor: colors.viewBackgroundColor,\n  },\n  pollContainer: {\n    flexDirection: 'row',\n    marginTop: 9,\n    marginBottom: 2,\n    alignItems: 'flex-end',\n  },\n  pollItem: {\n    color: colors.primaryTextColor,\n    flex: 1,\n  },\n  pollPoints: {\n    color: colors.insignificantColor,\n  },\n  touchableLink: {\n    borderRadius: 3,\n    transform: [\n      {translateX: -2},\n      {translateY: -2}\n    ]\n  },\n  touchableLinkInner: {\n    padding: 2\n  },\n});\n\nexport default class CommentsView extends Component {\n  constructor(props){\n    super(props);\n    var { story, storyLoading, storyError } = StoryStore.getState();\n    this.state = {\n      data: story,\n      dataSource: new ListView.DataSource({rowHasChanged: (row1, row2) => row1 !== row2}),\n      loading: storyLoading,\n      error: storyError,\n      pollDisplay: 'points',\n    };\n    this._onChange = this._onChange.bind(this);\n    this._fetchStory = this._fetchStory.bind(this);\n  }\n  componentDidMount(){\n    StoryStore.listen(this._onChange);\n    this._fetchStory();\n  }\n  componentWillUnmount(){\n    StoryStore.unlisten(this._onChange);\n  }\n  _fetchStory(){\n    StoryActions.fetchStory(this.props.data.id);\n  }\n  _onChange(state){\n    const {story} = state;\n    const comments = (story && story.comments) || [];\n    LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);\n    this.setState({\n      data: story,\n      dataSource: this.state.dataSource.cloneWithRows(comments),\n      loading: state.storyLoading,\n      error: state.storyError,\n    });\n\n    if (isAndroid && story && story.url){\n      const externalLink = !/^item/i.test(story.url);\n      const url = externalLink ? story.url : `https://news.ycombinator.com/item?id=${story.id}`;\n      ChromeCustomTabsClient.mayLaunchUrl(url);\n    }\n\n    /* Note:\n      Title update doesn't work yet due to https://github.com/facebook/react-native/issues/476\n      Hopefully this works https://github.com/bjornco/react-native/commit/5fcb2a8673a2c17f4fdb03327008397a10a9c53a\n    */\n    if (state.story && state.story.title){\n      var route = this.props.navigator.navigationContext.currentRoute;\n      if (!route) return;\n      if (route.title != state.story.title){\n        const {story} = state;\n        route.title = story.title;\n        if (!route.rightButtonIcon) route.rightButtonIcon = require('../images/share-icon.png');\n        route.onRightButtonPress = showActivity.bind(null, `https://news.ycombinator.com/item?id=${story.id}`, story.title);\n        this.props.navigator.replace(route);\n      }\n    }\n  }\n  _togglePollDisplay(){\n    LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);\n    this.setState({\n      pollDisplay: this.state.pollDisplay == 'points' ? 'percentage' : 'points',\n    });\n  }\n  _renderHeader(){\n    let {data, loading, error, pollDisplay} = this.state;\n    data = data || this.props.data;\n    const commentsText = <Text>&middot; {data.comments_count} comment{data.comments_count != 1 && 's'}</Text>;\n    const url = data.url;\n    const externalLink = !/^item/i.test(url);\n    let domainText = null;\n    let storyHeader = null;\n\n    if (externalLink){\n      domainText = <Text style={styles.storyDomain}>{domainify(data.url)}</Text>;\n      storyHeader = (\n        <TouchableHighlight onPress={showBrowser.bind(null, url)} onLongPress={showActivity.bind(null, url, data.title)} style={styles.touchableLink}>\n          <View style={[styles.storyLink, styles.touchableLinkInner]}>\n            <Text style={styles.storyTitle}>{data.title}</Text>\n            {domainText}\n          </View>\n        </TouchableHighlight>\n      );\n    } else {\n      storyHeader = <View><Text style={styles.storyTitle}>{data.title}</Text></View>;\n    }\n\n    const hnShortURL = `news.ycombinator.com/item?id=${data.id}`;\n    const hnURL = `https://${hnShortURL}`;\n\n    let contentSection;\n    if (data.content){\n      let pollElements;\n      if (data.poll && data.poll.length){\n        let maxPoints = Math.max.apply(null, data.poll.map((p) => p.points ));\n        let totalPoints = data.poll.reduce((a, b) => a + b.points, 0);\n        pollElements = data.poll.map((p) => {\n          let {points} = p;\n          let pointsText;\n          if (pollDisplay == 'points'){\n            pointsText = `${points} point${points != 1 ? 's' : ''}`;\n          } else {\n            pointsText = `${(points/totalPoints*100).toFixed(1)}%`;\n          }\n          return (\n            <TouchableWithoutFeedback key={p.item} onPress={this._togglePollDisplay.bind(this)}>\n              <View>\n                <View style={styles.pollContainer}>\n                  <Text style={styles.pollItem}>{p.item}</Text>\n                  <Text style={styles.pollPoints}>{pointsText}</Text>\n                </View>\n                <ProgressBar value={points} max={maxPoints}></ProgressBar>\n              </View>\n            </TouchableWithoutFeedback>\n          );\n        });\n      }\n\n      contentSection = (\n        <View style={styles.storyContent}>\n          <HTMLView html={data.content} onLinkPress={showBrowser} onLinkLongPress={showActivity}/>\n          {pollElements}\n        </View>\n      );\n    }\n\n    let commentsSection;\n    if (data && data.comments && data.comments.length){\n      commentsSection = null;\n    } else if (loading){\n      commentsSection = (\n        <View style={styles.viewCommentsBlank}>\n          <LoadingIndicator/>\n        </View>\n      );\n    } else if (error){\n      commentsSection = (\n        <View style={styles.viewCommentsBlank}>\n          <View style={styles.errorContainer}>\n            <Text style={styles.errorText}>Couldn't load comments.</Text>\n            <TouchableOpacity onPress={this._fetchStory}>\n              <Text style={styles.retryText}>Try again</Text>\n            </TouchableOpacity>\n          </View>\n        </View>\n      );\n    } else {\n      commentsSection = (\n        <View style={styles.viewCommentsBlank}>\n          <Text style={styles.noCommentsText}>No comments.</Text>\n        </View>\n      );\n    }\n\n    return (\n      <View>\n        <View style={styles.storySection}>\n          {storyHeader}\n          <View style={styles.storyMetadataWrap}>\n            <Text style={styles.storyMetadata}>{data.points} points by {data.user} </Text>\n            <Text style={styles.storyMetadata}>{data.time_ago} {data.comments_count>0 && commentsText}</Text>\n          </View>\n          <TouchableHighlight onPress={showBrowser.bind(null, hnURL)} onLongPress={showActivity.bind(null, hnURL, data.title)} style={styles.touchableLink}>\n            <View style={[styles.externalLink, styles.touchableLinkInner]}>\n              <Image style={styles.externalArrowIcon} source={require('../images/external-arrow.png')}/>\n              <Text style={styles.storyMetadata}>{hnShortURL}</Text>\n            </View>\n          </TouchableHighlight>\n        </View>\n        {contentSection}\n        <View style={styles.separator}/>\n        {commentsSection}\n      </View>\n    );\n  }\n  render(){\n    const {data, dataSource} = this.state;\n    const comments = (data && data.comments) || [];\n    const hasManyComments = JSON.stringify(comments).length > 20*1000;\n    const op = data && data.user;\n    return (\n      <ListView\n        renderHeader={this._renderHeader.bind(this)}\n        dataSource={dataSource}\n        pageSize={5}\n        renderRow={(comment) => <CommentRow key={comment.id} comment={comment} op={op} hasManyComments={hasManyComments}/>}\n        renderSeparator={(sectionID, rowID) => <View key={rowID} style={styles.separator}/>}\n        renderFooter={() => <View style={styles.footer}/>}\n      />\n    );\n  }\n}\n"
  },
  {
    "path": "views/StoriesView.js",
    "content": "'use strict';\n\nimport React, { Component } from 'react';\nimport {\n  StyleSheet,\n  View,\n  Text,\n  ListView,\n  TouchableOpacity,\n  TouchableNativeFeedback,\n  ActionSheetIOS,\n  LayoutAnimation,\n  Platform,\n} from 'react-native';\n\nconst isIOS = Platform.OS === 'ios';\nconst CrossTouchable = isIOS ? TouchableOpacity : TouchableNativeFeedback;\n\nimport StoryStore from '../stores/StoryStore';\nimport StoryActions from '../actions/StoryActions';\nimport LinkActions from '../actions/LinkActions';\n\nimport StoryRow from '../components/StoryRow';\nimport LoadingIndicator from '../components/LoadingIndicator';\nimport CommentsView from './CommentsView';\nimport showBrowser from '../utils/showBrowser';\nimport showActivity from '../utils/showActivity';\n\nimport colors from '../colors';\n\nconst hairlineWidth = isIOS ? StyleSheet.hairlineWidth : 1;\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n  },\n  navbarSpacing: {\n    marginTop: 64,\n  },\n  viewLoading: {\n    flex: 1,\n    flexDirection: 'row',\n    alignItems: 'center',\n    justifyContent: 'center',\n  },\n  viewError: {\n    flex: 1,\n    alignItems: 'center',\n    justifyContent: 'center',\n  },\n  errorText: {\n    opacity: .6,\n  },\n  itemSeparator: {\n    height: hairlineWidth,\n    backgroundColor: colors.separatorColor,\n    marginLeft: isIOS ? 15 : 0,\n    marginTop: -hairlineWidth,\n  },\n  itemHighligtedSeparator: {\n    opacity: 0,\n  },\n  wrapper: {\n    backgroundColor: colors.viewBackgroundColor,\n  },\n  moreLink: {\n    padding: 19,\n    textAlign: 'center',\n    color: colors.linkColor,\n    fontSize: 17,\n    textAlignVertical: 'center',\n  },\n});\n\nexport default class StoriesView extends Component {\n  constructor(props){\n    super(props);\n    const { stories, storiesLoading, storiesError, hasMoreStories } = StoryStore.getState();\n    this.state = {\n      stories,\n      loading: storiesLoading,\n      error: storiesError,\n      dataSource: new ListView.DataSource({rowHasChanged: (row1, row2) => row1 !== row2}),\n      hasMoreStories,\n    };\n    this._onChange = this._onChange.bind(this);\n  }\n  componentDidMount(){\n    StoryStore.listen(this._onChange);\n    StoryActions.fetchStories();\n  }\n  componentWillUnmount(){\n    StoryStore.unlisten(this._onChange);\n  }\n  _onChange(state){\n    const {stories, storiesLoading, storiesError, hasMoreStories} = state;\n    LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);\n    this.setState({\n      stories,\n      dataSource: this.state.dataSource.cloneWithRows([].concat(stories)),\n      loading: storiesLoading,\n      error: storiesError,\n      hasMoreStories,\n    });\n  }\n  _navigateToComments(data){\n    this.props.navigator.push({\n      id: 'Comments',\n      title: data.title,\n      component: CommentsView,\n      wrapperStyle: styles.wrapper,\n      rightButtonIcon: require('../images/share-icon.png'),\n      onRightButtonPress: showActivity.bind(null, `https://news.ycombinator.com/item?id=${data.id}`, data.title),\n      passProps: {\n        data: data,\n      }\n    });\n    // Log link visit to History\n    const {url} = data;\n    if (/^item/i.test(url)) LinkActions.addLink(url);\n  }\n  _renderRow(row, sectionID, rowID, highlightRow){\n    const position = parseInt(rowID, 10) + 1;\n    const {url} = row;\n    const externalLink = !/^item/i.test(url);\n    const navToComments = this._navigateToComments.bind(this, row);\n    const linkPress = externalLink ? showBrowser.bind(null, url) : navToComments;\n\n    return (\n      <StoryRow position={position} data={row} onCommentPress={navToComments} onPress={linkPress} onLongPress={showActivity.bind(null, url, row.title)} onShowUnderlay={() => highlightRow(sectionID, rowID)} onHideUnderlay={() => highlightRow(null, null)}/>\n    );\n  }\n  _renderSeparator(sectionID, rowID, adjacentRowHighlighted){\n    return <View key={rowID} style={[styles.itemSeparator, adjacentRowHighlighted && styles.itemHighligtedSeparator]}/>;\n  }\n  _fetchMoreStories(){\n    // Delay the fetching a bit to create that sense of something's happening in the background\n    if (this._fetchingMore) return;\n    this._fetchingMore = true;\n    setTimeout(() => {\n      StoryActions.fetchMoreStories();\n      this._fetchingMore = false;\n    }, 300);\n  }\n  _renderFooter(){\n    const {hasMoreStories, stories} = this.state;\n    if (hasMoreStories && stories && stories.length <= 30){\n      return (\n        <CrossTouchable onPress={this._fetchMoreStories.bind(this)}>\n          <View>\n            <Text style={styles.moreLink}>More&hellip;</Text>\n          </View>\n        </CrossTouchable>\n      );\n    }\n    return null;\n  }\n  render(){\n    const {loading, error, dataSource} = this.state;\n    if (loading){\n      return (\n        <View style={styles.viewLoading}>\n          <LoadingIndicator/>\n        </View>\n      );\n    }\n    if (error){\n      return (\n        <View style={styles.viewError}>\n          <Text style={styles.errorText}>Couldn't load stories.</Text>\n          <Text style={styles.errorText}>{error && error.message ? error.message : '😭'}</Text>\n        </View>\n      );\n    }\n    return (\n      <View style={styles.container}>\n        <ListView\n          style={isIOS && styles.navbarSpacing}\n          pageSize={10}\n          dataSource={dataSource}\n          renderRow={this._renderRow.bind(this)}\n          renderSeparator={this._renderSeparator.bind(this)}\n          renderFooter={this._renderFooter.bind(this)}\n        />\n        {/* Temporary FIX: Prevent the taps on NavigatorIOS buttons \"leaking\" into the ListView rows' taps */}\n        {isIOS && <View onStartShouldSetResponder={() => false} style={{width: 100, height: 10, position: 'absolute', top: styles.navbarSpacing-2}} />}\n        {isIOS && <View onStartShouldSetResponder={() => false} style={{width: 60, height: 10, position: 'absolute', top: styles.navbarSpacing-2, right: 0}} />}\n      </View>\n    );\n  }\n}\n"
  }
]