[
  {
    "path": ".azurepipelines/build-rn-code-push-1es.yml",
    "content": "trigger:\n- master\n\npr:\n- master\n\nresources:\n  repositories:\n  - repository: 1ESPipelineTemplates\n    type: git\n    name: 1ESPipelineTemplates/1ESPipelineTemplates\n    ref: refs/tags/release\nname: $(Build.SourceBranchName)_$(date:yyyyMMdd)$(rev:.r)\n\nextends:\n  ${{ if eq(variables['Build.SourceBranch'], 'refs/heads/master') }}:\n    template: v1/1ES.Official.PipelineTemplate.yml@1ESPipelineTemplates\n  ${{ else }}:\n    template: v1/1ES.Unofficial.PipelineTemplate.yml@1ESPipelineTemplates\n  parameters:\n    pool:\n      name: 1ES-PT-CBL-Mariner-2.0-Gen2\n      os: linux\n    customBuildTags:\n    - ES365AIMigrationTooling-BulkMigrated\n    sdl:\n      sourceAnalysisPool: 1ES-PT-Windows-2022\n      credscan:\n        suppressionsFile: $(Build.SourcesDirectory)/.config/CredScanSuppressions.json\n    stages:\n    - stage: Stage\n      jobs:\n      - job: HostJob\n        templateContext:\n          outputs:\n          - output: pipelineArtifact\n            displayName: \"Publish Artifact: artifacts\"\n            path: '$(Build.ArtifactStagingDirectory)/npm'\n            artifactName: npm\n            \n        steps:\n        - task: NodeTool@0\n          inputs:\n            versionSpec: '14.x'\n          displayName: 'Install Node.js'\n\n        - script: |\n            npm pack\n            npm install -g react-native-code-push*.tgz\n          displayName: 'Package react-native-code-push'\n          workingDirectory: $(Build.SourcesDirectory)\n\n        - task: DeleteFiles@1\n          inputs:\n            contents: node_modules\n          displayName: 'Delete node_modules'\n\n        - task: ArchiveFiles@2\n          inputs:\n            rootFolderOrFile: '$(Build.SourcesDirectory)'\n            includeRootFolder: false\n            archiveType: 'tar'\n            archiveFile: '$(Build.ArtifactStagingDirectory)/npm/$(Build.BuildId).tgz'\n            replaceExistingArchive: true\n            verbose: true\n          displayName: 'Prepare npm artifact'\n\n    - stage: APIScan\n      dependsOn: Stage\n      pool:\n        name: 1ES-PT-Windows-2022\n        os: windows\n      variables:\n        \"agent.source.skip\": true\n      jobs:\n      - job: APIScan\n        steps:\n        - task: DownloadPipelineArtifact@2\n          displayName: Download Build Artifacts for APIScan\n          inputs:\n            artifactName: npm\n            targetPath: '$(Agent.BuildDirectory)/npm'\n        - task: ExtractFiles@1\n          inputs:\n            archiveFilePatterns: '$(Agent.BuildDirectory)/npm/*.tgz'\n            destinationFolder: '$(Agent.BuildDirectory)/npm_extracted'\n        - task: AzureKeyVault@2\n          inputs:\n            azureSubscription: 'AC - Dev Infra & Build Pool'\n            KeyVaultName: 'mobile-center-sdk'\n            SecretsFilter: 'appcenter-sdk-managed-identity-clientid'\n            RunAsPreJob: false\n        - task: APIScan@2\n          displayName: 'Run APIScan'\n          inputs:\n            softwareFolder: '$(Agent.BuildDirectory)\\npm_extracted'\n            softwareName: 'react-native-code-push'\n            softwareVersionNum: '$(Build.BuildId)'\n            isLargeApp: false\n            toolVersion: 'Latest'\n            verbosityLevel: verbose\n          condition: and(succeeded(), ne(variables['DisableAPIScan'], 'true'))\n          env:\n            AzureServicesAuthConnectionString: 'runAs=App;AppId=$(appcenter-sdk-managed-identity-clientid)'"
  },
  {
    "path": ".azurepipelines/test-rn-code-push.yml",
    "content": "trigger:\n- master\n\npr:\n- master\n\nvariables:\n- name: api-level\n  value: '27' \n\npool:\n  vmImage: 'macOS-12'\n\nstages:\n- stage: RunTests\n  displayName: 'Run Android & IOS tests'\n  jobs:\n  - job: TestAndroid\n    timeoutInMinutes: 120\n    displayName: 'Test android'\n    steps:\n\n    - script: |\n        adb devices\n      displayName: 'Start adb server'\n\n    - script: |\n        $ANDROID_HOME/tools/bin/sdkmanager \"system-images;android-$(api-level);google_apis;x86\"\n      displayName: 'Download system image'\n\n    - script: |\n        $ANDROID_HOME/tools/bin/avdmanager create avd --force --name TestEmulator --abi google_apis/x86 --package 'system-images;android-$(api-level);google_apis;x86' --device \"Nexus 6P\"\n      displayName: 'Creating Android emulator'\n\n    - script: |\n        $ANDROID_HOME/emulator/emulator -avd TestEmulator -noaudio -no-window -no-snapshot-save -no-boot-anim -memory 6144 &\n      displayName: 'Start Android emulator'\n\n    - script: |\n        $ANDROID_HOME/platform-tools/adb wait-for-device shell 'while [[ -z $(getprop sys.boot_completed | tr -d '\\r') ]]; do sleep 1; done'\n      displayName: 'Wait for emulator to boot'\n   \n    - script: |\n         adb shell settings put global window_animation_scale 0.0    \n      displayName: 'Disable animations and transitions'  \n\n    - script: |\n         adb shell settings put global transition_animation_scale 0.0\n      displayName: 'Disable animations and transitions'\n\n    - script: |\n         adb shell settings put global animator_duration_scale 0.0   \n      displayName: 'Disable animations and transitions'\n\n    \n    - task: JavaToolInstaller@0\n      inputs:\n        versionSpec: '11'\n        jdkArchitectureOption: 'x64'\n        jdkSourceOption: 'PreInstalled'\n      displayName: 'Change Java version'\n\n    - script: |\n        npm install\n      displayName: 'Package Installation'\n\n    - script: |\n        npm run build:tests && npm run test:setup:android\n      displayName: 'Setup Android tests'\n\n    - script: |\n        npm run test:fast:android\n      displayName: 'Run Android test'\n\n  - job: TestIOS\n    timeoutInMinutes: 120\n    displayName: 'Test IOS'\n    steps:\n\n    - script: |\n        npm install\n      displayName: 'Install dependencies'\n\n    - script: |\n        npm run build:tests && npm run test:setup:ios\n      displayName: 'Setup iOS tests'\n\n    - script: |\n        npm run test:fast:ios\n      displayName: 'Run tests'\n\n    \n          \n\n"
  },
  {
    "path": ".config/CredScanSuppressions.json",
    "content": "{\n  \"tool\": \"Credential Scanner\",\n    \"suppressions\": [        \n      {\n        \"file\": \"/Examples/CodePushDemoApp/android/app/debug.keystore\",\n        \"_justification\": \"Used only in DemoApp\"\n      },\n      {\n        \"file\": \"/Examples/CodePushDemoAppCpp/windows/CodePushDemoAppCpp/CodePushDemoAppCpp_TemporaryKey.pfx\",\n        \"_justification\": \"Used only in DemoApp\"\n      }\n    ]\n}\n  "
  },
  {
    "path": ".github/CODEOWNERS",
    "content": "*       @microsoft/appcenter-fte\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE.md",
    "content": "Thanks so much for filing an issue or feature request! Please fill out the following (wherever relevant):\r\n\r\n### Steps to Reproduce\r\n1.\r\n2. \r\n3.\r\n\r\n### Expected Behavior\r\nWhat you expected to happen?\r\n\r\n### Actual Behavior\r\nWhat actually happens?\r\n```\r\n  STACK TRACE AND/OR SCREENSHOTS\r\n```\r\n\r\n### Reproducible Demo\r\n\r\n* Download https://github.com/microsoft/react-native-code-push/archive/master.zip and unzip. From `Examples` folder run `node create-app.js appName react-native@0.71.19 react-native-code-push@9.0.1` command to generate plain CodePushified React Native app. Please see description on top of `create-app.js` file content if needed\r\n* If you can't reproduce the bug on it, provide us as much info as possible about your project\r\n\r\n### Environment\r\n\r\n* react-native-code-push version:\r\n* react-native version:\r\n* iOS/Android/Windows version:\r\n* Does this reproduce on a debug build or release build?\r\n* Does this reproduce on a simulator, or only on a physical device?\r\n\r\n(The more info the faster we will be able to address it!)\r\n"
  },
  {
    "path": ".github/policies/resourceManagement.yml",
    "content": "id: \r\nname: GitOps.PullRequestIssueManagement\r\ndescription: GitOps.PullRequestIssueManagement primitive\r\nowner: \r\nresource: repository\r\ndisabled: false\r\nwhere: \r\nconfiguration:\r\n  resourceManagementConfiguration:\r\n    scheduledSearches:\r\n    - description: \r\n      frequencies:\r\n      - hourly:\r\n          hour: 4\r\n      filters:\r\n      - isOpen\r\n      - isNotLabeledWith:\r\n          label: bug\r\n      - isNotLabeledWith:\r\n          label: security\r\n      - isNotLabeledWith:\r\n          label: stale\r\n      - isNotLabeledWith:\r\n          label: do not close\r\n      - noActivitySince:\r\n          days: 60\r\n      - isIssue\r\n      - isNotAssigned\r\n      actions:\r\n      - addLabel:\r\n          label: stale\r\n      - addReply:\r\n          reply: This issue has been automatically marked as stale because it has not had any activity for 60 days. It will be closed if no further activity occurs within 15 days of this comment.\r\n    - description: \r\n      frequencies:\r\n      - hourly:\r\n          hour: 6\r\n      filters:\r\n      - isOpen\r\n      - isIssue\r\n      - hasLabel:\r\n          label: stale\r\n      - isNotLabeledWith:\r\n          label: bug\r\n      - isNotLabeledWith:\r\n          label: do not close\r\n      - isNotAssigned\r\n      - noActivitySince:\r\n          days: 15\r\n      actions:\r\n      - addReply:\r\n          reply: This issue will now be closed because it hasn't had any activity for 15 days after stale. Please feel free to open a new issue if you still have a question/issue or suggestion.\r\n      - closeIssue\r\n    eventResponderTasks:\r\n    - if:\r\n      - payloadType: Issue_Comment\r\n      - hasLabel:\r\n          label: stale\r\n      then:\r\n      - removeLabel:\r\n          label: stale\r\n      description: \r\nonFailure: \r\nonSuccess: \r\n"
  },
  {
    "path": ".gitignore",
    "content": "# gitignore contributors: remember to update .npmignore\n\n# OSX\n#\n.DS_Store\n\n# Xcode\n#\n# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore\n\n## Build generated\nbuild/\nDerivedData\n\n## Various settings\n*.pbxuser\n!default.pbxuser\n*.mode1v3\n!default.mode1v3\n*.mode2v3\n!default.mode2v3\n*.perspectivev3\n!default.perspectivev3\nxcuserdata\n\n## Other\n*.xccheckout\n*.moved-aside\n*.xcuserstate\n\n## Obj-C/Swift specific\n*.hmap\n*.ipa\n\n# CocoaPods\n#\n# We recommend against adding the Pods directory to your .gitignore. However\n# you should judge for yourself, the pros and cons are mentioned at:\n# http://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control\n#\n#Pods/\n\n# Carthage\n#\n# Add this line if you want to avoid checking in source code from Carthage dependencies.\n# Carthage/Checkouts\n\nCarthage/Build\n\n### Node\n\n# Logs\nlogs\n*.log\n\n# Runtime data\npids\n*.pid\n*.seed\n\n# Directory for instrumented libs generated by jscoverage/JSCover\nlib-cov\n\n# Coverage directory used by tools like istanbul\ncoverage\n\n# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)\n.grunt\n\n# node-waf configuration\n.lock-wscript\n\n# Compiled binary addons (http://nodejs.org/api/addons.html)\nbuild/Release\n\n# Dependency directory\n# https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git\nnode_modules\n\n# Xcode\n#\n# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore\n\n## Build generated\nbuild/\nDerivedData\n\n## Various settings\n*.pbxuser\n!default.pbxuser\n*.mode1v3\n!default.mode1v3\n*.mode2v3\n!default.mode2v3\n*.perspectivev3\n!default.perspectivev3\nxcuserdata\n\n## OSX\n.DS_Store\n\n## Other\n*.xccheckout\n*.moved-aside\n*.xcuserstate\n\n# Intellij project files\n*.iml\n*.ipr\n*.iws\n.idea/\n\n#Gradle\n.gradletasknamecache\n.gradle/\nbuild/\nbin/\n\n# Built application files\n*.apk\n*.ap_\n\n# Files for the Dalvik VM\n*.dex\n\n# Java class files\n*.class\n\n# Generated files\nbin/\ngen/\n\n# Gradle files\n.gradle/\nbuild/\n*/build/\n\n# Local configuration file (sdk path, etc)\nlocal.properties\n\n# Proguard folder generated by Eclipse\nproguard/\n\n# Log Files\n*.log\n\n# Android Studio Navigation editor temp files\n.navigation/\n\n# Android Studio captures folder\ncaptures/\n\n# Remove after this framework is published on NPM\ncode-push-plugin-testing-framework/node_modules\n\n# Windows\nwindows/.vs/\nwindows/obj/\n\n#Visual Studio files\n*.[Oo]bj\n*.user\n*.aps\n*.pch\n*.vspscc\n*.vssscc\n*_i.c\n*_p.c\n*.ncb\n*.suo\n*.tlb\n*.tlh\n*.bak\n*.[Cc]ache\n*.ilk\n*.log\n*.lib\n*.sbr\n*.sdf\n*.opensdf\n*.opendb\n*.unsuccessfulbuild\nipch/\n[Oo]bj/\n[Bb]in\n[Dd]ebug*/\n[Rr]elease*/\nAnkh.NoLoad\n\n# RN New Version App Generation\nExamples/testapp_rn\n\n# Android debug build files (conflict ignoring #Visual Studio files)\n!android/app/src/debug/\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\n# Don't publish example apps\nExamples/\nRecipes/\n\n# Don't publish testing code\nbin/\ntest/\n\n# Remove after this framework is published on NPM\ncode-push-plugin-testing-framework/\n\n# Android build artifacts and Android Studio bits\nandroid/app/build\nandroid/local.properties\nandroid/.gradle\nandroid/**/*.iml\nandroid/.idea\n\n\n# Windows\nwindows/.vs/\nwindows/obj/\n\n#Tests\nwindows/CodePush.Net46.Test\n\n#Visual Studio files\n*.[Oo]bj\n*.user\n*.aps\n*.pch\n*.vspscc\n*.vssscc\n*_i.c\n*_p.c\n*.ncb\n*.suo\n*.tlb\n*.tlh\n*.bak\n*.[Cc]ache\n*.ilk\n*.log\n*.lib\n*.sbr\n*.sdf\n*.opensdf\n*.opendb\n*.unsuccessfulbuild\nipch/\n[Oo]bj/\n[Bb]in\n[Dd]ebug*/\n[Rr]elease*/\nAnkh.NoLoad\n\n#NuGet\npackages/\n*.nupkg\n\n# VSCode\n.vscode/\n\n# IntelliJIDEA\n.idea/\n\n\n# Github\n.github/\n\n# Git\n.git/\n\n.watchmanconfig\n\n"
  },
  {
    "path": ".vscode/launch.json",
    "content": "{\n    \"version\": \"0.2.0\",\n    \"configurations\": [\n        {\n            \"name\": \"Tests-android\",\n            \"type\": \"node\",\n            \"request\": \"launch\",\n            \"preLaunchTask\": \"Setup-android\",\n            \"runtimeExecutable\": \"npm\",\n            \"runtimeArgs\": [\n                \"run\",\n                \"test:debugger:android\"\n            ],\n            \"port\": 9229,\n            \"stopOnEntry\": false,\n            \"sourceMaps\": true,\n            \"console\": \"internalConsole\",\n            \"internalConsoleOptions\": \"openOnSessionStart\",\n            \"autoAttachChildProcesses\": true,\n            \"timeout\": 100000\n        },\n        {\n            \"name\": \"Tests-ios\",\n            \"type\": \"node\",\n            \"request\": \"launch\",\n            \"preLaunchTask\": \"Setup-ios\",\n            \"runtimeExecutable\": \"npm\",\n            \"runtimeArgs\": [\n                \"run\",\n                \"test:debugger:ios\"\n            ],\n            \"port\": 9229,\n            \"stopOnEntry\": false,\n            \"sourceMaps\": true,\n            \"console\": \"internalConsole\",\n            \"internalConsoleOptions\": \"openOnSessionStart\",\n            \"autoAttachChildProcesses\": true,\n            \"timeout\": 100000\n        }\n    ]\n}\n"
  },
  {
    "path": ".vscode/settings.json",
    "content": "{\n    \"typescript.tsdk\": \"node_modules/typescript/lib\"\n}"
  },
  {
    "path": ".vscode/tasks.json",
    "content": "{\n    \"version\": \"2.0.0\",\n    \"tasks\": [\n        {\n            \"type\": \"shell\",\n            \"label\": \"Build\",\n            \"command\": \"npm\",\n            \"args\": [\n                \"run\",\n                \"build:tests\"\n            ],\n            \"presentation\": {\n                \"echo\": false,\n                \"focus\": false\n            },\n            \"problemMatcher\": [\n                \"$tsc\"\n            ]\n        },\n        {\n            \"type\": \"shell\",\n            \"label\": \"Setup-android\",\n            \"dependsOn\": \"Build\",\n            \"command\": \"npm\",\n            \"args\": [\n                \"run\",\n                \"test:setup:android\"\n            ],\n            \"presentation\": {\n                \"echo\": false,\n                \"focus\": false\n            },\n            \"problemMatcher\": [\n                \"$tsc\"\n            ]\n        },\n        {\n            \"type\": \"shell\",\n            \"label\": \"Setup-ios\",\n            \"dependsOn\": \"Build\",\n            \"command\": \"npm\",\n            \"args\": [\n                \"run\",\n                \"test:setup:ios\"\n            ],\n            \"presentation\": {\n                \"echo\": false,\n                \"focus\": false\n            },\n            \"problemMatcher\": [\n                \"$tsc\"\n            ]\n        }\n    ]\n}\n"
  },
  {
    "path": ".watchmanconfig",
    "content": "{}"
  },
  {
    "path": "AlertAdapter.js",
    "content": "import React, { Platform } from \"react-native\";\nlet { Alert } = React;\n\nif (Platform.OS === \"android\") {\n  const { NativeModules: { CodePushDialog } } = React;\n    \n  Alert = {\n    alert(title, message, buttons) {\n      if (buttons.length > 2) {\n        throw \"Can only show 2 buttons for Android dialog.\";\n      }\n      \n      const button1Text = buttons[0] ? buttons[0].text : null,\n            button2Text = buttons[1] ? buttons[1].text : null;\n      \n      CodePushDialog.showDialog(\n        title, message, button1Text, button2Text,\n        (buttonId) => { buttons[buttonId].onPress && buttons[buttonId].onPress(); }, \n        (error) => { throw error; });\n    }\n  };\n}\n\nmodule.exports = { Alert };"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing\n\n## Using the plugin\n\n### Environment setup\n\n`node.js` and `npm` are needed for using this project. `npm` comes bundled with the `node.js` installer. You can download the `node.js` installer here: https://nodejs.org/download/.\n\nOnce you have installed `node.js` and `npm`, install the dev dependencies for the project.\n\n```\nnpm install\n```\n\n### Using the plugin manually\n\nFollow these steps to test your modifications to the plugin manually:\n- clone this repository\n- install the dependencies\n\n\tNavigate to the root folder from your command line console and run:\n\t```\n\tnpm install\n\t```\n- install the plugin in a React-Native project\n\n\tNavigate to the root folder of your React-Native project from your command line console and run:\n\t```\n\tnpm install local_path_to_your_clone_of_this_repo\n\t```\n- configure the plugin using the steps in the README.md\n- build and run your app on an emulator or device\n\n## Test\n\n### Environment setup\n\nFirst, make sure you have installed the dependencies for the plugin by following the steps above.\n\nThen, make sure you have installed `react-native`.\n\n```\nnpm install -g react-native\n```\n\nTo run Android tests, make sure you have `sdk\\tools`, `sdk\\emulator` and  `sdk\\platform-tools` in your PATH.\n\nTo run iOS tests, make sure you've installed CocoaPods and have `.gem/bin` in your PATH.\n\n### Supported platforms\n\nThe plugin has end to end tests for Android and iOS. Depending on your development machine OS, you can run some or all the tests.\n\nOS            | Supported tests\n------------- | -------------\nOS X          | Android, iOS\nWindows       | Android\n\n### Test descriptions\n\nThe tests first build the app.\n\nThey then check if the required emulators are currently running.\n\nIf an Android emulator is not running, it attempts to boot the latest Android emulator. You can specify an emulator by adding env variable `ANDROID_EMU=yourEmulatorNameHere` to the npm command. For example: `ANDROID_EMU=yourEmulatorNameHere npm run test:android`.\n\nIf an iOS simulator is not running, it attempts to boot the latest iOS iPhone simulator. You can specify a simulator by adding env variable `IOS_EMU=yourSimulatorNameHere` to the npm command. For example: `IOS_EMU=\"iPhone 8 (0567DFF8-329E-41A3-BD6D-E48E9DD5EF39)\" npm run test:ios`.\n\nIf all the required emulators are not running and the tests fail to boot them, the tests will fail.\n\nIf you would like the tests to always restart the necessary emulators (killing them if they are currently running), setup a env variable `CLEAN=true` to the command. For example: `CLEAN=true npm run test`.\n\nThe desired unit tests are then run.\n\nIf you would like to skip building, add a `:fast` in the command you'd like to run. For example, `npm run test:ios` becomes `npm run test:fast:ios` or `npm run test:android` becomes `npm run test:fast:android`.\n\nThere is a both a full unit test suite and a \"core\" set of unit tests that you may run. If you would like to run only the core tests, setup a env variable `CORE=true` to the command. For example: `CORE=true npm run test:android`.\n\nIf you would like to pull the plugin from NPM rather than running the tests on the local version, setup a env variable `NPM=true` to the command. For example: `NPM=true npm run test:ios`.\n\n#### Default\n\nTo run all of the unit tests on Android and iOS:\n```\nnpm run test\n```\n\n#### iOS\n\nTo run all of the unit tests on iOS:\n```\nnpm run test:ios\n```\n\n#### Android\n\nTo run all of the unit tests on Android:\n```\nnpm run test:android\n```\n\n#### More examples\n\nAll possible testing configurations have tasks!\n\nThe platforms are ordered as follows, and ran in that order:\nandroid, ios\n\nTo run the core unit tests on Android:\n```\nCORE=true npm run test:android\n```\n\nTo run all of the unit tests on iOS and pull the plugin from NPM:\n```\nNPM=true npm run test:ios\n```\n\nTo run all of the unit tests on Android and iOS without building first:\n```\nnpm run test:fast\n```\n\nTo run all of the unit tests on iOS and restart the emulators:\n```\nCLEAN=true npm run test:ios\n```\n\nTo run the core unit tests on Android and pull the plugin from NPM:\n```\nNPM=true CORE=true npm run test:android\n```\n\n...and so on!\n"
  },
  {
    "path": "CodePush.js",
    "content": "import { AcquisitionManager as Sdk } from \"code-push/script/acquisition-sdk\";\nimport { Alert } from \"./AlertAdapter\";\nimport requestFetchAdapter from \"./request-fetch-adapter\";\nimport { AppState, Platform } from \"react-native\";\nimport log from \"./logging\";\nimport hoistStatics from 'hoist-non-react-statics';\n\nlet NativeCodePush = require(\"react-native\").NativeModules.CodePush;\nconst PackageMixins = require(\"./package-mixins\")(NativeCodePush);\n\nasync function checkForUpdate(deploymentKey = null, handleBinaryVersionMismatchCallback = null) {\n  /*\n   * Before we ask the server if an update exists, we\n   * need to retrieve three pieces of information from the\n   * native side: deployment key, app version (e.g. 1.0.1)\n   * and the hash of the currently running update (if there is one).\n   * This allows the client to only receive updates which are targetted\n   * for their specific deployment and version and which are actually\n   * different from the CodePush update they have already installed.\n   */\n  const nativeConfig = await getConfiguration();\n  /*\n   * If a deployment key was explicitly provided,\n   * then let's override the one we retrieved\n   * from the native-side of the app. This allows\n   * dynamically \"redirecting\" end-users at different\n   * deployments (e.g. an early access deployment for insiders).\n   */\n  const config = deploymentKey ? { ...nativeConfig, ...{ deploymentKey } } : nativeConfig;\n  const sdk = getPromisifiedSdk(requestFetchAdapter, config);\n\n  // Use dynamically overridden getCurrentPackage() during tests.\n  const localPackage = await module.exports.getCurrentPackage();\n\n  /*\n   * If the app has a previously installed update, and that update\n   * was targetted at the same app version that is currently running,\n   * then we want to use its package hash to determine whether a new\n   * release has been made on the server. Otherwise, we only need\n   * to send the app version to the server, since we are interested\n   * in any updates for current binary version, regardless of hash.\n   */\n  let queryPackage;\n  if (localPackage) {\n    queryPackage = localPackage;\n  } else {\n    queryPackage = { appVersion: config.appVersion };\n    if (Platform.OS === \"ios\" && config.packageHash) {\n      queryPackage.packageHash = config.packageHash;\n    }\n  }\n\n  const update = await sdk.queryUpdateWithCurrentPackage(queryPackage);\n\n  /*\n   * There are four cases where checkForUpdate will resolve to null:\n   * ----------------------------------------------------------------\n   * 1) The server said there isn't an update. This is the most common case.\n   * 2) The server said there is an update but it requires a newer binary version.\n   *    This would occur when end-users are running an older binary version than\n   *    is available, and CodePush is making sure they don't get an update that\n   *    potentially wouldn't be compatible with what they are running.\n   * 3) The server said there is an update, but the update's hash is the same as\n   *    the currently running update. This should _never_ happen, unless there is a\n   *    bug in the server, but we're adding this check just to double-check that the\n   *    client app is resilient to a potential issue with the update check.\n   * 4) The server said there is an update, but the update's hash is the same as that\n   *    of the binary's currently running version. This should only happen in Android -\n   *    unlike iOS, we don't attach the binary's hash to the updateCheck request\n   *    because we want to avoid having to install diff updates against the binary's\n   *    version, which we can't do yet on Android.\n   */\n  if (!update || update.updateAppVersion ||\n      localPackage && (update.packageHash === localPackage.packageHash) ||\n      (!localPackage || localPackage._isDebugOnly) && config.packageHash === update.packageHash) {\n    if (update && update.updateAppVersion) {\n      log(\"An update is available but it is not targeting the binary version of your app.\");\n      if (handleBinaryVersionMismatchCallback && typeof handleBinaryVersionMismatchCallback === \"function\") {\n        handleBinaryVersionMismatchCallback(update)\n      }\n    }\n\n    return null;\n  } else {\n    const remotePackage = { ...update, ...PackageMixins.remote(sdk.reportStatusDownload) };\n    remotePackage.failedInstall = await NativeCodePush.isFailedUpdate(remotePackage.packageHash);\n    remotePackage.deploymentKey = deploymentKey || nativeConfig.deploymentKey;\n    return remotePackage;\n  }\n}\n\nconst getConfiguration = (() => {\n  let config;\n  return async function getConfiguration() {\n    if (config) {\n      return config;\n    } else if (testConfig) {\n      return testConfig;\n    } else {\n      config = await NativeCodePush.getConfiguration();\n      return config;\n    }\n  }\n})();\n\nasync function getCurrentPackage() {\n  return await getUpdateMetadata(CodePush.UpdateState.LATEST);\n}\n\nasync function getUpdateMetadata(updateState) {\n  let updateMetadata = await NativeCodePush.getUpdateMetadata(updateState || CodePush.UpdateState.RUNNING);\n  if (updateMetadata) {\n    updateMetadata = {...PackageMixins.local, ...updateMetadata};\n    updateMetadata.failedInstall = await NativeCodePush.isFailedUpdate(updateMetadata.packageHash);\n    updateMetadata.isFirstRun = await NativeCodePush.isFirstRun(updateMetadata.packageHash);\n  }\n  return updateMetadata;\n}\n\nfunction getPromisifiedSdk(requestFetchAdapter, config) {\n  // Use dynamically overridden AcquisitionSdk during tests.\n  const sdk = new module.exports.AcquisitionSdk(requestFetchAdapter, config);\n  sdk.queryUpdateWithCurrentPackage = (queryPackage) => {\n    return new Promise((resolve, reject) => {\n      module.exports.AcquisitionSdk.prototype.queryUpdateWithCurrentPackage.call(sdk, queryPackage, (err, update) => {\n        if (err) {\n          reject(err);\n        } else {\n          resolve(update);\n        }\n      });\n    });\n  };\n\n  sdk.reportStatusDeploy = (deployedPackage, status, previousLabelOrAppVersion, previousDeploymentKey) => {\n    return new Promise((resolve, reject) => {\n      module.exports.AcquisitionSdk.prototype.reportStatusDeploy.call(sdk, deployedPackage, status, previousLabelOrAppVersion, previousDeploymentKey, (err) => {\n        if (err) {\n          reject(err);\n        } else {\n          resolve();\n        }\n      });\n    });\n  };\n\n  sdk.reportStatusDownload = (downloadedPackage) => {\n    return new Promise((resolve, reject) => {\n      module.exports.AcquisitionSdk.prototype.reportStatusDownload.call(sdk, downloadedPackage, (err) => {\n        if (err) {\n          reject(err);\n        } else {\n          resolve();\n        }\n      });\n    });\n  };\n\n  return sdk;\n}\n\n// This ensures that notifyApplicationReadyInternal is only called once\n// in the lifetime of this module instance.\nconst notifyApplicationReady = (() => {\n  let notifyApplicationReadyPromise;\n  return () => {\n    if (!notifyApplicationReadyPromise) {\n      notifyApplicationReadyPromise = notifyApplicationReadyInternal();\n    }\n\n    return notifyApplicationReadyPromise;\n  };\n})();\n\nasync function notifyApplicationReadyInternal() {\n  await NativeCodePush.notifyApplicationReady();\n  const statusReport = await NativeCodePush.getNewStatusReport();\n  statusReport && tryReportStatus(statusReport); // Don't wait for this to complete.\n\n  return statusReport;\n}\n\nasync function tryReportStatus(statusReport, retryOnAppResume) {\n  const config = await getConfiguration();\n  const previousLabelOrAppVersion = statusReport.previousLabelOrAppVersion;\n  const previousDeploymentKey = statusReport.previousDeploymentKey || config.deploymentKey;\n  try {\n    if (statusReport.appVersion) {\n      log(`Reporting binary update (${statusReport.appVersion})`);\n\n      if (!config.deploymentKey) {\n        throw new Error(\"Deployment key is missed\");\n      }\n\n      const sdk = getPromisifiedSdk(requestFetchAdapter, config);\n      await sdk.reportStatusDeploy(/* deployedPackage */ null, /* status */ null, previousLabelOrAppVersion, previousDeploymentKey);\n    } else {\n      const label = statusReport.package.label;\n      if (statusReport.status === \"DeploymentSucceeded\") {\n        log(`Reporting CodePush update success (${label})`);\n      } else {\n        log(`Reporting CodePush update rollback (${label})`);\n        await NativeCodePush.setLatestRollbackInfo(statusReport.package.packageHash);\n      }\n\n      config.deploymentKey = statusReport.package.deploymentKey;\n      const sdk = getPromisifiedSdk(requestFetchAdapter, config);\n      await sdk.reportStatusDeploy(statusReport.package, statusReport.status, previousLabelOrAppVersion, previousDeploymentKey);\n    }\n\n    NativeCodePush.recordStatusReported(statusReport);\n    retryOnAppResume && retryOnAppResume.remove();\n  } catch (e) {\n    log(`Report status failed: ${JSON.stringify(statusReport)}`);\n    NativeCodePush.saveStatusReportForRetry(statusReport);\n    // Try again when the app resumes\n    if (!retryOnAppResume) {\n      const resumeListener = AppState.addEventListener(\"change\", async (newState) => {\n        if (newState !== \"active\") return;\n        const refreshedStatusReport = await NativeCodePush.getNewStatusReport();\n        if (refreshedStatusReport) {\n          tryReportStatus(refreshedStatusReport, resumeListener);\n        } else {\n          resumeListener && resumeListener.remove();\n        }\n      });\n    }\n  }\n}\n\nasync function shouldUpdateBeIgnored(remotePackage, syncOptions) {\n  let { rollbackRetryOptions } = syncOptions;\n\n  const isFailedPackage = remotePackage && remotePackage.failedInstall;\n  if (!isFailedPackage || !syncOptions.ignoreFailedUpdates) {\n    return false;\n  }\n\n  if (!rollbackRetryOptions) {\n    return true;\n  }\n\n  if (typeof rollbackRetryOptions !== \"object\") {\n    rollbackRetryOptions = CodePush.DEFAULT_ROLLBACK_RETRY_OPTIONS;\n  } else {\n    rollbackRetryOptions = { ...CodePush.DEFAULT_ROLLBACK_RETRY_OPTIONS, ...rollbackRetryOptions };\n  }\n\n  if (!validateRollbackRetryOptions(rollbackRetryOptions)) {\n    return true;\n  }\n\n  const latestRollbackInfo = await NativeCodePush.getLatestRollbackInfo();\n  if (!validateLatestRollbackInfo(latestRollbackInfo, remotePackage.packageHash)) {\n    log(\"The latest rollback info is not valid.\");\n    return true;\n  }\n\n  const { delayInHours, maxRetryAttempts } = rollbackRetryOptions;\n  const hoursSinceLatestRollback = (Date.now() - latestRollbackInfo.time) / (1000 * 60 * 60);\n  if (hoursSinceLatestRollback >= delayInHours && maxRetryAttempts >= latestRollbackInfo.count) {\n    log(\"Previous rollback should be ignored due to rollback retry options.\");\n    return false;\n  }\n\n  return true;\n}\n\nfunction validateLatestRollbackInfo(latestRollbackInfo, packageHash) {\n  return latestRollbackInfo &&\n    latestRollbackInfo.time &&\n    latestRollbackInfo.count &&\n    latestRollbackInfo.packageHash &&\n    latestRollbackInfo.packageHash === packageHash;\n}\n\nfunction validateRollbackRetryOptions(rollbackRetryOptions) {\n  if (typeof rollbackRetryOptions.delayInHours !== \"number\") {\n    log(\"The 'delayInHours' rollback retry parameter must be a number.\");\n    return false;\n  }\n\n  if (typeof rollbackRetryOptions.maxRetryAttempts !== \"number\") {\n    log(\"The 'maxRetryAttempts' rollback retry parameter must be a number.\");\n    return false;\n  }\n\n  if (rollbackRetryOptions.maxRetryAttempts < 1) {\n    log(\"The 'maxRetryAttempts' rollback retry parameter cannot be less then 1.\");\n    return false;\n  }\n\n  return true;\n}\n\nvar testConfig;\n\n// This function is only used for tests. Replaces the default SDK, configuration and native bridge\nfunction setUpTestDependencies(testSdk, providedTestConfig, testNativeBridge) {\n  if (testSdk) module.exports.AcquisitionSdk = testSdk;\n  if (providedTestConfig) testConfig = providedTestConfig;\n  if (testNativeBridge) NativeCodePush = testNativeBridge;\n}\n\nasync function restartApp(onlyIfUpdateIsPending = false) {\n  NativeCodePush.restartApp(onlyIfUpdateIsPending);\n}\n\n// This function allows only one syncInternal operation to proceed at any given time.\n// Parallel calls to sync() while one is ongoing yields CodePush.SyncStatus.SYNC_IN_PROGRESS.\nconst sync = (() => {\n  let syncInProgress = false;\n  const setSyncCompleted = () => { syncInProgress = false; };\n\n  return (options = {}, syncStatusChangeCallback, downloadProgressCallback, handleBinaryVersionMismatchCallback) => {\n    let syncStatusCallbackWithTryCatch, downloadProgressCallbackWithTryCatch;\n    if (typeof syncStatusChangeCallback === \"function\") {\n      syncStatusCallbackWithTryCatch = (...args) => {\n        try {\n          syncStatusChangeCallback(...args);\n        } catch (error) {\n          log(`An error has occurred : ${error.stack}`);\n        }\n      }\n    }\n\n    if (typeof downloadProgressCallback === \"function\") {\n      downloadProgressCallbackWithTryCatch = (...args) => {\n        try {\n          downloadProgressCallback(...args);\n        } catch (error) {\n          log(`An error has occurred: ${error.stack}`);\n        }\n      }\n    }\n\n    if (syncInProgress) {\n      typeof syncStatusCallbackWithTryCatch === \"function\"\n        ? syncStatusCallbackWithTryCatch(CodePush.SyncStatus.SYNC_IN_PROGRESS)\n        : log(\"Sync already in progress.\");\n      return Promise.resolve(CodePush.SyncStatus.SYNC_IN_PROGRESS);\n    }\n\n    syncInProgress = true;\n    const syncPromise = syncInternal(options, syncStatusCallbackWithTryCatch, downloadProgressCallbackWithTryCatch, handleBinaryVersionMismatchCallback);\n    syncPromise\n      .then(setSyncCompleted)\n      .catch(setSyncCompleted);\n\n    return syncPromise;\n  };\n})();\n\n/*\n * The syncInternal method provides a simple, one-line experience for\n * incorporating the check, download and installation of an update.\n *\n * It simply composes the existing API methods together and adds additional\n * support for respecting mandatory updates, ignoring previously failed\n * releases, and displaying a standard confirmation UI to the end-user\n * when an update is available.\n */\nasync function syncInternal(options = {}, syncStatusChangeCallback, downloadProgressCallback, handleBinaryVersionMismatchCallback) {\n  let resolvedInstallMode;\n  const syncOptions = {\n    deploymentKey: null,\n    ignoreFailedUpdates: true,\n    rollbackRetryOptions: null,\n    installMode: CodePush.InstallMode.ON_NEXT_RESTART,\n    mandatoryInstallMode: CodePush.InstallMode.IMMEDIATE,\n    minimumBackgroundDuration: 0,\n    updateDialog: null,\n    ...options\n  };\n\n  syncStatusChangeCallback = typeof syncStatusChangeCallback === \"function\"\n    ? syncStatusChangeCallback\n    : (syncStatus) => {\n        switch(syncStatus) {\n          case CodePush.SyncStatus.CHECKING_FOR_UPDATE:\n            log(\"Checking for update.\");\n            break;\n          case CodePush.SyncStatus.AWAITING_USER_ACTION:\n            log(\"Awaiting user action.\");\n            break;\n          case CodePush.SyncStatus.DOWNLOADING_PACKAGE:\n            log(\"Downloading package.\");\n            break;\n          case CodePush.SyncStatus.INSTALLING_UPDATE:\n            log(\"Installing update.\");\n            break;\n          case CodePush.SyncStatus.UP_TO_DATE:\n            log(\"App is up to date.\");\n            break;\n          case CodePush.SyncStatus.UPDATE_IGNORED:\n            log(\"User cancelled the update.\");\n            break;\n          case CodePush.SyncStatus.UPDATE_INSTALLED:\n            if (resolvedInstallMode == CodePush.InstallMode.ON_NEXT_RESTART) {\n              log(\"Update is installed and will be run on the next app restart.\");\n            } else if (resolvedInstallMode == CodePush.InstallMode.ON_NEXT_RESUME) {\n              if (syncOptions.minimumBackgroundDuration > 0) {\n                log(`Update is installed and will be run after the app has been in the background for at least ${syncOptions.minimumBackgroundDuration} seconds.`);\n              } else {\n                log(\"Update is installed and will be run when the app next resumes.\");\n              }\n            }\n            break;\n          case CodePush.SyncStatus.UNKNOWN_ERROR:\n            log(\"An unknown error occurred.\");\n            break;\n        }\n      };\n\n  try {\n    await CodePush.notifyApplicationReady();\n\n    syncStatusChangeCallback(CodePush.SyncStatus.CHECKING_FOR_UPDATE);\n    const remotePackage = await checkForUpdate(syncOptions.deploymentKey, handleBinaryVersionMismatchCallback);\n\n    const doDownloadAndInstall = async () => {\n      syncStatusChangeCallback(CodePush.SyncStatus.DOWNLOADING_PACKAGE);\n      const localPackage = await remotePackage.download(downloadProgressCallback);\n\n      // Determine the correct install mode based on whether the update is mandatory or not.\n      resolvedInstallMode = localPackage.isMandatory ? syncOptions.mandatoryInstallMode : syncOptions.installMode;\n\n      syncStatusChangeCallback(CodePush.SyncStatus.INSTALLING_UPDATE);\n      await localPackage.install(resolvedInstallMode, syncOptions.minimumBackgroundDuration, () => {\n        syncStatusChangeCallback(CodePush.SyncStatus.UPDATE_INSTALLED);\n      });\n\n      return CodePush.SyncStatus.UPDATE_INSTALLED;\n    };\n\n    const updateShouldBeIgnored = await shouldUpdateBeIgnored(remotePackage, syncOptions);\n\n    if (!remotePackage || updateShouldBeIgnored) {\n      if (updateShouldBeIgnored) {\n          log(\"An update is available, but it is being ignored due to having been previously rolled back.\");\n      }\n\n      const currentPackage = await CodePush.getCurrentPackage();\n      if (currentPackage && currentPackage.isPending) {\n        syncStatusChangeCallback(CodePush.SyncStatus.UPDATE_INSTALLED);\n        return CodePush.SyncStatus.UPDATE_INSTALLED;\n      } else {\n        syncStatusChangeCallback(CodePush.SyncStatus.UP_TO_DATE);\n        return CodePush.SyncStatus.UP_TO_DATE;\n      }\n    } else if (syncOptions.updateDialog) {\n      // updateDialog supports any truthy value (e.g. true, \"goo\", 12),\n      // but we should treat a non-object value as just the default dialog\n      if (typeof syncOptions.updateDialog !== \"object\") {\n        syncOptions.updateDialog = CodePush.DEFAULT_UPDATE_DIALOG;\n      } else {\n        syncOptions.updateDialog = { ...CodePush.DEFAULT_UPDATE_DIALOG, ...syncOptions.updateDialog };\n      }\n\n      return await new Promise((resolve, reject) => {\n        let message = null;\n        let installButtonText = null;\n\n        const dialogButtons = [];\n\n        if (remotePackage.isMandatory) {\n          message = syncOptions.updateDialog.mandatoryUpdateMessage;\n          installButtonText = syncOptions.updateDialog.mandatoryContinueButtonLabel;\n        } else {\n          message = syncOptions.updateDialog.optionalUpdateMessage;\n          installButtonText = syncOptions.updateDialog.optionalInstallButtonLabel;\n          // Since this is an optional update, add a button\n          // to allow the end-user to ignore it\n          dialogButtons.push({\n            text: syncOptions.updateDialog.optionalIgnoreButtonLabel,\n            onPress: () => {\n              syncStatusChangeCallback(CodePush.SyncStatus.UPDATE_IGNORED);\n              resolve(CodePush.SyncStatus.UPDATE_IGNORED);\n            }\n          });\n        }\n        \n        // Since the install button should be placed to the \n        // right of any other button, add it last\n        dialogButtons.push({\n          text: installButtonText,\n          onPress:() => {\n            doDownloadAndInstall()\n              .then(resolve, reject);\n          }\n        })\n\n        // If the update has a description, and the developer\n        // explicitly chose to display it, then set that as the message\n        if (syncOptions.updateDialog.appendReleaseDescription && remotePackage.description) {\n          message += `${syncOptions.updateDialog.descriptionPrefix} ${remotePackage.description}`;\n        }\n\n        syncStatusChangeCallback(CodePush.SyncStatus.AWAITING_USER_ACTION);\n        Alert.alert(syncOptions.updateDialog.title, message, dialogButtons);\n      });\n    } else {\n      return await doDownloadAndInstall();\n    }\n  } catch (error) {\n    syncStatusChangeCallback(CodePush.SyncStatus.UNKNOWN_ERROR);\n    log(error.message);\n    throw error;\n  }\n};\n\nlet CodePush;\n\nfunction codePushify(options = {}) {\n  let React;\n  let ReactNative = require(\"react-native\");\n\n  try { React = require(\"react\"); } catch (e) { }\n  if (!React) {\n    try { React = ReactNative.React; } catch (e) { }\n    if (!React) {\n      throw new Error(\"Unable to find the 'React' module.\");\n    }\n  }\n\n  if (!React.Component) {\n    throw new Error(\n`Unable to find the \"Component\" class, please either:\n1. Upgrade to a newer version of React Native that supports it, or\n2. Call the codePush.sync API in your component instead of using the @codePush decorator`\n    );\n  }\n\n  const decorator = (RootComponent) => {\n    class CodePushComponent extends React.Component {\n      constructor(props) {\n        super(props);\n        this.rootComponentRef = React.createRef();\n      }\n\n      componentDidMount() {\n        if (options.checkFrequency === CodePush.CheckFrequency.MANUAL) {\n          CodePush.notifyAppReady();\n        } else {\n          const rootComponentInstance = this.rootComponentRef.current;\n\n          let syncStatusCallback;\n          if (rootComponentInstance && rootComponentInstance.codePushStatusDidChange) {\n            syncStatusCallback = rootComponentInstance.codePushStatusDidChange.bind(rootComponentInstance);\n          }\n\n          let downloadProgressCallback;\n          if (rootComponentInstance && rootComponentInstance.codePushDownloadDidProgress) {\n            downloadProgressCallback = rootComponentInstance.codePushDownloadDidProgress.bind(rootComponentInstance);\n          }\n\n          let handleBinaryVersionMismatchCallback;\n          if (rootComponentInstance && rootComponentInstance.codePushOnBinaryVersionMismatch) {\n            handleBinaryVersionMismatchCallback = rootComponentInstance.codePushOnBinaryVersionMismatch.bind(rootComponentInstance);\n          }\n\n          CodePush.sync(options, syncStatusCallback, downloadProgressCallback, handleBinaryVersionMismatchCallback);\n\n          if (options.checkFrequency === CodePush.CheckFrequency.ON_APP_RESUME) {\n            ReactNative.AppState.addEventListener(\"change\", (newState) => {\n              if (newState === \"active\") {\n                CodePush.sync(options, syncStatusCallback, downloadProgressCallback);\n              }\n            });\n          }\n        }\n      }\n\n      render() {\n        const props = {...this.props};\n\n        // We can set ref property on class components only (not stateless)\n        // Check it by render method\n        if (RootComponent.prototype && RootComponent.prototype.render) {\n          props.ref = this.rootComponentRef;\n        }\n\n        return <RootComponent {...props} />\n      }\n    }\n\n    return hoistStatics(CodePushComponent, RootComponent);\n  }\n\n  if (typeof options === \"function\") {\n    // Infer that the root component was directly passed to us.\n    return decorator(options);\n  } else {\n    return decorator;\n  }\n}\n\n// If the \"NativeCodePush\" variable isn't defined, then\n// the app didn't properly install the native module,\n// and therefore, it doesn't make sense initializing\n// the JS interface when it wouldn't work anyways.\nif (NativeCodePush) {\n  CodePush = codePushify;\n  Object.assign(CodePush, {\n    AcquisitionSdk: Sdk,\n    checkForUpdate,\n    getConfiguration,\n    getCurrentPackage,\n    getUpdateMetadata,\n    log,\n    notifyAppReady: notifyApplicationReady,\n    notifyApplicationReady,\n    restartApp,\n    setUpTestDependencies,\n    sync,\n    disallowRestart: NativeCodePush.disallow,\n    allowRestart: NativeCodePush.allow,\n    clearUpdates: NativeCodePush.clearUpdates,\n    InstallMode: {\n      IMMEDIATE: NativeCodePush.codePushInstallModeImmediate, // Restart the app immediately\n      ON_NEXT_RESTART: NativeCodePush.codePushInstallModeOnNextRestart, // Don't artificially restart the app. Allow the update to be \"picked up\" on the next app restart\n      ON_NEXT_RESUME: NativeCodePush.codePushInstallModeOnNextResume, // Restart the app the next time it is resumed from the background\n      ON_NEXT_SUSPEND: NativeCodePush.codePushInstallModeOnNextSuspend // Restart the app _while_ it is in the background,\n      // but only after it has been in the background for \"minimumBackgroundDuration\" seconds (0 by default),\n      // so that user context isn't lost unless the app suspension is long enough to not matter\n    },\n    SyncStatus: {\n      UP_TO_DATE: 0, // The running app is up-to-date\n      UPDATE_INSTALLED: 1, // The app had an optional/mandatory update that was successfully downloaded and is about to be installed.\n      UPDATE_IGNORED: 2, // The app had an optional update and the end-user chose to ignore it\n      UNKNOWN_ERROR: 3,\n      SYNC_IN_PROGRESS: 4, // There is an ongoing \"sync\" operation in progress.\n      CHECKING_FOR_UPDATE: 5,\n      AWAITING_USER_ACTION: 6,\n      DOWNLOADING_PACKAGE: 7,\n      INSTALLING_UPDATE: 8\n    },\n    CheckFrequency: {\n      ON_APP_START: 0,\n      ON_APP_RESUME: 1,\n      MANUAL: 2\n    },\n    UpdateState: {\n      RUNNING: NativeCodePush.codePushUpdateStateRunning,\n      PENDING: NativeCodePush.codePushUpdateStatePending,\n      LATEST: NativeCodePush.codePushUpdateStateLatest\n    },\n    DeploymentStatus: {\n      FAILED: \"DeploymentFailed\",\n      SUCCEEDED: \"DeploymentSucceeded\",\n    },\n    DEFAULT_UPDATE_DIALOG: {\n      appendReleaseDescription: false,\n      descriptionPrefix: \" Description: \",\n      mandatoryContinueButtonLabel: \"Continue\",\n      mandatoryUpdateMessage: \"An update is available that must be installed.\",\n      optionalIgnoreButtonLabel: \"Ignore\",\n      optionalInstallButtonLabel: \"Install\",\n      optionalUpdateMessage: \"An update is available. Would you like to install it?\",\n      title: \"Update available\"\n    },\n    DEFAULT_ROLLBACK_RETRY_OPTIONS: {\n      delayInHours: 24,\n      maxRetryAttempts: 1\n    }\n  });\n} else {\n  log(\"The CodePush module doesn't appear to be properly installed. Please double-check that everything is setup correctly.\");\n}\n\nmodule.exports = CodePush;\n"
  },
  {
    "path": "CodePush.podspec",
    "content": "require 'json'\n\npackage = JSON.parse(File.read(File.join(__dir__, 'package.json')))\n\nPod::Spec.new do |s|\n  s.name           = 'CodePush'\n  s.version        = package['version'].gsub(/v|-beta/, '')\n  s.summary        = package['description']\n  s.author         = package['author']\n  s.license        = package['license']\n  s.homepage       = package['homepage']\n  s.source         = { :git => 'https://github.com/microsoft/react-native-code-push.git', :tag => \"v#{s.version}\"}\n  s.ios.deployment_target = '15.5'\n  s.tvos.deployment_target = '15.5'\n  s.preserve_paths = '*.js'\n  s.library        = 'z'\n  s.source_files = 'ios/CodePush/*.{h,m}'\n  s.public_header_files = ['ios/CodePush/CodePush.h']\n\n  # Note: Even though there are copy/pasted versions of some of these dependencies in the repo, \n  # we explicitly let CocoaPods pull in the versions below so all dependencies are resolved and \n  # linked properly at a parent workspace level.\n  s.dependency 'React-Core'\n  s.dependency 'SSZipArchive', '~> 2.5.5'\n  s.dependency 'JWT', '~> 3.0.0-beta.12'\n  s.dependency 'Base64', '~> 1.1'\nend\n"
  },
  {
    "path": "Examples/CodePushDemoApp/.buckconfig",
    "content": "\n[android]\n  target = Google Inc.:Google APIs:23\n\n[maven_repositories]\n  central = https://repo1.maven.org/maven2\n"
  },
  {
    "path": "Examples/CodePushDemoApp/.editorconfig",
    "content": "# Windows files\n[*.bat]\nend_of_line = crlf\n"
  },
  {
    "path": "Examples/CodePushDemoApp/.eslintrc.js",
    "content": "module.exports = {\n  root: true,\n  extends: '@react-native-community',\n};\n"
  },
  {
    "path": "Examples/CodePushDemoApp/.flowconfig",
    "content": "[ignore]\n; We fork some components by platform\n.*/*[.]android.js\n\n; Ignore \"BUCK\" generated dirs\n<PROJECT_ROOT>/\\.buckd/\n\n; Ignore polyfills\nnode_modules/react-native/Libraries/polyfills/.*\n\n; Flow doesn't support platforms\n.*/Libraries/Utilities/LoadingView.js\n\n[untyped]\n.*/node_modules/@react-native-community/cli/.*/.*\n\n[include]\n\n[libs]\nnode_modules/react-native/interface.js\nnode_modules/react-native/flow/\n\n[options]\nemoji=true\n\nexact_by_default=true\n\nformat.bracket_spacing=false\n\nmodule.file_ext=.js\nmodule.file_ext=.json\nmodule.file_ext=.ios.js\n\nmunge_underscores=true\n\nmodule.name_mapper='^react-native/\\(.*\\)$' -> '<PROJECT_ROOT>/node_modules/react-native/\\1'\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\\)$' -> '<PROJECT_ROOT>/node_modules/react-native/Libraries/Image/RelativeImageStub'\n\nsuppress_type=$FlowIssue\nsuppress_type=$FlowFixMe\nsuppress_type=$FlowFixMeProps\nsuppress_type=$FlowFixMeState\n\n[lints]\nsketchy-null-number=warn\nsketchy-null-mixed=warn\nsketchy-number=warn\nuntyped-type-import=warn\nnonstrict-import=warn\ndeprecated-type=warn\nunsafe-getters-setters=warn\nunnecessary-invariant=warn\nsignature-verification-failure=warn\n\n[strict]\ndeprecated-type\nnonstrict-import\nsketchy-null\nunclear-type\nunsafe-getters-setters\nuntyped-import\nuntyped-type-import\n\n[version]\n^0.158.0\n"
  },
  {
    "path": "Examples/CodePushDemoApp/.gitattributes",
    "content": "# Windows files should use crlf line endings\n# https://help.github.com/articles/dealing-with-line-endings/\n*.bat text eol=crlf\n"
  },
  {
    "path": "Examples/CodePushDemoApp/.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\n\n# Android/IntelliJ\n#\nbuild/\n.idea\n.gradle\nlocal.properties\n*.iml\n*.hprof\n\n# node.js\n#\nnode_modules/\nnpm-debug.log\nyarn-error.log\n\n# BUCK\nbuck-out/\n\\.buckd/\n*.keystore\n!debug.keystore\n\n# fastlane\n#\n# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the\n# screenshots whenever they are needed.\n# For more information about the recommended setup visit:\n# https://docs.fastlane.tools/best-practices/source-control/\n\n*/fastlane/report.xml\n*/fastlane/Preview.html\n*/fastlane/screenshots\n\n# Bundle artifact\n*.jsbundle\n\n# CocoaPods\n/ios/Pods/\n"
  },
  {
    "path": "Examples/CodePushDemoApp/.prettierrc.js",
    "content": "module.exports = {\n  bracketSpacing: false,\n  jsxBracketSameLine: true,\n  singleQuote: true,\n  trailingComma: 'all',\n  arrowParens: 'avoid',\n};\n"
  },
  {
    "path": "Examples/CodePushDemoApp/.watchmanconfig",
    "content": "{}"
  },
  {
    "path": "Examples/CodePushDemoApp/App.js",
    "content": "import React, { Component } from 'react';\nimport {\n  AppRegistry,\n  Dimensions,\n  Image,\n  StyleSheet,\n  Text,\n  TouchableOpacity,\n  View,\n} from 'react-native';\n\nimport CodePush from \"react-native-code-push\";\n\nclass App extends Component<{}> {\n  constructor() {\n    super();\n    this.state = { restartAllowed: true };\n  }\n\n  codePushStatusDidChange(syncStatus) {\n    switch(syncStatus) {\n      case CodePush.SyncStatus.CHECKING_FOR_UPDATE:\n        this.setState({ syncMessage: \"Checking for update.\" });\n        break;\n      case CodePush.SyncStatus.DOWNLOADING_PACKAGE:\n        this.setState({ syncMessage: \"Downloading package.\" });\n        break;\n      case CodePush.SyncStatus.AWAITING_USER_ACTION:\n        this.setState({ syncMessage: \"Awaiting user action.\" });\n        break;\n      case CodePush.SyncStatus.INSTALLING_UPDATE:\n        this.setState({ syncMessage: \"Installing update.\" });\n        break;\n      case CodePush.SyncStatus.UP_TO_DATE:\n        this.setState({ syncMessage: \"App up to date.\", progress: false });\n        break;\n      case CodePush.SyncStatus.UPDATE_IGNORED:\n        this.setState({ syncMessage: \"Update cancelled by user.\", progress: false });\n        break;\n      case CodePush.SyncStatus.UPDATE_INSTALLED:\n        this.setState({ syncMessage: \"Update installed and will be applied on restart.\", progress: false });\n        break;\n      case CodePush.SyncStatus.UNKNOWN_ERROR:\n        this.setState({ syncMessage: \"An unknown error occurred.\", progress: false });\n        break;\n    }\n  }\n\n  codePushDownloadDidProgress(progress) {\n    this.setState({ progress });\n  }\n\n  toggleAllowRestart() {\n    this.state.restartAllowed\n      ? CodePush.disallowRestart()\n      : CodePush.allowRestart();\n\n    this.setState({ restartAllowed: !this.state.restartAllowed });\n  }\n\n  getUpdateMetadata() {\n    CodePush.getUpdateMetadata(CodePush.UpdateState.RUNNING)\n      .then((metadata: LocalPackage) => {\n        this.setState({ syncMessage: metadata ? JSON.stringify(metadata) : \"Running binary version\", progress: false });\n      }, (error: any) => {\n        this.setState({ syncMessage: \"Error: \" + error, progress: false });\n      });\n  }\n\n  /** Update is downloaded silently, and applied on restart (recommended) */\n  sync() {\n    CodePush.sync(\n      {},\n      this.codePushStatusDidChange.bind(this),\n      this.codePushDownloadDidProgress.bind(this)\n    );\n  }\n\n  /** Update pops a confirmation dialog, and then immediately reboots the app */\n  syncImmediate() {\n    CodePush.sync(\n      { installMode: CodePush.InstallMode.IMMEDIATE, updateDialog: true },\n      this.codePushStatusDidChange.bind(this),\n      this.codePushDownloadDidProgress.bind(this)\n    );\n  }\n\n  render() {\n    let progressView;\n\n    if (this.state.progress) {\n      progressView = (\n        <Text style={styles.messages}>{this.state.progress.receivedBytes} of {this.state.progress.totalBytes} bytes received</Text>\n      );\n    }\n\n    return (\n      <View style={styles.container}>\n        <Text style={styles.welcome}>\n          Welcome to CodePush!\n        </Text>\n        <TouchableOpacity onPress={this.sync.bind(this)}>\n          <Text style={styles.syncButton}>Press for background sync</Text>\n        </TouchableOpacity>\n        <TouchableOpacity onPress={this.syncImmediate.bind(this)}>\n          <Text style={styles.syncButton}>Press for dialog-driven sync</Text>\n        </TouchableOpacity>\n        {progressView}\n        <Image style={styles.image} resizeMode={\"contain\"} source={require(\"./images/laptop_phone_howitworks.png\")}/>\n        <TouchableOpacity onPress={this.toggleAllowRestart.bind(this)}>\n          <Text style={styles.restartToggleButton}>Restart { this.state.restartAllowed ? \"allowed\" : \"forbidden\"}</Text>\n        </TouchableOpacity>\n        <TouchableOpacity onPress={this.getUpdateMetadata.bind(this)}>\n          <Text style={styles.syncButton}>Press for Update Metadata</Text>\n        </TouchableOpacity>\n        <Text style={styles.messages}>{this.state.syncMessage || \"\"}</Text>\n      </View>\n    );\n  }\n}\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    alignItems: \"center\",\n    backgroundColor: \"#F5FCFF\",\n    paddingTop: 50\n  },\n  image: {\n    margin: 30,\n    width: Dimensions.get(\"window\").width - 100,\n    height: 365 * (Dimensions.get(\"window\").width - 100) / 651,\n  },\n  messages: {\n    marginTop: 30,\n    textAlign: \"center\",\n  },\n  restartToggleButton: {\n    color: \"blue\",\n    fontSize: 17\n  },\n  syncButton: {\n    color: \"green\",\n    fontSize: 17\n  },\n  welcome: {\n    fontSize: 20,\n    textAlign: \"center\",\n    margin: 20\n  },\n});\n\n/**\n * Configured with a MANUAL check frequency for easy testing. For production apps, it is recommended to configure a\n * different check frequency, such as ON_APP_START, for a 'hands-off' approach where CodePush.sync() does not\n * need to be explicitly called. All options of CodePush.sync() are also available in this decorator.\n */\nlet codePushOptions = { checkFrequency: CodePush.CheckFrequency.MANUAL };\n\nApp = CodePush(codePushOptions)(App);\n\nexport default App;\n"
  },
  {
    "path": "Examples/CodePushDemoApp/__tests__/App-test.js",
    "content": "/**\n * @format\n */\n\nimport 'react-native';\nimport React from 'react';\nimport App from '../App';\n\n// Note: test renderer must be required after react-native.\nimport renderer from 'react-test-renderer';\n\nit('renders correctly', () => {\n  renderer.create(<App />);\n});\n"
  },
  {
    "path": "Examples/CodePushDemoApp/android/app/BUCK",
    "content": "# 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\nload(\":build_defs.bzl\", \"create_aar_targets\", \"create_jar_targets\")\n\nlib_deps = []\n\ncreate_aar_targets(glob([\"libs/*.aar\"]))\n\ncreate_jar_targets(glob([\"libs/*.jar\"]))\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 = \"com.codepushdemoapp\",\n)\n\nandroid_resource(\n    name = \"res\",\n    package = \"com.codepushdemoapp\",\n    res = \"src/main/res\",\n)\n\nandroid_binary(\n    name = \"app\",\n    keystore = \"//android/keystores:debug\",\n    manifest = \"src/main/AndroidManifest.xml\",\n    package_type = \"debug\",\n    deps = [\n        \":app-code\",\n    ],\n)\n"
  },
  {
    "path": "Examples/CodePushDemoApp/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. If none specified and\n *   // \"index.android.js\" exists, it will be used. Otherwise \"index.js\" is\n *   // default. Can be overridden with ENTRY_FILE environment variable.\n *   entryFile: \"index.android.js\",\n *\n *   // https://reactnative.dev/docs/performance#enable-the-ram-format\n *   bundleCommand: \"ram-bundle\",\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 *   // whether to disable dev mode in custom build variants (by default only disabled in release)\n *   // for example: to disable dev mode in the staging build type (if configured)\n *   devDisabledInStaging: true,\n *   // The configuration property can be in the following formats\n *   //         'devDisabledIn${productFlavor}${buildType}'\n *   //         'devDisabledIn${buildType}'\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 *   // override which node gets called and with what additional arguments\n *   nodeExecutableAndArgs: [\"node\"],\n *\n *   // supply additional arguments to the packager\n *   extraPackagerArgs: []\n * ]\n */\n\nproject.ext.react = [\n    enableHermes: false,  // clean and rebuild if changing\n]\n\napply from: \"../../node_modules/react-native/react.gradle\"\napply from: \"../../node_modules/react-native-code-push/android/codepush.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\n/**\n * The preferred build flavor of JavaScriptCore.\n *\n * For example, to use the international variant, you can use:\n * `def jscFlavor = 'org.webkit:android-jsc-intl:+'`\n *\n * The international variant includes ICU i18n library and necessary data\n * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that\n * give correct results when using with locales other than en-US.  Note that\n * this variant is about 6MiB larger per architecture than default.\n */\ndef jscFlavor = 'org.webkit:android-jsc:+'\n\n/**\n * Whether to enable the Hermes VM.\n *\n * This should be set on project.ext.react and mirrored here.  If it is not set\n * on project.ext.react, JavaScript will not be compiled to Hermes Bytecode\n * and the benefits of using Hermes will therefore be sharply reduced.\n */\ndef enableHermes = project.ext.react.get(\"enableHermes\", false);\n\n/**\n * Architectures to build native code for in debug.\n */\ndef nativeArchitectures = project.getProperties().get(\"reactNativeDebugArchitectures\")\n\nandroid {\n    ndkVersion rootProject.ext.ndkVersion\n\n    compileSdkVersion rootProject.ext.compileSdkVersion\n\n    defaultConfig {\n        applicationId \"com.codepushdemoapp\"\n        minSdkVersion rootProject.ext.minSdkVersion\n        targetSdkVersion rootProject.ext.targetSdkVersion\n        versionCode 1\n        versionName \"1.0\"\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\", \"arm64-v8a\", \"x86_64\"\n        }\n    }\n    signingConfigs {\n        debug {\n            storeFile file('debug.keystore')\n            storePassword 'android'\n            keyAlias 'androiddebugkey'\n            keyPassword 'android'\n        }\n    }\n    buildTypes {\n        debug {\n            signingConfig signingConfigs.debug\n            if (nativeArchitectures) {\n                ndk {\n                    abiFilters nativeArchitectures.split(',')\n                }\n            }\n        }\n        release {\n            // Caution! In production, you need to generate your own keystore file.\n            // see https://reactnative.dev/docs/signed-apk-android.\n            signingConfig signingConfigs.debug\n            minifyEnabled enableProguardInReleaseBuilds\n            proguardFiles getDefaultProguardFile(\"proguard-android.txt\"), \"proguard-rules.pro\"\n        }\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            // https://developer.android.com/studio/build/configure-apk-splits.html\n            // Example: versionCode 1 will generate 1001 for armeabi-v7a, 1002 for x86, etc.\n            def versionCodes = [\"armeabi-v7a\": 1, \"x86\": 2, \"arm64-v8a\": 3, \"x86_64\": 4]\n            def abi = output.getFilter(OutputFile.ABI)\n            if (abi != null) {  // null for the universal-debug, universal-release variants\n                output.versionCodeOverride =\n                        defaultConfig.versionCode * 1000 + versionCodes.get(abi)\n            }\n\n        }\n    }\n}\n\ndependencies {\n    implementation fileTree(dir: \"libs\", include: [\"*.jar\"])\n    //noinspection GradleDynamicVersion\n    implementation \"com.facebook.react:react-native:+\"  // From node_modules\n\n    implementation \"androidx.swiperefreshlayout:swiperefreshlayout:1.0.0\"\n\n    debugImplementation(\"com.facebook.flipper:flipper:${FLIPPER_VERSION}\") {\n        exclude group:'com.facebook.fbjni'\n    }\n\n    debugImplementation(\"com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}\") {\n        exclude group:'com.facebook.flipper'\n        exclude group:'com.squareup.okhttp3', module:'okhttp'\n    }\n\n    debugImplementation(\"com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}\") {\n        exclude group:'com.facebook.flipper'\n    }\n\n    if (enableHermes) {\n        def hermesPath = \"../../node_modules/hermes-engine/android/\";\n        debugImplementation files(hermesPath + \"hermes-debug.aar\")\n        releaseImplementation files(hermesPath + \"hermes-release.aar\")\n    } else {\n        implementation jscFlavor\n    }\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.implementation\n    into 'libs'\n}\n\napply from: file(\"../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle\"); applyNativeModulesAppBuildGradle(project)\n"
  },
  {
    "path": "Examples/CodePushDemoApp/android/app/build_defs.bzl",
    "content": "\"\"\"Helper definitions to glob .aar and .jar targets\"\"\"\n\ndef create_aar_targets(aarfiles):\n    for aarfile in aarfiles:\n        name = \"aars__\" + aarfile[aarfile.rindex(\"/\") + 1:aarfile.rindex(\".aar\")]\n        lib_deps.append(\":\" + name)\n        android_prebuilt_aar(\n            name = name,\n            aar = aarfile,\n        )\n\ndef create_jar_targets(jarfiles):\n    for jarfile in jarfiles:\n        name = \"jars__\" + jarfile[jarfile.rindex(\"/\") + 1:jarfile.rindex(\".jar\")]\n        lib_deps.append(\":\" + name)\n        prebuilt_jar(\n            name = name,\n            binary_jar = jarfile,\n        )\n"
  },
  {
    "path": "Examples/CodePushDemoApp/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"
  },
  {
    "path": "Examples/CodePushDemoApp/android/app/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n  package=\"com.codepushdemoapp\">\n\n    <uses-permission android:name=\"android.permission.INTERNET\" />\n\n    <application\n      android:name=\".MainApplication\"\n      android:label=\"@string/app_name\"\n      android:icon=\"@mipmap/ic_launcher\"\n      android:roundIcon=\"@mipmap/ic_launcher_round\"\n      android:allowBackup=\"false\"\n      android:theme=\"@style/AppTheme\">\n      <activity\n        android:name=\".MainActivity\"\n        android:label=\"@string/app_name\"\n        android:configChanges=\"keyboard|keyboardHidden|orientation|screenSize|uiMode\"\n        android:launchMode=\"singleTask\"\n        android:windowSoftInputMode=\"adjustResize\">\n        <intent-filter>\n            <action android:name=\"android.intent.action.MAIN\" />\n            <category android:name=\"android.intent.category.LAUNCHER\" />\n        </intent-filter>\n      </activity>\n    </application>\n</manifest>\n"
  },
  {
    "path": "Examples/CodePushDemoApp/android/app/src/main/java/com/codepushdemoapp/MainActivity.java",
    "content": "package com.codepushdemoapp;\n\nimport com.facebook.react.ReactActivity;\n\npublic class MainActivity extends ReactActivity {\n\n  /**\n   * Returns the name of the main component registered from JavaScript. This is used to schedule\n   * rendering of the component.\n   */\n  @Override\n  protected String getMainComponentName() {\n    return \"CodePushDemoApp\";\n  }\n}\n"
  },
  {
    "path": "Examples/CodePushDemoApp/android/app/src/main/java/com/codepushdemoapp/MainApplication.java",
    "content": "package com.codepushdemoapp;\n\nimport android.app.Application;\nimport com.microsoft.codepush.react.CodePush;\nimport android.content.Context;\nimport com.facebook.react.PackageList;\nimport com.facebook.react.ReactApplication;\nimport com.facebook.react.ReactInstanceManager;\nimport com.facebook.react.ReactNativeHost;\nimport com.facebook.react.ReactPackage;\nimport com.facebook.soloader.SoLoader;\nimport java.lang.reflect.InvocationTargetException;\nimport java.util.List;\n\npublic class MainApplication extends Application implements ReactApplication {\n\n  private final ReactNativeHost mReactNativeHost =\n      new ReactNativeHost(this) {\n    @Override\n    protected String getJSBundleFile(){\n        return CodePush.getJSBundleFile();\n    }\n    \n        @Override\n        public boolean getUseDeveloperSupport() {\n          return BuildConfig.DEBUG;\n        }\n\n        @Override\n        protected List<ReactPackage> getPackages() {\n          @SuppressWarnings(\"UnnecessaryLocalVariable\")\n          List<ReactPackage> packages = new PackageList(this).getPackages();\n          // Packages that cannot be autolinked yet can be added manually here, for example:\n          // packages.add(new MyReactNativePackage());\n          return packages;\n        }\n\n        @Override\n        protected String getJSMainModuleName() {\n          return \"index\";\n        }\n      };\n\n  @Override\n  public ReactNativeHost getReactNativeHost() {\n    return mReactNativeHost;\n  }\n\n  @Override\n  public void onCreate() {\n    super.onCreate();\n    SoLoader.init(this, /* native exopackage */ false);\n    initializeFlipper(this, getReactNativeHost().getReactInstanceManager());\n  }\n\n  /**\n   * Loads Flipper in React Native templates. Call this in the onCreate method with something like\n   * initializeFlipper(this, getReactNativeHost().getReactInstanceManager());\n   *\n   * @param context\n   * @param reactInstanceManager\n   */\n  private static void initializeFlipper(\n      Context context, ReactInstanceManager reactInstanceManager) {\n    if (BuildConfig.DEBUG) {\n      try {\n        /*\n         We use reflection here to pick up the class that initializes Flipper,\n        since Flipper library is not available in release mode\n        */\n        Class<?> aClass = Class.forName(\"com.codepushdemoapp.ReactNativeFlipper\");\n        aClass\n            .getMethod(\"initializeFlipper\", Context.class, ReactInstanceManager.class)\n            .invoke(null, context, reactInstanceManager);\n      } catch (ClassNotFoundException e) {\n        e.printStackTrace();\n      } catch (NoSuchMethodException e) {\n        e.printStackTrace();\n      } catch (IllegalAccessException e) {\n        e.printStackTrace();\n      } catch (InvocationTargetException e) {\n        e.printStackTrace();\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "Examples/CodePushDemoApp/android/app/src/main/res/values/strings.xml",
    "content": "<resources>\n\t<string moduleConfig=\"true\" name=\"CodePushDeploymentKey\">deployment-key-here</string>\n    <string name=\"app_name\">CodePushDemoApp</string>\n</resources>\n"
  },
  {
    "path": "Examples/CodePushDemoApp/android/app/src/main/res/values/styles.xml",
    "content": "<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.DayNight.NoActionBar\">\n        <!-- Customize your theme here. -->\n    </style>\n\n</resources>\n"
  },
  {
    "path": "Examples/CodePushDemoApp/android/build.gradle",
    "content": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n    ext {\n        buildToolsVersion = \"30.0.2\"\n        minSdkVersion = 21\n        compileSdkVersion = 30\n        targetSdkVersion = 30\n        ndkVersion = \"21.4.7075529\"\n    }\n    repositories {\n        google()\n        mavenCentral()\n    }\n    dependencies {\n        classpath(\"com.android.tools.build:gradle:4.2.2\")\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        mavenCentral()\n        mavenLocal()\n        maven {\n            // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm\n            url(\"$rootDir/../node_modules/react-native/android\")\n        }\n        maven {\n            // Android JSC is installed from npm\n            url(\"$rootDir/../node_modules/jsc-android/dist\")\n        }\n\n        google()\n        maven { url 'https://www.jitpack.io' }\n    }\n}\n"
  },
  {
    "path": "Examples/CodePushDemoApp/android/gradle/wrapper/gradle-wrapper.properties",
    "content": "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-6.9-all.zip\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\n"
  },
  {
    "path": "Examples/CodePushDemoApp/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\n# AndroidX package structure to make it clearer which packages are bundled with the\n# Android operating system, and which are packaged with your app's APK\n# https://developer.android.com/topic/libraries/support-library/androidx-rn\nandroid.useAndroidX=true\n# Automatically convert third-party libraries to use AndroidX\nandroid.enableJetifier=true\n\n# Version of flipper SDK to use with React Native\nFLIPPER_VERSION=0.99.0\n"
  },
  {
    "path": "Examples/CodePushDemoApp/android/gradlew",
    "content": "#!/usr/bin/env sh\n\n#\n# Copyright 2015 the original author or authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\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='\"-Xmx64m\" \"-Xms64m\"'\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\nnonstop=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\n  NONSTOP* )\n    nonstop=true\n    ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\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\" -a \"$nonstop\" = \"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 or MSYS, switch paths to Windows format before running java\nif [ \"$cygwin\" = \"true\" -o \"$msys\" = \"true\" ] ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=`expr $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# Escape application args\nsave () {\n    for i do printf %s\\\\n \"$i\" | sed \"s/'/'\\\\\\\\''/g;1s/^/'/;\\$s/\\$/' \\\\\\\\/\" ; done\n    echo \" \"\n}\nAPP_ARGS=`save \"$@\"`\n\n# Collect all arguments for the java command, following the shell quoting and substitution rules\neval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS \"\\\"-Dorg.gradle.appname=$APP_BASE_NAME\\\"\" -classpath \"\\\"$CLASSPATH\\\"\" org.gradle.wrapper.GradleWrapperMain \"$APP_ARGS\"\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "Examples/CodePushDemoApp/android/gradlew.bat",
    "content": "@rem\r\n@rem Copyright 2015 the original author or authors.\r\n@rem\r\n@rem Licensed under the Apache License, Version 2.0 (the \"License\");\r\n@rem you may not use this file except in compliance with the License.\r\n@rem You may obtain a copy of the License at\r\n@rem\r\n@rem      https://www.apache.org/licenses/LICENSE-2.0\r\n@rem\r\n@rem Unless required by applicable law or agreed to in writing, software\r\n@rem distributed under the License is distributed on an \"AS IS\" BASIS,\r\n@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n@rem See the License for the specific language governing permissions and\r\n@rem limitations under the License.\r\n@rem\r\n\r\n@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\nset DIRNAME=%~dp0\r\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\r\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\r\n\r\n@rem Resolve any \".\" and \"..\" in APP_HOME to make it shorter.\r\nfor %%i in (\"%APP_HOME%\") do set APP_HOME=%%~fi\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=\"-Xmx64m\" \"-Xms64m\"\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 execute\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 execute\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:execute\r\n@rem Setup the command line\r\n\r\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\r\n\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 %*\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": "Examples/CodePushDemoApp/android/settings.gradle",
    "content": "rootProject.name = 'CodePushDemoApp'\napply from: file(\"../node_modules/@react-native-community/cli-platform-android/native_modules.gradle\"); applyNativeModulesSettingsGradle(settings)\ninclude ':app', ':react-native-code-push'\nproject(':react-native-code-push').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-code-push/android/app')\n"
  },
  {
    "path": "Examples/CodePushDemoApp/app.json",
    "content": "{\n  \"name\": \"CodePushDemoApp\",\n  \"displayName\": \"CodePushDemoApp\"\n}"
  },
  {
    "path": "Examples/CodePushDemoApp/babel.config.js",
    "content": "module.exports = {\n  presets: ['module:metro-react-native-babel-preset'],\n};\n"
  },
  {
    "path": "Examples/CodePushDemoApp/index.js",
    "content": "import { AppRegistry } from 'react-native';\nimport App from './App';\n\nAppRegistry.registerComponent('CodePushDemoApp', () => App);\n"
  },
  {
    "path": "Examples/CodePushDemoApp/ios/CodePushDemoApp/AppDelegate.h",
    "content": "#import <React/RCTBridgeDelegate.h>\n#import <UIKit/UIKit.h>\n\n@interface AppDelegate : UIResponder <UIApplicationDelegate, RCTBridgeDelegate>\n\n@property (nonatomic, strong) UIWindow *window;\n\n@end\n"
  },
  {
    "path": "Examples/CodePushDemoApp/ios/CodePushDemoApp/AppDelegate.m",
    "content": "#import \"AppDelegate.h\"\n#import <CodePush/CodePush.h>\n\n#import <React/RCTBridge.h>\n#import <React/RCTBundleURLProvider.h>\n#import <React/RCTRootView.h>\n\n#ifdef FB_SONARKIT_ENABLED\n#import <FlipperKit/FlipperClient.h>\n#import <FlipperKitLayoutPlugin/FlipperKitLayoutPlugin.h>\n#import <FlipperKitUserDefaultsPlugin/FKUserDefaultsPlugin.h>\n#import <FlipperKitNetworkPlugin/FlipperKitNetworkPlugin.h>\n#import <SKIOSNetworkPlugin/SKIOSNetworkAdapter.h>\n#import <FlipperKitReactPlugin/FlipperKitReactPlugin.h>\n\nstatic void InitializeFlipper(UIApplication *application) {\n  FlipperClient *client = [FlipperClient sharedClient];\n  SKDescriptorMapper *layoutDescriptorMapper = [[SKDescriptorMapper alloc] initWithDefaults];\n  [client addPlugin:[[FlipperKitLayoutPlugin alloc] initWithRootNode:application withDescriptorMapper:layoutDescriptorMapper]];\n  [client addPlugin:[[FKUserDefaultsPlugin alloc] initWithSuiteName:nil]];\n  [client addPlugin:[FlipperKitReactPlugin new]];\n  [client addPlugin:[[FlipperKitNetworkPlugin alloc] initWithNetworkAdapter:[SKIOSNetworkAdapter new]]];\n  [client start];\n}\n#endif\n\n@implementation AppDelegate\n\n- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions\n{\n#ifdef FB_SONARKIT_ENABLED\n  InitializeFlipper(application);\n#endif\n\n  RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];\n  RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge\n                                                   moduleName:@\"CodePushDemoApp\"\n                                            initialProperties:nil];\n\n  if (@available(iOS 13.0, *)) {\n      rootView.backgroundColor = [UIColor systemBackgroundColor];\n  } else {\n      rootView.backgroundColor = [UIColor whiteColor];\n  }\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- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge\n{\n#if DEBUG\n  return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@\"index\" fallbackResource:nil];\n#else\n  return [CodePush bundleURL];\n#endif\n}\n\n@end\n"
  },
  {
    "path": "Examples/CodePushDemoApp/ios/CodePushDemoApp/Images.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Examples/CodePushDemoApp/ios/CodePushDemoApp/Images.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}\n"
  },
  {
    "path": "Examples/CodePushDemoApp/ios/CodePushDemoApp/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>CFBundleDisplayName</key>\n\t<string>CodePushDemoApp</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>NSAppTransportSecurity</key>\n\t<dict>\n\t\t<key>NSExceptionDomains</key>\n\t\t<dict>\n\t\t\t<key>localhost</key>\n\t\t\t<dict>\n\t\t\t\t<key>NSExceptionAllowsInsecureHTTPLoads</key>\n\t\t\t\t<true/>\n\t\t\t</dict>\n\t\t</dict>\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\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n\t<key>UIViewControllerBasedStatusBarAppearance</key>\n\t<false/>\n\t<key>CodePushDeploymentKey</key>\n\t<string>deployment-key-here</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Examples/CodePushDemoApp/ios/CodePushDemoApp/LaunchScreen.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"15702\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" useTraitCollections=\"YES\" useSafeAreas=\"YES\" colorMatched=\"YES\" initialViewController=\"01J-lp-oVM\">\n    <device id=\"retina4_7\" orientation=\"portrait\" appearance=\"light\"/>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"15704\"/>\n        <capability name=\"Safe area layout guides\" minToolsVersion=\"9.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"EHf-IW-A2E\">\n            <objects>\n                <viewController id=\"01J-lp-oVM\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"Ze5-6b-2t3\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <label opaque=\"NO\" clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"CodePushDemoApp\" textAlignment=\"center\" lineBreakMode=\"middleTruncation\" baselineAdjustment=\"alignBaselines\" minimumFontSize=\"18\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"GJd-Yh-RWb\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"202\" width=\"375\" height=\"43\"/>\n                                <fontDescription key=\"fontDescription\" type=\"boldSystem\" pointSize=\"36\"/>\n                                <nil key=\"highlightedColor\"/>\n                            </label>\n                            <label opaque=\"NO\" clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Powered by React Native\" textAlignment=\"center\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" minimumFontSize=\"9\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"MN2-I3-ftu\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"626\" width=\"375\" height=\"21\"/>\n                                <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                                <nil key=\"highlightedColor\"/>\n                            </label>\n                        </subviews>\n                        <color key=\"backgroundColor\" systemColor=\"systemBackgroundColor\" cocoaTouchSystemColor=\"whiteColor\"/>\n                        <constraints>\n                            <constraint firstItem=\"Bcu-3y-fUS\" firstAttribute=\"bottom\" secondItem=\"MN2-I3-ftu\" secondAttribute=\"bottom\" constant=\"20\" id=\"OZV-Vh-mqD\"/>\n                            <constraint firstItem=\"Bcu-3y-fUS\" firstAttribute=\"centerX\" secondItem=\"GJd-Yh-RWb\" secondAttribute=\"centerX\" id=\"Q3B-4B-g5h\"/>\n                            <constraint firstItem=\"MN2-I3-ftu\" firstAttribute=\"centerX\" secondItem=\"Bcu-3y-fUS\" secondAttribute=\"centerX\" id=\"akx-eg-2ui\"/>\n                            <constraint firstItem=\"MN2-I3-ftu\" firstAttribute=\"leading\" secondItem=\"Bcu-3y-fUS\" secondAttribute=\"leading\" id=\"i1E-0Y-4RG\"/>\n                            <constraint firstItem=\"GJd-Yh-RWb\" firstAttribute=\"centerY\" secondItem=\"Ze5-6b-2t3\" secondAttribute=\"bottom\" multiplier=\"1/3\" constant=\"1\" id=\"moa-c2-u7t\"/>\n                            <constraint firstItem=\"GJd-Yh-RWb\" firstAttribute=\"leading\" secondItem=\"Bcu-3y-fUS\" secondAttribute=\"leading\" symbolic=\"YES\" id=\"x7j-FC-K8j\"/>\n                        </constraints>\n                        <viewLayoutGuide key=\"safeArea\" id=\"Bcu-3y-fUS\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"iYj-Kq-Ea1\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"52.173913043478265\" y=\"375\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "Examples/CodePushDemoApp/ios/CodePushDemoApp/main.m",
    "content": "#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": "Examples/CodePushDemoApp/ios/CodePushDemoApp.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 54;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t00E356F31AD99517003FC87E /* CodePushDemoAppTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* CodePushDemoAppTests.m */; };\n\t\t13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; };\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\t7209CF15AFD1B1A1154ADDC3 /* libPods-CodePushDemoApp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F822409B61CE9E11C825CB2E /* libPods-CodePushDemoApp.a */; };\n\t\t81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; };\n\t\t873543544E84903AB9AC764D /* libPods-CodePushDemoApp-CodePushDemoAppTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0684492BF481E6EAA4A6624A /* libPods-CodePushDemoApp-CodePushDemoAppTests.a */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXContainerItemProxy section */\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 = CodePushDemoApp;\n\t\t};\n/* End PBXContainerItemProxy section */\n\n/* Begin PBXFileReference section */\n\t\t00E356EE1AD99517003FC87E /* CodePushDemoAppTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CodePushDemoAppTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t00E356F21AD99517003FC87E /* CodePushDemoAppTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CodePushDemoAppTests.m; sourceTree = \"<group>\"; };\n\t\t0684492BF481E6EAA4A6624A /* libPods-CodePushDemoApp-CodePushDemoAppTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = \"libPods-CodePushDemoApp-CodePushDemoAppTests.a\"; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t13B07F961A680F5B00A75B9A /* CodePushDemoApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CodePushDemoApp.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = CodePushDemoApp/AppDelegate.h; sourceTree = \"<group>\"; };\n\t\t13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = CodePushDemoApp/AppDelegate.m; sourceTree = \"<group>\"; };\n\t\t13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = CodePushDemoApp/Images.xcassets; sourceTree = \"<group>\"; };\n\t\t13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = CodePushDemoApp/Info.plist; sourceTree = \"<group>\"; };\n\t\t13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = CodePushDemoApp/main.m; sourceTree = \"<group>\"; };\n\t\t3A1AC7C53CE0CC5BA2B85E4E /* Pods-CodePushDemoApp.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-CodePushDemoApp.debug.xcconfig\"; path = \"Target Support Files/Pods-CodePushDemoApp/Pods-CodePushDemoApp.debug.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t3FF5216EA67271BFA35BE5DD /* Pods-CodePushDemoApp-CodePushDemoAppTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-CodePushDemoApp-CodePushDemoAppTests.debug.xcconfig\"; path = \"Target Support Files/Pods-CodePushDemoApp-CodePushDemoAppTests/Pods-CodePushDemoApp-CodePushDemoAppTests.debug.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4B6E53AD2EAAA824D962A672 /* Pods-CodePushDemoApp.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-CodePushDemoApp.release.xcconfig\"; path = \"Target Support Files/Pods-CodePushDemoApp/Pods-CodePushDemoApp.release.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = CodePushDemoApp/LaunchScreen.storyboard; sourceTree = \"<group>\"; };\n\t\t9E42C477F1442EBF73599739 /* Pods-CodePushDemoApp-CodePushDemoAppTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-CodePushDemoApp-CodePushDemoAppTests.release.xcconfig\"; path = \"Target Support Files/Pods-CodePushDemoApp-CodePushDemoAppTests/Pods-CodePushDemoApp-CodePushDemoAppTests.release.xcconfig\"; sourceTree = \"<group>\"; };\n\t\tED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };\n\t\tF822409B61CE9E11C825CB2E /* libPods-CodePushDemoApp.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = \"libPods-CodePushDemoApp.a\"; sourceTree = BUILT_PRODUCTS_DIR; };\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\t873543544E84903AB9AC764D /* libPods-CodePushDemoApp-CodePushDemoAppTests.a in Frameworks */,\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\t7209CF15AFD1B1A1154ADDC3 /* libPods-CodePushDemoApp.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\t00E356EF1AD99517003FC87E /* CodePushDemoAppTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t00E356F21AD99517003FC87E /* CodePushDemoAppTests.m */,\n\t\t\t\t00E356F01AD99517003FC87E /* Supporting Files */,\n\t\t\t);\n\t\t\tpath = CodePushDemoAppTests;\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\t13B07FAE1A68108700A75B9A /* CodePushDemoApp */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\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\t81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */,\n\t\t\t\t13B07FB71A68108700A75B9A /* main.m */,\n\t\t\t);\n\t\t\tname = CodePushDemoApp;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t2D16E6871FA4F8E400B85C8A /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tED297162215061F000B7C4FE /* JavaScriptCore.framework */,\n\t\t\t\tF822409B61CE9E11C825CB2E /* libPods-CodePushDemoApp.a */,\n\t\t\t\t0684492BF481E6EAA4A6624A /* libPods-CodePushDemoApp-CodePushDemoAppTests.a */,\n\t\t\t);\n\t\t\tname = Frameworks;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t69F6BBD5C7690E30A982EAEE /* Pods */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t3A1AC7C53CE0CC5BA2B85E4E /* Pods-CodePushDemoApp.debug.xcconfig */,\n\t\t\t\t4B6E53AD2EAAA824D962A672 /* Pods-CodePushDemoApp.release.xcconfig */,\n\t\t\t\t3FF5216EA67271BFA35BE5DD /* Pods-CodePushDemoApp-CodePushDemoAppTests.debug.xcconfig */,\n\t\t\t\t9E42C477F1442EBF73599739 /* Pods-CodePushDemoApp-CodePushDemoAppTests.release.xcconfig */,\n\t\t\t);\n\t\t\tname = Pods;\n\t\t\tpath = Pods;\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);\n\t\t\tname = Libraries;\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 /* CodePushDemoApp */,\n\t\t\t\t832341AE1AAA6A7D00B99B32 /* Libraries */,\n\t\t\t\t00E356EF1AD99517003FC87E /* CodePushDemoAppTests */,\n\t\t\t\t83CBBA001A601CBA00E9B192 /* Products */,\n\t\t\t\t2D16E6871FA4F8E400B85C8A /* Frameworks */,\n\t\t\t\t69F6BBD5C7690E30A982EAEE /* Pods */,\n\t\t\t);\n\t\t\tindentWidth = 2;\n\t\t\tsourceTree = \"<group>\";\n\t\t\ttabWidth = 2;\n\t\t\tusesTabs = 0;\n\t\t};\n\t\t83CBBA001A601CBA00E9B192 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t13B07F961A680F5B00A75B9A /* CodePushDemoApp.app */,\n\t\t\t\t00E356EE1AD99517003FC87E /* CodePushDemoAppTests.xctest */,\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 /* CodePushDemoAppTests */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget \"CodePushDemoAppTests\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tE0C08DC1172810CC2B651913 /* [CP] Check Pods Manifest.lock */,\n\t\t\t\t00E356EA1AD99517003FC87E /* Sources */,\n\t\t\t\t00E356EB1AD99517003FC87E /* Frameworks */,\n\t\t\t\t00E356EC1AD99517003FC87E /* Resources */,\n\t\t\t\t96DA1F0133CE6AECB818D1F3 /* [CP] Embed Pods Frameworks */,\n\t\t\t\t8FCA0FCABC69767E741BB8F2 /* [CP] Copy Pods 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 = CodePushDemoAppTests;\n\t\t\tproductName = CodePushDemoAppTests;\n\t\t\tproductReference = 00E356EE1AD99517003FC87E /* CodePushDemoAppTests.xctest */;\n\t\t\tproductType = \"com.apple.product-type.bundle.unit-test\";\n\t\t};\n\t\t13B07F861A680F5B00A75B9A /* CodePushDemoApp */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget \"CodePushDemoApp\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tFAE53E3C42A14CE48C4E62D3 /* [CP] Check Pods Manifest.lock */,\n\t\t\t\tFD10A7F022414F080027D42C /* Start Packager */,\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\t3FB4CE61D43BB948153CCAD2 /* [CP] Embed Pods Frameworks */,\n\t\t\t\tE64717738EB438ACC77F81BB /* [CP] Copy Pods Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = CodePushDemoApp;\n\t\t\tproductName = CodePushDemoApp;\n\t\t\tproductReference = 13B07F961A680F5B00A75B9A /* CodePushDemoApp.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 = 1210;\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\tLastSwiftMigration = 1120;\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 \"CodePushDemoApp\" */;\n\t\t\tcompatibilityVersion = \"Xcode 12.0\";\n\t\t\tdevelopmentRegion = en;\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\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t13B07F861A680F5B00A75B9A /* CodePushDemoApp */,\n\t\t\t\t00E356ED1AD99517003FC87E /* CodePushDemoAppTests */,\n\t\t\t);\n\t\t};\n/* End PBXProject 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\t81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */,\n\t\t\t\t13B07FBF1A68108700A75B9A /* Images.xcassets 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 = \"set -e\\n\\nexport NODE_BINARY=node\\n../node_modules/react-native/scripts/react-native-xcode.sh\\n\";\n\t\t};\n\t\t3FB4CE61D43BB948153CCAD2 /* [CP] Embed Pods Frameworks */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t\t\"${PODS_ROOT}/Target Support Files/Pods-CodePushDemoApp/Pods-CodePushDemoApp-frameworks-${CONFIGURATION}-input-files.xcfilelist\",\n\t\t\t);\n\t\t\tname = \"[CP] Embed Pods Frameworks\";\n\t\t\toutputFileListPaths = (\n\t\t\t\t\"${PODS_ROOT}/Target Support Files/Pods-CodePushDemoApp/Pods-CodePushDemoApp-frameworks-${CONFIGURATION}-output-files.xcfilelist\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"\\\"${PODS_ROOT}/Target Support Files/Pods-CodePushDemoApp/Pods-CodePushDemoApp-frameworks.sh\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\t8FCA0FCABC69767E741BB8F2 /* [CP] Copy Pods Resources */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t\t\"${PODS_ROOT}/Target Support Files/Pods-CodePushDemoApp-CodePushDemoAppTests/Pods-CodePushDemoApp-CodePushDemoAppTests-resources-${CONFIGURATION}-input-files.xcfilelist\",\n\t\t\t);\n\t\t\tname = \"[CP] Copy Pods Resources\";\n\t\t\toutputFileListPaths = (\n\t\t\t\t\"${PODS_ROOT}/Target Support Files/Pods-CodePushDemoApp-CodePushDemoAppTests/Pods-CodePushDemoApp-CodePushDemoAppTests-resources-${CONFIGURATION}-output-files.xcfilelist\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"\\\"${PODS_ROOT}/Target Support Files/Pods-CodePushDemoApp-CodePushDemoAppTests/Pods-CodePushDemoApp-CodePushDemoAppTests-resources.sh\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\t96DA1F0133CE6AECB818D1F3 /* [CP] Embed Pods Frameworks */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t\t\"${PODS_ROOT}/Target Support Files/Pods-CodePushDemoApp-CodePushDemoAppTests/Pods-CodePushDemoApp-CodePushDemoAppTests-frameworks-${CONFIGURATION}-input-files.xcfilelist\",\n\t\t\t);\n\t\t\tname = \"[CP] Embed Pods Frameworks\";\n\t\t\toutputFileListPaths = (\n\t\t\t\t\"${PODS_ROOT}/Target Support Files/Pods-CodePushDemoApp-CodePushDemoAppTests/Pods-CodePushDemoApp-CodePushDemoAppTests-frameworks-${CONFIGURATION}-output-files.xcfilelist\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"\\\"${PODS_ROOT}/Target Support Files/Pods-CodePushDemoApp-CodePushDemoAppTests/Pods-CodePushDemoApp-CodePushDemoAppTests-frameworks.sh\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\tE0C08DC1172810CC2B651913 /* [CP] Check Pods Manifest.lock */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t\t\"${PODS_PODFILE_DIR_PATH}/Podfile.lock\",\n\t\t\t\t\"${PODS_ROOT}/Manifest.lock\",\n\t\t\t);\n\t\t\tname = \"[CP] Check Pods Manifest.lock\";\n\t\t\toutputFileListPaths = (\n\t\t\t);\n\t\t\toutputPaths = (\n\t\t\t\t\"$(DERIVED_FILE_DIR)/Pods-CodePushDemoApp-CodePushDemoAppTests-checkManifestLockResult.txt\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"diff \\\"${PODS_PODFILE_DIR_PATH}/Podfile.lock\\\" \\\"${PODS_ROOT}/Manifest.lock\\\" > /dev/null\\nif [ $? != 0 ] ; then\\n    # print error to STDERR\\n    echo \\\"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\\\" >&2\\n    exit 1\\nfi\\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\\necho \\\"SUCCESS\\\" > \\\"${SCRIPT_OUTPUT_FILE_0}\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\tE64717738EB438ACC77F81BB /* [CP] Copy Pods Resources */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t\t\"${PODS_ROOT}/Target Support Files/Pods-CodePushDemoApp/Pods-CodePushDemoApp-resources-${CONFIGURATION}-input-files.xcfilelist\",\n\t\t\t);\n\t\t\tname = \"[CP] Copy Pods Resources\";\n\t\t\toutputFileListPaths = (\n\t\t\t\t\"${PODS_ROOT}/Target Support Files/Pods-CodePushDemoApp/Pods-CodePushDemoApp-resources-${CONFIGURATION}-output-files.xcfilelist\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"\\\"${PODS_ROOT}/Target Support Files/Pods-CodePushDemoApp/Pods-CodePushDemoApp-resources.sh\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\tFAE53E3C42A14CE48C4E62D3 /* [CP] Check Pods Manifest.lock */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t\t\"${PODS_PODFILE_DIR_PATH}/Podfile.lock\",\n\t\t\t\t\"${PODS_ROOT}/Manifest.lock\",\n\t\t\t);\n\t\t\tname = \"[CP] Check Pods Manifest.lock\";\n\t\t\toutputFileListPaths = (\n\t\t\t);\n\t\t\toutputPaths = (\n\t\t\t\t\"$(DERIVED_FILE_DIR)/Pods-CodePushDemoApp-checkManifestLockResult.txt\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"diff \\\"${PODS_PODFILE_DIR_PATH}/Podfile.lock\\\" \\\"${PODS_ROOT}/Manifest.lock\\\" > /dev/null\\nif [ $? != 0 ] ; then\\n    # print error to STDERR\\n    echo \\\"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\\\" >&2\\n    exit 1\\nfi\\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\\necho \\\"SUCCESS\\\" > \\\"${SCRIPT_OUTPUT_FILE_0}\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\tFD10A7F022414F080027D42C /* Start Packager */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t);\n\t\t\tname = \"Start Packager\";\n\t\t\toutputFileListPaths = (\n\t\t\t);\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"export RCT_METRO_PORT=\\\"${RCT_METRO_PORT:=8081}\\\"\\necho \\\"export RCT_METRO_PORT=${RCT_METRO_PORT}\\\" > \\\"${SRCROOT}/../node_modules/react-native/scripts/.packager.env\\\"\\nif [ -z \\\"${RCT_NO_LAUNCH_PACKAGER+xxx}\\\" ] ; then\\n  if nc -w 5 -z localhost ${RCT_METRO_PORT} ; then\\n    if ! curl -s \\\"http://localhost:${RCT_METRO_PORT}/status\\\" | grep -q \\\"packager-status:running\\\" ; then\\n      echo \\\"Port ${RCT_METRO_PORT} already in use, packager is either not running or not running correctly\\\"\\n      exit 2\\n    fi\\n  else\\n    open \\\"$SRCROOT/../node_modules/react-native/scripts/launchPackager.command\\\" || echo \\\"Can't start packager automatically\\\"\\n  fi\\nfi\\n\";\n\t\t\tshowEnvVarsInLog = 0;\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 /* CodePushDemoAppTests.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 /* CodePushDemoApp */;\n\t\t\ttargetProxy = 00E356F41AD99517003FC87E /* PBXContainerItemProxy */;\n\t\t};\n/* End PBXTargetDependency section */\n\n/* Begin XCBuildConfiguration section */\n\t\t00E356F61AD99517003FC87E /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 3FF5216EA67271BFA35BE5DD /* Pods-CodePushDemoApp-CodePushDemoAppTests.debug.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tBUNDLE_LOADER = \"$(TEST_HOST)\";\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 = CodePushDemoAppTests/Info.plist;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 11.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t\t\"@loader_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tOTHER_LDFLAGS = (\n\t\t\t\t\t\"-ObjC\",\n\t\t\t\t\t\"-lc++\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tTEST_HOST = \"$(BUILT_PRODUCTS_DIR)/CodePushDemoApp.app/CodePushDemoApp\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t00E356F71AD99517003FC87E /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 9E42C477F1442EBF73599739 /* Pods-CodePushDemoApp-CodePushDemoAppTests.release.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tBUNDLE_LOADER = \"$(TEST_HOST)\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tINFOPLIST_FILE = CodePushDemoAppTests/Info.plist;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 11.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t\t\"@loader_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tOTHER_LDFLAGS = (\n\t\t\t\t\t\"-ObjC\",\n\t\t\t\t\t\"-lc++\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tTEST_HOST = \"$(BUILT_PRODUCTS_DIR)/CodePushDemoApp.app/CodePushDemoApp\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t13B07F941A680F5B00A75B9A /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 3A1AC7C53CE0CC5BA2B85E4E /* Pods-CodePushDemoApp.debug.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tENABLE_BITCODE = NO;\n\t\t\t\tINFOPLIST_FILE = CodePushDemoApp/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tOTHER_LDFLAGS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"-ObjC\",\n\t\t\t\t\t\"-lc++\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)\";\n\t\t\t\tPRODUCT_NAME = CodePushDemoApp;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tVERSIONING_SYSTEM = \"apple-generic\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t13B07F951A680F5B00A75B9A /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 4B6E53AD2EAAA824D962A672 /* Pods-CodePushDemoApp.release.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tINFOPLIST_FILE = CodePushDemoApp/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tOTHER_LDFLAGS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"-ObjC\",\n\t\t\t\t\t\"-lc++\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)\";\n\t\t\t\tPRODUCT_NAME = CodePushDemoApp;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tVERSIONING_SYSTEM = \"apple-generic\";\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_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;\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_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = 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_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\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\tENABLE_TESTABILITY = YES;\n\t\t\t\t\"EXCLUDED_ARCHS[sdk=iphonesimulator*]\" = \"arm64 \";\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_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\tIPHONEOS_DEPLOYMENT_TARGET = 11.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t/usr/lib/swift,\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tLIBRARY_SEARCH_PATHS = (\n\t\t\t\t\t\"\\\"$(SDKROOT)/usr/lib/swift\\\"\",\n\t\t\t\t\t\"\\\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\\\"\",\n\t\t\t\t\t\"\\\"$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)\\\"\",\n\t\t\t\t\t\"\\\"$(inherited)\\\"\",\n\t\t\t\t);\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_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;\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_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = 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_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\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\t\"EXCLUDED_ARCHS[sdk=iphonesimulator*]\" = \"arm64 \";\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 11.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t/usr/lib/swift,\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tLIBRARY_SEARCH_PATHS = (\n\t\t\t\t\t\"\\\"$(SDKROOT)/usr/lib/swift\\\"\",\n\t\t\t\t\t\"\\\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\\\"\",\n\t\t\t\t\t\"\\\"$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)\\\"\",\n\t\t\t\t\t\"\\\"$(inherited)\\\"\",\n\t\t\t\t);\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 \"CodePushDemoAppTests\" */ = {\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 \"CodePushDemoApp\" */ = {\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 \"CodePushDemoApp\" */ = {\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": "Examples/CodePushDemoApp/ios/CodePushDemoApp.xcodeproj/xcshareddata/xcschemes/CodePushDemoApp.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1210\"\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 = \"CodePushDemoApp.app\"\n               BlueprintName = \"CodePushDemoApp\"\n               ReferencedContainer = \"container:CodePushDemoApp.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 = \"CodePushDemoAppTests.xctest\"\n               BlueprintName = \"CodePushDemoAppTests\"\n               ReferencedContainer = \"container:CodePushDemoApp.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Release\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"13B07F861A680F5B00A75B9A\"\n            BuildableName = \"CodePushDemoApp.app\"\n            BlueprintName = \"CodePushDemoApp\"\n            ReferencedContainer = \"container:CodePushDemoApp.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\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 = \"CodePushDemoApp.app\"\n            BlueprintName = \"CodePushDemoApp\"\n            ReferencedContainer = \"container:CodePushDemoApp.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": "Examples/CodePushDemoApp/ios/CodePushDemoApp.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"group:CodePushDemoApp.xcodeproj\">\n   </FileRef>\n   <FileRef\n      location = \"group:Pods/Pods.xcodeproj\">\n   </FileRef>\n</Workspace>\n"
  },
  {
    "path": "Examples/CodePushDemoApp/ios/CodePushDemoApp.xcworkspace/xcshareddata/IDEWorkspaceChecks.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>IDEDidComputeMac32BitWarning</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "Examples/CodePushDemoApp/ios/CodePushDemoAppTests/CodePushDemoAppTests.m",
    "content": "#import <UIKit/UIKit.h>\n#import <XCTest/XCTest.h>\n\n#import <React/RCTLog.h>\n#import <React/RCTRootView.h>\n\n#define TIMEOUT_SECONDS 600\n#define TEXT_TO_LOOK_FOR @\"Welcome to React\"\n\n@interface CodePushDemoAppTests : XCTestCase\n\n@end\n\n@implementation CodePushDemoAppTests\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 = [[[RCTSharedApplication() delegate] window] rootViewController];\n  NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS];\n  BOOL foundElement = NO;\n\n  __block NSString *redboxError = nil;\n#ifdef DEBUG\n  RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) {\n    if (level >= RCTLogLevelError) {\n      redboxError = message;\n    }\n  });\n#endif\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#ifdef DEBUG\n  RCTSetLogFunction(RCTDefaultLogFunction);\n#endif\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": "Examples/CodePushDemoApp/ios/CodePushDemoAppTests/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>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": "Examples/CodePushDemoApp/ios/Podfile",
    "content": "require_relative '../node_modules/react-native/scripts/react_native_pods'\nrequire_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'\n\nplatform :ios, '11.0'\n\ntarget 'CodePushDemoApp' do\n  config = use_native_modules!\n\n  use_react_native!(\n    :path => config[:reactNativePath],\n    # to enable hermes on iOS, change `false` to `true` and then install pods\n    :hermes_enabled => false\n  )\n\n  target 'CodePushDemoAppTests' do\n    inherit! :complete\n    # Pods for testing\n  end\n\n  # Enables Flipper.\n  #\n  # Note that if you have use_frameworks! enabled, Flipper will not work and\n  # you should disable the next line.\n  use_flipper!()\n\n  post_install do |installer|\n    react_native_post_install(installer)\n    __apply_Xcode_12_5_M1_post_install_workaround(installer)\n  end\nend\n"
  },
  {
    "path": "Examples/CodePushDemoApp/metro.config.js",
    "content": "/**\n * Metro configuration for React Native\n * https://github.com/facebook/react-native\n *\n * @format\n */\n\nmodule.exports = {\n  transformer: {\n    getTransformOptions: async () => ({\n      transform: {\n        experimentalImportSupport: false,\n        inlineRequires: true,\n      },\n    }),\n  },\n};\n"
  },
  {
    "path": "Examples/CodePushDemoApp/package.json",
    "content": "{\n  \"name\": \"CodePushDemoApp\",\n  \"version\": \"0.0.1\",\n  \"private\": true,\n  \"scripts\": {\n    \"android\": \"react-native run-android\",\n    \"ios\": \"react-native run-ios\",\n    \"start\": \"react-native start\",\n    \"test\": \"jest\",\n    \"lint\": \"eslint .\"\n  },\n  \"dependencies\": {\n    \"react\": \"17.0.2\",\n    \"react-native\": \"0.68.5\",\n    \"react-native-code-push\": \"8.1.0\"\n  },\n  \"resolutions\": {\n    \"strip-ansi\": \"^6.0.1\",\n    \"ansi-regex\": \"^5.0.1\"\n  },\n  \"devDependencies\": {\n    \"@babel/core\": \"^7.15.8\",\n    \"@babel/runtime\": \"^7.15.4\",\n    \"@react-native-community/eslint-config\": \"^3.0.1\",\n    \"babel-jest\": \"^27.2.5\",\n    \"eslint\": \"^8.0.0\",\n    \"jest\": \"^27.2.5\",\n    \"metro-react-native-babel-preset\": \"^0.66.2\",\n    \"react-test-renderer\": \"17.0.2\"\n  },\n  \"jest\": {\n    \"preset\": \"react-native\"\n  }\n}\n"
  },
  {
    "path": "Examples/CodePushDemoAppCpp/.buckconfig",
    "content": "\n[android]\n  target = Google Inc.:Google APIs:23\n\n[maven_repositories]\n  central = https://repo1.maven.org/maven2\n"
  },
  {
    "path": "Examples/CodePushDemoAppCpp/.eslintrc.js",
    "content": "module.exports = {\n  root: true,\n  extends: '@react-native-community',\n};\n"
  },
  {
    "path": "Examples/CodePushDemoAppCpp/.flowconfig",
    "content": "[ignore]\n; We fork some components by platform\n.*/*[.]android.js\n\n; Ignore \"BUCK\" generated dirs\n<PROJECT_ROOT>/\\.buckd/\n\n; Ignore polyfills\nnode_modules/react-native/Libraries/polyfills/.*\n\n; These should not be required directly\n; require from fbjs/lib instead: require('fbjs/lib/warning')\nnode_modules/warning/.*\n\n; Flow doesn't support platforms\n.*/Libraries/Utilities/LoadingView.js\n\n[untyped]\n.*/node_modules/@react-native-community/cli/.*/.*\n\n[include]\n\n[libs]\nnode_modules/react-native/interface.js\nnode_modules/react-native/flow/\n\n[options]\nemoji=true\n\nesproposal.optional_chaining=enable\nesproposal.nullish_coalescing=enable\n\nmodule.file_ext=.js\nmodule.file_ext=.json\nmodule.file_ext=.ios.js\n\nmunge_underscores=true\n\nmodule.name_mapper='^react-native/\\(.*\\)$' -> '<PROJECT_ROOT>/node_modules/react-native/\\1'\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\\)$' -> '<PROJECT_ROOT>/node_modules/react-native/Libraries/Image/RelativeImageStub'\n\nsuppress_type=$FlowIssue\nsuppress_type=$FlowFixMe\nsuppress_type=$FlowFixMeProps\nsuppress_type=$FlowFixMeState\n\nsuppress_comment=\\\\(.\\\\|\\n\\\\)*\\\\$FlowFixMe\\\\($\\\\|[^(]\\\\|(\\\\(<VERSION>\\\\)? *\\\\(site=[a-z,_]*react_native\\\\(_ios\\\\)?_\\\\(oss\\\\|fb\\\\)[a-z,_]*\\\\)?)\\\\)\nsuppress_comment=\\\\(.\\\\|\\n\\\\)*\\\\$FlowIssue\\\\((\\\\(<VERSION>\\\\)? *\\\\(site=[a-z,_]*react_native\\\\(_ios\\\\)?_\\\\(oss\\\\|fb\\\\)[a-z,_]*\\\\)?)\\\\)?:? #[0-9]+\nsuppress_comment=\\\\(.\\\\|\\n\\\\)*\\\\$FlowExpectedError\n\n[lints]\nsketchy-null-number=warn\nsketchy-null-mixed=warn\nsketchy-number=warn\nuntyped-type-import=warn\nnonstrict-import=warn\ndeprecated-type=warn\nunsafe-getters-setters=warn\nunnecessary-invariant=warn\nsignature-verification-failure=warn\ndeprecated-utility=error\n\n[strict]\ndeprecated-type\nnonstrict-import\nsketchy-null\nunclear-type\nunsafe-getters-setters\nuntyped-import\nuntyped-type-import\n\n[version]\n^0.122.0\n"
  },
  {
    "path": "Examples/CodePushDemoAppCpp/.gitattributes",
    "content": "*.pbxproj -text\n"
  },
  {
    "path": "Examples/CodePushDemoAppCpp/.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\n\n# Android/IntelliJ\n#\nbuild/\n.idea\n.gradle\nlocal.properties\n*.iml\n\n# Visual Studio Code\n#\n.vscode/\n\n# node.js\n#\nnode_modules/\nnpm-debug.log\nyarn-error.log\n\n# BUCK\nbuck-out/\n\\.buckd/\n*.keystore\n!debug.keystore\n\n# fastlane\n#\n# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the\n# screenshots whenever they are needed.\n# For more information about the recommended setup visit:\n# https://docs.fastlane.tools/best-practices/source-control/\n\n*/fastlane/report.xml\n*/fastlane/Preview.html\n*/fastlane/screenshots\n\n# Bundle artifact\n*.jsbundle\n\n# CocoaPods\n/ios/Pods/\n"
  },
  {
    "path": "Examples/CodePushDemoAppCpp/.prettierrc.js",
    "content": "module.exports = {\n  bracketSpacing: false,\n  jsxBracketSameLine: true,\n  singleQuote: true,\n  trailingComma: 'all',\n};\n"
  },
  {
    "path": "Examples/CodePushDemoAppCpp/.watchmanconfig",
    "content": "{}\n"
  },
  {
    "path": "Examples/CodePushDemoAppCpp/App.js",
    "content": "import React, { Component } from 'react';\nimport {\n  AppRegistry,\n  Dimensions,\n  Image,\n  SafeAreaView,\n  ScrollView,\n  StyleSheet,\n  Text,\n  TouchableOpacity,\n  View,\n} from 'react-native';\n\nimport CodePush from \"react-native-code-push\";\n\nclass App extends Component<{}> {\n  constructor() {\n    super();\n    this.state = { restartAllowed: true };\n  }\n\n  codePushStatusDidChange(syncStatus) {\n    switch(syncStatus) {\n      case CodePush.SyncStatus.CHECKING_FOR_UPDATE:\n        this.setState({ syncMessage: \"Checking for update.\" });\n        break;\n      case CodePush.SyncStatus.DOWNLOADING_PACKAGE:\n        this.setState({ syncMessage: \"Downloading package.\" });\n        break;\n      case CodePush.SyncStatus.AWAITING_USER_ACTION:\n        this.setState({ syncMessage: \"Awaiting user action.\" });\n        break;\n      case CodePush.SyncStatus.INSTALLING_UPDATE:\n        this.setState({ syncMessage: \"Installing update.\" });\n        break;\n      case CodePush.SyncStatus.UP_TO_DATE:\n        this.setState({ syncMessage: \"App up to date.\", progress: false });\n        break;\n      case CodePush.SyncStatus.UPDATE_IGNORED:\n        this.setState({ syncMessage: \"Update cancelled by user.\", progress: false });\n        break;\n      case CodePush.SyncStatus.UPDATE_INSTALLED:\n        this.setState({ syncMessage: \"Update installed and will be applied on restart.\", progress: false });\n        break;\n      case CodePush.SyncStatus.UNKNOWN_ERROR:\n        this.setState({ syncMessage: \"An unknown error occurred.\", progress: false });\n        break;\n    }\n  }\n\n  codePushDownloadDidProgress(progress) {\n    this.setState({ progress });\n  }\n\n  toggleAllowRestart() {\n    this.state.restartAllowed\n      ? CodePush.disallowRestart()\n      : CodePush.allowRestart();\n\n    this.setState({ restartAllowed: !this.state.restartAllowed });\n  }\n\n  getUpdateMetadata() {\n    CodePush.getUpdateMetadata(CodePush.UpdateState.RUNNING)\n      .then((metadata: LocalPackage) => {\n        this.setState({ syncMessage: metadata ? JSON.stringify(metadata) : \"Running binary version\", progress: false });\n      }, (error: any) => {\n        this.setState({ syncMessage: \"Error: \" + error, progress: false });\n      });\n  }\n\n  /** Update is downloaded silently, and applied on restart (recommended) */\n  sync() {\n    CodePush.sync(\n      {},\n      this.codePushStatusDidChange.bind(this),\n      this.codePushDownloadDidProgress.bind(this)\n    );\n  }\n\n  /** Update pops a confirmation dialog, and then immediately reboots the app */\n  syncImmediate() {\n    CodePush.sync(\n      { installMode: CodePush.InstallMode.IMMEDIATE, updateDialog: true },\n      this.codePushStatusDidChange.bind(this),\n      this.codePushDownloadDidProgress.bind(this)\n    );\n  }\n  \n  restartApp() {\n\t  CodePush.restartApp();\n  }\n\n  render() {\n    let progressView;\n\n    if (this.state.progress) {\n      progressView = (\n        <Text style={styles.messages}>{this.state.progress.receivedBytes} of {this.state.progress.totalBytes} bytes received</Text>\n      );\n    }\n\n    return (\n\t\t<SafeAreaView>\n\t\t\t<ScrollView>\n\t\t\t\t<View style={styles.container}>\n\t\t\t\t\t<Text style={styles.welcome}>\n\t\t\t\t\t  Welcome to CodePush!\n\t\t\t\t\t</Text>\n\t\t\t\t\t<Text style={styles.welcome}>\n\t\t\t\t\t\tDemo bundle\n\t\t\t\t\t</Text>\n\t\t\t\t\t<TouchableOpacity onPress={this.restartApp.bind(this)}>\n\t\t\t\t\t\t<Text style={styles.syncButton}>Press to restart</Text>\n\t\t\t\t\t</TouchableOpacity>\n\t\t\t\t\t<TouchableOpacity onPress={this.sync.bind(this)}>\n\t\t\t\t\t  <Text style={styles.syncButton}>Press for background sync</Text>\n\t\t\t\t\t</TouchableOpacity>\n\t\t\t\t\t<TouchableOpacity onPress={this.syncImmediate.bind(this)}>\n\t\t\t\t\t  <Text style={styles.syncButton}>Press for dialog-driven sync</Text>\n\t\t\t\t\t</TouchableOpacity>\n\t\t\t\t\t{progressView}\n\t\t\t\t\t<TouchableOpacity onPress={this.toggleAllowRestart.bind(this)}>\n\t\t\t\t\t  <Text style={styles.restartToggleButton}>Restart { this.state.restartAllowed ? \"allowed\" : \"forbidden\"}</Text>\n\t\t\t\t\t</TouchableOpacity>\n\t\t\t\t\t<TouchableOpacity onPress={this.getUpdateMetadata.bind(this)}>\n\t\t\t\t\t  <Text style={styles.syncButton}>Press for Update Metadata</Text>\n\t\t\t\t\t</TouchableOpacity>\n\t\t\t\t\t<Text style={styles.messages}>{this.state.syncMessage || \"\"}</Text>\n\t\t\t\t</View>\n\t\t\t</ScrollView>\n\t\t</SafeAreaView>\n    );\n  }\n}\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    alignItems: \"center\",\n    backgroundColor: \"#F5FCFF\",\n    paddingTop: 50\n  },\n  image: {\n    margin: 30,\n    width: Dimensions.get(\"window\").width - 100,\n    height: 365 * (Dimensions.get(\"window\").width - 100) / 651,\n  },\n  messages: {\n    marginTop: 30,\n    textAlign: \"center\",\n  },\n  restartToggleButton: {\n    color: \"blue\",\n    fontSize: 17\n  },\n  syncButton: {\n    color: \"green\",\n    fontSize: 17\n  },\n  welcome: {\n    fontSize: 20,\n    textAlign: \"center\",\n    margin: 20\n  },\n});\n\n/**\n * Configured with a MANUAL check frequency for easy testing. For production apps, it is recommended to configure a\n * different check frequency, such as ON_APP_START, for a 'hands-off' approach where CodePush.sync() does not\n * need to be explicitly called. All options of CodePush.sync() are also available in this decorator.\n */\nlet codePushOptions = { checkFrequency: CodePush.CheckFrequency.MANUAL };\n\nApp = CodePush(codePushOptions)(App);\n\nexport default App;\n"
  },
  {
    "path": "Examples/CodePushDemoAppCpp/app.json",
    "content": "{\n  \"name\": \"CodePushDemoAppCpp\",\n  \"displayName\": \"CodePushDemoAppCpp\"\n}\n"
  },
  {
    "path": "Examples/CodePushDemoAppCpp/babel.config.js",
    "content": "module.exports = {\n  presets: ['module:metro-react-native-babel-preset'],\n};\n"
  },
  {
    "path": "Examples/CodePushDemoAppCpp/index.js",
    "content": "/**\n * @format\n */\n\nimport {AppRegistry} from 'react-native';\nimport App from './App';\nimport {name as appName} from './app.json';\n\nAppRegistry.registerComponent(appName, () => App);\n"
  },
  {
    "path": "Examples/CodePushDemoAppCpp/metro.config.js",
    "content": "/**\n * Metro configuration for React Native\n * https://github.com/facebook/react-native\n *\n * @format\n */\nconst path = require('path');\nconst blacklist = require('metro-config/src/defaults/blacklist');\n\nmodule.exports = {\n  resolver: {\n    blacklistRE: blacklist([\n      // This stops \"react-native run-windows\" from causing the metro server to crash if its already running\n      new RegExp(\n        `${path.resolve(__dirname, 'windows').replace(/[/\\\\]/g, '/')}.*`,\n      ),\n      // This prevents \"react-native run-windows\" from hitting: EBUSY: resource busy or locked, open msbuild.ProjectImports.zip\n      /.*\\.ProjectImports\\.zip/,\n    ]),\n  },\n  transformer: {\n    getTransformOptions: async () => ({\n      transform: {\n        experimentalImportSupport: false,\n        inlineRequires: false,\n      },\n    }),\n  },\n};\n"
  },
  {
    "path": "Examples/CodePushDemoAppCpp/package.json",
    "content": "{\n  \"name\": \"CodePushDemoAppCpp\",\n  \"version\": \"0.0.1\",\n  \"private\": true,\n  \"scripts\": {\n    \"start\": \"react-native start\",\n    \"test\": \"jest\",\n    \"lint\": \"eslint .\",\n    \"windows\": \"react-native run-windows\"\n  },\n  \"dependencies\": {\n    \"react\": \"^17.0.2\",\n    \"react-native\": \"^0.68.5\",\n    \"react-native-code-push\": \"^8.1.0\",\n    \"react-native-windows\": \"^1.0.0\"\n  },\n  \"resolutions\": {\n    \"strip-ansi\": \"^6.0.1\",\n    \"ansi-regex\": \"^5.0.1\",\n    \"node-fetch\": \"^2.6.7\"\n  },\n  \"devDependencies\": {\n    \"@babel/core\": \"^7.8.4\",\n    \"@babel/runtime\": \"^7.8.4\",\n    \"@react-native-community/eslint-config\": \"^3.0.1\",\n    \"appcenter-cli\": \"^2.14.0\",\n    \"babel-jest\": \"^27.2.5\",\n    \"eslint\": \"^8.0.0\",\n    \"jest\": \"^27.2.5\",\n    \"metro-react-native-babel-preset\": \"^0.66.2\",\n    \"react-test-renderer\": \"17.0.2\"\n  },\n  \"jest\": {\n    \"preset\": \"react-native\"\n  }\n}\n"
  },
  {
    "path": "Examples/CodePushDemoAppCpp/windows/.gitignore",
    "content": "*AppPackages*\n*BundleArtifacts*\n\n#OS junk files\n[Tt]humbs.db\n*.DS_Store\n\n#Visual Studio files\n*.[Oo]bj\n*.user\n*.aps\n*.pch\n*.vspscc\n*.vssscc\n*_i.c\n*_p.c\n*.ncb\n*.suo\n*.tlb\n*.tlh\n*.bak\n*.[Cc]ache\n*.ilk\n*.log\n*.lib\n*.sbr\n*.sdf\n*.opensdf\n*.opendb\n*.unsuccessfulbuild\nipch/\n[Oo]bj/\n[Bb]in\n[Dd]ebug*/\n[Rr]elease*/\nAnkh.NoLoad\n\n# Visual C++ cache files\nipch/\n*.aps\n*.ncb\n*.opendb\n*.opensdf\n*.sdf\n*.cachefile\n*.VC.db\n*.VC.VC.opendb\n\n#MonoDevelop\n*.pidb\n*.userprefs\n\n#Tooling\n_ReSharper*/\n*.resharper\n[Tt]est[Rr]esult*\n*.sass-cache\n\n#Project files\n[Bb]uild/\n\n#Subversion files\n.svn\n\n# Office Temp Files\n~$*\n\n# vim Temp Files\n*~\n\n#NuGet\npackages/\n*.nupkg\n\n#ncrunch\n*ncrunch*\n*crunch*.local.xml\n\n# visual studio database projects\n*.dbmdl\n\n#Test files\n*.testsettings\n\n#Other files\n*.DotSettings\n.vs/\n*project.lock.json\n\n#Files generated by the VS build\n**/Generated Files/**\n\n"
  },
  {
    "path": "Examples/CodePushDemoAppCpp/windows/CodePushDemoAppCpp/.gitignore",
    "content": "/Bundle\n"
  },
  {
    "path": "Examples/CodePushDemoAppCpp/windows/CodePushDemoAppCpp/App.cpp",
    "content": "#include \"pch.h\"\n\n#include \"App.h\"\n\n#include \"AutolinkedNativeModules.g.h\"\n#include \"ReactPackageProvider.h\"\n#include \"winrt/Microsoft.CodePush.ReactNative.h\"\n\n#include \"winrt/Windows.Storage.h\"\n#include \"winrt/Windows.Foundation.h\"\n#include \"winrt/Windows.Data.Json.h\"\n\n#include <string_view>\n\nusing namespace winrt::CodePushDemoAppCpp;\nusing namespace winrt::CodePushDemoAppCpp::implementation;\nusing namespace winrt;\nusing namespace Windows::UI::Xaml;\nusing namespace Windows::UI::Xaml::Controls;\nusing namespace Windows::UI::Xaml::Navigation;\nusing namespace Windows::ApplicationModel;\nusing namespace Windows::ApplicationModel::Activation;\n\nusing namespace Windows::Storage;\nusing namespace Windows::Data::Json;\n\nusing namespace Microsoft::ReactNative;\n\nusing namespace std;\n\n/// <summary>\n/// Initializes the singleton application object.  This is the first line of\n/// authored code executed, and as such is the logical equivalent of main() or\n/// WinMain().\n/// </summary>\nApp::App() noexcept\n{\n#if BUNDLE\n    m_host.InstanceSettings().JavaScriptBundleFile(L\"index.windows\");\n    m_host.InstanceSettings().UseWebDebugger(false);\n    m_host.InstanceSettings().UseFastRefresh(false);\n#else\n    m_host.InstanceSettings().JavaScriptMainModuleName(L\"index\");\n    m_host.InstanceSettings().UseWebDebugger(true);\n    m_host.InstanceSettings().UseFastRefresh(true);\n#endif\n\n#if _DEBUG\n    m_host.InstanceSettings().UseDeveloperSupport(true);\n#else\n    m_host.InstanceSettings().UseDeveloperSupport(false);\n#endif\n\n    RegisterAutolinkedNativeModulePackages(m_host.InstanceSettings().PackageProviders()); // Includes any autolinked modules\n\n    m_host.InstanceSettings().PackageProviders().Append(make<ReactPackageProvider>()); // Includes all modules in this project\n\n    InitializeComponent();\n    \n    Suspending({ this, &App::OnSuspending });\n\n#if defined _DEBUG && !defined DISABLE_XAML_GENERATED_BREAK_ON_UNHANDLED_EXCEPTION\n    UnhandledException([this](IInspectable const&, UnhandledExceptionEventArgs const& e)\n        {\n            if (IsDebuggerPresent())\n            {\n                auto errorMessage = e.Message();\n                __debugbreak();\n            }\n        });\n#endif\n}\n\n/// <summary>\n/// Invoked when the application is launched normally by the end user.  Other entry points\n/// will be used such as when the application is launched to open a specific file.\n/// </summary>\n/// <param name=\"e\">Details about the launch request and process.</param>\nvoid App::OnLaunched(activation::LaunchActivatedEventArgs const& e)\n{\n    winrt::Microsoft::CodePush::ReactNative::CodePushConfig::SetHost(Host());\n    auto configMap{ winrt::single_threaded_map<hstring, hstring>() };\n    configMap.Insert(L\"appVersion\", L\"1.0.0\");\n    configMap.Insert(L\"deploymentKey\", L\"<app deployment key>\");\n    winrt::Microsoft::CodePush::ReactNative::CodePushConfig::Init(configMap);\n\n    Frame rootFrame{ nullptr };\n    auto content = Window::Current().Content();\n    if (content)\n    {\n        rootFrame = content.try_as<Frame>();\n    }\n\n    // Do not repeat app initialization when the Window already has content,\n    // just ensure that the window is active\n    if (rootFrame == nullptr)\n    {\n        // Create a Frame to act as the navigation context and associate it with\n        // a SuspensionManager key\n        rootFrame = Frame();\n\n        rootFrame.NavigationFailed({ this, &App::OnNavigationFailed });\n\n        if (e.PreviousExecutionState() == ApplicationExecutionState::Terminated)\n        {\n            // Restore the saved session state only when appropriate, scheduling the\n            // final launch steps after the restore is complete\n        }\n\n        if (e.PrelaunchActivated() == false)\n        {\n            if (rootFrame.Content() == nullptr)\n            {\n                // When the navigation stack isn't restored navigate to the first page,\n                // configuring the new page by passing required information as a navigation\n                // parameter\n                rootFrame.Navigate(xaml_typename<CodePushDemoAppCpp::MainPage>(), box_value(e.Arguments()));\n            }\n            // Place the frame in the current Window\n            Window::Current().Content(rootFrame);\n            // Ensure the current window is active\n            Window::Current().Activate();\n        }\n    }\n    else\n    {\n        if (e.PrelaunchActivated() == false)\n        {\n            if (rootFrame.Content() == nullptr)\n            {\n                // When the navigation stack isn't restored navigate to the first page,\n                // configuring the new page by passing required information as a navigation\n                // parameter\n                rootFrame.Navigate(xaml_typename<CodePushDemoAppCpp::MainPage>(), box_value(e.Arguments()));\n            }\n            // Ensure the current window is active\n            Window::Current().Activate();\n        }\n    }\n}\n\n/// <summary>\n/// Invoked when application execution is being suspended.  Application state is saved\n/// without knowing whether the application will be terminated or resumed with the contents\n/// of memory still intact.\n/// </summary>\n/// <param name=\"sender\">The source of the suspend request.</param>\n/// <param name=\"e\">Details about the suspend request.</param>\nvoid App::OnSuspending([[maybe_unused]] IInspectable const& sender, [[maybe_unused]] SuspendingEventArgs const& e)\n{\n    // Save application state and stop any background activity\n}\n\n/// <summary>\n/// Invoked when Navigation to a certain page fails\n/// </summary>\n/// <param name=\"sender\">The Frame which failed navigation</param>\n/// <param name=\"e\">Details about the navigation failure</param>\nvoid App::OnNavigationFailed(IInspectable const&, NavigationFailedEventArgs const& e)\n{\n    throw hresult_error(E_FAIL, hstring(L\"Failed to load Page \") + e.SourcePageType().Name);\n}\n"
  },
  {
    "path": "Examples/CodePushDemoAppCpp/windows/CodePushDemoAppCpp/App.h",
    "content": "#pragma once\n\n#include \"App.xaml.g.h\"\n#include \"winrt/Microsoft.ReactNative.h\"\n\nnamespace activation = winrt::Windows::ApplicationModel::Activation;\n\nnamespace winrt::CodePushDemoAppCpp::implementation\n{\n    struct App : AppT<App>\n    {\n        App() noexcept;\n\n        void OnLaunched(Windows::ApplicationModel::Activation::LaunchActivatedEventArgs const&);\n        void OnSuspending(IInspectable const&, Windows::ApplicationModel::SuspendingEventArgs const&);\n        void OnNavigationFailed(IInspectable const&, Windows::UI::Xaml::Navigation::NavigationFailedEventArgs const&);\n    \n        winrt::Microsoft::ReactNative::ReactNativeHost& Host() noexcept { return m_host; }\n    private:\n        winrt::Microsoft::ReactNative::ReactNativeHost m_host;\n    };\n} // namespace winrt::CodePushDemoAppCpp::implementation\n"
  },
  {
    "path": "Examples/CodePushDemoAppCpp/windows/CodePushDemoAppCpp/App.idl",
    "content": "namespace CodePushDemoAppCpp\n{\n}\n"
  },
  {
    "path": "Examples/CodePushDemoAppCpp/windows/CodePushDemoAppCpp/App.xaml",
    "content": "﻿<Application\n    x:Class=\"CodePushDemoAppCpp.App\"\n    xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n    xmlns:local=\"using:CodePushDemoAppCpp\">\n</Application>\n"
  },
  {
    "path": "Examples/CodePushDemoAppCpp/windows/CodePushDemoAppCpp/AutolinkedNativeModules.g.cpp",
    "content": "// AutolinkedNativeModules.g.cpp contents generated by \"react-native autolink-windows\"\n// clang-format off\n#include \"pch.h\"\n#include \"AutolinkedNativeModules.g.h\"\n\n// Includes from react-native-code-push-windows\n#include \"winrt/Microsoft.CodePush.ReactNative.h\"\n\nnamespace winrt::Microsoft::ReactNative\n{\n\nvoid RegisterAutolinkedNativeModulePackages(winrt::Windows::Foundation::Collections::IVector<winrt::Microsoft::ReactNative::IReactPackageProvider> const& packageProviders)\n{ \n    // IReactPackageProviders from react-native-code-push-windows\n    packageProviders.Append(winrt::Microsoft::CodePush::ReactNative::ReactPackageProvider());\n}\n\n}\n"
  },
  {
    "path": "Examples/CodePushDemoAppCpp/windows/CodePushDemoAppCpp/AutolinkedNativeModules.g.h",
    "content": "// AutolinkedNativeModules.g.h contents generated by \"react-native autolink-windows\"\n\n#pragma once\n\nnamespace winrt::Microsoft::ReactNative\n{\n\nvoid RegisterAutolinkedNativeModulePackages(winrt::Windows::Foundation::Collections::IVector<winrt::Microsoft::ReactNative::IReactPackageProvider> const& packageProviders);\n\n}\n"
  },
  {
    "path": "Examples/CodePushDemoAppCpp/windows/CodePushDemoAppCpp/AutolinkedNativeModules.g.targets",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <!-- AutolinkedNativeModules.g.targets contents generated by \"react-native autolink-windows\" -->\n  <ItemGroup>\n    <!-- Projects from react-native-code-push-windows -->\n    <!-- We use direct dependecy instead to develop the CodePush component -->\n    <!-- <ProjectReference Include=\"$(ProjectDir)..\\..\\node_modules\\react-native-code-push-windows\\windows\\CodePush\\CodePush.vcxproj\">\n      <Project>{a6b6216e-fa3f-45e2-9c8e-40023cce9132}</Project>\n    </ProjectReference> -->\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "Examples/CodePushDemoAppCpp/windows/CodePushDemoAppCpp/CodePushDemoAppCpp.vcxproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"16.0\" DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <Import Project=\"..\\packages\\Microsoft.Windows.CppWinRT.2.0.200615.7\\build\\native\\Microsoft.Windows.CppWinRT.props\" Condition=\"Exists('..\\packages\\Microsoft.Windows.CppWinRT.2.0.200615.7\\build\\native\\Microsoft.Windows.CppWinRT.props')\" />\n  <PropertyGroup Label=\"Globals\">\n    <CppWinRTOptimized>true</CppWinRTOptimized>\n    <CppWinRTRootNamespaceAutoMerge>true</CppWinRTRootNamespaceAutoMerge>\n    <MinimalCoreWin>true</MinimalCoreWin>\n    <ProjectGuid>{609f44f6-01cf-4270-85a3-09f9ca10b434}</ProjectGuid>\n    <ProjectName>CodePushDemoAppCpp</ProjectName>\n    <RootNamespace>CodePushDemoAppCpp</RootNamespace>\n    <DefaultLanguage>en-US</DefaultLanguage>\n    <MinimumVisualStudioVersion>16.0</MinimumVisualStudioVersion>\n    <AppContainerApplication>true</AppContainerApplication>\n    <ApplicationType>Windows Store</ApplicationType>\n    <ApplicationTypeRevision>10.0</ApplicationTypeRevision>\n    <WindowsTargetPlatformVersion Condition=\" '$(WindowsTargetPlatformVersion)' == '' \">10.0.18362.0</WindowsTargetPlatformVersion>\n    <WindowsTargetPlatformMinVersion>10.0.16299.0</WindowsTargetPlatformMinVersion>\n    <PackageCertificateKeyFile>CodePushDemoAppCpp_TemporaryKey.pfx</PackageCertificateKeyFile>\n    <PackageCertificateThumbprint>5FBADC5BFA887CF7B571A1685542D69E23F6A0F2</PackageCertificateThumbprint>\n    <PackageCertificatePassword>password</PackageCertificatePassword>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Label=\"ReactNativeWindowsProps\">\n    <ReactNativeWindowsDir Condition=\"'$(ReactNativeWindowsDir)' == ''\">$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), 'node_modules\\react-native-windows\\package.json'))\\node_modules\\react-native-windows\\</ReactNativeWindowsDir>\n    <!-- This demo app uses bundle even in Debug mode -->\n    <UseBundle>true</UseBundle>\n    <!-- We use this project for developing the CodePush module. We disable autolinking to use it from the source location -->\n    <RunAutolinkCheck>false</RunAutolinkCheck>\n  </PropertyGroup>\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|ARM\">\n      <Configuration>Debug</Configuration>\n      <Platform>ARM</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|ARM64\">\n      <Configuration>Debug</Configuration>\n      <Platform>ARM64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|ARM\">\n      <Configuration>Release</Configuration>\n      <Platform>ARM</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|ARM64\">\n      <Configuration>Release</Configuration>\n      <Platform>ARM64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)'=='Debug'\" Label=\"Configuration\">\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <LinkIncremental>true</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)'=='Release'\" Label=\"Configuration\">\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <LinkIncremental>false</LinkIncremental>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"PropertySheet.props\" />\n  </ImportGroup>\n  <ImportGroup Label=\"ReactNativeWindowsPropertySheets\">\n    <Import Project=\"$(ReactNativeWindowsDir)\\PropertySheets\\external\\Microsoft.ReactNative.Uwp.CppApp.props\" Condition=\"Exists('$(ReactNativeWindowsDir)\\PropertySheets\\External\\Microsoft.ReactNative.Uwp.CppApp.props')\" />\n    <Import Project=\"..\\packages\\$(WinUIPackageProps)\" Condition=\"'$(WinUIPackageProps)'!='' And Exists('..\\packages\\$(WinUIPackageProps)')\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>\n      <WarningLevel>Level4</WarningLevel>\n      <AdditionalOptions>%(AdditionalOptions) /bigobj</AdditionalOptions>\n      <DisableSpecificWarnings>4453;28204</DisableSpecificWarnings>\n    </ClCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)'=='Debug'\">\n    <ClCompile>\n      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)'=='Release'\">\n    <ClCompile>\n      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClInclude Include=\"MainPage.h\">\n      <DependentUpon>MainPage.xaml</DependentUpon>\n      <SubType>Code</SubType>\n    </ClInclude>\n    <ClInclude Include=\"ReactPackageProvider.h\" />\n    <ClInclude Include=\"AutolinkedNativeModules.g.h\" />\n    <ClInclude Include=\"pch.h\" />\n    <ClInclude Include=\"App.h\">\n      <DependentUpon>App.xaml</DependentUpon>\n    </ClInclude>\n  </ItemGroup>\n  <ItemGroup>\n    <ApplicationDefinition Include=\"App.xaml\">\n      <SubType>Designer</SubType>\n    </ApplicationDefinition>\n  </ItemGroup>\n  <ItemGroup>\n    <AppxManifest Include=\"Package.appxmanifest\">\n      <SubType>Designer</SubType>\n    </AppxManifest>\n  </ItemGroup>\n  <ItemGroup>\n    <Image Include=\"Assets\\LockScreenLogo.scale-200.png\" />\n    <Image Include=\"Assets\\SplashScreen.scale-200.png\" />\n    <Image Include=\"Assets\\Square150x150Logo.scale-200.png\" />\n    <Image Include=\"Assets\\Square44x44Logo.scale-200.png\" />\n    <Image Include=\"Assets\\Square44x44Logo.targetsize-24_altform-unplated.png\" />\n    <Image Include=\"Assets\\StoreLogo.png\" />\n    <Image Include=\"Assets\\Wide310x150Logo.scale-200.png\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"MainPage.cpp\">\n      <DependentUpon>MainPage.xaml</DependentUpon>\n      <SubType>Code</SubType>\n    </ClCompile>\n    <ClCompile Include=\"ReactPackageProvider.cpp\" />\n    <ClCompile Include=\"AutolinkedNativeModules.g.cpp\" />\n    <ClCompile Include=\"pch.cpp\">\n      <PrecompiledHeader>Create</PrecompiledHeader>\n    </ClCompile>\n    <ClCompile Include=\"App.cpp\">\n      <DependentUpon>App.xaml</DependentUpon>\n    </ClCompile>\n    <ClCompile Include=\"$(GeneratedFilesDir)module.g.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Midl Include=\"App.idl\">\n      <DependentUpon>App.xaml</DependentUpon>\n    </Midl>\n    <Midl Include=\"MainPage.idl\">\n      <DependentUpon>MainPage.xaml</DependentUpon>\n      <SubType>Code</SubType>\n    </Midl>\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"packages.config\" />\n    <None Include=\"PropertySheet.props\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Page Include=\"MainPage.xaml\">\n      <SubType>Designer</SubType>\n    </Page>\n  </ItemGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\..\\..\\windows\\CodePush\\CodePush.vcxproj\">\n      <Project>{a6b6216e-fa3f-45e2-9c8e-40023cce9132}</Project>\n    </ProjectReference>\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ReactNativeWindowsTargets\">\n    <Import Project=\"$(ReactNativeWindowsDir)\\PropertySheets\\External\\Microsoft.ReactNative.Uwp.CppApp.targets\" Condition=\"Exists('$(ReactNativeWindowsDir)\\PropertySheets\\External\\Microsoft.ReactNative.Uwp.CppApp.targets')\" />\n  </ImportGroup>\n  <Target Name=\"EnsureReactNativeWindowsTargets\" BeforeTargets=\"PrepareForBuild\">\n    <PropertyGroup>\n      <ErrorText>This project references targets in your node_modules\\react-native-windows folder. The missing file is {0}.</ErrorText>\n    </PropertyGroup>\n    <Error Condition=\"!Exists('$(ReactNativeWindowsDir)\\PropertySheets\\External\\Microsoft.ReactNative.Uwp.CppApp.props')\" Text=\"$([System.String]::Format('$(ErrorText)', '$(ReactNativeWindowsDir)\\PropertySheets\\External\\Microsoft.ReactNative.Uwp.CppApp.props'))\" />\n    <Error Condition=\"!Exists('$(ReactNativeWindowsDir)\\PropertySheets\\External\\Microsoft.ReactNative.Uwp.CppApp.targets')\" Text=\"$([System.String]::Format('$(ErrorText)', '$(ReactNativeWindowsDir)\\PropertySheets\\External\\Microsoft.ReactNative.Uwp.CppApp.targets'))\" />\n  </Target>\n  <ImportGroup Label=\"ExtensionTargets\">\n    <Import Project=\"..\\packages\\Microsoft.Windows.CppWinRT.2.0.200615.7\\build\\native\\Microsoft.Windows.CppWinRT.targets\" Condition=\"Exists('..\\packages\\Microsoft.Windows.CppWinRT.2.0.200615.7\\build\\native\\Microsoft.Windows.CppWinRT.targets')\" />\n    <Import Project=\"..\\packages\\$(WinUIPackageName).$(WinUIPackageVersion)\\build\\native\\$(WinUIPackageName).targets\" Condition=\"Exists('..\\packages\\$(WinUIPackageName).$(WinUIPackageVersion)\\build\\native\\$(WinUIPackageName).targets')\" />\n  </ImportGroup>\n  <Target Name=\"EnsureNuGetPackageBuildImports\" BeforeTargets=\"PrepareForBuild\">\n    <PropertyGroup>\n      <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>\n    </PropertyGroup>\n    <Error Condition=\"!Exists('..\\packages\\Microsoft.Windows.CppWinRT.2.0.200615.7\\build\\native\\Microsoft.Windows.CppWinRT.props')\" Text=\"$([System.String]::Format('$(ErrorText)', '..\\packages\\Microsoft.Windows.CppWinRT.2.0.200615.7\\build\\native\\Microsoft.Windows.CppWinRT.props'))\" />\n    <Error Condition=\"!Exists('..\\packages\\Microsoft.Windows.CppWinRT.2.0.200615.7\\build\\native\\Microsoft.Windows.CppWinRT.targets')\" Text=\"$([System.String]::Format('$(ErrorText)', '..\\packages\\Microsoft.Windows.CppWinRT.2.0.200615.7\\build\\native\\Microsoft.Windows.CppWinRT.targets'))\" />\n    <Error Condition=\"!Exists('..\\packages\\$(WinUIPackageName).$(WinUIPackageVersion)\\build\\native\\$(WinUIPackageName).targets')\" Text=\"$([System.String]::Format('$(ErrorText)', '..\\packages\\$(WinUIPackageName).$(WinUIPackageVersion)\\build\\native\\$(WinUIPackageName).targets'))\" />\n  </Target>\n</Project>\n"
  },
  {
    "path": "Examples/CodePushDemoAppCpp/windows/CodePushDemoAppCpp/CodePushDemoAppCpp.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <ApplicationDefinition Include=\"App.xaml\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Midl Include=\"App.idl\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"pch.cpp\" />\n    <ClCompile Include=\"App.cpp\" />\n    <ClCompile Include=\"$(GeneratedFilesDir)module.g.cpp\" />\n    <ClCompile Include=\"ReactPackageProvider.cpp\" />\n    <ClCompile Include=\"AutolinkedNativeModules.g.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"pch.h\" />\n    <ClInclude Include=\"App.h\" />\n    <ClInclude Include=\"ReactPackageProvider.h\" />\n    <ClInclude Include=\"AutolinkedNativeModules.g.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Image Include=\"Assets\\Wide310x150Logo.scale-200.png\">\n      <Filter>Assets</Filter>\n    </Image>\n    <Image Include=\"Assets\\StoreLogo.png\">\n      <Filter>Assets</Filter>\n    </Image>\n    <Image Include=\"Assets\\Square150x150Logo.scale-200.png\">\n      <Filter>Assets</Filter>\n    </Image>\n    <Image Include=\"Assets\\Square44x44Logo.targetsize-24_altform-unplated.png\">\n      <Filter>Assets</Filter>\n    </Image>\n    <Image Include=\"Assets\\Square44x44Logo.scale-200.png\">\n      <Filter>Assets</Filter>\n    </Image>\n    <Image Include=\"Assets\\SplashScreen.scale-200.png\">\n      <Filter>Assets</Filter>\n    </Image>\n    <Image Include=\"Assets\\LockScreenLogo.scale-200.png\">\n      <Filter>Assets</Filter>\n    </Image>\n  </ItemGroup>\n  <ItemGroup>\n    <AppxManifest Include=\"Package.appxmanifest\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Filter Include=\"Assets\">\n      <UniqueIdentifier>{e48dc53e-40b1-40cb-970a-f89935452892}</UniqueIdentifier>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"PropertySheet.props\" />\n    <None Include=\"packages.config\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Page Include=\"MainPage.xaml\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "Examples/CodePushDemoAppCpp/windows/CodePushDemoAppCpp/MainPage.cpp",
    "content": "﻿#include \"pch.h\"\n#include \"MainPage.h\"\n#if __has_include(\"MainPage.g.cpp\")\n#include \"MainPage.g.cpp\"\n#endif\n\n#include \"App.h\"\n\n\n\nusing namespace winrt;\nusing namespace Windows::UI::Xaml;\n\nnamespace winrt::CodePushDemoAppCpp::implementation\n{\n    MainPage::MainPage()\n    {\n        InitializeComponent();\n        auto app = Application::Current().as<App>();\n        ReactRootView().ReactNativeHost(app->Host());\n    }\n}\n"
  },
  {
    "path": "Examples/CodePushDemoAppCpp/windows/CodePushDemoAppCpp/MainPage.h",
    "content": "﻿#pragma once\n#include \"MainPage.g.h\"\n#include <winrt/Microsoft.ReactNative.h>\n\n\nnamespace winrt::CodePushDemoAppCpp::implementation\n{\n    struct MainPage : MainPageT<MainPage>\n    {\n        MainPage();\n    };\n}\n\nnamespace winrt::CodePushDemoAppCpp::factory_implementation\n{\n    struct MainPage : MainPageT<MainPage, implementation::MainPage>\n    {\n    };\n}\n"
  },
  {
    "path": "Examples/CodePushDemoAppCpp/windows/CodePushDemoAppCpp/MainPage.idl",
    "content": "namespace CodePushDemoAppCpp\n{\n    [default_interface]\n    runtimeclass MainPage : Windows.UI.Xaml.Controls.Page\n    {\n        MainPage();\n    }\n}\n"
  },
  {
    "path": "Examples/CodePushDemoAppCpp/windows/CodePushDemoAppCpp/MainPage.xaml",
    "content": "<Page\n    x:Class=\"CodePushDemoAppCpp.MainPage\"\n    xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n    xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n    xmlns:local=\"using:CodePushDemoAppCpp\"\n    xmlns:react=\"using:Microsoft.ReactNative\"\n    xmlns:d=\"http://schemas.microsoft.com/expression/blend/2008\"\n    xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\"\n    mc:Ignorable=\"d\"\n    Background=\"{ThemeResource ApplicationPageBackgroundThemeBrush}\">\n    <react:ReactRootView \n        x:Name=\"ReactRootView\"\n        ComponentName=\"CodePushDemoAppCpp\"\n        Background=\"{ThemeResource ApplicationPageBackgroundThemeBrush}\"\n        MinHeight=\"400\"/>\n</Page>\n"
  },
  {
    "path": "Examples/CodePushDemoAppCpp/windows/CodePushDemoAppCpp/Package.appxmanifest",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<Package\n  xmlns=\"http://schemas.microsoft.com/appx/manifest/foundation/windows10\"\n  xmlns:mp=\"http://schemas.microsoft.com/appx/2014/phone/manifest\"\n  xmlns:uap=\"http://schemas.microsoft.com/appx/manifest/uap/windows10\"\n  IgnorableNamespaces=\"uap mp\">\n\n  <Identity\n    Name=\"bd8be20e-1e17-4299-8d0e-5862cc4428a8\"\n    Publisher=\"CN=Aleksey\"\n    Version=\"1.0.0.0\" />\n\n  <mp:PhoneIdentity PhoneProductId=\"bd8be20e-1e17-4299-8d0e-5862cc4428a8\" PhonePublisherId=\"00000000-0000-0000-0000-000000000000\"/>\n\n  <Properties>\n    <DisplayName>CodePushDemoAppCpp</DisplayName>\n    <PublisherDisplayName>Aleksey</PublisherDisplayName>\n    <Logo>Assets\\StoreLogo.png</Logo>\n  </Properties>\n\n  <Dependencies>\n    <TargetDeviceFamily Name=\"Windows.Universal\" MinVersion=\"10.0.0.0\" MaxVersionTested=\"10.0.0.0\" />\n  </Dependencies>\n\n  <Resources>\n    <Resource Language=\"x-generate\"/>\n  </Resources>\n\n  <Applications>\n    <Application\n      Id=\"App\"\n      Executable=\"$targetnametoken$.exe\"\n      EntryPoint=\"CodePushDemoAppCpp.App\">\n      <uap:VisualElements\n        DisplayName=\"CodePushDemoAppCpp\"\n        Square150x150Logo=\"Assets\\Square150x150Logo.png\"\n        Square44x44Logo=\"Assets\\Square44x44Logo.png\"\n        Description=\"CodePushDemoAppCpp\"\n        BackgroundColor=\"transparent\">\n        <uap:DefaultTile Wide310x150Logo=\"Assets\\Wide310x150Logo.png\"/>\n        <uap:SplashScreen Image=\"Assets\\SplashScreen.png\" />\n      </uap:VisualElements>\n    </Application>\n  </Applications>\n\n  <Capabilities>\n    <Capability Name=\"internetClient\" />\n  </Capabilities>\n</Package>\n"
  },
  {
    "path": "Examples/CodePushDemoAppCpp/windows/CodePushDemoAppCpp/PropertySheet.props",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ImportGroup Label=\"PropertySheets\" />\n  <PropertyGroup Label=\"UserMacros\" />\n  <!--\n    To customize common C++/WinRT project properties: \n    * right-click the project node\n    * expand the Common Properties item\n    * select the C++/WinRT property page\n\n    For more advanced scenarios, and complete documentation, please see:\n    https://github.com/Microsoft/xlang/tree/master/src/package/cppwinrt/nuget \n    -->\n  <PropertyGroup />\n  <ItemDefinitionGroup />\n</Project>\n"
  },
  {
    "path": "Examples/CodePushDemoAppCpp/windows/CodePushDemoAppCpp/ReactPackageProvider.cpp",
    "content": "#include \"pch.h\"\n#include \"ReactPackageProvider.h\"\n#include \"NativeModules.h\"\n\n\nusing namespace winrt::Microsoft::ReactNative;\n\nnamespace winrt::CodePushDemoAppCpp::implementation\n{\n\nvoid ReactPackageProvider::CreatePackage(IReactPackageBuilder const &packageBuilder) noexcept\n{\n    AddAttributedModules(packageBuilder);\n}\n\n} // namespace winrt::CodePushDemoAppCpp::implementation\n"
  },
  {
    "path": "Examples/CodePushDemoAppCpp/windows/CodePushDemoAppCpp/ReactPackageProvider.h",
    "content": "#pragma once\n\n#include \"winrt/Microsoft.ReactNative.h\"\n\nnamespace winrt::CodePushDemoAppCpp::implementation\n{\n    struct ReactPackageProvider : winrt::implements<ReactPackageProvider, winrt::Microsoft::ReactNative::IReactPackageProvider>\n    {\n    public: // IReactPackageProvider\n        void CreatePackage(winrt::Microsoft::ReactNative::IReactPackageBuilder const &packageBuilder) noexcept;\n    };\n} // namespace winrt::CodePushDemoAppCpp::implementation\n"
  },
  {
    "path": "Examples/CodePushDemoAppCpp/windows/CodePushDemoAppCpp/packages.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<packages>\n  <package id=\"Microsoft.Windows.CppWinRT\" version=\"2.0.200615.7\" targetFramework=\"native\" />\n  <package id=\"Microsoft.UI.Xaml\" version=\"2.3.191129002\" targetFramework=\"native\" />\n</packages>\n"
  },
  {
    "path": "Examples/CodePushDemoAppCpp/windows/CodePushDemoAppCpp/pch.cpp",
    "content": "﻿#include \"pch.h\"\n"
  },
  {
    "path": "Examples/CodePushDemoAppCpp/windows/CodePushDemoAppCpp/pch.h",
    "content": "﻿#pragma once\n\n#define NOMINMAX\n\n#include <hstring.h>\n#include <restrictederrorinfo.h>\n#include <unknwn.h>\n#include <windows.h>\n#include <winrt/Windows.ApplicationModel.Activation.h>\n#include <winrt/Windows.Foundation.Collections.h>\n#include <winrt/Windows.Foundation.h>\n#include <winrt/Windows.UI.Xaml.Controls.Primitives.h>\n#include <winrt/Windows.UI.Xaml.Controls.h>\n#include <winrt/Windows.UI.Xaml.Data.h>\n#include <winrt/Windows.UI.Xaml.Interop.h>\n#include <winrt/Windows.UI.Xaml.Markup.h>\n#include <winrt/Windows.UI.Xaml.Navigation.h>\n#include <winrt/Windows.UI.Xaml.h>\n\n#include <winrt/Microsoft.ReactNative.h>\n\n#include <winrt/Microsoft.UI.Xaml.Automation.Peers.h>\n#include <winrt/Microsoft.UI.Xaml.Controls.Primitives.h>\n#include <winrt/Microsoft.UI.Xaml.Controls.h>\n#include <winrt/Microsoft.UI.Xaml.Media.h>\n#include <winrt/Microsoft.UI.Xaml.XamlTypeInfo.h>\n"
  },
  {
    "path": "Examples/CodePushDemoAppCpp/windows/CodePushDemoAppCpp.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.29215.179\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"CodePushDemoAppCpp\", \"CodePushDemoAppCpp\\CodePushDemoAppCpp.vcxproj\", \"{609F44F6-01CF-4270-85A3-09F9CA10B434}\"\n\tProjectSection(ProjectDependencies) = postProject\n\t\t{F7D32BD0-2749-483E-9A0D-1635EF7E3136} = {F7D32BD0-2749-483E-9A0D-1635EF7E3136}\n\tEndProjectSection\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"Folly\", \"..\\node_modules\\react-native-windows\\Folly\\Folly.vcxproj\", \"{A990658C-CE31-4BCC-976F-0FC6B1AF693D}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"ReactCommon\", \"..\\node_modules\\react-native-windows\\ReactCommon\\ReactCommon.vcxproj\", \"{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}\"\n\tProjectSection(ProjectDependencies) = postProject\n\t\t{A990658C-CE31-4BCC-976F-0FC6B1AF693D} = {A990658C-CE31-4BCC-976F-0FC6B1AF693D}\n\tEndProjectSection\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"Chakra\", \"..\\node_modules\\react-native-windows\\Chakra\\Chakra.vcxitems\", \"{C38970C0-5FBF-4D69-90D8-CBAC225AE895}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"Microsoft.ReactNative\", \"..\\node_modules\\react-native-windows\\Microsoft.ReactNative\\Microsoft.ReactNative.vcxproj\", \"{F7D32BD0-2749-483E-9A0D-1635EF7E3136}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"JSI.Shared\", \"..\\node_modules\\react-native-windows\\JSI\\Shared\\JSI.Shared.vcxitems\", \"{0CC28589-39E4-4288-B162-97B959F8B843}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"JSI.Universal\", \"..\\node_modules\\react-native-windows\\JSI\\Universal\\JSI.Universal.vcxproj\", \"{A62D504A-16B8-41D2-9F19-E2E86019E5E4}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"Microsoft.ReactNative.Cxx\", \"..\\node_modules\\react-native-windows\\Microsoft.ReactNative.Cxx\\Microsoft.ReactNative.Cxx.vcxitems\", \"{DA8B35B3-DA00-4B02-BDE6-6A397B3FD46B}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"Common\", \"..\\node_modules\\react-native-windows\\Common\\Common.vcxproj\", \"{FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"ReactNative\", \"ReactNative\", \"{5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"Microsoft.ReactNative.Shared\", \"..\\node_modules\\react-native-windows\\Shared\\Shared.vcxitems\", \"{2049DBE9-8D13-42C9-AE4B-413AE38FFFD0}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"Mso\", \"..\\node_modules\\react-native-windows\\Mso\\Mso.vcxitems\", \"{84E05BFA-CBAF-4F0D-BFB6-4CE85742A57E}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"Include\", \"..\\node_modules\\react-native-windows\\include\\Include.vcxitems\", \"{EF074BA1-2D54-4D49-A28E-5E040B47CD2E}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"CodePush\", \"..\\..\\..\\windows\\CodePush\\CodePush.vcxproj\", \"{A6B6216E-FA3F-45E2-9C8E-40023CCE9132}\"\nEndProject\nGlobal\n\tGlobalSection(SharedMSBuildProjectFiles) = preSolution\n\t\t..\\node_modules\\react-native-windows\\JSI\\Shared\\JSI.Shared.vcxitems*{0cc28589-39e4-4288-b162-97b959f8b843}*SharedItemsImports = 9\n\t\t..\\node_modules\\react-native-windows\\Shared\\Shared.vcxitems*{2049dbe9-8d13-42c9-ae4b-413ae38fffd0}*SharedItemsImports = 9\n\t\t..\\node_modules\\react-native-windows\\Mso\\Mso.vcxitems*{84e05bfa-cbaf-4f0d-bfb6-4ce85742a57e}*SharedItemsImports = 9\n\t\t..\\node_modules\\react-native-windows\\JSI\\Shared\\JSI.Shared.vcxitems*{a62d504a-16b8-41d2-9f19-e2e86019e5e4}*SharedItemsImports = 4\n\t\t..\\node_modules\\react-native-windows\\Chakra\\Chakra.vcxitems*{c38970c0-5fbf-4d69-90d8-cbac225ae895}*SharedItemsImports = 9\n\t\t..\\node_modules\\react-native-windows\\Microsoft.ReactNative.Cxx\\Microsoft.ReactNative.Cxx.vcxitems*{da8b35b3-da00-4b02-bde6-6a397b3fd46b}*SharedItemsImports = 9\n\t\t..\\node_modules\\react-native-windows\\include\\Include.vcxitems*{ef074ba1-2d54-4d49-a28e-5e040b47cd2e}*SharedItemsImports = 9\n\t\t..\\node_modules\\react-native-windows\\Chakra\\Chakra.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4\n\t\t..\\node_modules\\react-native-windows\\Microsoft.ReactNative.Cxx\\Microsoft.ReactNative.Cxx.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4\n\t\t..\\node_modules\\react-native-windows\\Mso\\Mso.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4\n\t\t..\\node_modules\\react-native-windows\\Shared\\Shared.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4\n\tEndGlobalSection\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|ARM = Debug|ARM\n\t\tDebug|ARM64 = Debug|ARM64\n\t\tDebug|x64 = Debug|x64\n\t\tDebug|x86 = Debug|x86\n\t\tRelease|ARM = Release|ARM\n\t\tRelease|ARM64 = Release|ARM64\n\t\tRelease|x64 = Release|x64\n\t\tRelease|x86 = Release|x86\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{609F44F6-01CF-4270-85A3-09F9CA10B434}.Debug|ARM.ActiveCfg = Debug|ARM\n\t\t{609F44F6-01CF-4270-85A3-09F9CA10B434}.Debug|ARM.Build.0 = Debug|ARM\n\t\t{609F44F6-01CF-4270-85A3-09F9CA10B434}.Debug|ARM.Deploy.0 = Debug|ARM\n\t\t{609F44F6-01CF-4270-85A3-09F9CA10B434}.Debug|ARM64.ActiveCfg = Debug|ARM64\n\t\t{609F44F6-01CF-4270-85A3-09F9CA10B434}.Debug|ARM64.Build.0 = Debug|ARM64\n\t\t{609F44F6-01CF-4270-85A3-09F9CA10B434}.Debug|ARM64.Deploy.0 = Debug|ARM64\n\t\t{609F44F6-01CF-4270-85A3-09F9CA10B434}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{609F44F6-01CF-4270-85A3-09F9CA10B434}.Debug|x64.Build.0 = Debug|x64\n\t\t{609F44F6-01CF-4270-85A3-09F9CA10B434}.Debug|x64.Deploy.0 = Debug|x64\n\t\t{609F44F6-01CF-4270-85A3-09F9CA10B434}.Debug|x86.ActiveCfg = Debug|Win32\n\t\t{609F44F6-01CF-4270-85A3-09F9CA10B434}.Debug|x86.Build.0 = Debug|Win32\n\t\t{609F44F6-01CF-4270-85A3-09F9CA10B434}.Debug|x86.Deploy.0 = Debug|Win32\n\t\t{609F44F6-01CF-4270-85A3-09F9CA10B434}.Release|ARM.ActiveCfg = Release|ARM\n\t\t{609F44F6-01CF-4270-85A3-09F9CA10B434}.Release|ARM.Build.0 = Release|ARM\n\t\t{609F44F6-01CF-4270-85A3-09F9CA10B434}.Release|ARM.Deploy.0 = Release|ARM\n\t\t{609F44F6-01CF-4270-85A3-09F9CA10B434}.Release|ARM64.ActiveCfg = Release|ARM64\n\t\t{609F44F6-01CF-4270-85A3-09F9CA10B434}.Release|ARM64.Build.0 = Release|ARM64\n\t\t{609F44F6-01CF-4270-85A3-09F9CA10B434}.Release|ARM64.Deploy.0 = Release|ARM64\n\t\t{609F44F6-01CF-4270-85A3-09F9CA10B434}.Release|x64.ActiveCfg = Release|x64\n\t\t{609F44F6-01CF-4270-85A3-09F9CA10B434}.Release|x64.Build.0 = Release|x64\n\t\t{609F44F6-01CF-4270-85A3-09F9CA10B434}.Release|x64.Deploy.0 = Release|x64\n\t\t{609F44F6-01CF-4270-85A3-09F9CA10B434}.Release|x86.ActiveCfg = Release|Win32\n\t\t{609F44F6-01CF-4270-85A3-09F9CA10B434}.Release|x86.Build.0 = Release|Win32\n\t\t{609F44F6-01CF-4270-85A3-09F9CA10B434}.Release|x86.Deploy.0 = Release|Win32\n\t\t{A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|ARM.ActiveCfg = Debug|ARM\n\t\t{A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|ARM.Build.0 = Debug|ARM\n\t\t{A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|ARM64.ActiveCfg = Debug|ARM64\n\t\t{A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|ARM64.Build.0 = Debug|ARM64\n\t\t{A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x64.Build.0 = Debug|x64\n\t\t{A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x86.ActiveCfg = Debug|Win32\n\t\t{A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x86.Build.0 = Debug|Win32\n\t\t{A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|ARM.ActiveCfg = Release|ARM\n\t\t{A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|ARM.Build.0 = Release|ARM\n\t\t{A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|ARM64.ActiveCfg = Release|ARM64\n\t\t{A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|ARM64.Build.0 = Release|ARM64\n\t\t{A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x64.ActiveCfg = Release|x64\n\t\t{A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x64.Build.0 = Release|x64\n\t\t{A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x86.ActiveCfg = Release|Win32\n\t\t{A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x86.Build.0 = Release|Win32\n\t\t{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|ARM.ActiveCfg = Debug|ARM\n\t\t{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|ARM.Build.0 = Debug|ARM\n\t\t{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|ARM64.ActiveCfg = Debug|ARM64\n\t\t{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|ARM64.Build.0 = Debug|ARM64\n\t\t{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|x64.Build.0 = Debug|x64\n\t\t{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|x86.ActiveCfg = Debug|Win32\n\t\t{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|x86.Build.0 = Debug|Win32\n\t\t{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|ARM.ActiveCfg = Release|ARM\n\t\t{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|ARM.Build.0 = Release|ARM\n\t\t{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|ARM64.ActiveCfg = Release|ARM64\n\t\t{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|ARM64.Build.0 = Release|ARM64\n\t\t{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|x64.ActiveCfg = Release|x64\n\t\t{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|x64.Build.0 = Release|x64\n\t\t{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|x86.ActiveCfg = Release|Win32\n\t\t{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|x86.Build.0 = Release|Win32\n\t\t{F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|ARM.ActiveCfg = Debug|ARM\n\t\t{F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|ARM.Build.0 = Debug|ARM\n\t\t{F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|ARM64.ActiveCfg = Debug|ARM64\n\t\t{F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|ARM64.Build.0 = Debug|ARM64\n\t\t{F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|x64.Build.0 = Debug|x64\n\t\t{F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|x86.ActiveCfg = Debug|Win32\n\t\t{F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|x86.Build.0 = Debug|Win32\n\t\t{F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|ARM.ActiveCfg = Release|ARM\n\t\t{F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|ARM.Build.0 = Release|ARM\n\t\t{F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|ARM64.ActiveCfg = Release|ARM64\n\t\t{F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|ARM64.Build.0 = Release|ARM64\n\t\t{F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|x64.ActiveCfg = Release|x64\n\t\t{F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|x64.Build.0 = Release|x64\n\t\t{F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|x86.ActiveCfg = Release|Win32\n\t\t{F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|x86.Build.0 = Release|Win32\n\t\t{A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Debug|ARM.ActiveCfg = Debug|ARM\n\t\t{A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Debug|ARM.Build.0 = Debug|ARM\n\t\t{A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Debug|ARM64.ActiveCfg = Debug|ARM64\n\t\t{A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Debug|ARM64.Build.0 = Debug|ARM64\n\t\t{A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Debug|x64.Build.0 = Debug|x64\n\t\t{A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Debug|x86.ActiveCfg = Debug|Win32\n\t\t{A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Debug|x86.Build.0 = Debug|Win32\n\t\t{A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Release|ARM.ActiveCfg = Release|ARM\n\t\t{A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Release|ARM.Build.0 = Release|ARM\n\t\t{A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Release|ARM64.ActiveCfg = Release|ARM64\n\t\t{A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Release|ARM64.Build.0 = Release|ARM64\n\t\t{A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Release|x64.ActiveCfg = Release|x64\n\t\t{A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Release|x64.Build.0 = Release|x64\n\t\t{A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Release|x86.ActiveCfg = Release|Win32\n\t\t{A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Release|x86.Build.0 = Release|Win32\n\t\t{FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|ARM.ActiveCfg = Debug|ARM\n\t\t{FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|ARM.Build.0 = Debug|ARM\n\t\t{FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|ARM64.ActiveCfg = Debug|ARM64\n\t\t{FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|ARM64.Build.0 = Debug|ARM64\n\t\t{FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|x64.Build.0 = Debug|x64\n\t\t{FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|x86.ActiveCfg = Debug|Win32\n\t\t{FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|x86.Build.0 = Debug|Win32\n\t\t{FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|ARM.ActiveCfg = Release|ARM\n\t\t{FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|ARM.Build.0 = Release|ARM\n\t\t{FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|ARM64.ActiveCfg = Release|ARM64\n\t\t{FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|ARM64.Build.0 = Release|ARM64\n\t\t{FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|x64.ActiveCfg = Release|x64\n\t\t{FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|x64.Build.0 = Release|x64\n\t\t{FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|x86.ActiveCfg = Release|Win32\n\t\t{FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|x86.Build.0 = Release|Win32\n\t\t{A6B6216E-FA3F-45E2-9C8E-40023CCE9132}.Debug|ARM.ActiveCfg = Debug|ARM\n\t\t{A6B6216E-FA3F-45E2-9C8E-40023CCE9132}.Debug|ARM.Build.0 = Debug|ARM\n\t\t{A6B6216E-FA3F-45E2-9C8E-40023CCE9132}.Debug|ARM64.ActiveCfg = Debug|ARM64\n\t\t{A6B6216E-FA3F-45E2-9C8E-40023CCE9132}.Debug|ARM64.Build.0 = Debug|ARM64\n\t\t{A6B6216E-FA3F-45E2-9C8E-40023CCE9132}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{A6B6216E-FA3F-45E2-9C8E-40023CCE9132}.Debug|x64.Build.0 = Debug|x64\n\t\t{A6B6216E-FA3F-45E2-9C8E-40023CCE9132}.Debug|x86.ActiveCfg = Debug|Win32\n\t\t{A6B6216E-FA3F-45E2-9C8E-40023CCE9132}.Debug|x86.Build.0 = Debug|Win32\n\t\t{A6B6216E-FA3F-45E2-9C8E-40023CCE9132}.Release|ARM.ActiveCfg = Release|ARM\n\t\t{A6B6216E-FA3F-45E2-9C8E-40023CCE9132}.Release|ARM.Build.0 = Release|ARM\n\t\t{A6B6216E-FA3F-45E2-9C8E-40023CCE9132}.Release|ARM64.ActiveCfg = Release|ARM64\n\t\t{A6B6216E-FA3F-45E2-9C8E-40023CCE9132}.Release|ARM64.Build.0 = Release|ARM64\n\t\t{A6B6216E-FA3F-45E2-9C8E-40023CCE9132}.Release|x64.ActiveCfg = Release|x64\n\t\t{A6B6216E-FA3F-45E2-9C8E-40023CCE9132}.Release|x64.Build.0 = Release|x64\n\t\t{A6B6216E-FA3F-45E2-9C8E-40023CCE9132}.Release|x86.ActiveCfg = Release|Win32\n\t\t{A6B6216E-FA3F-45E2-9C8E-40023CCE9132}.Release|x86.Build.0 = Release|Win32\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(NestedProjects) = preSolution\n\t\t{A990658C-CE31-4BCC-976F-0FC6B1AF693D} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}\n\t\t{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}\n\t\t{C38970C0-5FBF-4D69-90D8-CBAC225AE895} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}\n\t\t{F7D32BD0-2749-483E-9A0D-1635EF7E3136} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}\n\t\t{0CC28589-39E4-4288-B162-97B959F8B843} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}\n\t\t{A62D504A-16B8-41D2-9F19-E2E86019E5E4} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}\n\t\t{DA8B35B3-DA00-4B02-BDE6-6A397B3FD46B} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}\n\t\t{FCA38F3C-7C73-4C47-BE4E-32F77FA8538D} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}\n\t\t{2049DBE9-8D13-42C9-AE4B-413AE38FFFD0} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}\n\t\t{84E05BFA-CBAF-4F0D-BFB6-4CE85742A57E} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}\n\t\t{EF074BA1-2D54-4D49-A28E-5E040B47CD2E} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {D43FAD39-F619-437D-BB40-04A3982ACB6A}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "Examples/create-app.js",
    "content": "/*\nThe script serves to generate CodePushified React Native app to reproduce issues or for testing purposes.\n\nNOTE: Use CodePushDemoApp and CodePushDemoAppCpp as reference how to implement CodePush in your app. For creating a working demo app\nfollow steps bellow.\n\nRequirements:\n    1. npm i -g react-native-cli\n    2. npm i -g appcenter-cli\n    3. appcenter login\n    4. If you use this script on macOS for react-native v0.60+ then you need to have CocoaPods installed. Use this command to (re)install CocoaPods:\n        sudo gem install cocoapods -n /usr/local/bin\n\nUsage: node create-app.js <appName> <reactNativeVersion> <reactNativeCodePushVersion>\n    1. node create-app.js \n    2. node create-app.js myapp\n    3. node create-app.js myapp react-native@0.62 react-native-code-push@6.1.0 \n    4. node create-app.js myapp react-native@latest Microsoft/react-native-code-push\n\nParameters:\n    1. <appName> - CodePushDemoAppTest\n    2. <reactNativeVersion> - react-native@latest\n    3. <reactNativeCodePushVersion> - react-native-code-push@latest\n*/\n\nconst fs = require('fs');\nconst path = require('path');\nconst nexpect = require('./nexpect');\nconst child_process = require('child_process');\nconst execSync = child_process.execSync;\n\nconst args = process.argv.slice(2);\nconst appName = args[0] || 'CodePushDemoAppTest';\n\nif (fs.existsSync(appName)) {\n    console.error(`Folder with name \"${appName}\" already exists! Please delete`);\n    process.exit();\n}\n\n\nconst appNameAndroid = `${appName}-android`;\nconst appNameIOS = `${appName}-ios`;\nlet owner = null;\nconst reactNativeVersion = args[1] || `react-native@${execCommand('npm view react-native version')}`.trim();\nconst reactNativeVersionIsLowerThanV049 = isReactNativeVersionLowerThan(49);\nconst reactNativeCodePushVersion = args[2] || `react-native-code-push@${execCommand('npm view react-native-code-push version')}`.trim();\n\nconst reactNativeVersionIsLowerThanV073 = isReactNativeVersionLowerThan(73)\nif (!isReactNativeVersionLowerThan(60) && process.platform === \"darwin\") {\n    try {\n        console.log(\"Verify that CocoaPods installed\");\n        execCommand(\"pod --version\");\n        console.log(\"CocoaPods has installed\");\n    } catch {\n        console.error(`'CocoaPods' are required to run the script, you can install it with\\n'sudo gem install cocoapods -n /usr/local/bin'\\ncommand`);\n        process.exit();\n    }\n}\n\nconsole.log(`App name: ${appName}`);\nconsole.log(`React Native version: ${reactNativeVersion}`);\nconsole.log(`React Native Module for CodePush version: ${reactNativeCodePushVersion} \\n`);\n\nlet androidStagingDeploymentKey = null;\nlet iosStagingDeploymentKey = null;\n\n\n\n//GENERATE START\ncreateCodePushApp(appNameAndroid, 'Android');\ncreateCodePushApp(appNameIOS, 'iOS');\n\ngeneratePlainReactNativeApp(appName, reactNativeVersion);\nprocess.chdir(appName);\ninstallCodePush(reactNativeCodePushVersion);\nlinkCodePush(androidStagingDeploymentKey, iosStagingDeploymentKey);\n//GENERATE END\n\n\n\nfunction createCodePushApp(name, os) {\n    try {\n        console.log(`Creating CodePush app \"${name}\" to release updates for ${os}...`);\n        try {\n            const appResult = execCommand(`appcenter apps create -d ${name} -n ${name} -o ${os} -p React-Native --output json`);\n            const app = JSON.parse(appResult);\n            owner = app.owner.name;\n            console.log(`App \"${name}\" has been created \\n`);\n        } catch (e) {\n            console.error(`Error: Unable to create CodePush app. Please check that you haven't application with \"${name}\" name on portal.`,);\n            console.error(\"Error: \", e.toString());\n        }\n        execCommand(`appcenter codepush deployment add -a ${owner}/${name} Staging`);\n    } catch (e) {\n        console.error(\"Error\", e.toString());\n    }\n\n    try {\n        const deploymentKeysResult = execCommand(`appcenter codepush deployment list -a ${owner}/${name} -k --output json`);\n        const deploymentKeys = JSON.parse(deploymentKeysResult);\n        const stagingDeploymentKey = deploymentKeys[0][1];\n        console.log(`Deployment key for ${os}: ${stagingDeploymentKey}`);\n        console.log(`Use \"appcenter codepush release-react ${owner}/${name}\" command to release updates for ${os} \\n`);\n\n        switch (os) {\n            case 'Android':\n                androidStagingDeploymentKey = stagingDeploymentKey;\n                break;\n            case 'iOS':\n                iosStagingDeploymentKey = stagingDeploymentKey;\n                break;\n        }\n    } catch (e) {\n        console.error(\"Error: Unable to load deployment keys\");\n        console.error(\"Error: \", e.toString());\n    }\n\n}\n\nfunction generatePlainReactNativeApp(appName, reactNativeVersion) {\n    console.log(`Installing React Native...`);\n    execCommand(`react-native init ${appName} --version ${reactNativeVersion.split('@')[1]}`);\n    console.log(`React Native has been installed \\n`);\n}\n\nfunction installCodePush(reactNativeCodePushVersion) {\n    console.log(`Installing React Native Module for CodePush...`);\n    execCommand(`npm i ${reactNativeCodePushVersion}`);\n    console.log(`React Native Module for CodePush has been installed \\n`);\n}\n\nfunction linkCodePush(androidStagingDeploymentKey, iosStagingDeploymentKey) {\n    console.log(`Linking React Native Module for CodePush...`);\n    if (isReactNativeVersionLowerThan(60)) {\n        nexpect.spawn(`react-native link react-native-code-push`)\n            .wait(\"What is your CodePush deployment key for Android (hit <ENTER> to ignore)\")\n            .sendline(androidStagingDeploymentKey)\n            .wait(\"What is your CodePush deployment key for iOS (hit <ENTER> to ignore)\")\n            .sendline(iosStagingDeploymentKey)\n            .run(function (err) {\n                if (!err) {\n                    console.log(`React Native Module for CodePush has been linked \\n`);\n                    setupAssets();\n                }\n                else {\n                    console.log(err);\n                }\n            });\n    } else {\n        androidSetup();\n        if (process.platform === 'darwin') {\n            iosSetup();\n        } else {\n            console.log('Your OS is not \"Mac OS\" so the iOS application will not be configured')\n        }\n        setupAssets();\n        console.log(`React Native Module for CodePush has been linked \\n`);\n    }\n}\n\nfunction setupAssets() {\n    let fileToEdit;\n    if (reactNativeVersionIsLowerThanV049) {\n        fs.unlinkSync('./index.ios.js');\n        fs.unlinkSync('./index.android.js');\n\n        fs.writeFileSync('demo.js', fs.readFileSync('../CodePushDemoApp-pre0.49/demo.js'));\n        fs.writeFileSync('index.ios.js', fs.readFileSync('../CodePushDemoApp-pre0.49/index.ios.js'));\n        fs.writeFileSync('index.android.js', fs.readFileSync('../CodePushDemoApp-pre0.49/index.android.js'));\n        fileToEdit = 'demo.js'\n    } else {\n        fs.writeFileSync('index.js', fs.readFileSync(__dirname + '/CodePushDemoApp/index.js'));\n        fs.writeFileSync('App.js', fs.readFileSync(__dirname + '/CodePushDemoApp/App.js'));\n        fileToEdit = 'index.js'\n    }\n\n    copyRecursiveSync(__dirname + '/CodePushDemoApp/images', './images');\n\n    fs.readFile(fileToEdit, 'utf8', function (err, data) {\n        if (err) {\n            return console.error(err);\n        }\n        const result = data.replace(/CodePushDemoApp/g, appName);\n\n        fs.writeFile(fileToEdit, result, 'utf8', function (err) {\n            if (err) return console.error(err);\n\n            if (!/^win/.test(process.platform)) {\n                optimizeToTestInDebugMode();\n                process.chdir('../');\n                grantAccess(appName);\n            }\n            console.log(`\\nReact Native app \"${appName}\" has been generated and CodePushified!`);\n            process.exit();\n        });\n    });\n}\n\nfunction optimizeToTestInDebugMode() {\n    const rnXcodeShLocationFolder = 'scripts';\n    try {\n        const rnVersions = JSON.parse(execCommand(`npm view react-native versions --json`));\n        const currentRNversion = JSON.parse(fs.readFileSync('./package.json'))['dependencies']['react-native'];\n        if (rnVersions.indexOf(currentRNversion) > -1 &&\n            rnVersions.indexOf(currentRNversion) < rnVersions.indexOf(\"0.46.0-rc.0\")) {\n            rnXcodeShLocationFolder = 'packager';\n        }\n    } catch (e) { }\n\n    const rnXcodeShPath = `node_modules/react-native/${rnXcodeShLocationFolder}/react-native-xcode.sh`;\n    // Replace \"if [[ \"$PLATFORM_NAME\" == *simulator ]]; then\" with \"if false; then\" to force bundling\n    execCommand(`sed -ie 's/if \\\\[\\\\[ \"\\$PLATFORM_NAME\" == \\\\*simulator \\\\]\\\\]; then/if false; then/' ${rnXcodeShPath}`);\n    execCommand(`perl -i -p0e 's/#ifdef DEBUG.*?#endif/jsCodeLocation = [CodePush bundleURL];/s' ios/${appName}/${getAppDelegateName()}`);\n    reactNativeVersionIsLowerThanV073 && execCommand(`sed -ie 's/targetName.toLowerCase().contains(\"release\")/true/' node_modules/react-native/react.gradle`);\n}\n\nfunction grantAccess(folderPath) {\n    execCommand('chown -R `whoami` ' + folderPath);\n}\n\nfunction copyRecursiveSync(src, dest) {\n    const exists = fs.existsSync(src);\n    const stats = exists && fs.statSync(src);\n    const isDirectory = exists && stats.isDirectory();\n    if (exists && isDirectory) {\n        fs.mkdirSync(dest);\n        fs.readdirSync(src).forEach(function (childItemName) {\n            copyRecursiveSync(path.join(src, childItemName),\n                path.join(dest, childItemName));\n        });\n    } else {\n        fs.linkSync(src, dest);\n    }\n}\n\nfunction isReactNativeVersionLowerThan(version) {\n    if (!reactNativeVersion ||\n        reactNativeVersion == \"react-native@latest\" ||\n        reactNativeVersion == \"react-native@next\")\n        return false;\n\n    const reactNativeVersionNumberString = reactNativeVersion.split(\"@\")[1];\n    return reactNativeVersionNumberString.split('.')[1] < version;\n}\n\n// Configuring android applications for react-native version higher than 0.60\nfunction androidSetup() {\n    const buildGradlePath = path.join('android', 'app', 'build.gradle');\n    const settingsGradlePath = path.join('android', 'settings.gradle');\n    const mainApplicationType = reactNativeVersionIsLowerThanV073 ? 'java' : 'kt';\n    const mainApplicationPath = path.join('android', 'app', 'src', 'main', 'java', 'com', appName, `MainApplication.${mainApplicationType}`);\n    const stringsResourcesPath = path.join('android', 'app', 'src', 'main', 'res', 'values', 'strings.xml');\n\n    let stringsResourcesContent = fs.readFileSync(stringsResourcesPath, \"utf8\");\n    const insertAfterString = \"<resources>\";\n    const deploymentKeyString = `\\t<string moduleConfig=\"true\" name=\"CodePushDeploymentKey\">${androidStagingDeploymentKey || \"deployment-key-here\"}</string>`;\n    stringsResourcesContent = stringsResourcesContent.replace(insertAfterString, `${insertAfterString}\\n${deploymentKeyString}`);\n    fs.writeFileSync(stringsResourcesPath, stringsResourcesContent);\n\n    let buildGradleContents = fs.readFileSync(buildGradlePath, \"utf8\");\n    const reactGradleLink = buildGradleContents.match(/\\napply from: [\"'].*?react\\.gradle[\"']/);\n    const codePushGradleLink = `\\napply from: \"../../node_modules/react-native-code-push/android/codepush.gradle\"`;\n    if (reactGradleLink != null) {\n        buildGradleContents = buildGradleContents.replace(reactGradleLink[0],\n            `${reactGradleLink[0]}${codePushGradleLink}`);\n        fs.writeFileSync(buildGradlePath, buildGradleContents);\n    }\n    // react.gradle script removed from 0.71 thus this workaround\n    else {\n        const appPluginLastLine = buildGradleContents.match(/apply plugin: \"com.facebook.react\"/)[0];\n        buildGradleContents = buildGradleContents.replace(appPluginLastLine, `${appPluginLastLine}${codePushGradleLink}`)\n        fs.writeFileSync(buildGradlePath, buildGradleContents);\n    }\n\n    let settingsGradleContents = fs.readFileSync(settingsGradlePath, \"utf8\");\n    const settingsGradleInclude = \"include \\':app\\'\";\n    const codePushProjectImport = `':react-native-code-push'\\nproject(':react-native-code-push').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-code-push/android/app')`;\n    settingsGradleContents = settingsGradleContents.replace(settingsGradleInclude,\n        `${settingsGradleInclude}, ${codePushProjectImport}`);\n    fs.writeFileSync(settingsGradlePath, settingsGradleContents);\n\n    let importCodePush = `\\nimport com.microsoft.codepush.react.CodePush;`;\n    let reactNativeHostInstantiationImport = \"import android.app.Application;\";\n    let mainApplicationContents = fs.readFileSync(mainApplicationPath, \"utf8\");\n    let getJSBundleFileOverride = \"\";\n    let reactNativeHostInstantiation = \"\";\n\n    // handle react-native version with java\n    if (reactNativeVersionIsLowerThanV073) {\n        reactNativeHostInstantiation = \"new ReactNativeHost(this) {\";\n\n        getJSBundleFileOverride = `\n        @Override\n        protected String getJSBundleFile(){\n            return CodePush.getJSBundleFile();\n        }\n        `;\n    }\n    // handle react-native version with kotlin\n    else {\n        reactNativeHostInstantiation = \"object : DefaultReactNativeHost(this) {\"\n        getJSBundleFileOverride = `\n         override fun getJSBundleFile(): String {\n            return CodePush.getJSBundleFile() \n        }\n        `;\n        importCodePush = importCodePush.replace(';', '');\n        reactNativeHostInstantiationImport = reactNativeHostInstantiationImport.replace(';', '');\n    }\n    mainApplicationContents = mainApplicationContents.replace(reactNativeHostInstantiation,\n        `${reactNativeHostInstantiation}${getJSBundleFileOverride}`);\n\n    mainApplicationContents = mainApplicationContents.replace(reactNativeHostInstantiationImport,\n        `${reactNativeHostInstantiationImport}${importCodePush}`);\n    fs.writeFileSync(mainApplicationPath, mainApplicationContents);\n}\n\nfunction getAppDelegateName() { return fs.readdirSync(path.join('ios', appName)).find(file => file === ('AppDelegate.mm') || file === 'AppDelegate.m') };\n\n// Configuring ios applications for react-native version higher than 0.60\nfunction iosSetup() {\n    const plistPath = path.join('ios', appName, 'Info.plist');\n\n    const appDelegatePath = path.join('ios', appName, getAppDelegateName());\n\n    let plistContents = fs.readFileSync(plistPath, \"utf8\");\n\n    const dictPlistTag = `</dict>\\n</plist>`;\n\n    const codePushDeploymentKey = iosStagingDeploymentKey || 'deployment-key-here';\n    plistContents = plistContents.replace(dictPlistTag,\n        `\\t<key>CodePushDeploymentKey</key>\\n\\t<string>${codePushDeploymentKey}</string>${dictPlistTag}`);\n    fs.writeFileSync(plistPath, plistContents);\n\n    let appDelegateContents = fs.readFileSync(appDelegatePath, \"utf8\");\n    const appDelegateHeaderImportStatement = `#import \"AppDelegate.h\"`;\n    const codePushHeaderImportStatementFormatted = `\\n#import <CodePush/CodePush.h>`;\n    appDelegateContents = appDelegateContents.replace(appDelegateHeaderImportStatement,\n        `${appDelegateHeaderImportStatement}${codePushHeaderImportStatementFormatted}`);\n\n\n    const oldBundleUrl = \"[[NSBundle mainBundle] URLForResource:@\\\"main\\\" withExtension:@\\\"jsbundle\\\"]\";\n    const codePushBundleUrl = \"[CodePush bundleURL]\";\n    appDelegateContents = appDelegateContents.replace(oldBundleUrl, codePushBundleUrl);\n    fs.writeFileSync(appDelegatePath, appDelegateContents);\n    execCommand(`cd ios && pod install && cd ..`);\n}\n\nfunction execCommand(command) {\n    console.log(`\\n\\x1b[2m${command}\\x1b[0m\\n`);\n    const result = execSync(command).toString();\n    return result;\n}\n"
  },
  {
    "path": "Examples/nexpect.js",
    "content": "/*\n * nexpect.js: Top-level include for the `nexpect` module.\n *\n * (C) 2011, Elijah Insua, Marak Squires, Charlie Robbins.\n *\n */\n\nvar spawn = require('child_process').spawn;\nvar util = require('util');\nvar AssertionError = require('assert').AssertionError;\n\nfunction chain (context) {\n  return {\n    expect: function (expectation) {\n      var _expect = function _expect (data) {\n        return testExpectation(data, expectation);\n      };\n\n      _expect.shift = true;\n      _expect.expectation = expectation;\n      _expect.description = '[expect] ' + expectation;\n      _expect.requiresInput = true;\n      context.queue.push(_expect);\n\n      return chain(context);\n    },\n    wait: function (expectation, callback) {\n      var _wait = function _wait (data) {\n        var val = testExpectation(data, expectation);\n        if (val === true && typeof callback === 'function') {\n          callback(data);\n        }\n        return val;\n      };\n\n      _wait.shift = false;\n      _wait.expectation = expectation;\n      _wait.description = '[wait] ' + expectation;\n      _wait.requiresInput = true;\n      context.queue.push(_wait);\n      return chain(context);\n    },\n    sendline: function (line) {\n      var _sendline = function _sendline () {\n        context.process.stdin.write(line + '\\n');\n\n        if (context.verbose) {\n          process.stdout.write(line + '\\n');\n        }\n      };\n\n      _sendline.shift = true;\n      _sendline.description = '[sendline] ' + line;\n      _sendline.requiresInput = false;\n      context.queue.push(_sendline);\n      return chain(context);\n    },\n    sendEof: function() {\n      var _sendEof = function _sendEof () {\n        context.process.stdin.destroy();\n      };\n      _sendEof.shift = true;\n      _sendEof.description = '[sendEof]';\n      _sendEof.requiresInput = false;\n      context.queue.push(_sendEof);\n      return chain(context);\n    },\n    run: function (callback) {\n      var errState = null,\n          responded = false,\n          stdout = [],\n          options;\n\n      //\n      // **onError**\n      //\n      // Helper function to respond to the callback with a\n      // specified error. Kills the child process if necessary.\n      //\n      function onError (err, kill) {\n        if (errState || responded) {\n          return;\n        }\n\n        errState = err;\n        responded = true;\n\n        if (kill) {\n          try { context.process.kill(); }\n          catch (ex) { }\n        }\n\n        callback(err);\n      }\n\n      //\n      // **validateFnType**\n      //\n      // Helper function to validate the `currentFn` in the\n      // `context.queue` for the target chain.\n      //\n      function validateFnType (currentFn) {\n        if (typeof currentFn !== 'function') {\n          //\n          // If the `currentFn` is not a function, short-circuit with an error.\n          //\n          onError(new Error('Cannot process non-function on nexpect stack.'), true);\n          return false;\n        }\n        else if (['_expect', '_sendline', '_wait', '_sendEof'].indexOf(currentFn.name) === -1) {\n          //\n          // If the `currentFn` is a function, but not those set by `.sendline()` or\n          // `.expect()` then short-circuit with an error.\n          //\n          onError(new Error('Unexpected context function name: ' + currentFn.name), true);\n          return false;\n        }\n\n        return true;\n      }\n\n      //\n      // **evalContext**\n      //\n      // Core evaluation logic that evaluates the next function in\n      // `context.queue` against the specified `data` where the last\n      // function run had `name`.\n      //\n      function evalContext (data, name) {\n        var currentFn = context.queue[0];\n\n        if (!currentFn || (name === '_expect' && currentFn.name === '_expect')) {\n          //\n          // If there is nothing left on the context or we are trying to\n          // evaluate two consecutive `_expect` functions, return.\n          //\n          return;\n        }\n\n        if (currentFn.shift) {\n          context.queue.shift();\n        }\n\n        if (!validateFnType(currentFn)) {\n          return;\n        }\n\n        if (currentFn.name === '_expect') {\n          //\n          // If this is an `_expect` function, then evaluate it and attempt\n          // to evaluate the next function (in case it is a `_sendline` function).\n          //\n          return currentFn(data) === true ?\n            evalContext(data, '_expect') :\n            onError(createExpectationError(currentFn.expectation, data), true);\n        }\n        else if (currentFn.name === '_wait') {\n          //\n          // If this is a `_wait` function, then evaluate it and if it returns true,\n          // then evaluate the function (in case it is a `_sendline` function).\n          //\n          if (currentFn(data) === true) {\n            context.queue.shift();\n            evalContext(data, '_expect');\n          }\n        }\n        else {\n          //\n          // If the `currentFn` is any other function then evaluate it\n          //\n          currentFn();\n\n          // Evaluate the next function if it does not need input\n          var nextFn = context.queue[0];\n          if (nextFn && !nextFn.requiresInput)\n            evalContext(data);\n        }\n      }\n\n      //\n      // **onLine**\n      //\n      // Preprocesses the `data` from `context.process` on the\n      // specified `context.stream` and then evaluates the processed lines:\n      //\n      // 1. Stripping ANSI colors (if necessary)\n      // 2. Removing case sensitivity (if necessary)\n      // 3. Splitting `data` into multiple lines.\n      //\n      function onLine (data) {\n        data = data.toString();\n\n        if (context.stripColors) {\n          data = data.replace(/\\u001b\\[\\d{0,2}m/g, '');\n        }\n\n        if (context.ignoreCase) {\n          data = data.toLowerCase();\n        }\n\n        var lines = data.split('\\n').filter(function (line) { return line.length > 0; });\n        stdout = stdout.concat(lines);\n\n        while (lines.length > 0) {\n          evalContext(lines.shift(), null);\n        }\n      }\n\n      //\n      // **flushQueue**\n      //\n      // Helper function which flushes any remaining functions from\n      // `context.queue` and responds to the `callback` accordingly.\n      //\n      function flushQueue () {\n        var remainingQueue = context.queue.slice(),\n            currentFn = context.queue.shift(),\n            lastLine = stdout[stdout.length - 1];\n\n        if (!lastLine) {\n          onError(createUnexpectedEndError(\n            'No data from child with non-empty queue.', remainingQueue));\n          return false;\n        }\n        else if (context.queue.length > 0) {\n          onError(createUnexpectedEndError(\n            'Non-empty queue on spawn exit.', remainingQueue));\n          return false;\n        }\n        else if (!validateFnType(currentFn)) {\n          // onError was called\n          return false;\n        }\n        else if (currentFn.name === '_sendline') {\n          onError(new Error('Cannot call sendline after the process has exited'));\n          return false;\n        }\n        else if (currentFn.name === '_wait' || currentFn.name === '_expect') {\n          if (currentFn(lastLine) !== true) {\n            onError(createExpectationError(currentFn.expectation, lastLine));\n            return false;\n          }\n        }\n\n        return true;\n      }\n\n      //\n      // **onData**\n      //\n      // Helper function for writing any data from a stream\n      // to `process.stdout`.\n      //\n      function onData (data) {\n        process.stdout.write(data);\n      }\n\n      options = {\n        cwd: context.cwd,\n        env: context.env\n      };\n\n      //\n      // Spawn the child process and begin processing the target\n      // stream for this chain.\n      //\n      if (!/^win/.test(process.platform)) {\n        context.process = spawn(context.command, context.params, options);\n      } else {\n        context.process = spawn('cmd', ['/c', `${context.command}`].concat(context.params), options);\n      }\n\n      if (context.verbose) {\n        context.process.stdout.on('data', onData);\n        context.process.stderr.on('data', onData);\n      }\n\n      if (context.stream === 'all') {\n        context.process.stdout.on('data', onLine);\n        context.process.stderr.on('data', onLine);\n      } else {\n        context.process[context.stream].on('data', onLine);\n      }\n\n      context.process.on('error', onError);\n\n      //\n      // When the process exits, check the output `code` and `signal`,\n      // flush `context.queue` (if necessary) and respond to the callback\n      // appropriately.\n      //\n      context.process.on('close', function (code, signal) {\n        if (code === 127) {\n          // XXX(sam) Not how node works (anymore?), 127 is what /bin/sh returns,\n          // but it appears node does not, or not in all conditions, blithely\n          // return 127 to user, it emits an 'error' from the child_process.\n\n          //\n          // If the response code is `127` then `context.command` was not found.\n          //\n          return onError(new Error('Command not found: ' + context.command));\n        }\n        else if (context.queue.length && !flushQueue()) {\n          // if flushQueue returned false, onError was called\n          return;\n        }\n\n        callback(null, stdout, signal || code);\n      });\n\n      return context.process;\n    }\n  };\n}\n\nfunction testExpectation(data, expectation) {\n  if (util.isRegExp(expectation)) {\n    return expectation.test(data);\n  } else {\n    return data.indexOf(expectation) > -1;\n  }\n}\n\nfunction createUnexpectedEndError(message, remainingQueue) {\n  var desc = remainingQueue.map(function(it) { return it.description; });\n  var msg = message + '\\n' + desc.join('\\n');\n  return new AssertionError({\n    message: msg,\n    expected: [],\n    actual: desc\n  });\n}\n\nfunction createExpectationError(expected, actual) {\n  var expectation;\n  if (util.isRegExp(expected))\n    expectation = 'to match ' + expected;\n  else\n    expectation = 'to contain ' + JSON.stringify(expected);\n\n  var err = new AssertionError({\n    message: util.format('expected %j %s', actual, expectation),\n    actual: actual,\n    expected: expected\n  });\n  return err;\n}\n\nfunction nspawn (command, params, options) {\n  if (arguments.length === 2) {\n    if (Array.isArray(arguments[1])) {\n      options = {};\n    }\n    else {\n      options = arguments[1];\n      params = null;\n    }\n  }\n\n  if (Array.isArray(command)) {\n    params  = command;\n    command = params.shift();\n  }\n  else if (typeof command === 'string') {\n    command = command.split(' ');\n    params  = params || command.slice(1);\n    command = command[0];\n  }\n\n  options = options || {};\n  context = {\n    command: command,\n    cwd: options.cwd || undefined,\n    env: options.env || undefined,\n    ignoreCase: options.ignoreCase,\n    params: params,\n    queue: [],\n    stream: options.stream || 'stdout',\n    stripColors: options.stripColors,\n    verbose: options.verbose\n  };\n\n  return chain(context);\n}\n\n//\n// Export the core `nspawn` function as well as `nexpect.nspawn` for\n// backwards compatibility.\n//\nmodule.exports.spawn  = nspawn;\nmodule.exports.nspawn = {\n  spawn: nspawn\n};\n"
  },
  {
    "path": "LICENSE.md",
    "content": "Microsoft CodePush Plugin for React Native\n\nCopyright (c) Microsoft Corporation\n\nAll rights reserved. \n\nMIT License\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
  },
  {
    "path": "README.md",
    "content": "# Archiving this repository\n\nVisual Studio App Center was retired on March 31, 2025, except for its Analytics and Diagnostics features. You can learn more about the retirement and the Analytics and Diagnostics extension [here](https://aka.ms/appcenter/retire). CodePush, along with other App Center features, was also retired on March 31, 2025. Consequently, we are archiving this repository.\n\n---\n\n[![appcenterbanner](https://user-images.githubusercontent.com/31293287/32969262-3cc5d48a-cb99-11e7-91bf-fa57c67a371c.png)](http://microsoft.github.io/code-push/)\n\n#### [Sign up With App Center](https://appcenter.ms/signup?utm_source=CodePush&utm_medium=Azure) to use CodePush\n\n## React Native Module for CodePush\n> [!WARNING]\n> React Native CodePush won't support new Architecture. In order to use this plugin on React Native versions starting from 0.76 you will need to [opt out](https://reactnative.dev/blog/2024/10/23/the-new-architecture-is-here#opt-out) from new architecture.\n>\n*Note: This README is only relevant to the latest version of our plugin. If you are using an older version, please switch to the relevant tag on [our GitHub repo](https://github.com/microsoft/react-native-code-push) to view the docs for that particular version.*\n\n![Switching tags](https://user-images.githubusercontent.com/42337914/57237511-0835de80-7030-11e9-88fa-64eb200478d0.png)\n\nThis plugin provides client-side integration for the [CodePush service](https://microsoft.github.io/code-push/), allowing you to easily add a dynamic update experience to your React Native app(s).\n\n<!-- React Native Catalog -->\n\n* [How does it work?](#how-does-it-work)\n* [Supported React Native Platforms](#supported-react-native-platforms)\n* [Supported Components](#supported-components)\n* [Getting Started](#getting-started)\n    * [iOS Setup](docs/setup-ios.md)\n    * [Android Setup](docs/setup-android.md)\n    * [Windows Setup](docs/setup-windows.md)\n* [Plugin Usage](#plugin-usage)\n    * [Store Guideline Compliance](#store-guideline-compliance)\n* [Releasing Updates](#releasing-updates)\n* [Multi-Deployment Testing](#multi-deployment-testing)\n    * [Android](docs/multi-deployment-testing-android.md)\n    * [iOS](docs/multi-deployment-testing-ios.md)\n* [Dynamic Deployment Assignment](#dynamic-deployment-assignment)\n* [API Reference](#api-reference)\n    * [JavaScript API](docs/api-js.md)\n    * [Objective-C API Reference (iOS)](docs/api-ios.md)\n    * [Java API Reference (Android)](docs/api-android.md)\n* [Debugging / Troubleshooting](#debugging--troubleshooting)\n* [Example Apps / Starters](#example-apps--starters)\n* [Continuous Integration / Delivery](#continuous-integration--delivery)\n* [TypeScript Consumption](#typescript-consumption)\n\n<!-- React Native Catalog -->\n\n## How does it work?\n\nA React Native app is composed of JavaScript files and any accompanying [images](https://reactnative.dev/docs/image), which are bundled together by the [metro bundler](https://github.com/facebook/metro) and distributed as part of a platform-specific binary (i.e. an `.ipa` or `.apk` file). Once the app is released, updating either the JavaScript code (e.g. making bug fixes, adding new features) or image assets, requires you to recompile and redistribute the entire binary, which of course, includes any review time associated with the store(s) you are publishing to.\n\nThe CodePush plugin helps get product improvements in front of your end users instantly, by keeping your JavaScript and images synchronized with updates you release to the CodePush server. This way, your app gets the benefits of an offline mobile experience, as well as the \"web-like\" agility of side-loading updates as soon as they are available. It's a win-win!\n\nIn order to ensure that your end users always have a functioning version of your app, the CodePush plugin maintains a copy of the previous update, so that in the event that you accidentally push an update which includes a crash, it can automatically roll back. This way, you can rest assured that your newfound release agility won't result in users becoming blocked before you have a chance to [roll back](https://docs.microsoft.com/en-us/appcenter/distribution/codepush/cli#rolling-back-updates) on the server. It's a win-win-win!\n\n*Note: Any product changes which touch native code (e.g. modifying your `AppDelegate.m`/`MainActivity.java` file, adding a new plugin) cannot be distributed via CodePush, and therefore, must be updated via the appropriate store(s).*\n\n## Supported React Native platforms\n\n- iOS (7+)\n- Android (4.1+) on TLS 1.2 compatible devices\n- Windows (UWP)\n\nWe try our best to maintain backwards compatibility of our plugin with previous versions of React Native, but due to the nature of the platform, and the existence of breaking changes between releases, it is possible that you need to use a specific version of the CodePush plugin in order to support the exact version of React Native you are using. The following table outlines which CodePush plugin versions officially support the respective React Native versions:\n\n| React Native version(s) | Supporting CodePush version(s)                        |\n|-------------------------|-------------------------------------------------------|\n| <0.14                   | **Unsupported**                                       |\n| v0.14                   | v1.3 *(introduced Android support)*                   |\n| v0.15-v0.18             | v1.4-v1.6 *(introduced iOS asset support)*            |\n| v0.19-v0.28             | v1.7-v1.17 *(introduced Android asset support)*       |\n| v0.29-v0.30             | v1.13-v1.17 *(RN refactored native hosting code)*     |\n| v0.31-v0.33             | v1.14.6-v1.17 *(RN refactored native hosting code)*   |\n| v0.34-v0.35             | v1.15-v1.17 *(RN refactored native hosting code)*     |\n| v0.36-v0.39             | v1.16-v1.17 *(RN refactored resume handler)*          |\n| v0.40-v0.42             | v1.17 *(RN refactored iOS header files)*              |\n| v0.43-v0.44             | v2.0+ *(RN refactored uimanager dependencies)*        |\n| v0.45                   | v3.0+ *(RN refactored instance manager code)*         |\n| v0.46                   | v4.0+ *(RN refactored js bundle loader code)*         |\n| v0.46-v0.53             | v5.1+ *(RN removed unused registration of JS modules)*|\n| v0.54-v0.55             | v5.3+ *(Android Gradle Plugin 3.x integration)*       |\n| v0.56-v0.58             | v5.4+ *(RN upgraded versions for Android tools)*      |\n| v0.59                   | v5.6+ *(RN refactored js bundle loader code)*         |\n| v0.60-v0.61             | v6.0+ *(RN migrated to Autolinking)*                  |\n| v0.62-v0.64             | v6.2+ *(RN removed LiveReload)*                       |\n| v0.65-v0.70             | v7.0+ *(RN updated iPhone-target-version)*            |\n| v0.71                   | v8.0+ *(RN moved to react-native-gradle-plugin)*      |\n\n*NOTE: `react-native-code-push` versions lower than **[v5.7.0](https://github.com/microsoft/react-native-code-push/releases/tag/v5.7.0)** will stop working in the near future. You can find more information in our [documentation](https://github.com/microsoft/code-push/blob/master/migration-notice.md).*\n\nWe work hard to respond to new RN releases, but they do occasionally break us. We will update this chart with each RN release, so that users can check to see what our \"official\" support is.\n\n### Supported Components\n\nWhen using the React Native assets system (i.e. using the `require(\"./foo.png\")` syntax), the following list represents the set of core components (and props) that support having their referenced images and videos updated via CodePush:\n\n| Component                                       | Prop(s)                                  |\n|-------------------------------------------------|------------------------------------------|\n| `Image`                                         | `source`                                 |\n| `MapView.Marker` <br />*(Requires [react-native-maps](https://github.com/lelandrichardson/react-native-maps) `>=O.3.2`)* | `image`                             |\n| `ProgressViewIOS`                               | `progressImage`, `trackImage`            |\n| `TabBarIOS.Item`                                | `icon`, `selectedIcon`                   |\n| `ToolbarAndroid` <br />*(React Native 0.21.0+)* | `actions[].icon`, `logo`, `overflowIcon` |\n| `Video`                                         | `source`                                 |\n\nThe following list represents the set of components (and props) that don't currently support their assets being updated via CodePush, due to their dependency on static images and videos (i.e. using the `{ uri: \"foo\" }` syntax):\n\n| Component   | Prop(s)                                                              |\n|-------------|----------------------------------------------------------------------|\n| `SliderIOS` | `maximumTrackImage`, `minimumTrackImage`, `thumbImage`, `trackImage` |\n| `Video`     | `source`                                                             |\n\nAs new core components are released, which support referencing assets, we'll update this list to ensure users know what exactly they can expect to update using CodePush.\n\n*Note: CodePush only works with Video components when using `require` in the source prop. For example:*\n\n```javascript\n<Video source={require(\"./foo.mp4\")} />\n```\n\n## Getting Started\n\nOnce you've followed the general-purpose [\"getting started\"](https://docs.microsoft.com/en-us/appcenter/distribution/codepush/index) instructions for setting up your CodePush account, you can start CodePush-ifying your React Native app by running the following command from within your app's root directory:\n\n```shell\nnpm install --save react-native-code-push\n```\n\nAs with all other React Native plugins, the integration experience is different for iOS and Android, so perform the following setup steps depending on which platform(s) you are targeting. Note, if you are targeting both platforms it is recommended to create separate CodePush applications for each platform.\n\nIf you want to see how other projects have integrated with CodePush, you can check out the excellent [example apps](#example-apps--starters) provided by the community. Additionally, if you'd like to quickly familiarize yourself with CodePush + React Native, you can check out the awesome getting started videos produced by [Bilal Budhani](https://www.youtube.com/watch?v=uN0FRWk-YW8&feature=youtu.be) and/or [Deepak Sisodiya ](https://www.youtube.com/watch?v=f6I9y7V-Ibk).\n\n*NOTE: This guide assumes you have used the `react-native init` command to initialize your React Native project. As of March 2017, the command `create-react-native-app` can also be used to initialize a React Native project. If using this command, please run `npm run eject` in your project's home directory to get a project very similar to what `react-native init` would have created.*\n\nThen continue with installing the native module\n  * [iOS Setup](docs/setup-ios.md)\n  * [Android Setup](docs/setup-android.md)\n  * [Windows Setup](docs/setup-windows.md)\n\n\n## Plugin Usage\n\nWith the CodePush plugin downloaded and linked, and your app asking CodePush where to get the right JS bundle from, the only thing left is to add the necessary code to your app to control the following policies:\n\n1. When (and how often) to check for an update? (for example app start, in response to clicking a button in a settings page, periodically at some fixed interval)\n\n2. When an update is available, how to present it to the end user?\n\nThe simplest way to do this is to \"CodePush-ify\" your app's root component. To do so, you can choose one of the following two options:\n\n* **Option 1: Wrap your root component with the `codePush` higher-order component:**\n\n  * For class component\n\n    ```javascript\n    import codePush from \"react-native-code-push\";\n\n    class MyApp extends Component {\n    }\n\n    MyApp = codePush(MyApp);\n    ```\n\n  * For functional component\n\n    ```javascript\n    import codePush from \"react-native-code-push\";\n\n    let MyApp: () => React$Node = () => {\n    }\n\n    MyApp = codePush(MyApp);\n    ```\n\n* **Option 2: Use the [ES7 decorator](https://github.com/wycats/javascript-decorators) syntax:**\n\n    *NOTE: Decorators are not yet supported in Babel 6.x pending proposal update.* You may need to enable it by installing and using [babel-preset-react-native-stage-0](https://github.com/skevy/babel-preset-react-native-stage-0#babel-preset-react-native-stage-0).\n\n  * For class component\n\n    ```javascript\n    import codePush from \"react-native-code-push\";\n\n    @codePush\n    class MyApp extends Component {\n    }\n    ```\n\n  * For functional component\n\n    ```javascript\n    import codePush from \"react-native-code-push\";\n\n    const MyApp: () => React$Node = () => {\n    }\n\n    export default codePush(MyApp);\n    ```\n\nBy default, CodePush will check for updates on every app start. If an update is available, it will be silently downloaded, and installed the next time the app is restarted (either explicitly by the end user or by the OS), which ensures the least invasive experience for your end users. If an available update is mandatory, then it will be installed immediately, ensuring that the end user gets it as soon as possible.\n\nIf you would like your app to discover updates more quickly, you can also choose to sync up with the CodePush server every time the app resumes from the background.\n\n* For class component\n\n    ```javascript\n    let codePushOptions = { checkFrequency: codePush.CheckFrequency.ON_APP_RESUME };\n\n    class MyApp extends Component {\n    }\n\n    MyApp = codePush(codePushOptions)(MyApp);\n    ```\n\n* For functional component\n\n    ```javascript\n    let codePushOptions = { checkFrequency: codePush.CheckFrequency.ON_APP_RESUME };\n\n    let MyApp: () => React$Node = () => {\n    }\n\n    MyApp = codePush(codePushOptions)(MyApp);\n    ```\n\nAlternatively, if you want fine-grained control over when the check happens (like a button press or timer interval), you can call [`CodePush.sync()`](docs/api-js.md#codepushsync) at any time with your desired `SyncOptions`, and optionally turn off CodePush's automatic checking by specifying a manual `checkFrequency`:\n\n```javascript\nlet codePushOptions = { checkFrequency: codePush.CheckFrequency.MANUAL };\n\nclass MyApp extends Component {\n    onButtonPress() {\n        codePush.sync({\n            updateDialog: true,\n            installMode: codePush.InstallMode.IMMEDIATE\n        });\n    }\n\n    render() {\n        return (\n            <View>\n                <TouchableOpacity onPress={this.onButtonPress}>\n                    <Text>Check for updates</Text>\n                </TouchableOpacity>\n            </View>\n        )\n    }\n}\n\nMyApp = codePush(codePushOptions)(MyApp);\n```\n\nIf you would like to display an update confirmation dialog (an \"active install\"), configure when an available update is installed (like force an immediate restart) or customize the update experience in any other way, refer to the [`codePush()`](docs/api-js.md#codepush) API reference for information on how to tweak this default behavior.\n\n*NOTE: If you are using [Redux](http://redux.js.org) and [Redux Saga](https://redux-saga.js.org/), you can alternatively use the [react-native-code-push-saga](http://github.com/lostintangent/react-native-code-push-saga) module, which allows you to customize when `sync` is called in a perhaps simpler/more idiomatic way.*\n\n### Store Guideline Compliance\n\nAndroid Google Play and iOS App Store have corresponding guidelines that have rules you should be aware of before integrating the CodePush solution within your application.\n\n#### Google play\n\nThird paragraph of [Device and Network Abuse](https://support.google.com/googleplay/android-developer/answer/9888379?hl=en) topic describe that updating source code by any method other than Google Play's update mechanism is restricted. But this restriction does not apply to updating javascript bundles.\n> This restriction does not apply to code that runs in a virtual machine and has limited access to Android APIs (such as JavaScript in a webview or browser).\n\nThat fully allow CodePush as it updates just JS bundles and can't update native code part.\n\n#### App Store\n\nParagraph **3.3.2**, since back in 2015's [Apple Developer Program License Agreement](https://developer.apple.com/programs/ios/information/) fully allowed performing over-the-air updates of JavaScript and assets -  and in its latest version (20170605) [downloadable here](https://developer.apple.com/terms/) this ruling is even broader:\n\n> Interpreted code may be downloaded to an Application but only so long as such code: (a) does not change the primary purpose of the Application by providing features or functionality that are inconsistent with the intended and advertised purpose of the Application as submitted to the App Store, (b) does not create a store or storefront for other code or applications, and (c) does not bypass signing, sandbox, or other security features of the OS.\n\nCodePush allows you to follow these rules in full compliance so long as the update you push does not significantly deviate your product from its original App Store approved intent.\n\nTo further remain in compliance with Apple's guidelines we suggest that App Store-distributed apps don't enable the `updateDialog` option when calling `sync`, since in the [App Store Review Guidelines](https://developer.apple.com/app-store/review/guidelines/) it is written that:\n\n> Apps must not force users to rate the app, review the app, download other apps, or other similar actions in order to access functionality, content, or use of the app.\n\nThis is not necessarily the case for `updateDialog`, since it won't force the user to download the new version, but at least you should be aware of that ruling if you decide to show it.\n\n## Releasing Updates\n\nOnce your app is configured and distributed to your users, and you have made some JS or asset changes, it's time to release them. The recommended way to release them is using the `release-react` command in the App Center CLI, which will bundle your JavaScript files, asset files, and release the update to the CodePush server.\n\n*NOTE: Before you can start releasing updates, please log into App Center by running the `appcenter login` command.*\n\nIn its most basic form, this command only requires one parameter: your owner name + \"/\" + app name.\n\n```shell\nappcenter codepush release-react -a <ownerName>/<appName>\n\nappcenter codepush release-react -a <ownerName>/MyApp-iOS\nappcenter codepush release-react -a <ownerName>/MyApp-Android\n```\n\nThe `release-react` command enables such a simple workflow because it provides many sensible defaults (like generating a release bundle, assuming your app's entry file on iOS is either `index.ios.js` or `index.js`). However, all of these defaults can be customized to allow incremental flexibility as necessary, which makes it a good fit for most scenarios.\n\n```shell\n# Release a mandatory update with a changelog\nappcenter codepush release-react -a <ownerName>/MyApp-iOS  -m --description \"Modified the header color\"\n\n# Release an update for an app that uses a non-standard entry file name, and also capture\n# the sourcemap file generated by react-native bundle\nappcenter codepush release-react -a <ownerName>/MyApp-iOS --entry-file MyApp.js --sourcemap-output ../maps/MyApp.map\n\n# Release a dev Android build to just 1/4 of your end users\nappcenter codepush release-react -a <ownerName>/MyApp-Android  --rollout 25 --development true\n\n# Release an update that targets users running any 1.1.* binary, as opposed to\n# limiting the update to exact version name in the build.gradle file\nappcenter codepush release-react -a <ownerName>/MyApp-Android  --target-binary-version \"~1.1.0\"\n\n```\n\nThe CodePush client supports differential updates, so even though you are releasing your JS bundle and assets on every update, your end users will only actually download the files they need. The service handles this automatically so that you can focus on creating awesome apps and we can worry about optimizing end user downloads.\n\nFor more details about how the `release-react` command works, as well as the various parameters it exposes, refer to the [CLI docs](https://github.com/microsoft/code-push/tree/v3.0.1/cli#releasing-updates-react-native). Additionally, if you would prefer to handle running the `react-native bundle` command yourself, and therefore, want an even more flexible solution than `release-react`, refer to the [`release` command](https://github.com/microsoft/code-push/tree/v3.0.1/cli#releasing-updates-general) for more details.\n\nIf you run into any issues, or have any questions/comments/feedback, you can ping us within the [#code-push](https://discord.gg/0ZcbPKXt5bWxFdFu) channel on Reactiflux, [e-mail us](mailto:codepushfeed@microsoft.com) and/or check out the [troubleshooting](#debugging--troubleshooting) details below.\n\n*NOTE: CodePush updates should be tested in modes other than Debug mode. In Debug mode, React Native app always downloads JS bundle generated by packager, so JS bundle downloaded by CodePush does not apply.*\n\n### Multi-Deployment Testing\n\nIn our [getting started](#getting-started) docs, we illustrated how to configure the CodePush plugin using a specific deployment key. However, in order to effectively test your releases, it is critical that you leverage the `Staging` and `Production` deployments that are auto-generated when you first created your CodePush app (or any custom deployments you may have created). This way, you never release an update to your end users that you haven't been able to validate yourself.\n\n*NOTE: Our client-side rollback feature can help unblock users after installing a release that resulted in a crash, and server-side rollbacks (i.e. `appcenter codepush rollback`) allow you to prevent additional users from installing a bad release once it's been identified. However, it's obviously better if you can prevent an erroneous update from being broadly released in the first place.*\n\nTaking advantage of the `Staging` and `Production` deployments allows you to achieve a workflow like the following (feel free to customize!):\n\n1. Release a CodePush update to your `Staging` deployment using the `appcenter codepush release-react` command (or `appcenter codepush release` if you need more control)\n\n2. Run your staging/beta build of your app, sync the update from the server, and verify it works as expected\n\n3. Promote the tested release from `Staging` to `Production` using the `appcenter codepush promote` command\n\n4. Run your production/release build of your app, sync the update from the server and verify it works as expected\n\n*NOTE: If you want to take a more cautious approach, you can even choose to perform a \"staged rollout\" as part of #3, which allows you to mitigate additional potential risk with the update (like did your testing in #2 touch all possible devices/conditions?) by only making the production update available to a percentage of your users (for example `appcenter codepush promote -a <ownerName>/<appName> -s Staging -d Production -r 20`). Then, after waiting for a reasonable amount of time to see if any crash reports or customer feedback comes in, you can expand it to your entire audience by running `appcenter codepush patch -a <ownerName>/<appName> Production -r 100`.*\n\nYou'll notice that the above steps refer to a \"staging build\" and \"production build\" of your app. If your build process already generates distinct binaries per \"environment\", then you don't need to read any further, since swapping out CodePush deployment keys is just like handling environment-specific config for any other service your app uses (like Facebook). However, if you're looking for examples (**including demo projects**) on how to setup your build process to accommodate this, then refer to the following sections, depending on the platform(s) your app is targeting:\n\n  * [Android](docs/multi-deployment-testing-android.md)\n  * [iOS](docs/multi-deployment-testing-ios.md)\n\n\n### Dynamic Deployment Assignment\n\nThe above section illustrated how you can leverage multiple CodePush deployments in order to effectively test your updates before broadly releasing them to your end users. However, since that workflow statically embeds the deployment assignment into the actual binary, a staging or production build will only ever sync updates from that deployment. In many cases, this is sufficient, since you only want your team, customers, stakeholders, etc. to sync with your pre-production releases, and therefore, only they need a build that knows how to sync with staging. However, if you want to be able to perform A/B tests, or provide early access of your app to certain users, it can prove very useful to be able to dynamically place specific users (or audiences) into specific deployments at runtime.\n\nIn order to achieve this kind of workflow, all you need to do is specify the deployment key you want the current user to syncronize with when calling the `codePush` method. When specified, this key will override the \"default\" one that was provided in your app's `Info.plist` (iOS) or `MainActivity.java` (Android) files. This allows you to produce a build for staging or production, that is also capable of being dynamically \"redirected\" as needed.\n\n```javascript\n// Imagine that \"userProfile\" is a prop that this component received\n// which includes the deployment key that the current user should use.\ncodePush.sync({ deploymentKey: userProfile.CODEPUSH_KEY });\n```\n\nWith that change in place, now it's just a matter of choosing how your app determines the right deployment key for the current user. In practice, there are typically two solutions for this:\n\n1. Expose a user-visible mechanism for changing deployments at any time. For example, your settings page could have a toggle for enabling \"beta\" access. This model works well if you're not concerned with the privacy of your pre-production updates, and you have power users that may want to opt-in to earlier (and potentially buggy) updates at their own will (kind of like Chrome channels). However, this solution puts the decision in the hands of your users, which doesn't help you perform A/B tests transparently.\n\n2. Annotate the server-side profile of your users with an additional piece of metadata that indicates the deployment they should sync with. By default, your app could just use the binary-embedded key, but after a user has authenticated, your server can choose to \"redirect\" them to a different deployment, which allows you to incrementally place certain users or groups in different deployments as needed. You could even choose to store the server-response in local storage so that it becomes the new default. How you store the key alongside your user's profiles is entirely up to your authentication solution (for example Auth0, Firebase, custom DB + REST API), but is generally pretty trivial to do.\n\n*NOTE: If needed, you could also implement a hybrid solution that allowed your end-users to toggle between different deployments, while also allowing your server to override that decision. This way, you have a hierarchy of \"deployment resolution\" that ensures your app has the ability to update itself out-of-the-box, your end users can feel rewarded by getting early access to bits, but you also have the ability to run A/B tests on your users as needed.*\n\nSince we recommend using the `Staging` deployment for pre-release testing of your updates (as explained in the previous section), it doesn't neccessarily make sense to use it for performing A/B tests on your users, as opposed to allowing early-access (as explained in option #1 above). Therefore, we recommend making full use of custom app deployments, so that you can segment your users however makes sense for your needs. For example, you could create long-term or even one-off deployments, release a variant of your app to it, and then place certain users into it in order to see how they engage.\n\n```javascript\n// #1) Create your new deployment to hold releases of a specific app variant\nappcenter codepush deployment add -a <ownerName>/<appName> test-variant-one\n\n// #2) Target any new releases at that custom deployment\nappcenter codepush release-react -a <ownerName>/<appName> -d test-variant-one\n```\n\n*NOTE: The total user count that is reported in your deployment's \"Install Metrics\" will take into account users that have \"switched\" from one deployment to another. For example, if your `Production` deployment currently reports having 1 total user, but you dynamically switch that user to `Staging`, then the `Production` deployment would report 0 total users, while `Staging` would report 1 (the user that just switched). This behavior allows you to accurately track your release adoption, even in the event of using a runtime-based deployment redirection solution.*\n\n---\n\n## API Reference\n\n* [JavaScript API](docs/api-js.md)\n* [Objective-C API Reference (iOS)](docs/api-ios.md)\n* [Java API Reference (Android)](docs/api-android.md)\n\n### Example Apps / Starters\n\nThe React Native community has graciously created some awesome open source apps that can serve as examples for developers that are getting started. The following is a list of OSS React Native apps that are also using CodePush, and can therefore be used to see how others are using the service:\n\n* [F8 App](https://github.com/fbsamples/f8app) - The official conference app for [F8 2016](https://www.fbf8.com/).\n* [Feline for Product Hunt](https://github.com/arjunkomath/Feline-for-Product-Hunt) - An Android client for Product Hunt.\n* [GeoEncoding](https://github.com/LynxITDigital/GeoEncoding) - An app by [Lynx IT Digital](https://digital.lynxit.com.au) which demonstrates how to use numerous React Native components and modules.\n* [Math Facts](https://github.com/Khan/math-facts) - An app by Khan Academy to help memorize math facts more easily.\n\nAdditionally, if you're looking to get started with React Native + CodePush, and are looking for an awesome starter kit, you should check out the following:\n\n* [Pepperoni](http://getpepperoni.com/)\n\n*Note: If you've developed a React Native app using CodePush, that is also open-source, please let us know. We would love to add it to this list!*\n\n### Debugging / Troubleshooting\n\nThe `sync` method includes a lot of diagnostic logging out-of-the-box, so if you're encountering an issue when using it, the best thing to try first is examining the output logs of your app. This will tell you whether the app is configured correctly (like can the plugin find your deployment key?), if the app is able to reach the server, if an available update is being discovered, if the update is being successfully downloaded/installed, etc. We want to continue improving the logging to be as intuitive/comprehensive as possible, so please [let us know](mailto:codepushfeed@microsoft.com) if you find it to be confusing or missing anything.\n\nThe simplest way to view these logs is to add the flag `--debug` for each command. This will output a log stream that is filtered to just CodePush messages. This makes it easy to identify issues, without needing to use a platform-specific tool, or wade through a potentially high volume of logs.\n\n<img width=\"540\" alt=\"screen shot 2016-06-21 at 10 15 42 am\" src=\"https://cloud.githubusercontent.com/assets/116461/16246973/838e2e98-37bc-11e6-9649-685f39e325a0.png\">\n\nAdditionally, you can also use any of the platform-specific tools to view the CodePush logs, if you are more comfortable with them. Simple start up the Chrome DevTools Console, the Xcode Console (iOS), the [OS X Console](https://en.wikipedia.org/wiki/Console_%28OS_X%29#.7E.2FLibrary.2FLogs) (iOS) and/or ADB logcat (Android), and look for messages which are prefixed with `[CodePush]`.\n\nNote that by default, React Native logs are disabled on iOS in release builds, so if you want to view them in a release build, you need to make the following changes to your `AppDelegate.m` file:\n\n1. Add an `#import <React/RCTLog.h>` statement. For RN < v0.40 use: `#import \"RCTLog.h\"`\n\n2. Add the following statement to the top of your `application:didFinishLaunchingWithOptions` method:\n\n    ```objective-c\n    RCTSetLogThreshold(RCTLogLevelInfo);\n    ```\n\nNow you'll be able to see CodePush logs in either debug or release mode, on both iOS or Android. If examining the logs don't provide an indication of the issue, please refer to the following common issues for additional resolution ideas:\n\n| Issue / Symptom | Possible Solution |\n|-----------------|-------------------|\n| Compilation Error | Double-check that your version of React Native is [compatible](#supported-react-native-platforms) with the CodePush version you are using. |\n| Network timeout / hang when calling `sync` or `checkForUpdate` in the iOS Simulator | Try resetting the simulator by selecting the `Simulator -> Reset Content and Settings..` menu item, and then re-running your app. |\n| Server responds with a `404` when calling `sync` or `checkForUpdate` | Double-check that the deployment key you added to your `Info.plist` (iOS), `build.gradle` (Android) or that you're passing to `sync`/`checkForUpdate`, is in fact correct. You can run `appcenter codepush deployment list <ownerName>/<appName> --displayKeys` to view the correct keys for your app deployments. |\n| Update not being discovered | Double-check that the version of your running app (like `1.0.0`) matches the version you specified when releasing the update to CodePush. Additionally, make sure that you are releasing to the same deployment that your app is configured to sync with. |\n| Update not being displayed after restart | If you're not calling `sync` on app start (like within `componentDidMount` of your root component), then you need to explicitly call `notifyApplicationReady` on app start, otherwise, the plugin will think your update failed and roll it back. |\n| I've released an update for iOS but my Android app also shows an update and it breaks it | Be sure you have different deployment keys for each platform in order to receive updates correctly |\n| I've released new update but changes are not reflected | Be sure that you are running app in modes other than Debug. In Debug mode, React Native app always downloads JS bundle generated by packager, so JS bundle downloaded by CodePush does not apply.\n| No JS bundle is being found when running your app against the iOS simulator | By default, React Native doesn't generate your JS bundle when running against the simulator. Therefore, if you're using `[CodePush bundleURL]`, and targetting the iOS simulator, you may be getting a `nil` result. This issue will be fixed in RN 0.22.0, but only for release builds. You can unblock this scenario right now by making [this change](https://github.com/facebook/react-native/commit/9ae3714f4bebdd2bcab4d7fdbf23acebdc5ed2ba) locally.\n\n### Continuous Integration / Delivery\n\nIn addition to being able to use the CodePush CLI to \"manually\" release updates, we believe that it's important to create a repeatable and sustainable solution for contiously delivering updates to your app. That way, it's simple enough for you and/or your team to create and maintain the rhythm of performing agile deployments. In order to assist with setting up a CodePush-based CD pipeline, refer to the following integrations with various CI servers:\n\n* [Visual Studio Team Services](https://marketplace.visualstudio.com/items?itemName=ms-vsclient.code-push) - *NOTE: VSTS also has extensions for publishing to [HockeyApp](https://marketplace.visualstudio.com/items?itemName=ms.hockeyapp) and the [Google Play](https://github.com/microsoft/google-play-vsts-extension) store, so it provides a pretty great mobile CD solution in general.*\n* [Travis CI](https://github.com/mondora/code-push-travis-cli)\n\nAdditionally, if you'd like more details of what a complete mobile CI/CD workflow  can look like, which includes CodePush, check out this [excellent article](https://medium.com/zeemee-engineering/zeemee-engineering-and-the-quest-for-the-holy-mobile-dev-grail-1310be4953d1) by the [ZeeMee engineering team](https://www.zeemee.com/).\n\n### TypeScript Consumption\n\nThis module ships its `*.d.ts` file as part of its NPM package, which allows you to simply `import` it, and receive intellisense in supporting editors (like Visual Studio Code), as well as compile-time type checking if you're using TypeScript. For the most part, this behavior should just work out of the box, however, if you've specified `es6` as the value for either the `target` or `module` [compiler option](http://www.typescriptlang.org/docs/handbook/compiler-options.html) in your [`tsconfig.json`](http://www.typescriptlang.org/docs/handbook/tsconfig-json.html) file, then just make sure that you also set the `moduleResolution` option to `node`. This ensures that the TypeScript compiler will look within the `node_modules` for the type definitions of imported modules. Otherwise, you'll get an error like the following when trying to import the `react-native-code-push` module: `error TS2307: Cannot find module 'react-native-code-push'`.\n\n---\n\nThis project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.\n"
  },
  {
    "path": "Recipes/UpdateButton.ios.js",
    "content": "'use strict';\n\nvar pkg = require('./package');\nvar React = require('react-native');\nvar {\n  AppRegistry,\n  StyleSheet,\n  Text,\n  View,\n} = React;\nvar Button = require('react-native-button');\n\nvar CodePush = require('react-native-code-push');\n\nvar UpdateButton = React.createClass({\n  getInitialState: function() {\n    return {};\n  },\n  componentDidMount: function() {\n    CodePush.checkForUpdate().done((update) => {\n      if (update && !update.downloadURL) {\n        this.setState({\n          update: update \n        });\n      }\n    });\n  },\n  update: function() {\n    this.state.update.download().done((newPackage) => {\n      newPackage.install();\n    });\n  },\n  render: function() {\n    var updateButton = null;\n    if (this.state.update) {\n      updateButton = <Button onPress={this.update}>Update</Button>;\n    }\n\n    return (\n      <View style={styles.container}>\n        <Text>\n          Welcome to {pkg.name} {pkg.version}!\n        </Text>\n        {updateButton}\n      </View>\n    );\n  }\n});\n\nvar styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    justifyContent: 'center',\n    alignItems: 'center',\n    backgroundColor: '#F5FCFF',\n  }\n});\n\nAppRegistry.registerComponent('UpdateButton', () => UpdateButton);\n"
  },
  {
    "path": "Recipes/UpdateOnStart.ios.js",
    "content": "'use strict';\n\nvar pkg = require('./package');\nvar React = require('react-native');\nvar {\n  AppRegistry,\n  StyleSheet,\n  Text,\n  View,\n} = React;\n\nvar CodePush = require('react-native-code-push');\n\nvar UpdateOnStart = React.createClass({\n  componentDidMount: function() {\n    CodePush.checkForUpdate().done((update) => {\n      if (update && update.downloadUrl) {\n        update.download().done((newPackage) => {\n          newPackage.install();\n        });\n      }\n    });\n  },\n  render: function() {\n    return (\n      <View style={styles.container}>\n        <Text>\n          Welcome to {pkg.name} {pkg.version}!\n        </Text>\n      </View>\n    );\n  }\n});\n\nvar styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    justifyContent: 'center',\n    alignItems: 'center',\n    backgroundColor: '#F5FCFF',\n  }\n});\n\nAppRegistry.registerComponent('UpdateOnStart', () => UpdateOnStart);\n"
  },
  {
    "path": "SECURITY.md",
    "content": "<!-- BEGIN MICROSOFT SECURITY.MD V0.0.5 BLOCK -->\n\n## Security\n\nMicrosoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).\n\nIf you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)), please report it to us as described below.\n\n## Reporting Security Issues\n\n**Please do not report security vulnerabilities through public GitHub issues.**\n\nInstead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report).\n\nIf you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com).  If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc).\n\nYou should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc).\n\nPlease include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:\n\n* Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)\n* Full paths of source file(s) related to the manifestation of the issue\n* The location of the affected source code (tag/branch/commit or direct URL)\n* Any special configuration required to reproduce the issue\n* Step-by-step instructions to reproduce the issue\n* Proof-of-concept or exploit code (if possible)\n* Impact of the issue, including how an attacker might exploit the issue\n\nThis information will help us triage your report more quickly.\n\nIf you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs.\n\n## Preferred Languages\n\nWe prefer all communications to be in English.\n\n## Policy\n\nMicrosoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd).\n\n<!-- END MICROSOFT SECURITY.MD BLOCK -->"
  },
  {
    "path": "android/app/build.gradle",
    "content": "apply plugin: \"com.android.library\"\n\ndef DEFAULT_COMPILE_SDK_VERSION = 26\ndef DEFAULT_BUILD_TOOLS_VERSION = \"26.0.3\"\ndef DEFAULT_TARGET_SDK_VERSION = 26\ndef DEFAULT_MIN_SDK_VERSION = 16\n\nandroid {\n    namespace \"com.microsoft.codepush.react\"\n\n    compileSdkVersion rootProject.hasProperty('compileSdkVersion') ? rootProject.compileSdkVersion : DEFAULT_COMPILE_SDK_VERSION\n    buildToolsVersion rootProject.hasProperty('buildToolsVersion') ? rootProject.buildToolsVersion : DEFAULT_BUILD_TOOLS_VERSION\n\n    defaultConfig {\n        minSdkVersion rootProject.hasProperty('minSdkVersion') ? rootProject.minSdkVersion : DEFAULT_MIN_SDK_VERSION\n        targetSdkVersion rootProject.hasProperty('targetSdkVersion') ? rootProject.targetSdkVersion : DEFAULT_TARGET_SDK_VERSION\n        versionCode 1\n        versionName \"1.0\"\n    }\n\n    lintOptions {\n        abortOnError false\n    }\n\n    defaultConfig {\n        consumerProguardFiles 'proguard-rules.pro'\n    }\n}\n\ndependencies {\n    implementation \"com.facebook.react:react-native:+\"\n    implementation 'com.nimbusds:nimbus-jose-jwt:9.37.3'\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# Invoked via reflection, when setting js bundle.\n-keepclassmembers class com.facebook.react.ReactInstanceManager {\n    private final ** mBundleLoader;\n}\n\n# Can't find referenced class org.bouncycastle.**\n-dontwarn com.nimbusds.jose.**\n"
  },
  {
    "path": "android/app/src/debug/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <uses-permission android:name=\"android.permission.INTERNET\" />\n\n    <application>\n        <activity android:name=\"com.facebook.react.devsupport.DevSettingsActivity\" />\n    </application>\n\n</manifest>\n"
  },
  {
    "path": "android/app/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <uses-permission android:name=\"android.permission.INTERNET\" />\n\n</manifest>\n"
  },
  {
    "path": "android/app/src/main/java/com/microsoft/codepush/react/CodePush.java",
    "content": "package com.microsoft.codepush.react;\n\nimport android.content.Context;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.content.res.Resources;\n\nimport com.facebook.react.ReactInstanceManager;\nimport com.facebook.react.ReactPackage;\nimport com.facebook.react.bridge.JavaScriptModule;\nimport com.facebook.react.bridge.NativeModule;\nimport com.facebook.react.bridge.ReactApplicationContext;\nimport com.facebook.react.devsupport.interfaces.DevSupportManager;\nimport com.facebook.react.modules.debug.interfaces.DeveloperSettings;\nimport com.facebook.react.uimanager.ViewManager;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.lang.reflect.Method;\n\npublic class CodePush implements ReactPackage {\n\n    private static boolean sIsRunningBinaryVersion = false;\n    private static boolean sNeedToReportRollback = false;\n    private static boolean sTestConfigurationFlag = false;\n    private static String sAppVersion = null;\n\n    private boolean mDidUpdate = false;\n\n    private String mAssetsBundleFileName;\n\n    // Helper classes.\n    private CodePushUpdateManager mUpdateManager;\n    private CodePushTelemetryManager mTelemetryManager;\n    private SettingsManager mSettingsManager;\n\n    // Config properties.\n    private String mDeploymentKey;\n    private static String mServerUrl = \"https://codepush.appcenter.ms/\";\n\n    private Context mContext;\n    private final boolean mIsDebugMode;\n\n    private static String mPublicKey;\n\n    private static ReactInstanceHolder mReactInstanceHolder;\n    private static CodePush mCurrentInstance;\n\n    public CodePush(String deploymentKey, Context context) {\n        this(deploymentKey, context, false);\n    }\n\n    public static String getServiceUrl() {\n        return mServerUrl;\n    }\n\n    public CodePush(String deploymentKey, Context context, boolean isDebugMode) {\n        mContext = context.getApplicationContext();\n\n        mUpdateManager = new CodePushUpdateManager(context.getFilesDir().getAbsolutePath());\n        mTelemetryManager = new CodePushTelemetryManager(mContext);\n        mDeploymentKey = deploymentKey;\n        mIsDebugMode = isDebugMode;\n        mSettingsManager = new SettingsManager(mContext);\n\n        if (sAppVersion == null) {\n            try {\n                PackageInfo pInfo = mContext.getPackageManager().getPackageInfo(mContext.getPackageName(), 0);\n                sAppVersion = pInfo.versionName;\n            } catch (PackageManager.NameNotFoundException e) {\n                throw new CodePushUnknownException(\"Unable to get package info for \" + mContext.getPackageName(), e);\n            }\n        }\n\n        mCurrentInstance = this;\n\n        String publicKeyFromStrings = getCustomPropertyFromStringsIfExist(\"PublicKey\");\n        if (publicKeyFromStrings != null) mPublicKey = publicKeyFromStrings;\n\n        String serverUrlFromStrings = getCustomPropertyFromStringsIfExist(\"ServerUrl\");\n        if (serverUrlFromStrings != null) mServerUrl = serverUrlFromStrings;\n\n        clearDebugCacheIfNeeded(null);\n        initializeUpdateAfterRestart();\n    }\n\n    public CodePush(String deploymentKey, Context context, boolean isDebugMode, String serverUrl) {\n        this(deploymentKey, context, isDebugMode);\n        mServerUrl = serverUrl;\n    }\n\n    public CodePush(String deploymentKey, Context context, boolean isDebugMode, int publicKeyResourceDescriptor) {\n        this(deploymentKey, context, isDebugMode);\n\n        mPublicKey = getPublicKeyByResourceDescriptor(publicKeyResourceDescriptor);\n    }\n\n    public CodePush(String deploymentKey, Context context, boolean isDebugMode, String serverUrl, Integer publicKeyResourceDescriptor) {\n        this(deploymentKey, context, isDebugMode);\n\n        if (publicKeyResourceDescriptor != null) {\n            mPublicKey = getPublicKeyByResourceDescriptor(publicKeyResourceDescriptor);\n        }\n\n        mServerUrl = serverUrl;\n    }\n\n    private String getPublicKeyByResourceDescriptor(int publicKeyResourceDescriptor){\n        String publicKey;\n        try {\n            publicKey = mContext.getString(publicKeyResourceDescriptor);\n        } catch (Resources.NotFoundException e) {\n            throw new CodePushInvalidPublicKeyException(\n                    \"Unable to get public key, related resource descriptor \" +\n                            publicKeyResourceDescriptor +\n                            \" can not be found\", e\n            );\n        }\n\n        if (publicKey.isEmpty()) {\n            throw new CodePushInvalidPublicKeyException(\"Specified public key is empty\");\n        }\n        return publicKey;\n    }\n\n    private String getCustomPropertyFromStringsIfExist(String propertyName) {\n        String property;\n      \n        String packageName = mContext.getPackageName();\n        int resId = mContext.getResources().getIdentifier(\"CodePush\" + propertyName, \"string\", packageName);\n        \n        if (resId != 0) {\n            property = mContext.getString(resId);\n\n            if (!property.isEmpty()) {\n                return property;\n            } else {\n                CodePushUtils.log(\"Specified \" + propertyName + \" is empty\");\n            } \n        }\n\n        return null;\n    }\n\n    private boolean isLiveReloadEnabled(ReactInstanceManager instanceManager) {\n        // Use instanceManager for checking if we use LiveReload mode. In this case we should not remove ReactNativeDevBundle.js file\n        // because we get error with trying to get this after reloading. Issue: https://github.com/microsoft/react-native-code-push/issues/1272\n        if (instanceManager != null) {\n            DevSupportManager devSupportManager = instanceManager.getDevSupportManager();\n            if (devSupportManager != null) {\n                DeveloperSettings devSettings = devSupportManager.getDevSettings();\n                Method[] methods = devSettings.getClass().getMethods();\n                for (Method m : methods) {\n                    if (m.getName().equals(\"isReloadOnJSChangeEnabled\")) {\n                        try {\n                            return (boolean) m.invoke(devSettings);\n                        } catch (Exception x) {\n                            return false;\n                        }\n                    }\n                }\n            }\n        }\n\n        return false;\n    }\n\n    public void clearDebugCacheIfNeeded(ReactInstanceManager instanceManager) {\n        if (mIsDebugMode && mSettingsManager.isPendingUpdate(null) && !isLiveReloadEnabled(instanceManager)) {\n            // This needs to be kept in sync with https://github.com/facebook/react-native/blob/master/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManager.java#L78\n            File cachedDevBundle = new File(mContext.getFilesDir(), \"ReactNativeDevBundle.js\");\n            if (cachedDevBundle.exists()) {\n                cachedDevBundle.delete();\n            }\n        }\n    }\n\n    public boolean didUpdate() {\n        return mDidUpdate;\n    }\n\n    public String getAppVersion() {\n        return sAppVersion;\n    }\n\n    public String getAssetsBundleFileName() {\n        return mAssetsBundleFileName;\n    }\n\n    public String getPublicKey() {\n        return mPublicKey;\n    }\n\n    long getBinaryResourcesModifiedTime() {\n        try {\n            String packageName = this.mContext.getPackageName();\n            int codePushApkBuildTimeId = this.mContext.getResources().getIdentifier(CodePushConstants.CODE_PUSH_APK_BUILD_TIME_KEY, \"string\", packageName);\n            // replace double quotes needed for correct restoration of long value from strings.xml\n            // https://github.com/microsoft/cordova-plugin-code-push/issues/264\n            String codePushApkBuildTime = this.mContext.getResources().getString(codePushApkBuildTimeId).replaceAll(\"\\\"\",\"\");\n            return Long.parseLong(codePushApkBuildTime);\n        } catch (Exception e) {\n            throw new CodePushUnknownException(\"Error in getting binary resources modified time\", e);\n        }\n    }\n\n    public String getPackageFolder() {\n        JSONObject codePushLocalPackage = mUpdateManager.getCurrentPackage();\n        if (codePushLocalPackage == null) {\n            return null;\n        }\n        return mUpdateManager.getPackageFolderPath(codePushLocalPackage.optString(\"packageHash\"));\n    }\n\n    @Deprecated\n    public static String getBundleUrl() {\n        return getJSBundleFile();\n    }\n\n    @Deprecated\n    public static String getBundleUrl(String assetsBundleFileName) {\n        return getJSBundleFile(assetsBundleFileName);\n    }\n\n    public Context getContext() {\n        return mContext;\n    }\n\n    public String getDeploymentKey() {\n        return mDeploymentKey;\n    }\n\n    public static String getJSBundleFile() {\n        return CodePush.getJSBundleFile(CodePushConstants.DEFAULT_JS_BUNDLE_NAME);\n    }\n\n    public static String getJSBundleFile(String assetsBundleFileName) {\n        if (mCurrentInstance == null) {\n            throw new CodePushNotInitializedException(\"A CodePush instance has not been created yet. Have you added it to your app's list of ReactPackages?\");\n        }\n\n        return mCurrentInstance.getJSBundleFileInternal(assetsBundleFileName);\n    }\n\n    public String getJSBundleFileInternal(String assetsBundleFileName) {\n        this.mAssetsBundleFileName = assetsBundleFileName;\n        String binaryJsBundleUrl = CodePushConstants.ASSETS_BUNDLE_PREFIX + assetsBundleFileName;\n\n        String packageFilePath = null;\n        try {\n            packageFilePath = mUpdateManager.getCurrentPackageBundlePath(this.mAssetsBundleFileName);\n        } catch (CodePushMalformedDataException e) {\n            // We need to recover the app in case 'codepush.json' is corrupted\n            CodePushUtils.log(e.getMessage());\n            clearUpdates();\n        }\n\n        if (packageFilePath == null) {\n            // There has not been any downloaded updates.\n            CodePushUtils.logBundleUrl(binaryJsBundleUrl);\n            sIsRunningBinaryVersion = true;\n            return binaryJsBundleUrl;\n        }\n\n        JSONObject packageMetadata = this.mUpdateManager.getCurrentPackage();\n        if (isPackageBundleLatest(packageMetadata)) {\n            CodePushUtils.logBundleUrl(packageFilePath);\n            sIsRunningBinaryVersion = false;\n            return packageFilePath;\n        } else {\n            // The binary version is newer.\n            this.mDidUpdate = false;\n            if (!this.mIsDebugMode || hasBinaryVersionChanged(packageMetadata)) {\n                this.clearUpdates();\n            }\n\n            CodePushUtils.logBundleUrl(binaryJsBundleUrl);\n            sIsRunningBinaryVersion = true;\n            return binaryJsBundleUrl;\n        }\n    }\n\n    public String getServerUrl() {\n        return mServerUrl;\n    }\n\n    void initializeUpdateAfterRestart() {\n        // Reset the state which indicates that\n        // the app was just freshly updated.\n        mDidUpdate = false;\n\n        JSONObject pendingUpdate = mSettingsManager.getPendingUpdate();\n        if (pendingUpdate != null) {\n            JSONObject packageMetadata = null;\n\n            try {\n                packageMetadata = this.mUpdateManager.getCurrentPackage();\n            } catch (CodePushMalformedDataException e) {\n                // We need to recover the app in case 'codepush.json' is corrupted\n                CodePushUtils.log(e);\n                clearUpdates();\n                return;\n            }\n            if (packageMetadata == null || !isPackageBundleLatest(packageMetadata) && hasBinaryVersionChanged(packageMetadata)) {\n                CodePushUtils.log(\"Skipping initializeUpdateAfterRestart(), binary version is newer\");\n                return;\n            }\n\n            try {\n                boolean updateIsLoading = pendingUpdate.getBoolean(CodePushConstants.PENDING_UPDATE_IS_LOADING_KEY);\n                if (updateIsLoading) {\n                    // Pending update was initialized, but notifyApplicationReady was not called.\n                    // Therefore, deduce that it is a broken update and rollback.\n                    CodePushUtils.log(\"Update did not finish loading the last time, rolling back to a previous version.\");\n                    sNeedToReportRollback = true;\n                    rollbackPackage();\n                } else {\n                    // There is in fact a new update running for the first\n                    // time, so update the local state to ensure the client knows.\n                    mDidUpdate = true;\n\n                    // Mark that we tried to initialize the new update, so that if it crashes,\n                    // we will know that we need to rollback when the app next starts.\n                    mSettingsManager.savePendingUpdate(pendingUpdate.getString(CodePushConstants.PENDING_UPDATE_HASH_KEY),\n                            /* isLoading */true);\n                }\n            } catch (JSONException e) {\n                // Should not happen.\n                throw new CodePushUnknownException(\"Unable to read pending update metadata stored in SharedPreferences\", e);\n            }\n        }\n    }\n\n    void invalidateCurrentInstance() {\n        mCurrentInstance = null;\n    }\n\n    boolean isDebugMode() {\n        return mIsDebugMode;\n    }\n\n    boolean isRunningBinaryVersion() {\n        return sIsRunningBinaryVersion;\n    }\n\n    private boolean isPackageBundleLatest(JSONObject packageMetadata) {\n        try {\n            Long binaryModifiedDateDuringPackageInstall = null;\n            String binaryModifiedDateDuringPackageInstallString = packageMetadata.optString(CodePushConstants.BINARY_MODIFIED_TIME_KEY, null);\n            if (binaryModifiedDateDuringPackageInstallString != null) {\n                binaryModifiedDateDuringPackageInstall = Long.parseLong(binaryModifiedDateDuringPackageInstallString);\n            }\n            String packageAppVersion = packageMetadata.optString(\"appVersion\", null);\n            long binaryResourcesModifiedTime = this.getBinaryResourcesModifiedTime();\n            return binaryModifiedDateDuringPackageInstall != null &&\n                    binaryModifiedDateDuringPackageInstall == binaryResourcesModifiedTime &&\n                    (isUsingTestConfiguration() || sAppVersion.equals(packageAppVersion));\n        } catch (NumberFormatException e) {\n            throw new CodePushUnknownException(\"Error in reading binary modified date from package metadata\", e);\n        }\n    }\n\n    private boolean hasBinaryVersionChanged(JSONObject packageMetadata) {\n        String packageAppVersion = packageMetadata.optString(\"appVersion\", null);\n        return !sAppVersion.equals(packageAppVersion);\n    }\n\n    boolean needToReportRollback() {\n        return sNeedToReportRollback;\n    }\n\n    public static void overrideAppVersion(String appVersionOverride) {\n        sAppVersion = appVersionOverride;\n    }\n\n    private void rollbackPackage() {\n        JSONObject failedPackage = mUpdateManager.getCurrentPackage();\n        mSettingsManager.saveFailedUpdate(failedPackage);\n        mUpdateManager.rollbackPackage();\n        mSettingsManager.removePendingUpdate();\n    }\n\n    public void setNeedToReportRollback(boolean needToReportRollback) {\n        CodePush.sNeedToReportRollback = needToReportRollback;\n    }\n\n    /* The below 3 methods are used for running tests.*/\n    public static boolean isUsingTestConfiguration() {\n        return sTestConfigurationFlag;\n    }\n\n    public void setDeploymentKey(String deploymentKey) {\n        mDeploymentKey = deploymentKey;\n    }\n\n    public static void setUsingTestConfiguration(boolean shouldUseTestConfiguration) {\n        sTestConfigurationFlag = shouldUseTestConfiguration;\n    }\n\n    public void clearUpdates() {\n        mUpdateManager.clearUpdates();\n        mSettingsManager.removePendingUpdate();\n        mSettingsManager.removeFailedUpdates();\n    }\n\n    public static void setReactInstanceHolder(ReactInstanceHolder reactInstanceHolder) {\n        mReactInstanceHolder = reactInstanceHolder;\n    }\n\n    static ReactInstanceManager getReactInstanceManager() {\n        if (mReactInstanceHolder == null) {\n            return null;\n        }\n        return mReactInstanceHolder.getReactInstanceManager();\n    }\n\n    @Override\n    public List<NativeModule> createNativeModules(ReactApplicationContext reactApplicationContext) {\n        CodePushNativeModule codePushModule = new CodePushNativeModule(reactApplicationContext, this, mUpdateManager, mTelemetryManager, mSettingsManager);\n        CodePushDialog dialogModule = new CodePushDialog(reactApplicationContext);\n\n        List<NativeModule> nativeModules = new ArrayList<>();\n        nativeModules.add(codePushModule);\n        nativeModules.add(dialogModule);\n        return nativeModules;\n    }\n\n    // Deprecated in RN v0.47.\n    public List<Class<? extends JavaScriptModule>> createJSModules() {\n        return new ArrayList<>();\n    }\n\n    @Override\n    public List<ViewManager> createViewManagers(ReactApplicationContext reactApplicationContext) {\n        return new ArrayList<>();\n    }\n}\n"
  },
  {
    "path": "android/app/src/main/java/com/microsoft/codepush/react/CodePushBuilder.java",
    "content": "package com.microsoft.codepush.react;\n\nimport android.content.Context;\n\npublic class CodePushBuilder {\n    private String mDeploymentKey;\n    private Context mContext;\n\n    private boolean mIsDebugMode;\n    private String mServerUrl;\n    private Integer mPublicKeyResourceDescriptor;\n\n    public CodePushBuilder(String deploymentKey, Context context) {\n        this.mDeploymentKey = deploymentKey;\n        this.mContext = context;\n        this.mServerUrl = CodePush.getServiceUrl();\n    }\n\n    public CodePushBuilder setIsDebugMode(boolean isDebugMode) {\n        this.mIsDebugMode = isDebugMode;\n        return this;\n    }\n\n    public CodePushBuilder setServerUrl(String serverUrl) {\n        this.mServerUrl = serverUrl;\n        return this;\n    }\n\n    public CodePushBuilder setPublicKeyResourceDescriptor(int publicKeyResourceDescriptor) {\n        this.mPublicKeyResourceDescriptor = publicKeyResourceDescriptor;\n        return this;\n    }\n\n    public CodePush build() {\n        return new CodePush(this.mDeploymentKey, this.mContext, this.mIsDebugMode, this.mServerUrl, this.mPublicKeyResourceDescriptor);\n    }\n}\n"
  },
  {
    "path": "android/app/src/main/java/com/microsoft/codepush/react/CodePushConstants.java",
    "content": "package com.microsoft.codepush.react;\n\npublic class CodePushConstants {\n    public static final String ASSETS_BUNDLE_PREFIX = \"assets://\";\n    public static final String BINARY_MODIFIED_TIME_KEY = \"binaryModifiedTime\";\n    public static final String CODE_PUSH_FOLDER_PREFIX = \"CodePush\";\n    public static final String CODE_PUSH_HASH_FILE_NAME = \"CodePushHash\";\n    public static final String CODE_PUSH_OLD_HASH_FILE_NAME = \"CodePushHash.json\";\n    public static final String CODE_PUSH_PREFERENCES = \"CodePush\";\n    public static final String CURRENT_PACKAGE_KEY = \"currentPackage\";\n    public static final String DEFAULT_JS_BUNDLE_NAME = \"index.android.bundle\";\n    public static final String DIFF_MANIFEST_FILE_NAME = \"hotcodepush.json\";\n    public static final int DOWNLOAD_BUFFER_SIZE = 1024 * 256;\n    public static final String DOWNLOAD_FILE_NAME = \"download.zip\";\n    public static final String DOWNLOAD_PROGRESS_EVENT_NAME = \"CodePushDownloadProgress\";\n    public static final String DOWNLOAD_URL_KEY = \"downloadUrl\";\n    public static final String FAILED_UPDATES_KEY = \"CODE_PUSH_FAILED_UPDATES\";\n    public static final String PACKAGE_FILE_NAME = \"app.json\";\n    public static final String PACKAGE_HASH_KEY = \"packageHash\";\n    public static final String PENDING_UPDATE_HASH_KEY = \"hash\";\n    public static final String PENDING_UPDATE_IS_LOADING_KEY = \"isLoading\";\n    public static final String PENDING_UPDATE_KEY = \"CODE_PUSH_PENDING_UPDATE\";\n    public static final String PREVIOUS_PACKAGE_KEY = \"previousPackage\";\n    public static final String REACT_NATIVE_LOG_TAG = \"ReactNative\";\n    public static final String RELATIVE_BUNDLE_PATH_KEY = \"bundlePath\";\n    public static final String STATUS_FILE = \"codepush.json\";\n    public static final String UNZIPPED_FOLDER_NAME = \"unzipped\";\n    public static final String CODE_PUSH_APK_BUILD_TIME_KEY = \"CODE_PUSH_APK_BUILD_TIME\";\n    public static final String BUNDLE_JWT_FILE = \".codepushrelease\";\n    public static final String LATEST_ROLLBACK_INFO_KEY = \"LATEST_ROLLBACK_INFO\";\n    public static final String LATEST_ROLLBACK_PACKAGE_HASH_KEY = \"packageHash\";\n    public static final String LATEST_ROLLBACK_TIME_KEY = \"time\";\n    public static final String LATEST_ROLLBACK_COUNT_KEY = \"count\";\n    public static final String CLIENT_UNIQUE_ID_KEY = \"clientUniqueId\";\n}\n"
  },
  {
    "path": "android/app/src/main/java/com/microsoft/codepush/react/CodePushDialog.java",
    "content": "package com.microsoft.codepush.react;\n\nimport android.app.Activity;\nimport android.app.AlertDialog;\nimport android.content.DialogInterface;\n\nimport com.facebook.react.bridge.Callback;\nimport com.facebook.react.bridge.LifecycleEventListener;\nimport com.facebook.react.bridge.ReactApplicationContext;\nimport com.facebook.react.bridge.ReactContextBaseJavaModule;\nimport com.facebook.react.bridge.ReactMethod;\n\npublic class CodePushDialog extends ReactContextBaseJavaModule{\n\n    public CodePushDialog(ReactApplicationContext reactContext) {\n        super(reactContext);\n    }\n\n    @ReactMethod\n    public void showDialog(final String title, final String message, final String button1Text,\n                           final String button2Text, final Callback successCallback, Callback errorCallback) {\n        Activity currentActivity = getCurrentActivity();\n        if (currentActivity == null || currentActivity.isFinishing()) {\n            // If getCurrentActivity is null, it could be because the app is backgrounded,\n            // so we show the dialog when the app resumes)\n            getReactApplicationContext().addLifecycleEventListener(new LifecycleEventListener() {\n                @Override\n                public void onHostResume() {\n                    Activity currentActivity = getCurrentActivity();\n                    if (currentActivity != null) {\n                        getReactApplicationContext().removeLifecycleEventListener(this);\n                        showDialogInternal(title, message, button1Text, button2Text, successCallback, currentActivity);\n                    }\n                }\n\n                @Override\n                public void onHostPause() {\n\n                }\n\n                @Override\n                public void onHostDestroy() {\n\n                }\n            });\n        } else {\n            showDialogInternal(title, message, button1Text, button2Text, successCallback, currentActivity);\n        }\n    }\n\n    private void showDialogInternal(String title, String message, String button1Text,\n                                    String button2Text, final Callback successCallback, Activity currentActivity) {\n        AlertDialog.Builder builder = new AlertDialog.Builder(currentActivity);\n\n        builder.setCancelable(false);\n\n        DialogInterface.OnClickListener clickListener = new DialogInterface.OnClickListener() {\n            @Override\n            public void onClick(DialogInterface dialog, int which) {\n                try {\n                    dialog.cancel();\n                    switch (which) {\n                        case DialogInterface.BUTTON_POSITIVE:\n                            successCallback.invoke(0);\n                            break;\n                        case DialogInterface.BUTTON_NEGATIVE:\n                            successCallback.invoke(1);\n                            break;\n                        default:\n                            throw new CodePushUnknownException(\"Unknown button ID pressed.\");\n                    }\n                } catch (Throwable e) {\n                    CodePushUtils.log(e);\n                }\n            }\n        };\n\n        if (title != null) {\n            builder.setTitle(title);\n        }\n\n        if (message != null) {\n            builder.setMessage(message);\n        }\n\n        if (button1Text != null) {\n            builder.setPositiveButton(button1Text, clickListener);\n        }\n\n        if (button2Text != null) {\n            builder.setNegativeButton(button2Text, clickListener);\n        }\n\n        AlertDialog dialog = builder.create();\n        dialog.show();\n    }\n\n    @Override\n    public String getName() {\n        return \"CodePushDialog\";\n    }\n}\n"
  },
  {
    "path": "android/app/src/main/java/com/microsoft/codepush/react/CodePushInstallMode.java",
    "content": "package com.microsoft.codepush.react;\n\npublic enum CodePushInstallMode {\n    IMMEDIATE(0),\n    ON_NEXT_RESTART(1),\n    ON_NEXT_RESUME(2),\n    ON_NEXT_SUSPEND(3);\n\n    private final int value;\n    CodePushInstallMode(int value) {\n        this.value = value;\n    }\n    public int getValue() {\n        return this.value;\n    }\n}"
  },
  {
    "path": "android/app/src/main/java/com/microsoft/codepush/react/CodePushInvalidPublicKeyException.java",
    "content": "package com.microsoft.codepush.react;\n\nclass CodePushInvalidPublicKeyException extends RuntimeException {\n\n    public CodePushInvalidPublicKeyException(String message, Throwable cause) {\n        super(message, cause);\n    }\n\n    public CodePushInvalidPublicKeyException(String message) {\n        super(message);\n    }\n}"
  },
  {
    "path": "android/app/src/main/java/com/microsoft/codepush/react/CodePushInvalidUpdateException.java",
    "content": "package com.microsoft.codepush.react;\n\npublic class CodePushInvalidUpdateException extends RuntimeException {\n    public CodePushInvalidUpdateException(String message) {\n        super(message);\n    }\n}\n"
  },
  {
    "path": "android/app/src/main/java/com/microsoft/codepush/react/CodePushMalformedDataException.java",
    "content": "package com.microsoft.codepush.react;\n\nimport java.net.MalformedURLException;\n\npublic class CodePushMalformedDataException extends RuntimeException {\n    public CodePushMalformedDataException(String path, Throwable cause) {\n        super(\"Unable to parse contents of \" + path + \", the file may be corrupted.\", cause);\n    }\n    public CodePushMalformedDataException(String url, MalformedURLException cause) {\n        super(\"The package has an invalid downloadUrl: \" + url, cause);\n    }\n}"
  },
  {
    "path": "android/app/src/main/java/com/microsoft/codepush/react/CodePushNativeModule.java",
    "content": "package com.microsoft.codepush.react;\n\nimport android.app.Activity;\nimport android.content.SharedPreferences;\nimport android.os.AsyncTask;\nimport android.os.Handler;\nimport android.os.Looper;\nimport android.provider.Settings;\nimport android.view.View;\n\nimport com.facebook.react.ReactApplication;\nimport com.facebook.react.ReactInstanceManager;\nimport com.facebook.react.ReactRootView;\nimport com.facebook.react.bridge.Arguments;\nimport com.facebook.react.bridge.JSBundleLoader;\nimport com.facebook.react.bridge.LifecycleEventListener;\nimport com.facebook.react.bridge.Promise;\nimport com.facebook.react.bridge.ReactApplicationContext;\nimport com.facebook.react.bridge.ReactContextBaseJavaModule;\nimport com.facebook.react.bridge.ReactMethod;\nimport com.facebook.react.bridge.ReadableMap;\nimport com.facebook.react.bridge.WritableMap;\nimport com.facebook.react.modules.core.ChoreographerCompat;\nimport com.facebook.react.modules.core.DeviceEventManagerModule;\nimport com.facebook.react.modules.core.ReactChoreographer;\n\nimport org.json.JSONArray;\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.io.IOException;\nimport java.lang.reflect.Field;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.UUID;\n\npublic class CodePushNativeModule extends ReactContextBaseJavaModule {\n    private String mBinaryContentsHash = null;\n    private String mClientUniqueId = null;\n    private LifecycleEventListener mLifecycleEventListener = null;\n    private int mMinimumBackgroundDuration = 0;\n\n    private CodePush mCodePush;\n    private SettingsManager mSettingsManager;\n    private CodePushTelemetryManager mTelemetryManager;\n    private CodePushUpdateManager mUpdateManager;\n\n    private  boolean _allowed = true;\n    private  boolean _restartInProgress = false;\n    private  ArrayList<Boolean> _restartQueue = new ArrayList<>();\n\n    public CodePushNativeModule(ReactApplicationContext reactContext, CodePush codePush, CodePushUpdateManager codePushUpdateManager, CodePushTelemetryManager codePushTelemetryManager, SettingsManager settingsManager) {\n        super(reactContext);\n\n        mCodePush = codePush;\n        mSettingsManager = settingsManager;\n        mTelemetryManager = codePushTelemetryManager;\n        mUpdateManager = codePushUpdateManager;\n\n        // Initialize module state while we have a reference to the current context.\n        mBinaryContentsHash = CodePushUpdateUtils.getHashForBinaryContents(reactContext, mCodePush.isDebugMode());\n\n        SharedPreferences preferences = codePush.getContext().getSharedPreferences(CodePushConstants.CODE_PUSH_PREFERENCES, 0);\n        mClientUniqueId = preferences.getString(CodePushConstants.CLIENT_UNIQUE_ID_KEY, null);\n        if (mClientUniqueId == null) {\n            mClientUniqueId = UUID.randomUUID().toString();\n            preferences.edit().putString(CodePushConstants.CLIENT_UNIQUE_ID_KEY, mClientUniqueId).apply();\n        }\n    }\n\n    @Override\n    public Map<String, Object> getConstants() {\n        final Map<String, Object> constants = new HashMap<>();\n\n        constants.put(\"codePushInstallModeImmediate\", CodePushInstallMode.IMMEDIATE.getValue());\n        constants.put(\"codePushInstallModeOnNextRestart\", CodePushInstallMode.ON_NEXT_RESTART.getValue());\n        constants.put(\"codePushInstallModeOnNextResume\", CodePushInstallMode.ON_NEXT_RESUME.getValue());\n        constants.put(\"codePushInstallModeOnNextSuspend\", CodePushInstallMode.ON_NEXT_SUSPEND.getValue());\n\n        constants.put(\"codePushUpdateStateRunning\", CodePushUpdateState.RUNNING.getValue());\n        constants.put(\"codePushUpdateStatePending\", CodePushUpdateState.PENDING.getValue());\n        constants.put(\"codePushUpdateStateLatest\", CodePushUpdateState.LATEST.getValue());\n\n        return constants;\n    }\n\n    @Override\n    public String getName() {\n        return \"CodePush\";\n    }\n\n    private void loadBundleLegacy() {\n        final Activity currentActivity = getCurrentActivity();\n        if (currentActivity == null) {\n            // The currentActivity can be null if it is backgrounded / destroyed, so we simply\n            // no-op to prevent any null pointer exceptions.\n            return;\n        }\n        mCodePush.invalidateCurrentInstance();\n\n        currentActivity.runOnUiThread(new Runnable() {\n            @Override\n            public void run() {\n                currentActivity.recreate();\n            }\n        });\n    }\n\n    // Use reflection to find and set the appropriate fields on ReactInstanceManager. See #556 for a proposal for a less brittle way\n    // to approach this.\n    private void setJSBundle(ReactInstanceManager instanceManager, String latestJSBundleFile) throws IllegalAccessException {\n        try {\n            JSBundleLoader latestJSBundleLoader;\n            if (latestJSBundleFile.toLowerCase().startsWith(\"assets://\")) {\n                latestJSBundleLoader = JSBundleLoader.createAssetLoader(getReactApplicationContext(), latestJSBundleFile, false);\n            } else {\n                latestJSBundleLoader = JSBundleLoader.createFileLoader(latestJSBundleFile);\n            }\n\n            Field bundleLoaderField = instanceManager.getClass().getDeclaredField(\"mBundleLoader\");\n            bundleLoaderField.setAccessible(true);\n            bundleLoaderField.set(instanceManager, latestJSBundleLoader);\n        } catch (Exception e) {\n            CodePushUtils.log(\"Unable to set JSBundle - CodePush may not support this version of React Native\");\n            throw new IllegalAccessException(\"Could not setJSBundle\");\n        }\n    }\n\n    private void loadBundle() {\n        clearLifecycleEventListener();\n        try {\n            mCodePush.clearDebugCacheIfNeeded(resolveInstanceManager());\n        } catch(Exception e) {\n            // If we got error in out reflection we should clear debug cache anyway.\n            mCodePush.clearDebugCacheIfNeeded(null);\n        }\n\n        try {\n            // #1) Get the ReactInstanceManager instance, which is what includes the\n            //     logic to reload the current React context.\n            final ReactInstanceManager instanceManager = resolveInstanceManager();\n            if (instanceManager == null) {\n                return;\n            }\n\n            String latestJSBundleFile = mCodePush.getJSBundleFileInternal(mCodePush.getAssetsBundleFileName());\n\n            // #2) Update the locally stored JS bundle file path\n            setJSBundle(instanceManager, latestJSBundleFile);\n\n            // #3) Get the context creation method and fire it on the UI thread (which RN enforces)\n            new Handler(Looper.getMainLooper()).post(new Runnable() {\n                @Override\n                public void run() {\n                    try {\n                        // We don't need to resetReactRootViews anymore \n                        // due the issue https://github.com/facebook/react-native/issues/14533\n                        // has been fixed in RN 0.46.0\n                        //resetReactRootViews(instanceManager);\n\n                        instanceManager.recreateReactContextInBackground();\n                        mCodePush.initializeUpdateAfterRestart();\n                    } catch (Exception e) {\n                        // The recreation method threw an unknown exception\n                        // so just simply fallback to restarting the Activity (if it exists)\n                        loadBundleLegacy();\n                    }\n                }\n            });\n\n        } catch (Exception e) {\n            // Our reflection logic failed somewhere\n            // so fall back to restarting the Activity (if it exists)\n            CodePushUtils.log(\"Failed to load the bundle, falling back to restarting the Activity (if it exists). \" + e.getMessage());\n            loadBundleLegacy();\n        }\n    }\n\n    // This workaround has been implemented in order to fix https://github.com/facebook/react-native/issues/14533\n    // resetReactRootViews allows to call recreateReactContextInBackground without any exceptions\n    // This fix also relates to https://github.com/microsoft/react-native-code-push/issues/878\n    private void resetReactRootViews(ReactInstanceManager instanceManager) throws NoSuchFieldException, IllegalAccessException {\n        Field mAttachedRootViewsField = instanceManager.getClass().getDeclaredField(\"mAttachedRootViews\");\n        mAttachedRootViewsField.setAccessible(true);\n        List<ReactRootView> mAttachedRootViews = (List<ReactRootView>)mAttachedRootViewsField.get(instanceManager);\n        for (ReactRootView reactRootView : mAttachedRootViews) {\n            reactRootView.removeAllViews();\n            reactRootView.setId(View.NO_ID);\n        }\n        mAttachedRootViewsField.set(instanceManager, mAttachedRootViews);\n    }\n\n    private void clearLifecycleEventListener() {\n        // Remove LifecycleEventListener to prevent infinite restart loop\n        if (mLifecycleEventListener != null) {\n            getReactApplicationContext().removeLifecycleEventListener(mLifecycleEventListener);\n            mLifecycleEventListener = null;\n        }\n    }\n\n    // Use reflection to find the ReactInstanceManager. See #556 for a proposal for a less brittle way to approach this.\n    private ReactInstanceManager resolveInstanceManager() throws NoSuchFieldException, IllegalAccessException {\n        ReactInstanceManager instanceManager = CodePush.getReactInstanceManager();\n        if (instanceManager != null) {\n            return instanceManager;\n        }\n\n        final Activity currentActivity = getCurrentActivity();\n        if (currentActivity == null) {\n            return null;\n        }\n\n        ReactApplication reactApplication = (ReactApplication) currentActivity.getApplication();\n        instanceManager = reactApplication.getReactNativeHost().getReactInstanceManager();\n\n        return instanceManager;\n    }\n\n    private void restartAppInternal(boolean onlyIfUpdateIsPending) {\n        if (this._restartInProgress) {\n            CodePushUtils.log(\"Restart request queued until the current restart is completed\");\n            this._restartQueue.add(onlyIfUpdateIsPending);\n            return;\n        } else if (!this._allowed) {\n            CodePushUtils.log(\"Restart request queued until restarts are re-allowed\");\n            this._restartQueue.add(onlyIfUpdateIsPending);\n            return;\n        }\n\n        this._restartInProgress = true;\n        if (!onlyIfUpdateIsPending || mSettingsManager.isPendingUpdate(null)) {\n            loadBundle();\n            CodePushUtils.log(\"Restarting app\");\n            return;\n        }\n\n        this._restartInProgress = false;\n        if (this._restartQueue.size() > 0) {\n            boolean buf = this._restartQueue.get(0);\n            this._restartQueue.remove(0);\n            this.restartAppInternal(buf);\n        }\n    }\n\n    @ReactMethod\n    public void allow(Promise promise) {\n        CodePushUtils.log(\"Re-allowing restarts\");\n        this._allowed = true;\n\n        if (_restartQueue.size() > 0) {\n            CodePushUtils.log(\"Executing pending restart\");\n            boolean buf = this._restartQueue.get(0);\n            this._restartQueue.remove(0);\n            this.restartAppInternal(buf);\n        }\n\n        promise.resolve(null);\n        return;\n    }\n\n    @ReactMethod\n    public void clearPendingRestart(Promise promise) {\n        this._restartQueue.clear();\n        promise.resolve(null);\n        return;\n    }\n\n    @ReactMethod\n    public void disallow(Promise promise) {\n        CodePushUtils.log(\"Disallowing restarts\");\n        this._allowed = false;\n        promise.resolve(null);\n        return;\n    }\n\n    @ReactMethod\n    public void restartApp(boolean onlyIfUpdateIsPending, Promise promise) {\n        try {\n            restartAppInternal(onlyIfUpdateIsPending);\n            promise.resolve(null);\n        } catch(CodePushUnknownException e) {\n            CodePushUtils.log(e);\n            promise.reject(e);\n        }\n    }\n\n    @ReactMethod\n    public void downloadUpdate(final ReadableMap updatePackage, final boolean notifyProgress, final Promise promise) {\n        AsyncTask<Void, Void, Void> asyncTask = new AsyncTask<Void, Void, Void>() {\n            @Override\n            protected Void doInBackground(Void... params) {\n                try {\n                    JSONObject mutableUpdatePackage = CodePushUtils.convertReadableToJsonObject(updatePackage);\n                    CodePushUtils.setJSONValueForKey(mutableUpdatePackage, CodePushConstants.BINARY_MODIFIED_TIME_KEY, \"\" + mCodePush.getBinaryResourcesModifiedTime());\n                    mUpdateManager.downloadPackage(mutableUpdatePackage, mCodePush.getAssetsBundleFileName(), new DownloadProgressCallback() {\n                        private boolean hasScheduledNextFrame = false;\n                        private DownloadProgress latestDownloadProgress = null;\n\n                        @Override\n                        public void call(DownloadProgress downloadProgress) {\n                            if (!notifyProgress) {\n                                return;\n                            }\n\n                            latestDownloadProgress = downloadProgress;\n                            // If the download is completed, synchronously send the last event.\n                            if (latestDownloadProgress.isCompleted()) {\n                                dispatchDownloadProgressEvent();\n                                return;\n                            }\n\n                            if (hasScheduledNextFrame) {\n                                return;\n                            }\n\n                            hasScheduledNextFrame = true;\n                            getReactApplicationContext().runOnUiQueueThread(new Runnable() {\n                                @Override\n                                public void run() {\n                                    ReactChoreographer.getInstance().postFrameCallback(ReactChoreographer.CallbackType.TIMERS_EVENTS, new ChoreographerCompat.FrameCallback() {\n                                        @Override\n                                        public void doFrame(long frameTimeNanos) {\n                                            if (!latestDownloadProgress.isCompleted()) {\n                                                dispatchDownloadProgressEvent();\n                                            }\n\n                                            hasScheduledNextFrame = false;\n                                        }\n                                    });\n                                }\n                            });\n                        }\n\n                        public void dispatchDownloadProgressEvent() {\n                            getReactApplicationContext()\n                                    .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)\n                                    .emit(CodePushConstants.DOWNLOAD_PROGRESS_EVENT_NAME, latestDownloadProgress.createWritableMap());\n                        }\n                    }, mCodePush.getPublicKey());\n\n                    JSONObject newPackage = mUpdateManager.getPackage(CodePushUtils.tryGetString(updatePackage, CodePushConstants.PACKAGE_HASH_KEY));\n                    promise.resolve(CodePushUtils.convertJsonObjectToWritable(newPackage));\n                } catch (CodePushInvalidUpdateException e) {\n                    CodePushUtils.log(e);\n                    mSettingsManager.saveFailedUpdate(CodePushUtils.convertReadableToJsonObject(updatePackage));\n                    promise.reject(e);\n                } catch (IOException | CodePushUnknownException e) {\n                    CodePushUtils.log(e);\n                    promise.reject(e);\n                }\n\n                return null;\n            }\n        };\n\n        asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);\n    }\n\n    @ReactMethod\n    public void getConfiguration(Promise promise) {\n        try {\n            WritableMap configMap =  Arguments.createMap();\n            configMap.putString(\"appVersion\", mCodePush.getAppVersion());\n            configMap.putString(\"clientUniqueId\", mClientUniqueId);\n            configMap.putString(\"deploymentKey\", mCodePush.getDeploymentKey());\n            configMap.putString(\"serverUrl\", mCodePush.getServerUrl());\n\n            // The binary hash may be null in debug builds\n            if (mBinaryContentsHash != null) {\n                configMap.putString(CodePushConstants.PACKAGE_HASH_KEY, mBinaryContentsHash);\n            }\n\n            promise.resolve(configMap);\n        } catch(CodePushUnknownException e) {\n            CodePushUtils.log(e);\n            promise.reject(e);\n        }\n    }\n\n    @ReactMethod\n    public void getUpdateMetadata(final int updateState, final Promise promise) {\n        AsyncTask<Void, Void, Void> asyncTask = new AsyncTask<Void, Void, Void>() {\n            @Override\n            protected Void doInBackground(Void... params) {\n                try {\n                    JSONObject currentPackage = mUpdateManager.getCurrentPackage();\n\n                    if (currentPackage == null) {\n                        promise.resolve(null);\n                        return null;\n                    }\n\n                    Boolean currentUpdateIsPending = false;\n\n                    if (currentPackage.has(CodePushConstants.PACKAGE_HASH_KEY)) {\n                        String currentHash = currentPackage.optString(CodePushConstants.PACKAGE_HASH_KEY, null);\n                        currentUpdateIsPending = mSettingsManager.isPendingUpdate(currentHash);\n                    }\n\n                    if (updateState == CodePushUpdateState.PENDING.getValue() && !currentUpdateIsPending) {\n                        // The caller wanted a pending update\n                        // but there isn't currently one.\n                        promise.resolve(null);\n                    } else if (updateState == CodePushUpdateState.RUNNING.getValue() && currentUpdateIsPending) {\n                        // The caller wants the running update, but the current\n                        // one is pending, so we need to grab the previous.\n                        JSONObject previousPackage = mUpdateManager.getPreviousPackage();\n\n                        if (previousPackage == null) {\n                            promise.resolve(null);\n                            return null;\n                        }\n\n                        promise.resolve(CodePushUtils.convertJsonObjectToWritable(previousPackage));\n                    } else {\n                        // The current package satisfies the request:\n                        // 1) Caller wanted a pending, and there is a pending update\n                        // 2) Caller wanted the running update, and there isn't a pending\n                        // 3) Caller wants the latest update, regardless if it's pending or not\n                        if (mCodePush.isRunningBinaryVersion()) {\n                            // This only matters in Debug builds. Since we do not clear \"outdated\" updates,\n                            // we need to indicate to the JS side that somehow we have a current update on\n                            // disk that is not actually running.\n                            CodePushUtils.setJSONValueForKey(currentPackage, \"_isDebugOnly\", true);\n                        }\n\n                        // Enable differentiating pending vs. non-pending updates\n                        CodePushUtils.setJSONValueForKey(currentPackage, \"isPending\", currentUpdateIsPending);\n                        promise.resolve(CodePushUtils.convertJsonObjectToWritable(currentPackage));\n                    }\n                } catch (CodePushMalformedDataException e) {\n                    // We need to recover the app in case 'codepush.json' is corrupted\n                    CodePushUtils.log(e.getMessage());\n                    clearUpdates();\n                    promise.resolve(null);\n                } catch(CodePushUnknownException e) {\n                    CodePushUtils.log(e);\n                    promise.reject(e);\n                }\n\n                return null;\n            }\n        };\n\n        asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);\n    }\n\n    @ReactMethod\n    public void getNewStatusReport(final Promise promise) {\n        AsyncTask<Void, Void, Void> asyncTask = new AsyncTask<Void, Void, Void>() {\n            @Override\n            protected Void doInBackground(Void... params) {\n                try {\n                    if (mCodePush.needToReportRollback()) {\n                        mCodePush.setNeedToReportRollback(false);\n                        JSONArray failedUpdates = mSettingsManager.getFailedUpdates();\n                        if (failedUpdates != null && failedUpdates.length() > 0) {\n                            try {\n                                JSONObject lastFailedPackageJSON = failedUpdates.getJSONObject(failedUpdates.length() - 1);\n                                WritableMap lastFailedPackage = CodePushUtils.convertJsonObjectToWritable(lastFailedPackageJSON);\n                                WritableMap failedStatusReport = mTelemetryManager.getRollbackReport(lastFailedPackage);\n                                if (failedStatusReport != null) {\n                                    promise.resolve(failedStatusReport);\n                                    return null;\n                                }\n                            } catch (JSONException e) {\n                                throw new CodePushUnknownException(\"Unable to read failed updates information stored in SharedPreferences.\", e);\n                            }\n                        }\n                    } else if (mCodePush.didUpdate()) {\n                        JSONObject currentPackage = mUpdateManager.getCurrentPackage();\n                        if (currentPackage != null) {\n                            WritableMap newPackageStatusReport = mTelemetryManager.getUpdateReport(CodePushUtils.convertJsonObjectToWritable(currentPackage));\n                            if (newPackageStatusReport != null) {\n                                promise.resolve(newPackageStatusReport);\n                                return null;\n                            }\n                        }\n                    } else if (mCodePush.isRunningBinaryVersion()) {\n                        WritableMap newAppVersionStatusReport = mTelemetryManager.getBinaryUpdateReport(mCodePush.getAppVersion());\n                        if (newAppVersionStatusReport != null) {\n                            promise.resolve(newAppVersionStatusReport);\n                            return null;\n                        }\n                    } else {\n                        WritableMap retryStatusReport = mTelemetryManager.getRetryStatusReport();\n                        if (retryStatusReport != null) {\n                            promise.resolve(retryStatusReport);\n                            return null;\n                        }\n                    }\n                    \n                    promise.resolve(\"\");\n                } catch(CodePushUnknownException e) {\n                    CodePushUtils.log(e);\n                    promise.reject(e);\n                }\n                return null;\n            }\n        };\n\n        asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);\n    }\n\n    @ReactMethod\n    public void installUpdate(final ReadableMap updatePackage, final int installMode, final int minimumBackgroundDuration, final Promise promise) {\n        AsyncTask<Void, Void, Void> asyncTask = new AsyncTask<Void, Void, Void>() {\n            @Override\n            protected Void doInBackground(Void... params) {\n                try {\n                    mUpdateManager.installPackage(CodePushUtils.convertReadableToJsonObject(updatePackage), mSettingsManager.isPendingUpdate(null));\n\n                    String pendingHash = CodePushUtils.tryGetString(updatePackage, CodePushConstants.PACKAGE_HASH_KEY);\n                    if (pendingHash == null) {\n                        throw new CodePushUnknownException(\"Update package to be installed has no hash.\");\n                    } else {\n                        mSettingsManager.savePendingUpdate(pendingHash, /* isLoading */false);\n                    }\n\n                    if (installMode == CodePushInstallMode.ON_NEXT_RESUME.getValue() ||\n                        // We also add the resume listener if the installMode is IMMEDIATE, because\n                        // if the current activity is backgrounded, we want to reload the bundle when\n                        // it comes back into the foreground.\n                        installMode == CodePushInstallMode.IMMEDIATE.getValue() ||\n                        installMode == CodePushInstallMode.ON_NEXT_SUSPEND.getValue()) {\n\n                        // Store the minimum duration on the native module as an instance\n                        // variable instead of relying on a closure below, so that any\n                        // subsequent resume-based installs could override it.\n                        CodePushNativeModule.this.mMinimumBackgroundDuration = minimumBackgroundDuration;\n\n                        if (mLifecycleEventListener == null) {\n                            // Ensure we do not add the listener twice.\n                            mLifecycleEventListener = new LifecycleEventListener() {\n                                private Date lastPausedDate = null;\n                                private Handler appSuspendHandler = new Handler(Looper.getMainLooper());\n                                private Runnable loadBundleRunnable = new Runnable() {\n                                    @Override\n                                    public void run() {\n                                        CodePushUtils.log(\"Loading bundle on suspend\");\n                                        restartAppInternal(false);\n                                    }\n                                };\n\n                                @Override\n                                public void onHostResume() {\n                                    appSuspendHandler.removeCallbacks(loadBundleRunnable);\n                                    // As of RN 36, the resume handler fires immediately if the app is in\n                                    // the foreground, so explicitly wait for it to be backgrounded first\n                                    if (lastPausedDate != null) {\n                                        long durationInBackground = (new Date().getTime() - lastPausedDate.getTime()) / 1000;\n                                        if (installMode == CodePushInstallMode.IMMEDIATE.getValue()\n                                                || durationInBackground >= CodePushNativeModule.this.mMinimumBackgroundDuration) {\n                                            CodePushUtils.log(\"Loading bundle on resume\");\n                                            restartAppInternal(false);\n                                        }\n                                    }\n                                }\n\n                                @Override\n                                public void onHostPause() {\n                                    // Save the current time so that when the app is later\n                                    // resumed, we can detect how long it was in the background.\n                                    lastPausedDate = new Date();\n\n                                    if (installMode == CodePushInstallMode.ON_NEXT_SUSPEND.getValue() && mSettingsManager.isPendingUpdate(null)) {\n                                        appSuspendHandler.postDelayed(loadBundleRunnable, minimumBackgroundDuration * 1000);\n                                    }\n                                }\n\n                                @Override\n                                public void onHostDestroy() {\n                                }\n                            };\n\n                            getReactApplicationContext().addLifecycleEventListener(mLifecycleEventListener);\n                        }\n                    }\n\n                    promise.resolve(\"\");\n                } catch(CodePushUnknownException e) {\n                    CodePushUtils.log(e);\n                    promise.reject(e);\n                }\n\n                return null;\n            }\n        };\n\n        asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);\n    }\n\n    @ReactMethod\n    public void isFailedUpdate(String packageHash, Promise promise) {\n        try {\n            promise.resolve(mSettingsManager.isFailedHash(packageHash));\n        } catch (CodePushUnknownException e) {\n            CodePushUtils.log(e);\n            promise.reject(e);\n        }\n    }\n\n    @ReactMethod\n    public void getLatestRollbackInfo(Promise promise) {\n        try {\n            JSONObject latestRollbackInfo = mSettingsManager.getLatestRollbackInfo();\n            if (latestRollbackInfo != null) {\n                promise.resolve(CodePushUtils.convertJsonObjectToWritable(latestRollbackInfo));\n            } else {\n                promise.resolve(null);\n            }\n        } catch (CodePushUnknownException e) {\n            CodePushUtils.log(e);\n            promise.reject(e);\n        }\n    }\n\n    @ReactMethod\n    public void setLatestRollbackInfo(String packageHash, Promise promise) {\n        try {\n            mSettingsManager.setLatestRollbackInfo(packageHash);\n            promise.resolve(null);\n        } catch (CodePushUnknownException e) {\n            CodePushUtils.log(e);\n            promise.reject(e);\n        }\n    }\n\n    @ReactMethod\n    public void isFirstRun(String packageHash, Promise promise) {\n        try {\n            boolean isFirstRun = mCodePush.didUpdate()\n                    && packageHash != null\n                    && packageHash.length() > 0\n                    && packageHash.equals(mUpdateManager.getCurrentPackageHash());\n            promise.resolve(isFirstRun);\n        } catch(CodePushUnknownException e) {\n            CodePushUtils.log(e);\n            promise.reject(e);\n        }\n    }\n\n    @ReactMethod\n    public void notifyApplicationReady(Promise promise) {\n        try {\n            mSettingsManager.removePendingUpdate();\n            promise.resolve(\"\");\n        } catch(CodePushUnknownException e) {\n            CodePushUtils.log(e);\n            promise.reject(e);\n        }\n    }\n\n    @ReactMethod\n    public void recordStatusReported(ReadableMap statusReport) {\n        try {\n            mTelemetryManager.recordStatusReported(statusReport);\n        } catch(CodePushUnknownException e) {\n            CodePushUtils.log(e);\n        }\n    }\n\n    @ReactMethod\n    public void saveStatusReportForRetry(ReadableMap statusReport) {\n        try {\n            mTelemetryManager.saveStatusReportForRetry(statusReport);\n        } catch(CodePushUnknownException e) {\n            CodePushUtils.log(e);\n        }\n    }\n\n    @ReactMethod\n    // Replaces the current bundle with the one downloaded from removeBundleUrl.\n    // It is only to be used during tests. No-ops if the test configuration flag is not set.\n    public void downloadAndReplaceCurrentBundle(String remoteBundleUrl) {\n        try {\n            if (mCodePush.isUsingTestConfiguration()) {\n                try {\n                    mUpdateManager.downloadAndReplaceCurrentBundle(remoteBundleUrl, mCodePush.getAssetsBundleFileName());\n                } catch (IOException e) {\n                    throw new CodePushUnknownException(\"Unable to replace current bundle\", e);\n                }\n            }\n        } catch(CodePushUnknownException | CodePushMalformedDataException e) {\n            CodePushUtils.log(e);\n        }\n    }\n\n    /**\n     * This method clears CodePush's downloaded updates.\n     * It is needed to switch to a different deployment if the current deployment is more recent.\n     * Note: we don’t recommend to use this method in scenarios other than that (CodePush will call\n     * this method automatically when needed in other cases) as it could lead to unpredictable\n     * behavior.\n     */\n    @ReactMethod\n    public void clearUpdates() {\n        CodePushUtils.log(\"Clearing updates.\");\n        mCodePush.clearUpdates();\n    }\n\n    @ReactMethod\n    public void addListener(String eventName) {\n        // Set up any upstream listeners or background tasks as necessary\n    }\n\n    @ReactMethod\n    public void removeListeners(Integer count) {\n        // Remove upstream listeners, stop unnecessary background tasks\n    }\n}\n"
  },
  {
    "path": "android/app/src/main/java/com/microsoft/codepush/react/CodePushNotInitializedException.java",
    "content": "package com.microsoft.codepush.react;\n\npublic final class CodePushNotInitializedException extends RuntimeException {\n\n    public CodePushNotInitializedException(String message, Throwable cause) {\n        super(message, cause);\n    }\n\n    public CodePushNotInitializedException(String message) {\n        super(message);\n    }\n}"
  },
  {
    "path": "android/app/src/main/java/com/microsoft/codepush/react/CodePushTelemetryManager.java",
    "content": "package com.microsoft.codepush.react;\n\nimport android.content.Context;\nimport android.content.SharedPreferences;\n\nimport com.facebook.react.bridge.Arguments;\nimport com.facebook.react.bridge.ReadableMap;\nimport com.facebook.react.bridge.WritableMap;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\npublic class CodePushTelemetryManager {\n    private SharedPreferences mSettings;\n    private final String APP_VERSION_KEY = \"appVersion\";\n    private final String DEPLOYMENT_FAILED_STATUS = \"DeploymentFailed\";\n    private final String DEPLOYMENT_KEY_KEY = \"deploymentKey\";\n    private final String DEPLOYMENT_SUCCEEDED_STATUS = \"DeploymentSucceeded\";\n    private final String LABEL_KEY = \"label\";\n    private final String LAST_DEPLOYMENT_REPORT_KEY = \"CODE_PUSH_LAST_DEPLOYMENT_REPORT\";\n    private final String PACKAGE_KEY = \"package\";\n    private final String PREVIOUS_DEPLOYMENT_KEY_KEY = \"previousDeploymentKey\";\n    private final String PREVIOUS_LABEL_OR_APP_VERSION_KEY = \"previousLabelOrAppVersion\";\n    private final String RETRY_DEPLOYMENT_REPORT_KEY = \"CODE_PUSH_RETRY_DEPLOYMENT_REPORT\";\n    private final String STATUS_KEY = \"status\";\n\n    public CodePushTelemetryManager(Context applicationContext) {\n        mSettings = applicationContext.getSharedPreferences(CodePushConstants.CODE_PUSH_PREFERENCES, 0);\n    }\n\n    public WritableMap getBinaryUpdateReport(String appVersion) {\n        String previousStatusReportIdentifier = this.getPreviousStatusReportIdentifier();\n        WritableMap reportMap = null;\n        if (previousStatusReportIdentifier == null) {\n            this.clearRetryStatusReport();\n            reportMap = Arguments.createMap();\n            reportMap.putString(APP_VERSION_KEY, appVersion);\n        } else if (!previousStatusReportIdentifier.equals(appVersion)) {\n            this.clearRetryStatusReport();\n            reportMap = Arguments.createMap();\n            if (this.isStatusReportIdentifierCodePushLabel(previousStatusReportIdentifier)) {\n                String previousDeploymentKey = this.getDeploymentKeyFromStatusReportIdentifier(previousStatusReportIdentifier);\n                String previousLabel = this.getVersionLabelFromStatusReportIdentifier(previousStatusReportIdentifier);\n                reportMap.putString(APP_VERSION_KEY, appVersion);\n                reportMap.putString(PREVIOUS_DEPLOYMENT_KEY_KEY, previousDeploymentKey);\n                reportMap.putString(PREVIOUS_LABEL_OR_APP_VERSION_KEY, previousLabel);\n            } else {\n                // Previous status report was with a binary app version.\n                reportMap.putString(APP_VERSION_KEY, appVersion);\n                reportMap.putString(PREVIOUS_LABEL_OR_APP_VERSION_KEY, previousStatusReportIdentifier);\n            }\n        }\n\n        return reportMap;\n    }\n\n    public WritableMap getRetryStatusReport() {\n        String retryStatusReportString = mSettings.getString(RETRY_DEPLOYMENT_REPORT_KEY, null);\n        if (retryStatusReportString != null) {\n            clearRetryStatusReport();\n            try {\n                JSONObject retryStatusReport = new JSONObject(retryStatusReportString);\n                return CodePushUtils.convertJsonObjectToWritable(retryStatusReport);\n            } catch (JSONException e) {\n                e.printStackTrace();\n            }\n        }\n\n        return null;\n    }\n\n    public WritableMap getRollbackReport(WritableMap lastFailedPackage) {\n        WritableMap reportMap =  Arguments.createMap();\n        reportMap.putMap(PACKAGE_KEY, lastFailedPackage);\n        reportMap.putString(STATUS_KEY, DEPLOYMENT_FAILED_STATUS);\n        return reportMap;\n    }\n\n    public WritableMap getUpdateReport(WritableMap currentPackage) {\n        String currentPackageIdentifier = this.getPackageStatusReportIdentifier(currentPackage);\n        String previousStatusReportIdentifier = this.getPreviousStatusReportIdentifier();\n        WritableMap reportMap = null;\n        if (currentPackageIdentifier != null) {\n            if (previousStatusReportIdentifier == null) {\n                this.clearRetryStatusReport();\n                reportMap = Arguments.createMap();\n                reportMap.putMap(PACKAGE_KEY, currentPackage);\n                reportMap.putString(STATUS_KEY, DEPLOYMENT_SUCCEEDED_STATUS);\n            } else if (!previousStatusReportIdentifier.equals(currentPackageIdentifier)) {\n                this.clearRetryStatusReport();\n                reportMap = Arguments.createMap();\n                if (this.isStatusReportIdentifierCodePushLabel(previousStatusReportIdentifier)) {\n                    String previousDeploymentKey = this.getDeploymentKeyFromStatusReportIdentifier(previousStatusReportIdentifier);\n                    String previousLabel = this.getVersionLabelFromStatusReportIdentifier(previousStatusReportIdentifier);\n                    reportMap.putMap(PACKAGE_KEY, currentPackage);\n                    reportMap.putString(STATUS_KEY, DEPLOYMENT_SUCCEEDED_STATUS);\n                    reportMap.putString(PREVIOUS_DEPLOYMENT_KEY_KEY, previousDeploymentKey);\n                    reportMap.putString(PREVIOUS_LABEL_OR_APP_VERSION_KEY, previousLabel);\n                } else {\n                    // Previous status report was with a binary app version.\n                    reportMap.putMap(PACKAGE_KEY, currentPackage);\n                    reportMap.putString(STATUS_KEY, DEPLOYMENT_SUCCEEDED_STATUS);\n                    reportMap.putString(PREVIOUS_LABEL_OR_APP_VERSION_KEY, previousStatusReportIdentifier);\n                }\n            }\n        }\n\n        return reportMap;\n    }\n\n    public void recordStatusReported(ReadableMap statusReport) {\n        // We don't need to record rollback reports, so exit early if that's what was specified.\n        if (statusReport.hasKey(STATUS_KEY) && DEPLOYMENT_FAILED_STATUS.equals(statusReport.getString(STATUS_KEY))) {\n            return;\n        }\n        \n        if (statusReport.hasKey(APP_VERSION_KEY)) {\n            saveStatusReportedForIdentifier(statusReport.getString(APP_VERSION_KEY));\n        } else if (statusReport.hasKey(PACKAGE_KEY)) {\n            String packageIdentifier = getPackageStatusReportIdentifier(statusReport.getMap(PACKAGE_KEY));\n            saveStatusReportedForIdentifier(packageIdentifier);\n        }\n    }\n\n    public void saveStatusReportForRetry(ReadableMap statusReport) {\n        JSONObject statusReportJSON = CodePushUtils.convertReadableToJsonObject(statusReport);\n        mSettings.edit().putString(RETRY_DEPLOYMENT_REPORT_KEY, statusReportJSON.toString()).commit();\n    }\n\n    private void clearRetryStatusReport() {\n        mSettings.edit().remove(RETRY_DEPLOYMENT_REPORT_KEY).commit();\n    }\n\n    private String getDeploymentKeyFromStatusReportIdentifier(String statusReportIdentifier) {\n        String[] parsedIdentifier = statusReportIdentifier.split(\":\");\n        if (parsedIdentifier.length > 0) {\n            return parsedIdentifier[0];\n        } else {\n            return null;\n        }\n    }\n\n    private String getPackageStatusReportIdentifier(ReadableMap updatePackage) {\n        // Because deploymentKeys can be dynamically switched, we use a\n        // combination of the deploymentKey and label as the packageIdentifier.\n        String deploymentKey = CodePushUtils.tryGetString(updatePackage, DEPLOYMENT_KEY_KEY);\n        String label = CodePushUtils.tryGetString(updatePackage, LABEL_KEY);\n        if (deploymentKey != null && label != null) {\n            return deploymentKey + \":\" + label;\n        } else {\n            return null;\n        }\n    }\n\n    private String getPreviousStatusReportIdentifier() {\n        return mSettings.getString(LAST_DEPLOYMENT_REPORT_KEY, null);\n    }\n\n    private String getVersionLabelFromStatusReportIdentifier(String statusReportIdentifier) {\n        String[] parsedIdentifier = statusReportIdentifier.split(\":\");\n        if (parsedIdentifier.length > 1) {\n            return parsedIdentifier[1];\n        } else {\n            return null;\n        }\n    }\n\n    private boolean isStatusReportIdentifierCodePushLabel(String statusReportIdentifier) {\n        return statusReportIdentifier != null && statusReportIdentifier.contains(\":\");\n    }\n\n    private void saveStatusReportedForIdentifier(String appVersionOrPackageIdentifier) {\n        mSettings.edit().putString(LAST_DEPLOYMENT_REPORT_KEY, appVersionOrPackageIdentifier).commit();\n    }\n}\n"
  },
  {
    "path": "android/app/src/main/java/com/microsoft/codepush/react/CodePushUnknownException.java",
    "content": "package com.microsoft.codepush.react;\n\nclass CodePushUnknownException extends RuntimeException {\n\n    public CodePushUnknownException(String message, Throwable cause) {\n        super(message, cause);\n    }\n\n    public CodePushUnknownException(String message) {\n        super(message);\n    }\n}"
  },
  {
    "path": "android/app/src/main/java/com/microsoft/codepush/react/CodePushUpdateManager.java",
    "content": "package com.microsoft.codepush.react;\n\nimport android.os.Build;\n\nimport org.json.JSONObject;\n\nimport java.io.BufferedInputStream;\nimport java.io.BufferedOutputStream;\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.net.HttpURLConnection;\nimport java.net.MalformedURLException;\nimport java.net.URL;\nimport java.nio.ByteBuffer;\n\nimport javax.net.ssl.HttpsURLConnection;\n\npublic class CodePushUpdateManager {\n\n    private String mDocumentsDirectory;\n\n    public CodePushUpdateManager(String documentsDirectory) {\n        mDocumentsDirectory = documentsDirectory;\n    }\n\n    private String getDownloadFilePath() {\n        return CodePushUtils.appendPathComponent(getCodePushPath(), CodePushConstants.DOWNLOAD_FILE_NAME);\n    }\n\n    private String getUnzippedFolderPath() {\n        return CodePushUtils.appendPathComponent(getCodePushPath(), CodePushConstants.UNZIPPED_FOLDER_NAME);\n    }\n\n    private String getDocumentsDirectory() {\n        return mDocumentsDirectory;\n    }\n\n    private String getCodePushPath() {\n        String codePushPath = CodePushUtils.appendPathComponent(getDocumentsDirectory(), CodePushConstants.CODE_PUSH_FOLDER_PREFIX);\n        if (CodePush.isUsingTestConfiguration()) {\n            codePushPath = CodePushUtils.appendPathComponent(codePushPath, \"TestPackages\");\n        }\n\n        return codePushPath;\n    }\n\n    private String getStatusFilePath() {\n        return CodePushUtils.appendPathComponent(getCodePushPath(), CodePushConstants.STATUS_FILE);\n    }\n\n    public JSONObject getCurrentPackageInfo() {\n        String statusFilePath = getStatusFilePath();\n        if (!FileUtils.fileAtPathExists(statusFilePath)) {\n            return new JSONObject();\n        }\n\n        try {\n            return CodePushUtils.getJsonObjectFromFile(statusFilePath);\n        } catch (IOException e) {\n            // Should not happen.\n            throw new CodePushUnknownException(\"Error getting current package info\", e);\n        }\n    }\n\n    public void updateCurrentPackageInfo(JSONObject packageInfo) {\n        try {\n            CodePushUtils.writeJsonToFile(packageInfo, getStatusFilePath());\n        } catch (IOException e) {\n            // Should not happen.\n            throw new CodePushUnknownException(\"Error updating current package info\", e);\n        }\n    }\n\n    public String getCurrentPackageFolderPath() {\n        JSONObject info = getCurrentPackageInfo();\n        String packageHash = info.optString(CodePushConstants.CURRENT_PACKAGE_KEY, null);\n        if (packageHash == null) {\n            return null;\n        }\n\n        return getPackageFolderPath(packageHash);\n    }\n\n    public String getCurrentPackageBundlePath(String bundleFileName) {\n        String packageFolder = getCurrentPackageFolderPath();\n        if (packageFolder == null) {\n            return null;\n        }\n\n        JSONObject currentPackage = getCurrentPackage();\n        if (currentPackage == null) {\n            return null;\n        }\n\n        String relativeBundlePath = currentPackage.optString(CodePushConstants.RELATIVE_BUNDLE_PATH_KEY, null);\n        if (relativeBundlePath == null) {\n            return CodePushUtils.appendPathComponent(packageFolder, bundleFileName);\n        } else {\n            return CodePushUtils.appendPathComponent(packageFolder, relativeBundlePath);\n        }\n    }\n\n    public String getPackageFolderPath(String packageHash) {\n        return CodePushUtils.appendPathComponent(getCodePushPath(), packageHash);\n    }\n\n    public String getCurrentPackageHash() {\n        JSONObject info = getCurrentPackageInfo();\n        return info.optString(CodePushConstants.CURRENT_PACKAGE_KEY, null);\n    }\n\n    public String getPreviousPackageHash() {\n        JSONObject info = getCurrentPackageInfo();\n        return info.optString(CodePushConstants.PREVIOUS_PACKAGE_KEY, null);\n    }\n\n    public JSONObject getCurrentPackage() {\n        String packageHash = getCurrentPackageHash();\n        if (packageHash == null) {\n            return null;\n        }\n\n        return getPackage(packageHash);\n    }\n\n    public JSONObject getPreviousPackage() {\n        String packageHash = getPreviousPackageHash();\n        if (packageHash == null) {\n            return null;\n        }\n\n        return getPackage(packageHash);\n    }\n\n    public JSONObject getPackage(String packageHash) {\n        String folderPath = getPackageFolderPath(packageHash);\n        String packageFilePath = CodePushUtils.appendPathComponent(folderPath, CodePushConstants.PACKAGE_FILE_NAME);\n        try {\n            return CodePushUtils.getJsonObjectFromFile(packageFilePath);\n        } catch (IOException e) {\n            return null;\n        }\n    }\n\n    public void downloadPackage(JSONObject updatePackage, String expectedBundleFileName,\n                                DownloadProgressCallback progressCallback,\n                                String stringPublicKey) throws IOException {\n        String newUpdateHash = updatePackage.optString(CodePushConstants.PACKAGE_HASH_KEY, null);\n        String newUpdateFolderPath = getPackageFolderPath(newUpdateHash);\n        String newUpdateMetadataPath = CodePushUtils.appendPathComponent(newUpdateFolderPath, CodePushConstants.PACKAGE_FILE_NAME);\n        if (FileUtils.fileAtPathExists(newUpdateFolderPath)) {\n            // This removes any stale data in newPackageFolderPath that could have been left\n            // uncleared due to a crash or error during the download or install process.\n            FileUtils.deleteDirectoryAtPath(newUpdateFolderPath);\n        }\n\n        String downloadUrlString = updatePackage.optString(CodePushConstants.DOWNLOAD_URL_KEY, null);\n        HttpURLConnection connection = null;\n        BufferedInputStream bin = null;\n        FileOutputStream fos = null;\n        BufferedOutputStream bout = null;\n        File downloadFile = null;\n        boolean isZip = false;\n\n        // Download the file while checking if it is a zip and notifying client of progress.\n        try {\n            URL downloadUrl = new URL(downloadUrlString);\n            connection = (HttpURLConnection) (downloadUrl.openConnection());\n\n            if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP &&\n                downloadUrl.toString().startsWith(\"https\")) {\n                try {\n                    ((HttpsURLConnection)connection).setSSLSocketFactory(new TLSSocketFactory());\n                } catch (Exception e) {\n                    throw new CodePushUnknownException(\"Error set SSLSocketFactory. \", e);\n                }\n            }\n\n            connection.setRequestProperty(\"Accept-Encoding\", \"identity\");\n            bin = new BufferedInputStream(connection.getInputStream());\n\n            long totalBytes = connection.getContentLength();\n            long receivedBytes = 0;\n\n            File downloadFolder = new File(getCodePushPath());\n            downloadFolder.mkdirs();\n            downloadFile = new File(downloadFolder, CodePushConstants.DOWNLOAD_FILE_NAME);\n            fos = new FileOutputStream(downloadFile);\n            bout = new BufferedOutputStream(fos, CodePushConstants.DOWNLOAD_BUFFER_SIZE);\n            byte[] data = new byte[CodePushConstants.DOWNLOAD_BUFFER_SIZE];\n            byte[] header = new byte[4];\n\n            int numBytesRead = 0;\n            while ((numBytesRead = bin.read(data, 0, CodePushConstants.DOWNLOAD_BUFFER_SIZE)) >= 0) {\n                if (receivedBytes < 4) {\n                    for (int i = 0; i < numBytesRead; i++) {\n                        int headerOffset = (int) (receivedBytes) + i;\n                        if (headerOffset >= 4) {\n                            break;\n                        }\n\n                        header[headerOffset] = data[i];\n                    }\n                }\n\n                receivedBytes += numBytesRead;\n                bout.write(data, 0, numBytesRead);\n                progressCallback.call(new DownloadProgress(totalBytes, receivedBytes));\n            }\n\n            if (totalBytes != receivedBytes) {\n                throw new CodePushUnknownException(\"Received \" + receivedBytes + \" bytes, expected \" + totalBytes);\n            }\n\n            isZip = ByteBuffer.wrap(header).getInt() == 0x504b0304;\n        } catch (MalformedURLException e) {\n            throw new CodePushMalformedDataException(downloadUrlString, e);\n        } finally {\n            try {\n                if (bout != null) bout.close();\n                if (fos != null) fos.close();\n                if (bin != null) bin.close();\n                if (connection != null) connection.disconnect();\n            } catch (IOException e) {\n                throw new CodePushUnknownException(\"Error closing IO resources.\", e);\n            }\n        }\n\n        if (isZip) {\n            // Unzip the downloaded file and then delete the zip\n            String unzippedFolderPath = getUnzippedFolderPath();\n            FileUtils.unzipFile(downloadFile, unzippedFolderPath);\n            FileUtils.deleteFileOrFolderSilently(downloadFile);\n\n            // Merge contents with current update based on the manifest\n            String diffManifestFilePath = CodePushUtils.appendPathComponent(unzippedFolderPath,\n                    CodePushConstants.DIFF_MANIFEST_FILE_NAME);\n            boolean isDiffUpdate = FileUtils.fileAtPathExists(diffManifestFilePath);\n            if (isDiffUpdate) {\n                String currentPackageFolderPath = getCurrentPackageFolderPath();\n                CodePushUpdateUtils.copyNecessaryFilesFromCurrentPackage(diffManifestFilePath, currentPackageFolderPath, newUpdateFolderPath);\n                File diffManifestFile = new File(diffManifestFilePath);\n                diffManifestFile.delete();\n            }\n\n            FileUtils.copyDirectoryContents(unzippedFolderPath, newUpdateFolderPath);\n            FileUtils.deleteFileAtPathSilently(unzippedFolderPath);\n\n            // For zip updates, we need to find the relative path to the jsBundle and save it in the\n            // metadata so that we can find and run it easily the next time.\n            String relativeBundlePath = CodePushUpdateUtils.findJSBundleInUpdateContents(newUpdateFolderPath, expectedBundleFileName);\n\n            if (relativeBundlePath == null) {\n                throw new CodePushInvalidUpdateException(\"Update is invalid - A JS bundle file named \\\"\" + expectedBundleFileName + \"\\\" could not be found within the downloaded contents. Please check that you are releasing your CodePush updates using the exact same JS bundle file name that was shipped with your app's binary.\");\n            } else {\n                if (FileUtils.fileAtPathExists(newUpdateMetadataPath)) {\n                    File metadataFileFromOldUpdate = new File(newUpdateMetadataPath);\n                    metadataFileFromOldUpdate.delete();\n                }\n\n                if (isDiffUpdate) {\n                    CodePushUtils.log(\"Applying diff update.\");\n                } else {\n                    CodePushUtils.log(\"Applying full update.\");\n                }\n\n                boolean isSignatureVerificationEnabled = (stringPublicKey != null);\n\n                String signaturePath = CodePushUpdateUtils.getSignatureFilePath(newUpdateFolderPath);\n                boolean isSignatureAppearedInBundle = FileUtils.fileAtPathExists(signaturePath);\n\n                if (isSignatureVerificationEnabled) {\n                    if (isSignatureAppearedInBundle) {\n                        CodePushUpdateUtils.verifyFolderHash(newUpdateFolderPath, newUpdateHash);\n                        CodePushUpdateUtils.verifyUpdateSignature(newUpdateFolderPath, newUpdateHash, stringPublicKey);\n                    } else {\n                        throw new CodePushInvalidUpdateException(\n                                \"Error! Public key was provided but there is no JWT signature within app bundle to verify. \" +\n                                \"Possible reasons, why that might happen: \\n\" +\n                                \"1. You've been released CodePush bundle update using version of CodePush CLI that is not support code signing.\\n\" +\n                                \"2. You've been released CodePush bundle update without providing --privateKeyPath option.\"\n                        );\n                    }\n                } else {\n                    if (isSignatureAppearedInBundle) {\n                        CodePushUtils.log(\n                                \"Warning! JWT signature exists in codepush update but code integrity check couldn't be performed because there is no public key configured. \" +\n                                \"Please ensure that public key is properly configured within your application.\"\n                        );\n                        CodePushUpdateUtils.verifyFolderHash(newUpdateFolderPath, newUpdateHash);\n                    } else {\n                        if (isDiffUpdate) {\n                            CodePushUpdateUtils.verifyFolderHash(newUpdateFolderPath, newUpdateHash);\n                        }\n                    }\n                }\n\n                CodePushUtils.setJSONValueForKey(updatePackage, CodePushConstants.RELATIVE_BUNDLE_PATH_KEY, relativeBundlePath);\n            }\n        } else {\n            // File is a jsbundle, move it to a folder with the packageHash as its name\n            FileUtils.moveFile(downloadFile, newUpdateFolderPath, expectedBundleFileName);\n        }\n\n        // Save metadata to the folder.\n        CodePushUtils.writeJsonToFile(updatePackage, newUpdateMetadataPath);\n    }\n\n    public void installPackage(JSONObject updatePackage, boolean removePendingUpdate) {\n        String packageHash = updatePackage.optString(CodePushConstants.PACKAGE_HASH_KEY, null);\n        JSONObject info = getCurrentPackageInfo();\n\n        String currentPackageHash = info.optString(CodePushConstants.CURRENT_PACKAGE_KEY, null);\n        if (packageHash != null && packageHash.equals(currentPackageHash)) {\n            // The current package is already the one being installed, so we should no-op.\n            return;\n        }\n\n        if (removePendingUpdate) {\n            String currentPackageFolderPath = getCurrentPackageFolderPath();\n            if (currentPackageFolderPath != null) {\n                FileUtils.deleteDirectoryAtPath(currentPackageFolderPath);\n            }\n        } else {\n            String previousPackageHash = getPreviousPackageHash();\n            if (previousPackageHash != null && !previousPackageHash.equals(packageHash)) {\n                FileUtils.deleteDirectoryAtPath(getPackageFolderPath(previousPackageHash));\n            }\n\n            CodePushUtils.setJSONValueForKey(info, CodePushConstants.PREVIOUS_PACKAGE_KEY, info.optString(CodePushConstants.CURRENT_PACKAGE_KEY, null));\n        }\n\n        CodePushUtils.setJSONValueForKey(info, CodePushConstants.CURRENT_PACKAGE_KEY, packageHash);\n        updateCurrentPackageInfo(info);\n    }\n\n    public void rollbackPackage() {\n        JSONObject info = getCurrentPackageInfo();\n        String currentPackageFolderPath = getCurrentPackageFolderPath();\n        FileUtils.deleteDirectoryAtPath(currentPackageFolderPath);\n        CodePushUtils.setJSONValueForKey(info, CodePushConstants.CURRENT_PACKAGE_KEY, info.optString(CodePushConstants.PREVIOUS_PACKAGE_KEY, null));\n        CodePushUtils.setJSONValueForKey(info, CodePushConstants.PREVIOUS_PACKAGE_KEY, null);\n        updateCurrentPackageInfo(info);\n    }\n\n    public void downloadAndReplaceCurrentBundle(String remoteBundleUrl, String bundleFileName) throws IOException {\n        URL downloadUrl;\n        HttpURLConnection connection = null;\n        BufferedInputStream bin = null;\n        FileOutputStream fos = null;\n        BufferedOutputStream bout = null;\n        try {\n            downloadUrl = new URL(remoteBundleUrl);\n            connection = (HttpURLConnection) (downloadUrl.openConnection());\n            bin = new BufferedInputStream(connection.getInputStream());\n            File downloadFile = new File(getCurrentPackageBundlePath(bundleFileName));\n            downloadFile.delete();\n            fos = new FileOutputStream(downloadFile);\n            bout = new BufferedOutputStream(fos, CodePushConstants.DOWNLOAD_BUFFER_SIZE);\n            byte[] data = new byte[CodePushConstants.DOWNLOAD_BUFFER_SIZE];\n            int numBytesRead = 0;\n            while ((numBytesRead = bin.read(data, 0, CodePushConstants.DOWNLOAD_BUFFER_SIZE)) >= 0) {\n                bout.write(data, 0, numBytesRead);\n            }\n        } catch (MalformedURLException e) {\n            throw new CodePushMalformedDataException(remoteBundleUrl, e);\n        } finally {\n            try {\n                if (bout != null) bout.close();\n                if (fos != null) fos.close();\n                if (bin != null) bin.close();\n                if (connection != null) connection.disconnect();\n            } catch (IOException e) {\n                throw new CodePushUnknownException(\"Error closing IO resources.\", e);\n            }\n        }\n    }\n\n    public void clearUpdates() {\n        FileUtils.deleteDirectoryAtPath(getCodePushPath());\n    }\n}\n"
  },
  {
    "path": "android/app/src/main/java/com/microsoft/codepush/react/CodePushUpdateState.java",
    "content": "package com.microsoft.codepush.react;\n\npublic enum CodePushUpdateState {\n    RUNNING(0),\n    PENDING(1),\n    LATEST(2);\n\n    private final int value;\n    CodePushUpdateState(int value) {\n        this.value = value;\n    }\n    public int getValue() {\n        return this.value;\n    }\n}"
  },
  {
    "path": "android/app/src/main/java/com/microsoft/codepush/react/CodePushUpdateUtils.java",
    "content": "package com.microsoft.codepush.react;\n\nimport android.content.Context;\nimport android.util.Base64;\n\nimport com.nimbusds.jose.JWSVerifier;\nimport com.nimbusds.jose.crypto.RSASSAVerifier;\nimport com.nimbusds.jwt.SignedJWT;\n\nimport java.security.interfaces.*;\n\nimport org.json.JSONArray;\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.security.DigestInputStream;\nimport java.security.KeyFactory;\nimport java.security.MessageDigest;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.PublicKey;\nimport java.security.spec.X509EncodedKeySpec;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Map;\n\npublic class CodePushUpdateUtils {\n\n    public static final String NEW_LINE = System.getProperty(\"line.separator\");\n\n    // Note: The hashing logic here must mirror the hashing logic in other native SDK's, as well as in the\n    // CLI. Ensure that any changes here are propagated to these other locations.\n    public static boolean isHashIgnored(String relativeFilePath) {\n        final String __MACOSX = \"__MACOSX/\";\n        final String DS_STORE = \".DS_Store\";\n        final String CODEPUSH_METADATA = \".codepushrelease\";\n\n        return relativeFilePath.startsWith(__MACOSX)\n                || relativeFilePath.equals(DS_STORE)\n                || relativeFilePath.endsWith(\"/\" + DS_STORE)\n                || relativeFilePath.equals(CODEPUSH_METADATA)\n                || relativeFilePath.endsWith(\"/\" + CODEPUSH_METADATA);\n    }\n\n    private static void addContentsOfFolderToManifest(String folderPath, String pathPrefix, ArrayList<String> manifest) {\n        File folder = new File(folderPath);\n        File[] folderFiles = folder.listFiles();\n        for (File file : folderFiles) {\n            String fileName = file.getName();\n            String fullFilePath = file.getAbsolutePath();\n            String relativePath = (pathPrefix.isEmpty() ? \"\" : (pathPrefix + \"/\")) + fileName;\n\n            if (CodePushUpdateUtils.isHashIgnored(relativePath)) {\n                continue;\n            }\n\n            if (file.isDirectory()) {\n                addContentsOfFolderToManifest(fullFilePath, relativePath, manifest);\n            } else {\n                try {\n                    manifest.add(relativePath + \":\" + computeHash(new FileInputStream(file)));\n                } catch (FileNotFoundException e) {\n                    // Should not happen.\n                    throw new CodePushUnknownException(\"Unable to compute hash of update contents.\", e);\n                }\n            }\n        }\n    }\n\n    private static String computeHash(InputStream dataStream) {\n        MessageDigest messageDigest = null;\n        DigestInputStream digestInputStream = null;\n        try {\n            messageDigest = MessageDigest.getInstance(\"SHA-256\");\n            digestInputStream = new DigestInputStream(dataStream, messageDigest);\n            byte[] byteBuffer = new byte[1024 * 8];\n            while (digestInputStream.read(byteBuffer) != -1) ;\n        } catch (NoSuchAlgorithmException | IOException e) {\n            // Should not happen.\n            throw new CodePushUnknownException(\"Unable to compute hash of update contents.\", e);\n        } finally {\n            try {\n                if (digestInputStream != null) {\n                    digestInputStream.close();\n                }\n                if (dataStream != null) {\n                    dataStream.close();\n                }\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n        }\n\n        byte[] hash = messageDigest.digest();\n        return String.format(\"%064x\", new java.math.BigInteger(1, hash));\n    }\n\n    public static void copyNecessaryFilesFromCurrentPackage(String diffManifestFilePath, String currentPackageFolderPath, String newPackageFolderPath) throws IOException {\n        if (currentPackageFolderPath == null || !new File(currentPackageFolderPath).exists()) {\n            CodePushUtils.log(\"Unable to copy files from current package during diff update, because currentPackageFolderPath is invalid.\");\n            return;\n        }\n        FileUtils.copyDirectoryContents(currentPackageFolderPath, newPackageFolderPath);\n        JSONObject diffManifest = CodePushUtils.getJsonObjectFromFile(diffManifestFilePath);\n        try {\n            JSONArray deletedFiles = diffManifest.getJSONArray(\"deletedFiles\");\n            for (int i = 0; i < deletedFiles.length(); i++) {\n                String fileNameToDelete = deletedFiles.getString(i);\n                File fileToDelete = new File(newPackageFolderPath, fileNameToDelete);\n                if (fileToDelete.exists()) {\n                    fileToDelete.delete();\n                }\n            }\n        } catch (JSONException e) {\n            throw new CodePushUnknownException(\"Unable to copy files from current package during diff update\", e);\n        }\n    }\n\n    public static String findJSBundleInUpdateContents(String folderPath, String expectedFileName) {\n        File folder = new File(folderPath);\n        File[] folderFiles = folder.listFiles();\n        for (File file : folderFiles) {\n            String fullFilePath = CodePushUtils.appendPathComponent(folderPath, file.getName());\n            if (file.isDirectory()) {\n                String mainBundlePathInSubFolder = findJSBundleInUpdateContents(fullFilePath, expectedFileName);\n                if (mainBundlePathInSubFolder != null) {\n                    return CodePushUtils.appendPathComponent(file.getName(), mainBundlePathInSubFolder);\n                }\n            } else {\n                String fileName = file.getName();\n                if (fileName.equals(expectedFileName)) {\n                    return fileName;\n                }\n            }\n        }\n\n        return null;\n    }\n\n    public static String getHashForBinaryContents(Context context, boolean isDebugMode) {\n        try {\n            return CodePushUtils.getStringFromInputStream(context.getAssets().open(CodePushConstants.CODE_PUSH_HASH_FILE_NAME));\n        } catch (IOException e) {\n            try {\n                return CodePushUtils.getStringFromInputStream(context.getAssets().open(CodePushConstants.CODE_PUSH_OLD_HASH_FILE_NAME));\n            } catch (IOException ex) {\n                if (!isDebugMode) {\n                    // Only print this message in \"Release\" mode. In \"Debug\", we may not have the\n                    // hash if the build skips bundling the files.\n                    CodePushUtils.log(\"Unable to get the hash of the binary's bundled resources - \\\"codepush.gradle\\\" may have not been added to the build definition.\");\n                }\n            }\n            return null;\n        }\n    }\n\n    // Hashing algorithm:\n    // 1. Recursively generate a sorted array of format <relativeFilePath>: <sha256FileHash>\n    // 2. JSON stringify the array\n    // 3. SHA256-hash the result\n    public static void verifyFolderHash(String folderPath, String expectedHash) {\n        CodePushUtils.log(\"Verifying hash for folder path: \" + folderPath);\n        ArrayList<String> updateContentsManifest = new ArrayList<>();\n        addContentsOfFolderToManifest(folderPath, \"\", updateContentsManifest);\n        //sort manifest strings to make sure, that they are completely equal with manifest strings has been generated in cli!\n        Collections.sort(updateContentsManifest);\n        JSONArray updateContentsJSONArray = new JSONArray();\n        for (String manifestEntry : updateContentsManifest) {\n            updateContentsJSONArray.put(manifestEntry);\n        }\n\n        // The JSON serialization turns path separators into \"\\/\", e.g. \"CodePush\\/assets\\/image.png\"\n        String updateContentsManifestString = updateContentsJSONArray.toString().replace(\"\\\\/\", \"/\");\n        CodePushUtils.log(\"Manifest string: \" + updateContentsManifestString);\n\n        String updateContentsManifestHash = computeHash(new ByteArrayInputStream(updateContentsManifestString.getBytes()));\n\n        CodePushUtils.log(\"Expected hash: \" + expectedHash + \", actual hash: \" + updateContentsManifestHash);\n        if (!expectedHash.equals(updateContentsManifestHash)) {\n            throw new CodePushInvalidUpdateException(\"The update contents failed the data integrity check.\");\n        }\n\n        CodePushUtils.log(\"The update contents succeeded the data integrity check.\");\n    }\n\n    public static Map<String, Object> verifyAndDecodeJWT(String jwt, PublicKey publicKey) {\n        try {\n            SignedJWT signedJWT = SignedJWT.parse(jwt);\n            JWSVerifier verifier = new RSASSAVerifier((RSAPublicKey) publicKey);\n            if (signedJWT.verify(verifier)) {\n                Map<String, Object> claims = signedJWT.getJWTClaimsSet().getClaims();\n                CodePushUtils.log(\"JWT verification succeeded, payload content: \" + claims.toString());\n                return claims;\n            }\n            return null;\n        } catch (Exception ex) {\n            CodePushUtils.log(ex.getMessage());\n            CodePushUtils.log(ex.getStackTrace().toString());\n            return null;\n        }\n    }\n\n    public static PublicKey parsePublicKey(String stringPublicKey) {\n        try {\n            //remove unnecessary \"begin/end public key\" entries from string\n            stringPublicKey = stringPublicKey\n                    .replace(\"-----BEGIN PUBLIC KEY-----\", \"\")\n                    .replace(\"-----END PUBLIC KEY-----\", \"\")\n                    .replace(NEW_LINE, \"\");\n            byte[] byteKey = Base64.decode(stringPublicKey.getBytes(), Base64.DEFAULT);\n            X509EncodedKeySpec X509Key = new X509EncodedKeySpec(byteKey);\n            KeyFactory kf = KeyFactory.getInstance(\"RSA\");\n\n            return kf.generatePublic(X509Key);\n        } catch (Exception e) {\n            CodePushUtils.log(e.getMessage());\n            CodePushUtils.log(e.getStackTrace().toString());\n            return null;\n        }\n    }\n\n    public static String getSignatureFilePath(String updateFolderPath) {\n        return CodePushUtils.appendPathComponent(\n                CodePushUtils.appendPathComponent(updateFolderPath, CodePushConstants.CODE_PUSH_FOLDER_PREFIX),\n                CodePushConstants.BUNDLE_JWT_FILE\n        );\n    }\n\n    public static String getSignature(String folderPath) {\n        final String signatureFilePath = getSignatureFilePath(folderPath);\n\n        try {\n            return FileUtils.readFileToString(signatureFilePath);\n        } catch (IOException e) {\n            CodePushUtils.log(e.getMessage());\n            CodePushUtils.log(e.getStackTrace().toString());\n            return null;\n        }\n    }\n\n    public static void verifyUpdateSignature(String folderPath, String packageHash, String stringPublicKey) throws CodePushInvalidUpdateException {\n        CodePushUtils.log(\"Verifying signature for folder path: \" + folderPath);\n\n        final PublicKey publicKey = parsePublicKey(stringPublicKey);\n        if (publicKey == null) {\n            throw new CodePushInvalidUpdateException(\"The update could not be verified because no public key was found.\");\n        }\n\n        final String signature = getSignature(folderPath);\n        if (signature == null) {\n            throw new CodePushInvalidUpdateException(\"The update could not be verified because no signature was found.\");\n        }\n\n        final Map<String, Object> claims = verifyAndDecodeJWT(signature, publicKey);\n        if (claims == null) {\n            throw new CodePushInvalidUpdateException(\"The update could not be verified because it was not signed by a trusted party.\");\n        }\n\n        final String contentHash = (String) claims.get(\"contentHash\");\n        if (contentHash == null) {\n            throw new CodePushInvalidUpdateException(\"The update could not be verified because the signature did not specify a content hash.\");\n        }\n\n        if (!contentHash.equals(packageHash)) {\n            throw new CodePushInvalidUpdateException(\"The update contents failed the code signing check.\");\n        }\n\n        CodePushUtils.log(\"The update contents succeeded the code signing check.\");\n    }\n}\n"
  },
  {
    "path": "android/app/src/main/java/com/microsoft/codepush/react/CodePushUtils.java",
    "content": "package com.microsoft.codepush.react;\n\nimport android.util.Log;\n\nimport com.facebook.react.bridge.Arguments;\nimport com.facebook.react.bridge.NoSuchKeyException;\nimport com.facebook.react.bridge.ReadableArray;\nimport com.facebook.react.bridge.ReadableMap;\nimport com.facebook.react.bridge.ReadableMapKeySetIterator;\nimport com.facebook.react.bridge.ReadableType;\nimport com.facebook.react.bridge.WritableArray;\nimport com.facebook.react.bridge.WritableMap;\n\nimport org.json.JSONArray;\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.io.BufferedReader;\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.util.Iterator;\n\npublic class CodePushUtils {\n\n    public static String appendPathComponent(String basePath, String appendPathComponent) {\n        return new File(basePath, appendPathComponent).getAbsolutePath();\n    }\n\n    public static WritableArray convertJsonArrayToWritable(JSONArray jsonArr) {\n        WritableArray arr = Arguments.createArray();\n        for (int i=0; i<jsonArr.length(); i++) {\n            Object obj = null;\n            try {\n                obj = jsonArr.get(i);\n            } catch (JSONException jsonException) {\n                // Should not happen.\n                throw new CodePushUnknownException(i + \" should be within bounds of array \" + jsonArr.toString(), jsonException);\n            }\n\n            if (obj instanceof JSONObject)\n                arr.pushMap(convertJsonObjectToWritable((JSONObject) obj));\n            else if (obj instanceof JSONArray)\n                arr.pushArray(convertJsonArrayToWritable((JSONArray) obj));\n            else if (obj instanceof String)\n                arr.pushString((String) obj);\n            else if (obj instanceof Double)\n                arr.pushDouble((Double) obj);\n            else if (obj instanceof Integer)\n                arr.pushInt((Integer) obj);\n            else if (obj instanceof Boolean)\n                arr.pushBoolean((Boolean) obj);\n            else if (obj == null)\n                arr.pushNull();\n            else\n                throw new CodePushUnknownException(\"Unrecognized object: \" + obj);\n        }\n\n        return arr;\n    }\n\n    public static WritableMap convertJsonObjectToWritable(JSONObject jsonObj) {\n        WritableMap map = Arguments.createMap();\n        Iterator<String> it = jsonObj.keys();\n        while(it.hasNext()){\n            String key = it.next();\n            Object obj = null;\n            try {\n                if (!jsonObj.isNull(key)) {\n                    obj = jsonObj.get(key);\n                }\n            } catch (JSONException jsonException) {\n                // Should not happen.\n                throw new CodePushUnknownException(\"Key \" + key + \" should exist in \" + jsonObj.toString() + \".\", jsonException);\n            }\n\n            if (obj instanceof JSONObject)\n                map.putMap(key, convertJsonObjectToWritable((JSONObject) obj));\n            else if (obj instanceof JSONArray)\n                map.putArray(key, convertJsonArrayToWritable((JSONArray) obj));\n            else if (obj instanceof String)\n                map.putString(key, (String) obj);\n            else if (obj instanceof Double)\n                map.putDouble(key, (Double) obj);\n            else if (obj instanceof Long)\n                map.putDouble(key, ((Long) obj).doubleValue());\n            else if (obj instanceof Integer)\n                map.putInt(key, (Integer) obj);\n            else if (obj instanceof Boolean)\n                map.putBoolean(key, (Boolean) obj);\n            else if (obj == null)\n                map.putNull(key);\n            else\n                throw new CodePushUnknownException(\"Unrecognized object: \" + obj);\n        }\n\n        return map;\n    }\n\n    public static JSONArray convertReadableToJsonArray(ReadableArray arr) {\n        JSONArray jsonArr = new JSONArray();\n        for (int i=0; i<arr.size(); i++) {\n            ReadableType type = arr.getType(i);\n            switch (type) {\n                case Map:\n                    jsonArr.put(convertReadableToJsonObject(arr.getMap(i)));\n                    break;\n                case Array:\n                    jsonArr.put(convertReadableToJsonArray(arr.getArray(i)));\n                    break;\n                case String:\n                    jsonArr.put(arr.getString(i));\n                    break;\n                case Number:\n                    Double number = arr.getDouble(i);\n                    if ((number == Math.floor(number)) && !Double.isInfinite(number)) {\n                        // This is a whole number.\n                        jsonArr.put(number.longValue());\n                    } else {\n                        try {\n                            jsonArr.put(number.doubleValue());\n                        } catch (JSONException jsonException) {\n                            throw new CodePushUnknownException(\"Unable to put value \" + arr.getDouble(i) + \" in JSONArray\");\n                        }\n                    }\n                    break;\n                case Boolean:\n                    jsonArr.put(arr.getBoolean(i));\n                    break;\n                case Null:\n                    jsonArr.put(null);\n                    break;\n            }\n        }\n\n        return jsonArr;\n    }\n\n    public static JSONObject convertReadableToJsonObject(ReadableMap map) {\n        JSONObject jsonObj = new JSONObject();\n        ReadableMapKeySetIterator it = map.keySetIterator();\n        while (it.hasNextKey()) {\n            String key = it.nextKey();\n            ReadableType type = map.getType(key);\n            try {\n                switch (type) {\n                    case Map:\n                        jsonObj.put(key, convertReadableToJsonObject(map.getMap(key)));\n                        break;\n                    case Array:\n                        jsonObj.put(key, convertReadableToJsonArray(map.getArray(key)));\n                        break;\n                    case String:\n                        jsonObj.put(key, map.getString(key));\n                        break;\n                    case Number:\n                        jsonObj.put(key, map.getDouble(key));\n                        break;\n                    case Boolean:\n                        jsonObj.put(key, map.getBoolean(key));\n                        break;\n                    case Null:\n                        jsonObj.put(key, null);\n                        break;\n                    default:\n                        throw new CodePushUnknownException(\"Unrecognized type: \" + type + \" of key: \" + key);\n                }\n            } catch (JSONException jsonException) {\n                throw new CodePushUnknownException(\"Error setting key: \" + key + \" in JSONObject\", jsonException);\n            }\n        }\n\n        return jsonObj;\n    }\n\n    public static String getStringFromInputStream(InputStream inputStream) throws IOException {\n        BufferedReader bufferedReader = null;\n        try {\n            StringBuilder buffer = new StringBuilder();\n            bufferedReader = new BufferedReader(new InputStreamReader(inputStream));\n\n            String line;\n            while ((line = bufferedReader.readLine()) != null) {\n                buffer.append(line);\n                buffer.append(\"\\n\");\n            }\n\n            return buffer.toString().trim();\n        } finally {\n            if (bufferedReader != null) bufferedReader.close();\n            if (inputStream != null) inputStream.close();\n        }\n    }\n\n    public static JSONObject getJsonObjectFromFile(String filePath) throws IOException {\n        String content = FileUtils.readFileToString(filePath);\n        try {\n            return new JSONObject(content);\n        } catch (JSONException jsonException) {\n            // Should not happen\n            throw new CodePushMalformedDataException(filePath, jsonException);\n        }\n    }\n\n    public static void log(String message) {\n        Log.d(CodePushConstants.REACT_NATIVE_LOG_TAG, \"[CodePush] \" + message);\n    }\n\n    public static void log(Throwable tr) {\n        Log.e(CodePushConstants.REACT_NATIVE_LOG_TAG, \"[CodePush] Exception\", tr);\n    }\n\n    public static void logBundleUrl(String path) {\n        log(\"Loading JS bundle from \\\"\" + path + \"\\\"\");\n    }\n\n    public static void setJSONValueForKey(JSONObject json, String key, Object value) {\n        try {\n            json.put(key, value);\n        } catch (JSONException e) {\n            throw new CodePushUnknownException(\"Unable to set value \" + value + \" for key \" + key + \" to JSONObject\");\n        }\n    }\n\n    public static String tryGetString(ReadableMap map, String key) {\n        try {\n            return map.getString(key);\n        } catch (NoSuchKeyException e) {\n            return null;\n        }\n    }\n\n    public static void writeJsonToFile(JSONObject json, String filePath) throws IOException {\n        String jsonString = json.toString();\n        FileUtils.writeStringToFile(jsonString, filePath);\n    }\n}\n"
  },
  {
    "path": "android/app/src/main/java/com/microsoft/codepush/react/DownloadProgress.java",
    "content": "package com.microsoft.codepush.react;\n\nimport com.facebook.react.bridge.WritableMap;\nimport com.facebook.react.bridge.WritableNativeMap;\n\nclass DownloadProgress {\n    private long mTotalBytes;\n    private long mReceivedBytes;\n\n    public DownloadProgress (long totalBytes, long receivedBytes){\n        mTotalBytes = totalBytes;\n        mReceivedBytes = receivedBytes;\n    }\n\n    public WritableMap createWritableMap() {\n        WritableMap map = new WritableNativeMap();\n        if (mTotalBytes < Integer.MAX_VALUE) {\n            map.putInt(\"totalBytes\", (int) mTotalBytes);\n            map.putInt(\"receivedBytes\", (int) mReceivedBytes);\n        } else {\n            map.putDouble(\"totalBytes\", mTotalBytes);\n            map.putDouble(\"receivedBytes\", mReceivedBytes);\n        }\n        return map;\n    }\n\n    public boolean isCompleted() {\n        return mTotalBytes == mReceivedBytes;\n    }\n}\n"
  },
  {
    "path": "android/app/src/main/java/com/microsoft/codepush/react/DownloadProgressCallback.java",
    "content": "package com.microsoft.codepush.react;\n\ninterface DownloadProgressCallback {\n    void call(DownloadProgress downloadProgress);\n}\n"
  },
  {
    "path": "android/app/src/main/java/com/microsoft/codepush/react/FileUtils.java",
    "content": "package com.microsoft.codepush.react;\n\nimport java.io.BufferedInputStream;\nimport java.io.BufferedReader;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.io.PrintWriter;\nimport java.util.zip.ZipEntry;\nimport java.util.zip.ZipInputStream;\n\npublic class FileUtils {\n\n    private static final int WRITE_BUFFER_SIZE = 1024 * 8;\n\n    public static void copyDirectoryContents(String sourceDirectoryPath, String destinationDirectoryPath) throws IOException {\n        File sourceDir = new File(sourceDirectoryPath);\n        File destDir = new File(destinationDirectoryPath);\n        if (!destDir.exists()) {\n            destDir.mkdir();\n        }\n\n        for (File sourceFile : sourceDir.listFiles()) {\n            if (sourceFile.isDirectory()) {\n                copyDirectoryContents(\n                        CodePushUtils.appendPathComponent(sourceDirectoryPath, sourceFile.getName()),\n                        CodePushUtils.appendPathComponent(destinationDirectoryPath, sourceFile.getName()));\n            } else {\n                File destFile = new File(destDir, sourceFile.getName());\n                FileInputStream fromFileStream = null;\n                BufferedInputStream fromBufferedStream = null;\n                FileOutputStream destStream = null;\n                byte[] buffer = new byte[WRITE_BUFFER_SIZE];\n                try {\n                    fromFileStream = new FileInputStream(sourceFile);\n                    fromBufferedStream = new BufferedInputStream(fromFileStream);\n                    destStream = new FileOutputStream(destFile);\n                    int bytesRead;\n                    while ((bytesRead = fromBufferedStream.read(buffer)) > 0) {\n                        destStream.write(buffer, 0, bytesRead);\n                    }\n                } finally {\n                    try {\n                        if (fromFileStream != null) fromFileStream.close();\n                        if (fromBufferedStream != null) fromBufferedStream.close();\n                        if (destStream != null) destStream.close();\n                    } catch (IOException e) {\n                        throw new CodePushUnknownException(\"Error closing IO resources.\", e);\n                    }\n                }\n            }\n        }\n    }\n\n    public static void deleteDirectoryAtPath(String directoryPath) {\n        if (directoryPath == null) {\n            CodePushUtils.log(\"deleteDirectoryAtPath attempted with null directoryPath\");\n            return;\n        }\n        File file = new File(directoryPath);\n        if (file.exists()) {\n            deleteFileOrFolderSilently(file);\n        }\n    }\n\n    public static void deleteFileAtPathSilently(String path) {\n        deleteFileOrFolderSilently(new File(path));\n    }\n\n    public static void deleteFileOrFolderSilently(File file) {\n        if (file.isDirectory()) {\n            File[] files = file.listFiles();\n            for (File fileEntry : files) {\n                if (fileEntry.isDirectory()) {\n                    deleteFileOrFolderSilently(fileEntry);\n                } else {\n                    fileEntry.delete();\n                }\n            }\n        }\n\n        if (!file.delete()) {\n            CodePushUtils.log(\"Error deleting file \" + file.getName());\n        }\n    }\n\n    public static boolean fileAtPathExists(String filePath) {\n        return new File(filePath).exists();\n    }\n\n    public static void moveFile(File fileToMove, String newFolderPath, String newFileName) {\n        File newFolder = new File(newFolderPath);\n        if (!newFolder.exists()) {\n            newFolder.mkdirs();\n        }\n\n        File newFilePath = new File(newFolderPath, newFileName);\n        if (!fileToMove.renameTo(newFilePath)) {\n            throw new CodePushUnknownException(\"Unable to move file from \" +\n                    fileToMove.getAbsolutePath() + \" to \" + newFilePath.getAbsolutePath() + \".\");\n        }\n    }\n\n    public static String readFileToString(String filePath) throws IOException {\n        FileInputStream fin = null;\n        BufferedReader reader = null;\n        try {\n            File fl = new File(filePath);\n            fin = new FileInputStream(fl);\n            reader = new BufferedReader(new InputStreamReader(fin));\n            StringBuilder sb = new StringBuilder();\n            String line = null;\n            while ((line = reader.readLine()) != null) {\n                sb.append(line).append(\"\\n\");\n            }\n\n            return sb.toString();\n        } finally {\n            if (reader != null) reader.close();\n            if (fin != null) fin.close();\n        }\n    }\n\n    private static String validateFileName(String fileName, File destinationFolder) throws IOException {\n        String destinationFolderCanonicalPath = destinationFolder.getCanonicalPath() + File.separator;\n\n        File file = new File(destinationFolderCanonicalPath, fileName);\n        String canonicalPath = file.getCanonicalPath();\n\n        if (!canonicalPath.startsWith(destinationFolderCanonicalPath)) {\n            throw new IllegalStateException(\"File is outside extraction target directory.\");\n        }\n\n        return canonicalPath;\n    }\n\n    public static void unzipFile(File zipFile, String destination) throws IOException {\n        FileInputStream fileStream = null;\n        BufferedInputStream bufferedStream = null;\n        ZipInputStream zipStream = null;\n        try {\n            fileStream = new FileInputStream(zipFile);\n            bufferedStream = new BufferedInputStream(fileStream);\n            zipStream = new ZipInputStream(bufferedStream);\n            ZipEntry entry;\n\n            File destinationFolder = new File(destination);\n            if (destinationFolder.exists()) {\n                deleteFileOrFolderSilently(destinationFolder);\n            }\n\n            destinationFolder.mkdirs();\n\n            byte[] buffer = new byte[WRITE_BUFFER_SIZE];\n            while ((entry = zipStream.getNextEntry()) != null) {\n                String fileName = validateFileName(entry.getName(), destinationFolder);\n                File file = new File(fileName);\n                if (entry.isDirectory()) {\n                    file.mkdirs();\n                } else {\n                    File parent = file.getParentFile();\n                    if (!parent.exists()) {\n                        parent.mkdirs();\n                    }\n\n                    FileOutputStream fout = new FileOutputStream(file);\n                    try {\n                        int numBytesRead;\n                        while ((numBytesRead = zipStream.read(buffer)) != -1) {\n                            fout.write(buffer, 0, numBytesRead);\n                        }\n                    } finally {\n                        fout.close();\n                    }\n                }\n                long time = entry.getTime();\n                if (time > 0) {\n                    file.setLastModified(time);\n                }\n            }\n        } finally {\n            try {\n                if (zipStream != null) zipStream.close();\n                if (bufferedStream != null) bufferedStream.close();\n                if (fileStream != null) fileStream.close();\n            } catch (IOException e) {\n                throw new CodePushUnknownException(\"Error closing IO resources.\", e);\n            }\n        }\n    }\n\n    public static void writeStringToFile(String content, String filePath) throws IOException {\n        PrintWriter out = null;\n        try {\n            out = new PrintWriter(filePath);\n            out.print(content);\n        } finally {\n            if (out != null) out.close();\n        }\n    }\n}\n"
  },
  {
    "path": "android/app/src/main/java/com/microsoft/codepush/react/ReactInstanceHolder.java",
    "content": "package com.microsoft.codepush.react;\n\nimport com.facebook.react.ReactInstanceManager;\n\n/**\n * Provides access to a {@link ReactInstanceManager}.\n *\n * ReactNativeHost already implements this interface, if you make use of that react-native\n * component (just add `implements ReactInstanceHolder`).\n */\npublic interface ReactInstanceHolder {\n\n  /**\n   * Get the current {@link ReactInstanceManager} instance. May return null.\n   */\n  ReactInstanceManager getReactInstanceManager();\n}\n"
  },
  {
    "path": "android/app/src/main/java/com/microsoft/codepush/react/SettingsManager.java",
    "content": "package com.microsoft.codepush.react;\n\nimport android.content.Context;\nimport android.content.SharedPreferences;\n\nimport org.json.JSONArray;\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\npublic class SettingsManager {\n\n    private SharedPreferences mSettings;\n\n    public SettingsManager(Context applicationContext) {\n        mSettings = applicationContext.getSharedPreferences(CodePushConstants.CODE_PUSH_PREFERENCES, 0);\n    }\n\n    public JSONArray getFailedUpdates() {\n        String failedUpdatesString = mSettings.getString(CodePushConstants.FAILED_UPDATES_KEY, null);\n        if (failedUpdatesString == null) {\n            return new JSONArray();\n        }\n\n        try {\n            return new JSONArray(failedUpdatesString);\n        } catch (JSONException e) {\n            // Unrecognized data format, clear and replace with expected format.\n            JSONArray emptyArray = new JSONArray();\n            mSettings.edit().putString(CodePushConstants.FAILED_UPDATES_KEY, emptyArray.toString()).commit();\n            return emptyArray;\n        }\n    }\n\n    public JSONObject getPendingUpdate() {\n        String pendingUpdateString = mSettings.getString(CodePushConstants.PENDING_UPDATE_KEY, null);\n        if (pendingUpdateString == null) {\n            return null;\n        }\n\n        try {\n            return new JSONObject(pendingUpdateString);\n        } catch (JSONException e) {\n            // Should not happen.\n            CodePushUtils.log(\"Unable to parse pending update metadata \" + pendingUpdateString +\n                    \" stored in SharedPreferences\");\n            return null;\n        }\n    }\n\n\n    public boolean isFailedHash(String packageHash) {\n        JSONArray failedUpdates = getFailedUpdates();\n        if (packageHash != null) {\n            for (int i = 0; i < failedUpdates.length(); i++) {\n                try {\n                    JSONObject failedPackage = failedUpdates.getJSONObject(i);\n                    String failedPackageHash = failedPackage.getString(CodePushConstants.PACKAGE_HASH_KEY);\n                    if (packageHash.equals(failedPackageHash)) {\n                        return true;\n                    }\n                } catch (JSONException e) {\n                    throw new CodePushUnknownException(\"Unable to read failedUpdates data stored in SharedPreferences.\", e);\n                }\n            }\n        }\n\n        return false;\n    }\n\n    public boolean isPendingUpdate(String packageHash) {\n        JSONObject pendingUpdate = getPendingUpdate();\n\n        try {\n            return pendingUpdate != null &&\n                    !pendingUpdate.getBoolean(CodePushConstants.PENDING_UPDATE_IS_LOADING_KEY) &&\n                    (packageHash == null || pendingUpdate.getString(CodePushConstants.PENDING_UPDATE_HASH_KEY).equals(packageHash));\n        } catch (JSONException e) {\n            throw new CodePushUnknownException(\"Unable to read pending update metadata in isPendingUpdate.\", e);\n        }\n    }\n\n    public void removeFailedUpdates() {\n        mSettings.edit().remove(CodePushConstants.FAILED_UPDATES_KEY).commit();\n    }\n\n    public void removePendingUpdate() {\n        mSettings.edit().remove(CodePushConstants.PENDING_UPDATE_KEY).commit();\n    }\n\n    public void saveFailedUpdate(JSONObject failedPackage) {\n        try {\n            if (isFailedHash(failedPackage.getString(CodePushConstants.PACKAGE_HASH_KEY))) {\n                // Do not need to add the package if it is already in the failedUpdates.\n                return;\n            }\n        } catch (JSONException e) {\n            throw new CodePushUnknownException(\"Unable to read package hash from package.\", e);\n        }\n\n        String failedUpdatesString = mSettings.getString(CodePushConstants.FAILED_UPDATES_KEY, null);\n        JSONArray failedUpdates;\n        if (failedUpdatesString == null) {\n            failedUpdates = new JSONArray();\n        } else {\n            try {\n                failedUpdates = new JSONArray(failedUpdatesString);\n            } catch (JSONException e) {\n                // Should not happen.\n                throw new CodePushMalformedDataException(\"Unable to parse failed updates information \" +\n                        failedUpdatesString + \" stored in SharedPreferences\", e);\n            }\n        }\n\n        failedUpdates.put(failedPackage);\n        mSettings.edit().putString(CodePushConstants.FAILED_UPDATES_KEY, failedUpdates.toString()).commit();\n    }\n\n    public JSONObject getLatestRollbackInfo() {\n        String latestRollbackInfoString = mSettings.getString(CodePushConstants.LATEST_ROLLBACK_INFO_KEY, null);\n        if (latestRollbackInfoString == null) {\n            return null;\n        }\n\n        try {\n            return new JSONObject(latestRollbackInfoString);\n        } catch (JSONException e) {\n            // Should not happen.\n            CodePushUtils.log(\"Unable to parse latest rollback metadata \" + latestRollbackInfoString +\n                    \" stored in SharedPreferences\");\n            return null;\n        }\n    }\n\n    public void setLatestRollbackInfo(String packageHash) {\n        JSONObject latestRollbackInfo = getLatestRollbackInfo();\n        int count = 0;\n\n        if (latestRollbackInfo != null) {\n            try {\n                String latestRollbackPackageHash = latestRollbackInfo.getString(CodePushConstants.LATEST_ROLLBACK_PACKAGE_HASH_KEY);\n                if (latestRollbackPackageHash.equals(packageHash)) {\n                    count = latestRollbackInfo.getInt(CodePushConstants.LATEST_ROLLBACK_COUNT_KEY);\n                }\n            } catch (JSONException e) {\n                CodePushUtils.log(\"Unable to parse latest rollback info.\");\n            }\n        } else {\n            latestRollbackInfo = new JSONObject();\n        }\n\n        try {\n            latestRollbackInfo.put(CodePushConstants.LATEST_ROLLBACK_PACKAGE_HASH_KEY, packageHash);\n            latestRollbackInfo.put(CodePushConstants.LATEST_ROLLBACK_TIME_KEY, System.currentTimeMillis());\n            latestRollbackInfo.put(CodePushConstants.LATEST_ROLLBACK_COUNT_KEY, count + 1);\n            mSettings.edit().putString(CodePushConstants.LATEST_ROLLBACK_INFO_KEY, latestRollbackInfo.toString()).commit();\n        } catch (JSONException e) {\n            throw new CodePushUnknownException(\"Unable to save latest rollback info.\", e);\n        }\n    }\n\n    public void savePendingUpdate(String packageHash, boolean isLoading) {\n        JSONObject pendingUpdate = new JSONObject();\n        try {\n            pendingUpdate.put(CodePushConstants.PENDING_UPDATE_HASH_KEY, packageHash);\n            pendingUpdate.put(CodePushConstants.PENDING_UPDATE_IS_LOADING_KEY, isLoading);\n            mSettings.edit().putString(CodePushConstants.PENDING_UPDATE_KEY, pendingUpdate.toString()).commit();\n        } catch (JSONException e) {\n            // Should not happen.\n            throw new CodePushUnknownException(\"Unable to save pending update.\", e);\n        }\n    }\n\n}\n"
  },
  {
    "path": "android/app/src/main/java/com/microsoft/codepush/react/TLSSocketFactory.java",
    "content": "package com.microsoft.codepush.react;\n\nimport java.io.IOException;\nimport java.net.InetAddress;\nimport java.net.Socket;\nimport java.net.UnknownHostException;\nimport java.security.KeyManagementException;\nimport java.security.NoSuchAlgorithmException;\n\nimport javax.net.ssl.SSLContext;\nimport javax.net.ssl.SSLSocket;\nimport javax.net.ssl.SSLSocketFactory;\n\npublic class TLSSocketFactory extends SSLSocketFactory {\n\n    private SSLSocketFactory delegate;\n\n    public TLSSocketFactory() throws KeyManagementException, NoSuchAlgorithmException {\n        SSLContext context = SSLContext.getInstance(\"TLS\");\n        context.init(null, null, null);\n        delegate = context.getSocketFactory();\n    }\n\n    @Override\n    public String[] getDefaultCipherSuites() {\n        return delegate.getDefaultCipherSuites();\n    }\n\n    @Override\n    public String[] getSupportedCipherSuites() {\n        return delegate.getSupportedCipherSuites();\n    }\n\n    @Override\n    public Socket createSocket() throws IOException {\n        return enableTLSOnSocket(delegate.createSocket());\n    }\n\n    @Override\n    public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {\n        return enableTLSOnSocket(delegate.createSocket(s, host, port, autoClose));\n    }\n\n    @Override\n    public Socket createSocket(String host, int port) throws IOException, UnknownHostException {\n        return enableTLSOnSocket(delegate.createSocket(host, port));\n    }\n\n    @Override\n    public Socket createSocket(String host, int port, InetAddress localHost, int localPort)\n            throws IOException, UnknownHostException {\n        return enableTLSOnSocket(delegate.createSocket(host, port, localHost, localPort));\n    }\n\n    @Override\n    public Socket createSocket(InetAddress host, int port) throws IOException {\n        return enableTLSOnSocket(delegate.createSocket(host, port));\n    }\n\n    @Override\n    public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort)\n            throws IOException {\n        return enableTLSOnSocket(delegate.createSocket(address, port, localAddress, localPort));\n    }\n\n    private Socket enableTLSOnSocket(Socket socket) {\n        if (socket != null && (socket instanceof SSLSocket)) {\n            ((SSLSocket) socket).setEnabledProtocols(new String[] { \"TLSv1.1\", \"TLSv1.2\" });\n        }\n        return socket;\n    }\n}\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        google()\n        mavenCentral()\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:1.3.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    android {\n        namespace \"com.microsoft.codepush.react\"\n    }\n    repositories {\n        mavenLocal()\n        mavenCentral()\n    }\n}\n"
  },
  {
    "path": "android/codepush.gradle",
    "content": "// Adapted from https://raw.githubusercontent.com/facebook/react-native/d16ff3bd8b92fa84a9007bf5ebedd8153e4c089d/react.gradle\n\nimport java.nio.file.Paths;\n\ndef config = project.extensions.findByName(\"react\") ?: [:]\ndef bundleAssetName = config.bundleAssetName ? config.bundleAssetName.get() : \"index.android.bundle\"\n\n// because elvis operator\ndef elvisFile(thing) {\n    return thing ? file(thing) : null;\n}\n\nvoid runBefore(String dependentTaskName, Task task) {\n    Task dependentTask = tasks.findByPath(dependentTaskName);\n    if (dependentTask != null) {\n        dependentTask.dependsOn task\n    }\n}\n\n/**\n * Finds the path of the installed npm package with the given name using Node's\n * module resolution algorithm, which searches \"node_modules\" directories up to\n * the file system root. This handles various cases, including:\n *\n *   - Working in the open-source RN repo:\n *       Gradle: /path/to/react-native/ReactAndroid\n *       Node module: /path/to/react-native/node_modules/[package]\n *\n *   - Installing RN as a dependency of an app and searching for hoisted\n *     dependencies:\n *       Gradle: /path/to/app/node_modules/react-native/ReactAndroid\n *       Node module: /path/to/app/node_modules/[package]\n *\n *   - Working in a larger repo (e.g., Facebook) that contains RN:\n *       Gradle: /path/to/repo/path/to/react-native/ReactAndroid\n *       Node module: /path/to/repo/node_modules/[package]\n *\n * The search begins at the given base directory (a File object). The returned\n * path is a string.\n */\nstatic def findNodeModulePath(baseDir, packageName) {\n    def basePath = baseDir.toPath().normalize()\n    // Node's module resolution algorithm searches up to the root directory,\n    // after which the base path will be null\n    while (basePath) {\n        def candidatePath = Paths.get(basePath.toString(), \"node_modules\", packageName)\n        if (candidatePath.toFile().exists()) {\n            return candidatePath.toString()\n        }\n        basePath = basePath.getParent()\n    }\n    return null\n}\n\nandroid.buildTypes.each { buildType ->\n    // to prevent incorrect long value restoration from strings.xml we need to wrap it with double quotes\n    // https://github.com/microsoft/cordova-plugin-code-push/issues/264\n    buildType.resValue 'string', \"CODE_PUSH_APK_BUILD_TIME\", String.format(\"\\\"%d\\\"\", System.currentTimeMillis())\n}\n\ngradle.projectsEvaluated {\n    def debuggableVariants = config.debuggableVariants ? config.debuggableVariants.get() : ['debug']\n\n    android.applicationVariants.all { variant ->\n        // No code push for debuggable variants\n        if (debuggableVariants.contains(variant.name)) {\n            return;\n        }\n\n        def nodeModulesPath;\n        if (project.hasProperty('nodeModulesPath')) {\n            nodeModulesPath = \"${project.nodeModulesPath}/react-native-code-push\"\n        } else {\n            nodeModulesPath = findNodeModulePath(projectDir, \"react-native-code-push\")\n        }\n\n        def targetName = variant.name.capitalize()\n        def targetPath = variant.dirName\n\n        def jsBundleDir;\n        def resourcesDir;\n        def jsBundleFile;\n\n        // Additional node commandline arguments\n        def nodeExecutableAndArgs = config.nodeExecutableAndArgs ? config.nodeExecutableAndArgs.get(): [\"node\"]\n        def extraPackagerArgs = config.extraPackagerArgs ? config.extraPackagerArgs.get() : []\n\n        // Make this task run right after the bundle task\n        def generateBundledResourcesHash;\n\n        def reactBundleTask = tasks.findByName(\"createBundle${targetName}JsAndAssets\")\n        if (reactBundleTask) {\n            jsBundleDir = reactBundleTask.property('jsBundleDir').asFile.get()\n            resourcesDir = reactBundleTask.property('resourcesDir').asFile.get()\n\n            // mitigates Resource and asset merger: Duplicate resources error\n            project.delete(files(\"${jsBundleDir}\"))\n            \n            jsBundleDir.mkdirs()\n            resourcesDir.mkdirs()\n\n            jsBundleFile = file(\"$jsBundleDir/$bundleAssetName\")\n\n            generateBundledResourcesHash = tasks.create(\n                    name: \"generateBundledResourcesHash${targetName}\",\n                    type: Exec) {\n                commandLine (*nodeExecutableAndArgs, \"${nodeModulesPath}/scripts/generateBundledResourcesHash.js\", resourcesDir, jsBundleFile, jsBundleDir)\n\n                enabled !debuggableVariants.contains(variant.name) ?: targetName.toLowerCase().contains(\"release\")\n            }\n\n            runBefore(\"merge${targetName}Resources\", generateBundledResourcesHash)\n            runBefore(\"merge${targetName}Assets\", generateBundledResourcesHash)\n        } else {\n            def jsBundleDirConfigName = \"jsBundleDir${targetName}\"\n            jsBundleDir = elvisFile(config.\"$jsBundleDirConfigName\") ? elvisFile(config.\"$jsBundleDirConfigName\").get():\n                    file(\"$buildDir/intermediates/assets/${targetPath}\")\n\n            def resourcesDirConfigName = \"resourcesDir${targetName}\"\n            resourcesDir = elvisFile(config.\"${resourcesDirConfigName}\") ? elvisFile(config.\"${resourcesDirConfigName}\").get():\n                    file(\"$buildDir/intermediates/res/merged/${targetPath}\")\n\n            // In case version of 'Android Plugin for Gradle'' is lower than 1.3.0\n            // '$buildDir' has slightly different structure - 'merged' folder\n            // does not exists so '${targetPath}' folder contains directly in 'res' folder.\n            if (!resourcesDir.exists() && file(\"$buildDir/intermediates/res/${targetPath}\").exists()) {\n                resourcesDir = file(\"$buildDir/intermediates/res/${targetPath}\")\n            }\n\n            jsBundleFile = file(\"$jsBundleDir/$bundleAssetName\")\n\n            def resourcesMapTempFileName = \"CodePushResourcesMap-\" + java.util.UUID.randomUUID().toString().substring(0,8) + \".json\"\n\n            generateBundledResourcesHash = tasks.create(\n                    name: \"generateBundledResourcesHash${targetName}\",\n                    type: Exec) {\n                commandLine (*nodeExecutableAndArgs, \"${nodeModulesPath}/scripts/generateBundledResourcesHash.js\", resourcesDir, jsBundleFile, jsBundleDir, resourcesMapTempFileName)\n            }\n\n            // Make this task run right before the bundle task\n            def recordFilesBeforeBundleCommand = tasks.create(\n                    name: \"recordFilesBeforeBundleCommand${targetName}\",\n                    type: Exec) {\n                commandLine (*nodeExecutableAndArgs, \"${nodeModulesPath}/scripts/recordFilesBeforeBundleCommand.js\", resourcesDir, resourcesMapTempFileName)\n            }\n\n            recordFilesBeforeBundleCommand.dependsOn(\"merge${targetName}Resources\")\n            recordFilesBeforeBundleCommand.dependsOn(\"merge${targetName}Assets\")\n            runBefore(\"bundle${targetName}JsAndAssets\", recordFilesBeforeBundleCommand)\n\n            // We need to generate and record the resources map, but we use it to generate the bundle hash\n            generateBundledResourcesHash.dependsOn(\"recordFilesBeforeBundleCommand${targetName}\")\n        }\n\n        generateBundledResourcesHash.dependsOn(\"createBundle${targetName}JsAndAssets\")\n\n        runBefore(\"processArmeabi-v7a${targetName}Resources\", generateBundledResourcesHash)\n        runBefore(\"processX86${targetName}Resources\", generateBundledResourcesHash)\n        runBefore(\"processUniversal${targetName}Resources\", generateBundledResourcesHash)\n        runBefore(\"process${targetName}Resources\", generateBundledResourcesHash)\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": "include ':app'"
  },
  {
    "path": "code-push-plugin-testing-framework/package.json",
    "content": "{\n  \"name\": \"code-push-plugin-testing-framework\",\n  \"version\": \"0.0.1\",\n  \"description\": \"Plugin Testing Framework for CodePush Plugins\",\n  \"main\": \"script/index.js\",\n  \"scripts\": {\n    \"test\": \"gulp\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/microsoft/code-push.git\"\n  },\n  \"author\": {\n    \"name\": \"Microsoft Corporation\"\n  },\n  \"license\": \"MIT\",\n  \"homepage\": \"https://microsoft.github.io/code-push\",\n  \"dependencies\": {\n    \"@types/uuid\": \"^8.3.1\",\n    \"base-64\": \"^1.0.0\",\n    \"mocha\": \"latest\",\n    \"mocha-junit-reporter\": \"latest\",\n    \"q\": \"^1.5.1\",\n    \"replace\": \"latest\",\n    \"superagent\": \"^6.1.0\",\n    \"superagent-proxy\": \"^3.0.0\",\n    \"uuid\": \"^8.3.2\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/microsoft/code-push/issues\"\n  },\n  \"readme\": \"ERROR: No README data found!\",\n  \"_id\": \"code-push-plugin-testing-framework@0.0.1\",\n  \"_shasum\": \"6ea33a661710628af266d714949fe95f88d71f0d\",\n  \"_from\": \"../code-push/plugin-testing-framework/bin\",\n  \"_resolved\": \"file:../code-push/plugin-testing-framework/bin\"\n}\n"
  },
  {
    "path": "code-push-plugin-testing-framework/script/index.js",
    "content": "\"use strict\";\nvar Platform = require(\"./platform\");\nexports.Platform = Platform;\nvar PluginTestingFramework = require(\"./test\");\nexports.PluginTestingFramework = PluginTestingFramework;\nvar projectManager_1 = require(\"./projectManager\");\nexports.ProjectManager = projectManager_1.ProjectManager;\nexports.setupTestRunScenario = projectManager_1.setupTestRunScenario;\nexports.setupUpdateScenario = projectManager_1.setupUpdateScenario;\nvar ServerUtil = require(\"./serverUtil\");\nexports.ServerUtil = ServerUtil;\nvar testBuilder_1 = require(\"./testBuilder\");\nexports.TestBuilder = testBuilder_1.TestBuilder;\nvar TestConfig = require(\"./testConfig\");\nexports.TestConfig = TestConfig;\nvar testUtil_1 = require(\"./testUtil\");\nexports.TestUtil = testUtil_1.TestUtil;\n"
  },
  {
    "path": "code-push-plugin-testing-framework/script/platform.js",
    "content": "\"use strict\";\nvar Q = require(\"q\");\nvar testUtil_1 = require(\"./testUtil\");\n//////////////////////////////////////////////////////////////////////////////////////////\n// PLATFORMS\n/**\n * Android implementations of IPlatform.\n */\nvar Android = (function () {\n    function Android(emulatorManager) {\n        this.emulatorManager = emulatorManager;\n    }\n    /**\n     * Gets the platform name. (e.g. \"android\" for the Android platform).\n     */\n    Android.prototype.getName = function () {\n        return \"android\";\n    };\n    /**\n     * The command line flag used to determine whether or not this platform should run.\n     * Runs when the flag is present, doesn't run otherwise.\n     */\n    Android.prototype.getCommandLineFlagName = function () {\n        return \"--android\";\n    };\n    /**\n     * Gets the server url used for testing.\n     */\n    Android.prototype.getServerUrl = function () {\n        if (!this.serverUrl)\n            this.serverUrl = process.env.ANDROID_SERVER ? process.env.ANDROID_SERVER : Android.DEFAULT_ANDROID_SERVER_URL;\n        return this.serverUrl;\n    };\n    /**\n     * Gets an IEmulatorManager that is used to control the emulator during the tests.\n     */\n    Android.prototype.getEmulatorManager = function () {\n        return this.emulatorManager;\n    };\n    /**\n     * Gets the default deployment key.\n     */\n    Android.prototype.getDefaultDeploymentKey = function () {\n        return \"mock-android-deployment-key\";\n    };\n    Android.DEFAULT_ANDROID_SERVER_URL = \"http://10.0.2.2:3001\";\n    return Android;\n}());\nexports.Android = Android;\n/**\n * IOS implementation of IPlatform.\n */\nvar IOS = (function () {\n    function IOS(emulatorManager) {\n        this.emulatorManager = emulatorManager;\n    }\n    /**\n     * Gets the platform name. (e.g. \"android\" for the Android platform).\n     */\n    IOS.prototype.getName = function () {\n        return \"ios\";\n    };\n    /**\n     * The command line flag used to determine whether or not this platform should run.\n     * Runs when the flag is present, doesn't run otherwise.\n     */\n    IOS.prototype.getCommandLineFlagName = function () {\n        return \"--ios\";\n    };\n    /**\n     * Gets the server url used for testing.\n     */\n    IOS.prototype.getServerUrl = function () {\n        if (!this.serverUrl)\n            this.serverUrl = process.env.IOS_SERVER ? process.env.IOS_SERVER : IOS.DEFAULT_IOS_SERVER_URL;\n\n        return this.serverUrl;\n    };\n    /**\n     * Gets an IEmulatorManager that is used to control the emulator during the tests.\n     */\n    IOS.prototype.getEmulatorManager = function () {\n        return this.emulatorManager;\n    };\n    /**\n     * Gets the default deployment key.\n     */\n    IOS.prototype.getDefaultDeploymentKey = function () {\n        return \"mock-ios-deployment-key\";\n    };\n    IOS.DEFAULT_IOS_SERVER_URL = \"http://127.0.0.1:3000\";\n    return IOS;\n}());\nexports.IOS = IOS;\n//////////////////////////////////////////////////////////////////////////////////////////\n// EMULATOR MANAGERS\n// bootEmulatorInternal constants\nvar emulatorMaxReadyAttempts = 50;\nvar emulatorReadyCheckDelayMs = 5 * 1000;\n/**\n * Helper function for EmulatorManager implementations to use to boot an emulator with a given platformName and check, start, and kill methods.\n */\nfunction bootEmulatorInternal(platformName, restartEmulators, targetEmulator, checkEmulator, startEmulator, killEmulator) {\n    var deferred = Q.defer();\n    console.log(\"Setting up \" + platformName + \" emulator.\");\n    function onEmulatorReady() {\n        console.log(platformName + \" emulator is ready!\");\n        deferred.resolve(undefined);\n        return deferred.promise;\n    }\n    // Called to check if the emulator for the platform is initialized.\n    function checkEmulatorReady() {\n        var checkDeferred = Q.defer();\n        console.log(\"Checking if \" + platformName + \" emulator is ready yet...\");\n        // Dummy command that succeeds if emulator is ready and fails otherwise.\n        checkEmulator(targetEmulator)\n            .then(function () {\n                checkDeferred.resolve(undefined);\n            }, function (error) {\n                console.info(error);\n                console.log(platformName + \" emulator is not ready yet!\");\n                checkDeferred.reject(error);\n            });\n        return checkDeferred.promise;\n    }\n    var emulatorReadyAttempts = 0;\n    // Loops checks to see if the emulator is ready and eventually fails after surpassing emulatorMaxReadyAttempts.\n    function checkEmulatorReadyLooper() {\n        var looperDeferred = Q.defer();\n        emulatorReadyAttempts++;\n        if (emulatorReadyAttempts > emulatorMaxReadyAttempts) {\n            console.log(platformName + \" emulator is not ready after \" + emulatorMaxReadyAttempts + \" attempts, abort.\");\n            deferred.reject(platformName + \" emulator failed to boot.\");\n            looperDeferred.resolve(undefined);\n        }\n        setTimeout(function () {\n            checkEmulatorReady()\n                .then(function () {\n                    looperDeferred.resolve(undefined);\n                    onEmulatorReady();\n                }, function () {\n                    return checkEmulatorReadyLooper().then(function () { looperDeferred.resolve(undefined); }, function () { looperDeferred.reject(undefined); });\n                });\n        }, emulatorReadyCheckDelayMs);\n        return looperDeferred.promise;\n    }\n    // Starts and loops the emulator.\n    function startEmulatorAndLoop() {\n        console.log(\"Booting \" + platformName + \" emulator named \" + targetEmulator + \".\");\n        startEmulator(targetEmulator).catch(function (error) { console.log(error); deferred.reject(error); });\n        return checkEmulatorReadyLooper();\n    }\n    var promise;\n    if (restartEmulators) {\n        console.log(\"Killing \" + platformName + \" emulator.\");\n        promise = killEmulator().catch(function () { return null; }).then(startEmulatorAndLoop);\n    }\n    else {\n        promise = checkEmulatorReady().then(onEmulatorReady, startEmulatorAndLoop);\n    }\n    return deferred.promise;\n}\nvar AndroidEmulatorManager = (function () {\n    function AndroidEmulatorManager() {\n    }\n    /**\n     * Returns the target emulator, which is specified through the command line.\n     */\n    AndroidEmulatorManager.prototype.getTargetEmulator = function () {\n        let _this = this;\n        if (this.targetEmulator)\n            return Q(this.targetEmulator);\n        else {\n            const deferred = Q.defer();\n            const targetAndroidEmulator = process.env.ANDROID_EMU;\n            if (!targetAndroidEmulator) {\n                // If no Android simulator is specified, get the most recent Android simulator to run tests on.\n                testUtil_1.TestUtil.getProcessOutput(\"emulator -list-avds\", { noLogCommand: true, noLogStdOut: true, noLogStdErr: true })\n                    .then((Devices) => {\n                        const listOfDevices = Devices.trim().split(\"\\n\");\n                        deferred.resolve(listOfDevices[listOfDevices.length - 1]);\n                    }, (error) => {\n                        deferred.reject(error);\n                    });\n            }\n            else {\n                // Use the simulator specified on the command line.\n                deferred.resolve(targetAndroidEmulator);\n            }\n            return deferred.promise\n                .then((targetEmulator) => {\n                    _this.targetEmulator = targetEmulator;\n                    console.log(\"Using Android simulator named \" + _this.targetEmulator);\n                    return _this.targetEmulator;\n                });\n        }\n    };\n    /**\n     * Boots the target emulator.\n     */\n    AndroidEmulatorManager.prototype.bootEmulator = function (restartEmulators) {\n        function checkAndroidEmulator(androidEmulatorName) {\n            // A command that does nothing but only succeeds if the emulator is running.\n            // List all of the packages on the device.\n            return testUtil_1.TestUtil.getProcessOutput(\"adb shell pm list packages\", { noLogCommand: true, noLogStdOut: true, noLogStdErr: true }).then(function () { return null; });\n        }\n        function startAndroidEmulator(androidEmulatorName) {\n            const androidEmulatorCommand = `emulator @${androidEmulatorName}`;\n            let osSpecificCommand = \"\";\n            if (process.platform === \"darwin\") {\n                osSpecificCommand = `${androidEmulatorCommand} &`;\n            } else {\n                osSpecificCommand = `START /B ${androidEmulatorCommand}`;\n            }\n            return testUtil_1.TestUtil.getProcessOutput(osSpecificCommand, { noLogStdErr: true, timeout: 5000 });\n        }\n        function killAndroidEmulator() {\n            return testUtil_1.TestUtil.getProcessOutput(\"adb emu kill\").then(function () { return null; });\n        }\n        return this.getTargetEmulator()\n            .then(function (targetEmulator) {\n                return bootEmulatorInternal(\"Android\", restartEmulators, targetEmulator, checkAndroidEmulator, startAndroidEmulator, killAndroidEmulator);\n            });\n    };\n    /**\n     * Launches an already installed application by app id.\n     */\n    AndroidEmulatorManager.prototype.launchInstalledApplication = function (appId) {\n        return testUtil_1.TestUtil.getProcessOutput(\"adb shell monkey -p \" + appId + \" -c android.intent.category.LAUNCHER 1\").then(function () { return null; });\n    };\n    /**\n     * Ends a running application given its app id.\n     */\n    AndroidEmulatorManager.prototype.endRunningApplication = function (appId) {\n        return testUtil_1.TestUtil.getProcessOutput(\"adb shell am force-stop \" + appId).then(function () { return Q.delay(10000); });\n    };\n    /**\n     * Restarts an already installed application by app id.\n     */\n    AndroidEmulatorManager.prototype.restartApplication = function (appId) {\n        var _this = this;\n        return this.endRunningApplication(appId)\n            .then(function () {\n                // Wait for a 1 second before restarting.\n                return Q.delay(1000);\n            })\n            .then(function () {\n                return _this.launchInstalledApplication(appId);\n            });\n    };\n    /**\n     * Navigates away from the current app, waits for a delay (defaults to 1 second), then navigates to the specified app.\n     */\n    AndroidEmulatorManager.prototype.resumeApplication = function (appId, delayBeforeResumingMs) {\n        var _this = this;\n        if (delayBeforeResumingMs === void 0) { delayBeforeResumingMs = 1000; }\n        // Open a default Android app (for example, settings).\n        return this.launchInstalledApplication(\"com.android.settings\")\n            .then(function () {\n                console.log(\"Waiting for \" + delayBeforeResumingMs + \"ms before resuming the test application.\");\n                return Q.delay(delayBeforeResumingMs);\n            })\n            .then(function () {\n                // Reopen the app.\n                return _this.launchInstalledApplication(appId);\n            });\n    };\n    /**\n     * Prepares the emulator for a test.\n     */\n    AndroidEmulatorManager.prototype.prepareEmulatorForTest = function (appId) {\n        return this.endRunningApplication(appId)\n            .then(function () {\n                return commandWithCheckAppExistence(\"adb shell pm clear\", appId);\n            });\n    };\n    /**\n     * Uninstalls the app from the emulator.\n     */\n    AndroidEmulatorManager.prototype.uninstallApplication = function (appId) {\n        return commandWithCheckAppExistence(\"adb uninstall\", appId);\n    };\n    return AndroidEmulatorManager;\n}());\nexports.AndroidEmulatorManager = AndroidEmulatorManager;\nvar IOSEmulatorManager = (function () {\n    function IOSEmulatorManager() {\n    }\n    /**\n     * Returns the target emulator, which is specified through the command line.\n     */\n    IOSEmulatorManager.prototype.getTargetEmulator = function () {\n        let _this = this;\n        if (this.targetEmulator)\n            return Q(this.targetEmulator);\n        else {\n            let deferred = Q.defer();\n            let targetIOSEmulator = process.env.IOS_EMU;\n            if (!targetIOSEmulator) {\n                // If no iOS simulator is specified, get the most recent iOS simulator to run tests on.\n                testUtil_1.TestUtil.getProcessOutput(\"xcrun simctl list\", { noLogCommand: true, noLogStdOut: true, noLogStdErr: true })\n                    .then((listOfDevicesWithDevicePairs) => {\n                        let listOfDevices = listOfDevicesWithDevicePairs.slice(listOfDevicesWithDevicePairs.indexOf(\"-- iOS\"), listOfDevicesWithDevicePairs.indexOf(\"-- tvOS\"));\n                        let phoneDevice = /iPhone\\ \\S*\\ ?.*?\\(([0-9A-Z-]*)\\)/g;\n                        let match = phoneDevice.exec(listOfDevices);\n                        deferred.resolve(match[1]);\n                    }, (error) => {\n                        deferred.reject(error);\n                    });\n            }\n            else {\n                // Use the simulator specified on the command line.\n                deferred.resolve(targetIOSEmulator);\n            }\n            return deferred.promise\n                .then((targetEmulator) => {\n                    _this.targetEmulator = targetEmulator;\n                    console.log(\"Using iOS simulator named \" + _this.targetEmulator);\n                    return _this.targetEmulator;\n                });\n        }\n    };\n    /**\n     * Boots the target emulator.\n     */\n    IOSEmulatorManager.prototype.bootEmulator = function (restartEmulators) {\n        function checkIOSEmulator(iOSEmulatorId) {\n            // A command that does nothing but only succeeds if the emulator is running.\n            return testUtil_1.TestUtil.getProcessOutput(\"xcrun simctl getenv booted SIMULATOR_UDID\", { noLogCommand: true, noLogStdOut: true, noLogStdErr: true }).then(function (simUdid) {\n                return simUdid.trim() == iOSEmulatorId.trim() ? true : Promise.reject(new Error('Waiting for device to boot')); \n            });\n        }\n        function startIOSEmulator(iOSEmulatorId) {\n            return testUtil_1.TestUtil.getProcessOutput(\"xcrun simctl boot \" + iOSEmulatorId, { noLogStdErr: true })\n                .catch(function (error) { return undefined; /* Always fails because we do not specify a template, which is not necessary to just start the emulator */ }).then(function () { return null; });\n        }\n        function killIOSEmulator() {\n            return testUtil_1.TestUtil.getProcessOutput(\"xcrun simctl shutdown all\").then(function () { return null; });\n        }\n        return this.getTargetEmulator()\n            .then(function (targetEmulator) {\n                return bootEmulatorInternal(\"iOS\", restartEmulators, targetEmulator, checkIOSEmulator, startIOSEmulator, killIOSEmulator);\n            });\n    };\n    /**\n     * Launches an already installed application by app id.\n     */\n    IOSEmulatorManager.prototype.launchInstalledApplication = function (appId) {\n        return testUtil_1.TestUtil.getProcessOutput(\"xcrun simctl launch booted \" + appId, undefined).then(function () { return null; });\n    };\n    /**\n     * Ends a running application given its app id.\n     */\n    IOSEmulatorManager.prototype.endRunningApplication = function (appId) {\n        return testUtil_1.TestUtil.getProcessOutput(\"xcrun simctl terminate booted \" + appId, undefined).then(function () { return null; })\n    };\n    /**\n     * Restarts an already installed application by app id.\n     */\n    IOSEmulatorManager.prototype.restartApplication = function (appId) {\n        var _this = this;\n        return this.endRunningApplication(appId)\n            .then(function () {\n                // Wait for a second before restarting.\n                return Q.delay(1000);\n            })\n            .then(function () { return _this.launchInstalledApplication(appId); });\n    };\n    /**\n     * Navigates away from the current app, waits for a delay (defaults to 1 second), then navigates to the specified app.\n     */\n    IOSEmulatorManager.prototype.resumeApplication = function (appId, delayBeforeResumingMs) {\n        var _this = this;\n        if (delayBeforeResumingMs === void 0) { delayBeforeResumingMs = 1000; }\n        // Open a default iOS app (for example, settings).\n        return this.launchInstalledApplication(\"com.apple.Preferences\")\n            .then(function () {\n                console.log(\"Waiting for \" + delayBeforeResumingMs + \"ms before resuming the test application.\");\n                return Q.delay(delayBeforeResumingMs);\n            })\n            .then(function () {\n                // Reopen the app.\n                return _this.launchInstalledApplication(appId);\n            });\n    };\n    /**\n     * Prepares the emulator for a test.\n     */\n    IOSEmulatorManager.prototype.prepareEmulatorForTest = function (appId) {\n        return this.endRunningApplication(appId);\n    };\n    /**\n     * Uninstalls the app from the emulator.\n     */\n    IOSEmulatorManager.prototype.uninstallApplication = function (appId) {\n        return testUtil_1.TestUtil.getProcessOutput(\"xcrun simctl uninstall booted \" + appId).then(function () { return null; });\n    };\n    return IOSEmulatorManager;\n}());\nexports.IOSEmulatorManager = IOSEmulatorManager;\n\nfunction commandWithCheckAppExistence(command, appId) {\n    return testUtil_1.TestUtil.getProcessOutput(\"adb shell pm list packages\", { noLogCommand: true, noLogStdOut: true, noLogStdErr: true })\n        .then((output) => {\n            return output.includes(appId);\n        }).then((isAppExist) => {\n            if (isAppExist) {\n                return testUtil_1.TestUtil.getProcessOutput(`${command} ${appId}`).then(function () { return null; });\n            }\n            console.log(`Command \"${command}\" is skipped because the application has not yet been installed`)\n            return null;\n        });\n}\n"
  },
  {
    "path": "code-push-plugin-testing-framework/script/projectManager.js",
    "content": "\"use strict\";\nvar TestConfig = require(\"./testConfig\");\n/**\n * In charge of project related operations.\n */\nvar ProjectManager = (function () {\n    function ProjectManager() {\n    }\n    //// ABSTRACT METHODS\n    // (not actually abstract because there are some issues with our dts generator that causes it to incorrectly generate abstract classes)\n    /**\n     * Returns the name of the plugin being tested, for example Cordova or React-Native.\n     *\n     * Overwrite this in your implementation!\n     */\n    ProjectManager.prototype.getPluginName = function () { throw ProjectManager.NOT_IMPLEMENTED_ERROR_MSG; };\n    /**\n     * Creates a new test application at the specified path, and configures it\n     * with the given server URL, android and ios deployment keys.\n     *\n     * Overwrite this in your implementation!\n     */\n    ProjectManager.prototype.setupProject = function (projectDirectory, templatePath, appName, appNamespace, version) {\n        if (version === void 0) { version = ProjectManager.DEFAULT_APP_VERSION; }\n        throw ProjectManager.NOT_IMPLEMENTED_ERROR_MSG;\n    };\n    /**\n     * Sets up the scenario for a test in an already existing project.\n     *\n     * Overwrite this in your implementation!\n     */\n    ProjectManager.prototype.setupScenario = function (projectDirectory, appId, templatePath, jsPath, targetPlatform, version) {\n        if (version === void 0) { version = ProjectManager.DEFAULT_APP_VERSION; }\n        throw ProjectManager.NOT_IMPLEMENTED_ERROR_MSG;\n    };\n    /**\n     * Creates a CodePush update package zip for a project.\n     *\n     * Overwrite this in your implementation!\n     */\n    ProjectManager.prototype.createUpdateArchive = function (projectDirectory, targetPlatform, isDiff) { throw ProjectManager.NOT_IMPLEMENTED_ERROR_MSG; };\n    /**\n     * Prepares a specific platform for tests.\n     *\n     * Overwrite this in your implementation!\n     */\n    ProjectManager.prototype.preparePlatform = function (projectDirectory, targetPlatform) { throw ProjectManager.NOT_IMPLEMENTED_ERROR_MSG; };\n    /**\n     * Cleans up a specific platform after tests.\n     *\n     * Overwrite this in your implementation!\n     */\n    ProjectManager.prototype.cleanupAfterPlatform = function (projectDirectory, targetPlatform) { throw ProjectManager.NOT_IMPLEMENTED_ERROR_MSG; };\n    /**\n     * Runs the test app on the given target / platform.\n     *\n     * Overwrite this in your implementation!\n     */\n    ProjectManager.prototype.runApplication = function (projectDirectory, targetPlatform) { throw ProjectManager.NOT_IMPLEMENTED_ERROR_MSG; };\n    ProjectManager.DEFAULT_APP_VERSION = \"Store version\";\n    ProjectManager.NOT_IMPLEMENTED_ERROR_MSG = \"This method is unimplemented! Please extend ProjectManager and overwrite it!\";\n    return ProjectManager;\n}());\nexports.ProjectManager = ProjectManager;\n//////////////////////////////////////////////////////////////////////////////////////////\n// Wrapper functions for simpler code in test cases.\n/**\n * Wrapper for ProjectManager.setupScenario in the TestRun directory.\n */\nfunction setupTestRunScenario(projectManager, targetPlatform, scenarioJsPath, version) {\n    return projectManager.setupScenario(TestConfig.testRunDirectory, TestConfig.TestNamespace, TestConfig.templatePath, scenarioJsPath, targetPlatform, version);\n}\nexports.setupTestRunScenario = setupTestRunScenario;\n/**\n * Creates an update and zip for the test app using the specified scenario and version.\n */\nfunction setupUpdateScenario(projectManager, targetPlatform, scenarioJsPath, version) {\n    return projectManager.setupScenario(TestConfig.updatesDirectory, TestConfig.TestNamespace, TestConfig.templatePath, scenarioJsPath, targetPlatform, version)\n        .then(projectManager.createUpdateArchive.bind(projectManager, TestConfig.updatesDirectory, targetPlatform));\n}\nexports.setupUpdateScenario = setupUpdateScenario;\n"
  },
  {
    "path": "code-push-plugin-testing-framework/script/serverUtil.js",
    "content": "\"use strict\";\n// IMPORTS\nvar assert = require(\"assert\");\nvar bodyParser = require(\"body-parser\");\nvar express = require(\"express\");\nvar Q = require(\"q\");\n//////////////////////////////////////////////////////////////////////////////////////////\n// Use these functions to set up and shut down the server.\n/**\n * Sets up the server that the test app uses to send test messages and check for and download updates.\n */\nfunction setupServer(targetPlatform) {\n    console.log(\"Setting up server at \" + targetPlatform.getServerUrl());\n    var app = express();\n    app.use(bodyParser.json());\n    app.use(bodyParser.urlencoded({ extended: true }));\n    app.use(function (req, res, next) {\n        res.setHeader(\"Access-Control-Allow-Origin\", \"*\");\n        res.setHeader(\"Access-Control-Allow-Methods\", \"*\");\n        res.setHeader(\"Access-Control-Allow-Headers\", \"origin, content-type, accept, X-CodePush-SDK-Version\");\n        next();\n    });\n    app.get(\"/v0.1/public/codepush/update_check\", function (req, res) {\n        exports.updateCheckCallback && exports.updateCheckCallback(req);\n        res.send(exports.updateResponse);\n        console.log(\"Update check called from the app.\");\n        console.log(\"Request: \" + JSON.stringify(req.query));\n        console.log(\"Response: \" + JSON.stringify(exports.updateResponse));\n    });\n    app.get(\"/v0.1/public/codepush/report_status/download\", function (req, res) {\n        console.log(\"Application downloading the package.\");\n        res.download(exports.updatePackagePath);\n    });\n    app.post(\"/reportTestMessage\", function (req, res) {\n        console.log(\"Application reported a test message.\");\n        console.log(\"Body: \" + JSON.stringify(req.body));\n        if (!exports.testMessageResponse) {\n            console.log(\"Sending OK\");\n            res.sendStatus(200);\n        }\n        else {\n            console.log(\"Sending body: \" + exports.testMessageResponse);\n            res.status(200).send(exports.testMessageResponse);\n        }\n        exports.testMessageCallback && exports.testMessageCallback(req.body);\n    });\n    var serverPortRegEx = /:([0-9]+)/;\n    exports.server = app.listen(+targetPlatform.getServerUrl().match(serverPortRegEx)[1]);\n}\nexports.setupServer = setupServer;\n/**\n * Closes the server.\n */\nfunction cleanupServer() {\n    if (exports.server) {\n        exports.server.close();\n        exports.server = undefined;\n    }\n}\nexports.cleanupServer = cleanupServer;\n//////////////////////////////////////////////////////////////////////////////////////////\n// Classes and methods used for sending mock responses to the app.\n/**\n * Class used to mock the codePush.checkForUpdate() response from the server.\n */\nvar CheckForUpdateResponseMock = (function () {\n    function CheckForUpdateResponseMock() {\n    }\n    return CheckForUpdateResponseMock;\n}());\nexports.CheckForUpdateResponseMock = CheckForUpdateResponseMock;\n/**\n * The model class of the codePush.checkForUpdate() request to the server.\n */\nvar UpdateCheckRequestMock = (function () {\n    function UpdateCheckRequestMock() {\n    }\n    return UpdateCheckRequestMock;\n}());\nexports.UpdateCheckRequestMock = UpdateCheckRequestMock;\n/**\n * Returns a default empty response to give to the app in a checkForUpdate request\n */\nfunction createDefaultResponse() {\n    var defaultResponse = new CheckForUpdateResponseMock();\n    defaultResponse.download_url = \"\";\n    defaultResponse.is_disabled = false;\n    defaultResponse.description = \"\";\n    defaultResponse.is_available = false;\n    defaultResponse.is_mandatory = false;\n    defaultResponse.target_binary_range = \"\";\n    defaultResponse.package_hash = \"\";\n    defaultResponse.label = \"\";\n    defaultResponse.package_size = 0;\n    defaultResponse.should_run_binary_version = false;\n    defaultResponse.update_app_version = false;\n    return defaultResponse;\n}\nexports.createDefaultResponse = createDefaultResponse;\n/**\n * Returns a default update response to give to the app in a checkForUpdate request\n */\nfunction createUpdateResponse(mandatory, targetPlatform, randomHash) {\n    if (mandatory === void 0) { mandatory = false; }\n    if (randomHash === void 0) { randomHash = true; }\n    var updateResponse = new CheckForUpdateResponseMock();\n    updateResponse.is_available = true;\n    updateResponse.is_disabled = false;\n    updateResponse.target_binary_range = \"1.0.0\";\n    updateResponse.download_url = \"mock.url/v0.1/public/codepush/report_status/download\";\n    updateResponse.is_mandatory = mandatory;\n    updateResponse.label = \"mock-update\";\n    updateResponse.package_hash = \"12345-67890\";\n    updateResponse.package_size = 12345;\n    updateResponse.should_run_binary_version = false;\n    updateResponse.update_app_version = false;\n    if (!!targetPlatform)\n        updateResponse.download_url = targetPlatform.getServerUrl() + \"/v0.1/public/codepush/report_status/download\";\n    // We need unique hashes to avoid conflicts.\n    if (randomHash) {\n        updateResponse.package_hash = \"randomHash-\" + Math.floor(Math.random() * 10000);\n    }\n    return updateResponse;\n}\nexports.createUpdateResponse = createUpdateResponse;\n/**\n * Returns a promise that waits for the next set of test messages sent by the app and resolves if that they are equal to the expected messages or rejects if they are not.\n */\nfunction expectTestMessages(expectedMessages) {\n    var deferred = Q.defer();\n    var messageIndex = 0;\n    var lastRequestBody = null;\n    exports.testMessageCallback = function (requestBody) {\n        try {\n            console.log(\"Message index: \" + messageIndex);\n            // We should ignore duplicated requests. It is only CI issue. \n            if (lastRequestBody === null || !areEqual(requestBody, lastRequestBody)) {\n                if (typeof expectedMessages[messageIndex] === \"string\") {\n                    assert.equal(requestBody.message, expectedMessages[messageIndex]);\n                }\n                else {\n                    assert(areEqual(requestBody, expectedMessages[messageIndex]));\n                }\n\n                lastRequestBody = requestBody;\n                \n                /* end of message array */\n                if (++messageIndex === expectedMessages.length) {\n                    deferred.resolve(undefined);\n                }\n            }\n        }\n        catch (e) {\n            deferred.reject(e);\n        }\n    };\n    return deferred.promise;\n}\nexports.expectTestMessages = expectTestMessages;\n;\n//////////////////////////////////////////////////////////////////////////////////////////\n// Test messages used by the test app to send state information to the server.\n/**\n * Contains all the messages sent from the application to the mock server during tests.\n */\nvar TestMessage = (function () {\n    function TestMessage() {\n    }\n    TestMessage.CHECK_UP_TO_DATE = \"CHECK_UP_TO_DATE\";\n    TestMessage.CHECK_UPDATE_AVAILABLE = \"CHECK_UPDATE_AVAILABLE\";\n    TestMessage.CHECK_ERROR = \"CHECK_ERROR\";\n    TestMessage.DOWNLOAD_SUCCEEDED = \"DOWNLOAD_SUCCEEDED\";\n    TestMessage.DOWNLOAD_ERROR = \"DOWNLOAD_ERROR\";\n    TestMessage.UPDATE_INSTALLED = \"UPDATE_INSTALLED\";\n    TestMessage.INSTALL_ERROR = \"INSTALL_ERROR\";\n    TestMessage.DEVICE_READY_AFTER_UPDATE = \"DEVICE_READY_AFTER_UPDATE\";\n    TestMessage.UPDATE_FAILED_PREVIOUSLY = \"UPDATE_FAILED_PREVIOUSLY\";\n    TestMessage.NOTIFY_APP_READY_SUCCESS = \"NOTIFY_APP_READY_SUCCESS\";\n    TestMessage.NOTIFY_APP_READY_FAILURE = \"NOTIFY_APP_READY_FAILURE\";\n    TestMessage.SKIPPED_NOTIFY_APPLICATION_READY = \"SKIPPED_NOTIFY_APPLICATION_READY\";\n    TestMessage.SYNC_STATUS = \"SYNC_STATUS\";\n    TestMessage.RESTART_SUCCEEDED = \"RESTART_SUCCEEDED\";\n    TestMessage.RESTART_FAILED = \"RESTART_FAILED\";\n    TestMessage.PENDING_PACKAGE = \"PENDING_PACKAGE\";\n    TestMessage.CURRENT_PACKAGE = \"CURRENT_PACKAGE\";\n    TestMessage.SYNC_UP_TO_DATE = 0;\n    TestMessage.SYNC_UPDATE_INSTALLED = 1;\n    TestMessage.SYNC_UPDATE_IGNORED = 2;\n    TestMessage.SYNC_ERROR = 3;\n    TestMessage.SYNC_IN_PROGRESS = 4;\n    TestMessage.SYNC_CHECKING_FOR_UPDATE = 5;\n    TestMessage.SYNC_AWAITING_USER_ACTION = 6;\n    TestMessage.SYNC_DOWNLOADING_PACKAGE = 7;\n    TestMessage.SYNC_INSTALLING_UPDATE = 8;\n    return TestMessage;\n}());\nexports.TestMessage = TestMessage;\n/**\n * Contains all the messages sent from the mock server back to the application during tests.\n */\nvar TestMessageResponse = (function () {\n    function TestMessageResponse() {\n    }\n    TestMessageResponse.SKIP_NOTIFY_APPLICATION_READY = \"SKIP_NOTIFY_APPLICATION_READY\";\n    return TestMessageResponse;\n}());\nexports.TestMessageResponse = TestMessageResponse;\n/**\n * Defines the messages sent from the application to the mock server during tests.\n */\nvar AppMessage = (function () {\n    function AppMessage(message, args) {\n        this.message = message;\n        this.args = args;\n    }\n    AppMessage.fromString = function (message) {\n        return new AppMessage(message, undefined);\n    };\n    return AppMessage;\n}());\nexports.AppMessage = AppMessage;\n/**\n * Checks if two messages are equal.\n */\nfunction areEqual(m1, m2) {\n    /* compare objects */\n    if (m1 === m2) {\n        return true;\n    }\n    /* compare messages */\n    if (!m1 || !m2 || m1.message !== m2.message) {\n        return false;\n    }\n    /* compare arguments */\n    if (m1.args === m2.args) {\n        return true;\n    }\n    if (!m1.args || !m2.args || m1.args.length !== m2.args.length) {\n        return false;\n    }\n    for (var i = 0; i < m1.args.length; i++) {\n        if (m1.args[i] !== m2.args[i]) {\n            return false;\n        }\n    }\n    return true;\n}\nexports.areEqual = areEqual;\n"
  },
  {
    "path": "code-push-plugin-testing-framework/script/test.js",
    "content": "\"use strict\";\nvar Q = require(\"q\");\nvar ServerUtil = require(\"./serverUtil\");\nvar testBuilder_1 = require(\"./testBuilder\");\nvar TestConfig = require(\"./testConfig\");\nvar testUtil_1 = require(\"./testUtil\");\n//////////////////////////////////////////////////////////////////////////////////////////\n/**\n * Call this function to initialize the automated tests.\n */\nfunction initializeTests(projectManager, supportedTargetPlatforms, describeTests) {\n    // DETERMINE PLATFORMS TO TEST //\n    /** The platforms to test on. */\n    var targetPlatforms = [];\n    supportedTargetPlatforms.forEach(function (supportedPlatform) {\n        if (testUtil_1.TestUtil.readMochaCommandLineFlag(supportedPlatform.getCommandLineFlagName()))\n            targetPlatforms.push(supportedPlatform);\n    });\n    // Log current configuration\n    console.log(\"Initializing tests for \" + testUtil_1.TestUtil.getPluginName());\n    console.log(TestConfig.TestAppName + \"\\n\" + TestConfig.TestNamespace);\n    console.log(\"Testing \" + TestConfig.thisPluginPath + \".\");\n    targetPlatforms.forEach(function (platform) {\n        console.log(\"On \" + platform.getName());\n    });\n    console.log(\"test run directory = \" + TestConfig.testRunDirectory);\n    console.log(\"updates directory = \" + TestConfig.updatesDirectory);\n    if (TestConfig.onlyRunCoreTests)\n        console.log(\"--only running core tests--\");\n    if (TestConfig.shouldSetup)\n        console.log(\"--setting up--\");\n    if (TestConfig.restartEmulators)\n        console.log(\"--restarting emulators--\");\n    // FUNCTIONS //\n    function cleanupTest() {\n        console.log(\"Cleaning up!\");\n        ServerUtil.updateResponse = undefined;\n        ServerUtil.testMessageCallback = undefined;\n        ServerUtil.updateCheckCallback = undefined;\n        ServerUtil.testMessageResponse = undefined;\n    }\n    /**\n     * Sets up tests for each platform.\n     * Creates the test project directory and the test update directory.\n     * Starts required emulators.\n     */\n    function setupTests() {\n        it(\"sets up tests correctly\", function (done) {\n            var promises = [];\n            targetPlatforms.forEach(function (platform) {\n                promises.push(platform.getEmulatorManager().bootEmulator(TestConfig.restartEmulators));\n            });\n            console.log(\"Building test project.\");\n            // create the test project\n            promises.push(createTestProject(TestConfig.testRunDirectory)\n                .then(function () {\n                    console.log(\"Building update project.\");\n                    // create the update project\n                    return createTestProject(TestConfig.updatesDirectory);\n                }).then(function () { return null; }));\n            Q.all(promises).then(function () { done(); }, function (error) { done(error); });\n        });\n    }\n    /**\n     * Creates a test project directory at the given path.\n     */\n    function createTestProject(directory) {\n        return projectManager.setupProject(directory, TestConfig.templatePath, TestConfig.TestAppName, TestConfig.TestNamespace);\n    }\n    /**\n     * Creates and runs the tests from the projectManager and TestBuilderDescribe objects passed to initializeTests.\n     */\n    function createAndRunTests(targetPlatform) {\n        describe(\"CodePush\", function () {\n            before(function () {\n                ServerUtil.setupServer(targetPlatform);\n                return targetPlatform.getEmulatorManager().uninstallApplication(TestConfig.TestNamespace)\n                    .then(projectManager.preparePlatform.bind(projectManager, TestConfig.testRunDirectory, targetPlatform))\n                    .then(projectManager.preparePlatform.bind(projectManager, TestConfig.updatesDirectory, targetPlatform));\n            });\n            after(function () {\n                ServerUtil.cleanupServer();\n                return projectManager.cleanupAfterPlatform(TestConfig.testRunDirectory, targetPlatform).then(projectManager.cleanupAfterPlatform.bind(projectManager, TestConfig.updatesDirectory, targetPlatform));\n            });\n            testBuilder_1.TestContext.projectManager = projectManager;\n            testBuilder_1.TestContext.targetPlatform = targetPlatform;\n            // Build the tests.\n            describeTests(projectManager, targetPlatform);\n        });\n    }\n    // BEGIN TESTING //\n    describe(\"CodePush \" + projectManager.getPluginName() + \" Plugin\", function () {\n        this.timeout(100 * 60 * 1000);\n        if (TestConfig.shouldSetup)\n            describe(\"Setting Up For Tests\", function () { return setupTests(); });\n        else {\n            targetPlatforms.forEach(function (platform) {\n                var prefix = (TestConfig.onlyRunCoreTests ? \"Core Tests \" : \"Tests \") + TestConfig.thisPluginPath + \" on \";\n                describe(prefix + platform.getName(), function () { return createAndRunTests(platform); });\n            });\n        }\n    });\n}\nexports.initializeTests = initializeTests;\n"
  },
  {
    "path": "code-push-plugin-testing-framework/script/testBuilder.js",
    "content": "\"use strict\";\nvar ServerUtil = require(\"./serverUtil\");\nvar TestConfig = require(\"./testConfig\");\n//////////////////////////////////////////////////////////////////////////////////////////\n// Use this class to create and structure the tests.\n// Usage is almost identical to Mocha, but with the addition of the optional \"scenarioPath\" in describe() and the required \"isCoreTest\" in it().\nvar TestBuilder = (function () {\n    function TestBuilder() {\n    }\n    TestBuilder.describe = getDescribe();\n    TestBuilder.it = getIt();\n    return TestBuilder;\n}());\nexports.TestBuilder = TestBuilder;\n//////////////////////////////////////////////////////////////////////////////////////////\n// Mocha mimicry\n/** Singleton class for TestBuilder.describe to use internally to define the context. */\nvar TestContext = (function () {\n    function TestContext() {\n    }\n    return TestContext;\n}());\nexports.TestContext = TestContext;\nfunction describeInternal(func, description, spec, scenarioPath) {\n    if (!TestContext.projectManager || !TestContext.targetPlatform) {\n        throw new Error(\"TestContext.projectManager or TestContext.targetPlatform are not defined! Did you call TestBuilder.describe outside of a function you passed to PluginTestingFramework.initializeTests?\");\n    }\n    return func(description, function () {\n        afterEach(function () {\n            console.log(\"Cleaning up!\");\n            ServerUtil.updateResponse = undefined;\n            ServerUtil.testMessageCallback = undefined;\n            ServerUtil.updateCheckCallback = undefined;\n            ServerUtil.testMessageResponse = undefined;\n        });\n        beforeEach(function () {\n            return TestContext.targetPlatform.getEmulatorManager().prepareEmulatorForTest(TestConfig.TestNamespace)\n                .catch(function () { });\n        });\n        if (scenarioPath) {\n            before(function () {\n                return TestContext.projectManager.setupScenario(TestConfig.testRunDirectory, TestConfig.TestNamespace, TestConfig.templatePath, scenarioPath, TestContext.targetPlatform);\n            });\n        }\n        spec();\n    });\n}\n/**\n * Returns a hybrid type that mimics mocha's describe object.\n */\nfunction getDescribe() {\n    var describer = function (description, spec, scenarioPath) {\n        describeInternal(describe, description, spec, scenarioPath);\n    };\n    describer.only = function (description, spec, scenarioPath) {\n        describeInternal(describe.only, description, spec, scenarioPath);\n    };\n    describer.skip = function (description, spec, scenarioPath) {\n        describeInternal(describe.skip, description, spec, scenarioPath);\n    };\n    return describer;\n}\nfunction itInternal(func, expectation, isCoreTest, assertion) {\n    if ((!TestConfig.onlyRunCoreTests || isCoreTest)) {\n        // Create a wrapper around the assertion to set the timeout on the test to 10 minutes.\n        var assertionWithTimeout = function (done) {\n            this.timeout(10 * 2 * 60 * 1000);\n            assertion(done);\n        };\n        return it(expectation, assertionWithTimeout);\n    }\n    return null;\n}\n/**\n * Returns a hybrid type that mimics mocha's it object.\n */\nfunction getIt() {\n    var itr = function (expectation, isCoreTest, assertion) {\n        itInternal(it, expectation, isCoreTest, assertion);\n    };\n    itr.only = function (expectation, isCoreTest, assertion) {\n        itInternal(it.only, expectation, isCoreTest, assertion);\n    };\n    itr.skip = function (expectation, isCoreTest, assertion) {\n        itInternal(it.skip, expectation, isCoreTest, assertion);\n    };\n    return itr;\n}\n"
  },
  {
    "path": "code-push-plugin-testing-framework/script/testConfig.js",
    "content": "\"use strict\";\n// IMPORTS //\nvar os = require(\"os\");\nvar path = require(\"path\");\nvar TestUtil_1 = require(\"./testUtil\");\n//////////////////////////////////////////////////////////////////////////////////////////\n// Configuration variables.\n// What plugin to use, what project directories to use, etc.\n// COMMAND LINE OPTION NAMES, FLAGS, AND DEFAULTS\nvar DEFAULT_TEST_RUN_DIRECTORY = path.join(os.tmpdir(), TestUtil_1.TestUtil.getPluginName(), \"test-run\");\nvar DEFAULT_UPDATES_DIRECTORY = path.join(os.tmpdir(), TestUtil_1.TestUtil.getPluginName(), \"updates\");\nvar DEFAULT_PLUGIN_PATH = path.join(__dirname, \"../..\");\nvar NPM_PLUGIN_PATH = TestUtil_1.TestUtil.getPluginName();\nvar SETUP_FLAG_NAME = \"--setup\";\nvar DEFAULT_PLUGIN_TGZ_NAME = TestUtil_1.TestUtil.getPluginName() + \"-\" + TestUtil_1.TestUtil.getPluginVersion() + \".tgz\";\n// CONST VARIABLES\nexports.TestAppName = \"TestCodePush\";\nexports.TestNamespace = \"com.testcodepush\";\nexports.AcquisitionSDKPluginName = \"code-push\";\nexports.templatePath = path.join(__dirname, \"../../test/template\");\nexports.thisPluginInstallString = TestUtil_1.TestUtil.resolveBooleanVariables(process.env.NPM) ? `npm install ${NPM_PLUGIN_PATH}` : `npm pack ${DEFAULT_PLUGIN_PATH} && npm install ${DEFAULT_PLUGIN_TGZ_NAME} && npm link`;\nexports.testRunDirectory = process.env.RUN_DIR ? process.env.RUN_DIR: DEFAULT_TEST_RUN_DIRECTORY;\nexports.updatesDirectory = process.env.UPDATE_DIR ? process.env.UPDATE_DIR : DEFAULT_UPDATES_DIRECTORY;\nexports.onlyRunCoreTests = TestUtil_1.TestUtil.resolveBooleanVariables(process.env.CORE);\nexports.shouldSetup = TestUtil_1.TestUtil.readMochaCommandLineFlag(SETUP_FLAG_NAME);\nexports.restartEmulators = TestUtil_1.TestUtil.resolveBooleanVariables(process.env.CLEAN);\n"
  },
  {
    "path": "code-push-plugin-testing-framework/script/testUtil.js",
    "content": "\"use strict\";\nvar archiver = require(\"archiver\");\nvar child_process = require(\"child_process\");\nvar fs = require(\"fs\");\nvar replace = require(\"replace\");\nvar Q = require(\"q\");\nvar TestUtil = (function () {\n    function TestUtil() {\n    }\n    //// Command Line Input Functions\n    /**\n     * Reads a command line option passed to mocha and returns a default if unspecified.\n     */\n    TestUtil.readMochaCommandLineOption = function (optionName, defaultValue) {\n        var optionValue = undefined;\n        for (var i = 0; i < process.argv.length; i++) {\n            if (process.argv[i] === optionName) {\n                if (i + 1 < process.argv.length) {\n                    optionValue = process.argv[i + 1];\n                }\n                break;\n            }\n        }\n        if (!optionValue)\n            optionValue = defaultValue;\n        return optionValue;\n    };\n    /**\n     * Reads command line options passed to mocha.\n     */\n    TestUtil.readMochaCommandLineFlag = function (optionName) {\n        for (var i = 0; i < process.argv.length; i++) {\n            if (process.argv[i] === optionName) {\n                return true;\n            }\n        }\n        return false;\n    };\n    //// Utility Functions\n    /**\n     * Executes a child process and returns a promise that resolves with its output or rejects with its error.\n     */\n    TestUtil.getProcessOutput = function (command, options) {\n        var deferred = Q.defer();\n        options = options || {};\n        // set default options\n        if (options.maxBuffer === undefined)\n            options.maxBuffer = 1024 * 1024 * 500;\n        if (options.timeout === undefined)\n            options.timeout = 10 * 60 * 1000;\n        if (!options.noLogCommand)\n            console.log(\"Running command: \" + command);\n        var execProcess = child_process.exec(command, options, function (error, stdout, stderr) {\n            if (error) {\n                if (!options.noLogStdErr)\n                    console.error(\"\" + error);\n                deferred.reject(error);\n            }\n            else {\n                deferred.resolve(stdout.toString());\n            }\n        });\n        if (!options.noLogStdOut)\n            execProcess.stdout.pipe(process.stdout);\n        if (!options.noLogStdErr)\n            execProcess.stderr.pipe(process.stderr);\n        execProcess.on('error', function (error) {\n            if (!options.noLogStdErr)\n                console.error(\"\" + error);\n            deferred.reject(error);\n        });\n        return deferred.promise;\n    };\n    /**\n     * Returns the name of the plugin that is being tested.\n     */\n    TestUtil.getPluginName = function () {\n        var packageFile = JSON.parse(fs.readFileSync(\"./package.json\", \"utf8\"));\n        return packageFile.name;\n    };\n\n    TestUtil.getPluginVersion = function () {\n        var packageFile = JSON.parse(fs.readFileSync(\"./package.json\", \"utf8\"));\n        return packageFile.version;\n    };\n    /**\n     * Replaces a regex in a file with a given string.\n     */\n    TestUtil.replaceString = function (filePath, regex, replacement) {\n        console.log(\"replacing \\\"\" + regex + \"\\\" with \\\"\" + replacement + \"\\\" in \" + filePath);\n        replace({ regex: regex, replacement: replacement, recursive: false, silent: true, paths: [filePath] });\n    };\n    /**\n     * Copies a file from a given location to another.\n     */\n    TestUtil.copyFile = function (source, destination, overwrite) {\n        var deferred = Q.defer();\n        try {\n            var errorHandler = function (error) {\n                deferred.reject(error);\n            };\n            if (overwrite && fs.existsSync(destination)) {\n                fs.unlinkSync(destination);\n            }\n            var readStream = fs.createReadStream(source);\n            readStream.on(\"error\", errorHandler);\n            var writeStream = fs.createWriteStream(destination);\n            writeStream.on(\"error\", errorHandler);\n            writeStream.on(\"close\", deferred.resolve.bind(undefined, undefined));\n            readStream.pipe(writeStream);\n        }\n        catch (e) {\n            deferred.reject(e);\n        }\n        return deferred.promise;\n    };\n    /**\n     * Archives the contents of sourceFolder and puts it in an archive at archivePath in targetFolder.\n     */\n    TestUtil.archiveFolder = function (sourceFolder, targetFolder, archivePath, isDiff) {\n        var deferred = Q.defer();\n        var archive = archiver.create(\"zip\", {});\n        console.log(\"Creating an update archive at: \" + archivePath);\n        if (fs.existsSync(archivePath)) {\n            fs.unlinkSync(archivePath);\n        }\n        var writeStream = fs.createWriteStream(archivePath);\n        writeStream.on(\"close\", function () {\n            deferred.resolve(archivePath);\n        });\n        archive.on(\"error\", function (e) {\n            deferred.reject(e);\n        });\n        if (isDiff) {\n            archive.append(\"{\\\"deletedFiles\\\":[]}\", { name: \"hotcodepush.json\" });\n        }\n        archive.directory(sourceFolder, targetFolder);\n        archive.pipe(writeStream);\n        archive.finalize();\n        return deferred.promise;\n    };\n\n    /**\n     * Check that boolean environment variable string is 'true.\n     */\n    TestUtil.resolveBooleanVariables = function(variable) {\n        if (variable) {\n            return variable.toLowerCase() === 'true';\n        }\n    \n        return false;\n    }\n    //// Placeholders\n    // Used in the template to represent data that needs to be added by the testing framework at runtime.\n    TestUtil.ANDROID_KEY_PLACEHOLDER = \"CODE_PUSH_ANDROID_DEPLOYMENT_KEY\";\n    TestUtil.IOS_KEY_PLACEHOLDER = \"CODE_PUSH_IOS_DEPLOYMENT_KEY\";\n    TestUtil.SERVER_URL_PLACEHOLDER = \"CODE_PUSH_SERVER_URL\";\n    TestUtil.INDEX_JS_PLACEHOLDER = \"CODE_PUSH_INDEX_JS_PATH\";\n    TestUtil.CODE_PUSH_APP_VERSION_PLACEHOLDER = \"CODE_PUSH_APP_VERSION\";\n    TestUtil.CODE_PUSH_TEST_APP_NAME_PLACEHOLDER = \"CODE_PUSH_TEST_APP_NAME\";\n    TestUtil.CODE_PUSH_APP_ID_PLACEHOLDER = \"CODE_PUSH_TEST_APPLICATION_ID\";\n    TestUtil.PLUGIN_VERSION_PLACEHOLDER = \"CODE_PUSH_PLUGIN_VERSION\";\n    return TestUtil;\n}());\nexports.TestUtil = TestUtil;\n"
  },
  {
    "path": "code-push-plugin-testing-framework/typings/code-push-plugin-testing-framework.d.ts",
    "content": "declare module 'code-push-plugin-testing-framework/script/platform' {\n\timport Q = require(\"q\");\n\t/**\n\t * Defines a platform supported by CodePush.\n\t */\n\texport interface IPlatform {\n\t    /**\n\t     * Gets the platform name. (e.g. \"android\" for the Android platform).\n\t     */\n\t    getName(): string;\n\t    /**\n\t     * The command line flag used to determine whether or not this platform should run.\n\t     * Runs when the flag is present, doesn't run otherwise.\n\t     */\n\t    getCommandLineFlagName(): string;\n\t    /**\n\t     * Gets the server url used for testing.\n\t     */\n\t    getServerUrl(): string;\n\t    /**\n\t     * Gets an IEmulatorManager that is used to control the emulator during the tests.\n\t     */\n\t    getEmulatorManager(): IEmulatorManager;\n\t    /**\n\t     * Gets the default deployment key.\n\t     */\n\t    getDefaultDeploymentKey(): string;\n\t}\n\t/**\n\t * Manages the interaction with the emulator.\n\t */\n\texport interface IEmulatorManager {\n\t    /**\n\t     * Returns the target emulator, which is specified through the command line.\n\t     */\n\t    getTargetEmulator(): Q.Promise<string>;\n\t    /**\n\t     * Boots the target emulator.\n\t     */\n\t    bootEmulator(restartEmulators: boolean): Q.Promise<void>;\n\t    /**\n\t     * Launches an already installed application by app id.\n\t     */\n\t    launchInstalledApplication(appId: string): Q.Promise<void>;\n\t    /**\n\t     * Ends a running application given its app id.\n\t     */\n\t    endRunningApplication(appId: string): Q.Promise<void>;\n\t    /**\n\t     * Restarts an already installed application by app id.\n\t     */\n\t    restartApplication(appId: string): Q.Promise<void>;\n\t    /**\n\t     * Navigates away from the current app, waits for a delay (defaults to 1 second), then navigates to the specified app.\n\t     */\n\t    resumeApplication(appId: string, delayBeforeResumingMs?: number): Q.Promise<void>;\n\t    /**\n\t     * Prepares the emulator for a test.\n\t     */\n\t    prepareEmulatorForTest(appId: string): Q.Promise<void>;\n\t    /**\n\t     * Uninstalls the app from the emulator.\n\t     */\n\t    uninstallApplication(appId: string): Q.Promise<void>;\n\t}\n\t/**\n\t * Android implementations of IPlatform.\n\t */\n\texport class Android implements IPlatform {\n\t    private emulatorManager;\n\t    private serverUrl;\n\t    constructor(emulatorManager: IEmulatorManager);\n\t    /**\n\t     * Gets the platform name. (e.g. \"android\" for the Android platform).\n\t     */\n\t    getName(): string;\n\t    /**\n\t     * The command line flag used to determine whether or not this platform should run.\n\t     * Runs when the flag is present, doesn't run otherwise.\n\t     */\n\t    getCommandLineFlagName(): string;\n\t    private static DEFAULT_ANDROID_SERVER_URL;\n\t    /**\n\t     * Gets the server url used for testing.\n\t     */\n\t    getServerUrl(): string;\n\t    /**\n\t     * Gets an IEmulatorManager that is used to control the emulator during the tests.\n\t     */\n\t    getEmulatorManager(): IEmulatorManager;\n\t    /**\n\t     * Gets the default deployment key.\n\t     */\n\t    getDefaultDeploymentKey(): string;\n\t}\n\t/**\n\t * IOS implementation of IPlatform.\n\t */\n\texport class IOS implements IPlatform {\n\t    private emulatorManager;\n\t    private serverUrl;\n\t    constructor(emulatorManager: IEmulatorManager);\n\t    /**\n\t     * Gets the platform name. (e.g. \"android\" for the Android platform).\n\t     */\n\t    getName(): string;\n\t    /**\n\t     * The command line flag used to determine whether or not this platform should run.\n\t     * Runs when the flag is present, doesn't run otherwise.\n\t     */\n\t    getCommandLineFlagName(): string;\n\t    private static DEFAULT_IOS_SERVER_URL;\n\t    /**\n\t     * Gets the server url used for testing.\n\t     */\n\t    getServerUrl(): string;\n\t    /**\n\t     * Gets an IEmulatorManager that is used to control the emulator during the tests.\n\t     */\n\t    getEmulatorManager(): IEmulatorManager;\n\t    /**\n\t     * Gets the default deployment key.\n\t     */\n\t    getDefaultDeploymentKey(): string;\n\t}\n\texport class AndroidEmulatorManager implements IEmulatorManager {\n\t    private targetEmulator;\n\t    /**\n\t     * Returns the target emulator, which is specified through the command line.\n\t     */\n\t    getTargetEmulator(): Q.Promise<string>;\n\t    /**\n\t     * Boots the target emulator.\n\t     */\n\t    bootEmulator(restartEmulators: boolean): Q.Promise<void>;\n\t    /**\n\t     * Launches an already installed application by app id.\n\t     */\n\t    launchInstalledApplication(appId: string): Q.Promise<void>;\n\t    /**\n\t     * Ends a running application given its app id.\n\t     */\n\t    endRunningApplication(appId: string): Q.Promise<void>;\n\t    /**\n\t     * Restarts an already installed application by app id.\n\t     */\n\t    restartApplication(appId: string): Q.Promise<void>;\n\t    /**\n\t     * Navigates away from the current app, waits for a delay (defaults to 1 second), then navigates to the specified app.\n\t     */\n\t    resumeApplication(appId: string, delayBeforeResumingMs?: number): Q.Promise<void>;\n\t    /**\n\t     * Prepares the emulator for a test.\n\t     */\n\t    prepareEmulatorForTest(appId: string): Q.Promise<void>;\n\t    /**\n\t     * Uninstalls the app from the emulator.\n\t     */\n\t    uninstallApplication(appId: string): Q.Promise<void>;\n\t}\n\texport class IOSEmulatorManager implements IEmulatorManager {\n\t    private targetEmulator;\n\t    /**\n\t     * Returns the target emulator, which is specified through the command line.\n\t     */\n\t    getTargetEmulator(): Q.Promise<string>;\n\t    /**\n\t     * Boots the target emulator.\n\t     */\n\t    bootEmulator(restartEmulators: boolean): Q.Promise<void>;\n\t    /**\n\t     * Launches an already installed application by app id.\n\t     */\n\t    launchInstalledApplication(appId: string): Q.Promise<void>;\n\t    /**\n\t     * Ends a running application given its app id.\n\t     */\n\t    endRunningApplication(appId: string): Q.Promise<void>;\n\t    /**\n\t     * Restarts an already installed application by app id.\n\t     */\n\t    restartApplication(appId: string): Q.Promise<void>;\n\t    /**\n\t     * Navigates away from the current app, waits for a delay (defaults to 1 second), then navigates to the specified app.\n\t     */\n\t    resumeApplication(appId: string, delayBeforeResumingMs?: number): Q.Promise<void>;\n\t    /**\n\t     * Prepares the emulator for a test.\n\t     */\n\t    prepareEmulatorForTest(appId: string): Q.Promise<void>;\n\t    /**\n\t     * Uninstalls the app from the emulator.\n\t     */\n\t    uninstallApplication(appId: string): Q.Promise<void>;\n\t}\n\n}\ndeclare module 'code-push-plugin-testing-framework/script/projectManager' {\n\timport Q = require(\"q\");\n\timport platform = require('code-push-plugin-testing-framework/script/platform');\n\t/**\n\t * In charge of project related operations.\n\t */\n\texport class ProjectManager {\n\t    static DEFAULT_APP_VERSION: string;\n\t    private static NOT_IMPLEMENTED_ERROR_MSG;\n\t    /**\n\t     * Returns the name of the plugin being tested, for example Cordova or React-Native.\n\t     *\n\t     * Overwrite this in your implementation!\n\t     */\n\t    getPluginName(): string;\n\t    /**\n\t     * Creates a new test application at the specified path, and configures it\n\t     * with the given server URL, android and ios deployment keys.\n\t     *\n\t     * Overwrite this in your implementation!\n\t     */\n\t    setupProject(projectDirectory: string, templatePath: string, appName: string, appNamespace: string, version?: string): Q.Promise<void>;\n\t    /**\n\t     * Sets up the scenario for a test in an already existing project.\n\t     *\n\t     * Overwrite this in your implementation!\n\t     */\n\t    setupScenario(projectDirectory: string, appId: string, templatePath: string, jsPath: string, targetPlatform: platform.IPlatform, version?: string): Q.Promise<void>;\n\t    /**\n\t     * Creates a CodePush update package zip for a project.\n\t     *\n\t     * Overwrite this in your implementation!\n\t     */\n\t    createUpdateArchive(projectDirectory: string, targetPlatform: platform.IPlatform, isDiff?: boolean): Q.Promise<string>;\n\t    /**\n\t     * Prepares a specific platform for tests.\n\t     *\n\t     * Overwrite this in your implementation!\n\t     */\n\t    preparePlatform(projectDirectory: string, targetPlatform: platform.IPlatform): Q.Promise<void>;\n\t    /**\n\t     * Cleans up a specific platform after tests.\n\t     *\n\t     * Overwrite this in your implementation!\n\t     */\n\t    cleanupAfterPlatform(projectDirectory: string, targetPlatform: platform.IPlatform): Q.Promise<void>;\n\t    /**\n\t     * Runs the test app on the given target / platform.\n\t     *\n\t     * Overwrite this in your implementation!\n\t     */\n\t    runApplication(projectDirectory: string, targetPlatform: platform.IPlatform): Q.Promise<void>;\n\t}\n\t/**\n\t * Wrapper for ProjectManager.setupScenario in the TestRun directory.\n\t */\n\texport function setupTestRunScenario(projectManager: ProjectManager, targetPlatform: platform.IPlatform, scenarioJsPath: string, version?: string): Q.Promise<void>;\n\t/**\n\t * Creates an update and zip for the test app using the specified scenario and version.\n\t */\n\texport function setupUpdateScenario(projectManager: ProjectManager, targetPlatform: platform.IPlatform, scenarioJsPath: string, version: string): Q.Promise<string>;\n\n}\ndeclare module 'code-push-plugin-testing-framework/script/test' {\n\timport Platform = require('code-push-plugin-testing-framework/script/platform');\n\timport { ProjectManager } from 'code-push-plugin-testing-framework/script/projectManager';\n\t/**\n\t * Call this function to initialize the automated tests.\n\t */\n\texport function initializeTests(projectManager: ProjectManager, supportedTargetPlatforms: Platform.IPlatform[], describeTests: (projectManager: ProjectManager, targetPlatform: Platform.IPlatform) => void): void;\n\n}\ndeclare module 'code-push-plugin-testing-framework/script/serverUtil' {\n\timport platform = require('code-push-plugin-testing-framework/script/platform');\n\timport Q = require(\"q\");\n\t/** The server to respond to requests from the app. */\n\texport var server: any;\n\t/** Response the server gives the next update check request */\n\texport var updateResponse: any;\n\t/** Response the server gives the next test message request */\n\texport var testMessageResponse: any;\n\t/** Called after the next test message request */\n\texport var testMessageCallback: (requestBody: any) => void;\n\t/** Called after the next update check request */\n\texport var updateCheckCallback: (requestBody: any) => void;\n\t/** Location of the update package given in the update check response */\n\texport var updatePackagePath: string;\n\t/**\n\t * Sets up the server that the test app uses to send test messages and check for and download updates.\n\t */\n\texport function setupServer(targetPlatform: platform.IPlatform): void;\n\t/**\n\t * Closes the server.\n\t */\n\texport function cleanupServer(): void;\n\t/**\n\t * Class used to mock the codePush.checkForUpdate() response from the server.\n\t */\n\texport class CheckForUpdateResponseMock {\n\t\tdownload_url: string;\n\t\tis_available: boolean;\n\t\tshould_run_binary_version: boolean;\n\t\tpackage_size: number;\n\t\tupdate_app_version: boolean;\n\t\ttarget_binary_range: string;\n\t\tis_disabled: boolean;\n\t\tdescription: string;\n\t\tlabel: string;\n\t\tpackage_hash: string;\n\t\tis_mandatory: boolean;\n\t}\n\t/**\n\t * The model class of the codePush.checkForUpdate() request to the server.\n\t */\n\texport class UpdateCheckRequestMock {\n\t    deploymentKey: string;\n\t    appVersion: string;\n\t    packageHash: string;\n\t    isCompanion: boolean;\n\t}\n\t/**\n\t * Returns a default empty response to give to the app in a checkForUpdate request\n\t */\n\texport function createDefaultResponse(): CheckForUpdateResponseMock;\n\t/**\n\t * Returns a default update response to give to the app in a checkForUpdate request\n\t */\n\texport function createUpdateResponse(mandatory?: boolean, targetPlatform?: platform.IPlatform, randomHash?: boolean): CheckForUpdateResponseMock;\n\t/**\n\t * Returns a promise that waits for the next set of test messages sent by the app and resolves if that they are equal to the expected messages or rejects if they are not.\n\t */\n\texport function expectTestMessages(expectedMessages: (string | AppMessage)[]): Q.Promise<void>;\n\t/**\n\t * Contains all the messages sent from the application to the mock server during tests.\n\t */\n\texport class TestMessage {\n\t    static CHECK_UP_TO_DATE: string;\n\t    static CHECK_UPDATE_AVAILABLE: string;\n\t    static CHECK_ERROR: string;\n\t    static DOWNLOAD_SUCCEEDED: string;\n\t    static DOWNLOAD_ERROR: string;\n\t    static UPDATE_INSTALLED: string;\n\t    static INSTALL_ERROR: string;\n\t    static DEVICE_READY_AFTER_UPDATE: string;\n\t    static UPDATE_FAILED_PREVIOUSLY: string;\n\t    static NOTIFY_APP_READY_SUCCESS: string;\n\t    static NOTIFY_APP_READY_FAILURE: string;\n\t    static SKIPPED_NOTIFY_APPLICATION_READY: string;\n\t    static SYNC_STATUS: string;\n\t    static RESTART_SUCCEEDED: string;\n\t    static RESTART_FAILED: string;\n\t    static PENDING_PACKAGE: string;\n\t    static CURRENT_PACKAGE: string;\n\t    static SYNC_UP_TO_DATE: number;\n\t    static SYNC_UPDATE_INSTALLED: number;\n\t    static SYNC_UPDATE_IGNORED: number;\n\t    static SYNC_ERROR: number;\n\t    static SYNC_IN_PROGRESS: number;\n\t    static SYNC_CHECKING_FOR_UPDATE: number;\n\t    static SYNC_AWAITING_USER_ACTION: number;\n\t    static SYNC_DOWNLOADING_PACKAGE: number;\n\t    static SYNC_INSTALLING_UPDATE: number;\n\t}\n\t/**\n\t * Contains all the messages sent from the mock server back to the application during tests.\n\t */\n\texport class TestMessageResponse {\n\t    static SKIP_NOTIFY_APPLICATION_READY: string;\n\t}\n\t/**\n\t * Defines the messages sent from the application to the mock server during tests.\n\t */\n\texport class AppMessage {\n\t    message: string;\n\t    args: any[];\n\t    constructor(message: string, args: any[]);\n\t    static fromString(message: string): AppMessage;\n\t}\n\t/**\n\t * Checks if two messages are equal.\n\t */\n\texport function areEqual(m1: AppMessage, m2: AppMessage): boolean;\n\n}\ndeclare module 'code-push-plugin-testing-framework/script/testBuilder' {\n\timport Platform = require('code-push-plugin-testing-framework/script/platform');\n\timport { ProjectManager } from 'code-push-plugin-testing-framework/script/projectManager';\n\texport class TestBuilder {\n\t    static describe: ITestBuilderContextDefintion;\n\t    static it: ITestBuilderTestDefinition;\n\t}\n\t/** Singleton class for TestBuilder.describe to use internally to define the context. */\n\texport class TestContext {\n\t    static projectManager: ProjectManager;\n\t    static targetPlatform: Platform.IPlatform;\n\t}\n\texport interface ITestBuilderContextDefintion {\n\t    (description: string, spec: () => void, scenarioPath?: string): void;\n\t    only(description: string, spec: () => void, scenarioPath?: string): void;\n\t    skip(description: string, spec: () => void, scenarioPath?: string): void;\n\t}\n\texport interface ITestBuilderTestDefinition {\n\t    (expectation: string, isCoreTest: boolean, assertion: (done: Mocha.Done) => void): void;\n\t    only(expectation: string, isCoreTest: boolean, assertion: (done: Mocha.Done) => void): void;\n\t    skip(expectation: string, isCoreTest: boolean, assertion: (done: Mocha.Done) => void): void;\n\t}\n\n}\ndeclare module 'code-push-plugin-testing-framework/script/testConfig' {\n\texport const TestAppName: string;\n\texport const TestNamespace: string;\n\texport const AcquisitionSDKPluginName: string;\n\texport const templatePath: string;\n\texport const thisPluginInstallString: string;\n\texport const testRunDirectory: string;\n\texport const updatesDirectory: string;\n\texport const onlyRunCoreTests: boolean;\n\texport const shouldSetup: boolean;\n\texport const restartEmulators: boolean;\n\n}\ndeclare module 'code-push-plugin-testing-framework/script/testUtil' {\n\timport Q = require(\"q\");\n\texport class TestUtil {\n\t    static ANDROID_KEY_PLACEHOLDER: string;\n\t    static IOS_KEY_PLACEHOLDER: string;\n\t    static SERVER_URL_PLACEHOLDER: string;\n\t    static INDEX_JS_PLACEHOLDER: string;\n\t    static CODE_PUSH_APP_VERSION_PLACEHOLDER: string;\n\t    static CODE_PUSH_TEST_APP_NAME_PLACEHOLDER: string;\n\t    static CODE_PUSH_APP_ID_PLACEHOLDER: string;\n\t    static PLUGIN_VERSION_PLACEHOLDER: string;\n\t    /**\n\t     * Reads a command line option passed to mocha and returns a default if unspecified.\n\t     */\n\t    static readMochaCommandLineOption(optionName: string, defaultValue?: string): string;\n\t    /**\n\t     * Reads command line options passed to mocha.\n\t     */\n\t    static readMochaCommandLineFlag(optionName: string): boolean;\n\t    /**\n\t     * Executes a child process and returns a promise that resolves with its output or rejects with its error.\n\t     */\n\t    static getProcessOutput(command: string, options?: {\n\t        cwd?: string;\n\t        stdio?: any;\n\t        customFds?: any;\n\t        env?: any;\n\t        encoding?: string;\n\t        timeout?: number;\n\t        maxBuffer?: number;\n\t        killSignal?: string;\n\t        noLogCommand?: boolean;\n\t        noLogStdOut?: boolean;\n\t        noLogStdErr?: boolean;\n\t    }): Q.Promise<string>;\n\t    /**\n\t     * Returns the name of the plugin that is being tested.\n\t     */\n\t    static getPluginName(): string;\n\t    /**\n\t     * Replaces a regex in a file with a given string.\n\t     */\n\t    static replaceString(filePath: string, regex: string, replacement: string): void;\n\t    /**\n\t     * Copies a file from a given location to another.\n\t     */\n\t    static copyFile(source: string, destination: string, overwrite: boolean): Q.Promise<void>;\n\t    /**\n\t     * Archives the contents of sourceFolder and puts it in an archive at archivePath in targetFolder.\n\t     */\n\t    static archiveFolder(sourceFolder: string, targetFolder: string, archivePath: string, isDiff: boolean): Q.Promise<string>;\n\t}\n\n}\ndeclare module 'code-push-plugin-testing-framework/script/index' {\n\timport * as Platform from 'code-push-plugin-testing-framework/script/platform';\n\timport * as PluginTestingFramework from 'code-push-plugin-testing-framework/script/test';\n\timport { ProjectManager, setupTestRunScenario, setupUpdateScenario } from 'code-push-plugin-testing-framework/script/projectManager';\n\timport * as ServerUtil from 'code-push-plugin-testing-framework/script/serverUtil';\n\timport { TestBuilder } from 'code-push-plugin-testing-framework/script/testBuilder';\n\timport * as TestConfig from 'code-push-plugin-testing-framework/script/testConfig';\n\timport { TestUtil } from 'code-push-plugin-testing-framework/script/testUtil';\n\texport { Platform, PluginTestingFramework, ProjectManager, setupTestRunScenario, setupUpdateScenario, ServerUtil, TestBuilder, TestConfig, TestUtil };\n\n}\ndeclare module 'code-push-plugin-testing-framework' {\n\timport main = require('code-push-plugin-testing-framework/script/index');\n\texport = main;\n}\n"
  },
  {
    "path": "docs/api-android.md",
    "content": "### Java API Reference (Android)\n\n### API for React Native 0.60 version and above\n\nSince `autolinking` uses `react-native.config.js` to link plugins, constructors are specified in that file. But you can override custom variables to manage the CodePush plugin by placing these values in string resources.\n\n* __Public Key__ - used for bundle verification in the Code Signing Feature. Please refer to [Code Signing](setup-android.md#code-signing-setup) section for more details about the Code Signing Feature.\n    To set the public key, you should add the content of the public key to `strings.xml` with name `CodePushPublicKey`. CodePush automatically gets this property and enables the Code Signing feature. For example:\n    ```xml\n    <string moduleConfig=\"true\" name=\"CodePushPublicKey\">your-public-key</string>\n    ```\n\n* __Server Url__ - used for specifying CodePush Server Url.\n    The Default value: \"https://codepush.appcenter.ms/\" is overridden by adding your path to `strings.xml` with name `CodePushServerUrl`. CodePush automatically gets this property and will use this path to send requests. For example:\n    ```xml\n    <string moduleConfig=\"true\" name=\"CodePushServerUrl\">https://yourcodepush.server.com</string>\n    ```\n\n### API for React Native lower than 0.60\n\nThe Java API is made available by importing the `com.microsoft.codepush.react.CodePush` class into your `MainActivity.java` file, and consists of a single public class named `CodePush`.\n\n#### CodePush\n\nConstructs the CodePush client runtime and represents the `ReactPackage` instance that you add to you app's list of packages.\n\n##### Constructors\n\n- __CodePush(String deploymentKey, Activity mainActivity)__ - Creates a new instance of the CodePush runtime, that will be used to query the service for updates via the provided deployment key. The `mainActivity` parameter should always be set to `this` when configuring your React packages list inside the `MainActivity` class. This constructor puts the CodePush runtime into \"release mode\", so if you want to enable debugging behavior, use the following constructor instead.\n\n- __CodePush(String deploymentKey, Activity mainActivity, bool isDebugMode)__ - Equivalent to the previous constructor but allows you to specify whether you want the CodePush runtime to be in debug mode or not. When using this constructor, the `isDebugMode` parameter should always be set to `BuildConfig.DEBUG` in order to stay synchronized with your build type. When putting CodePush into debug mode, the following behaviors are enabled:\n\n    1. Old CodePush updates aren't deleted from storage whenever a new binary is deployed to the emulator/device. This behavior enables you to deploy new binaries, without bumping the version during development, and without continuously getting the same update every time your app calls `sync`.\n\n    2. The local cache that the React Native runtime maintains in debug mode is deleted whenever a CodePush update is installed. This ensures that when the app is restarted after an update is applied, you will see the expected changes. As soon as [this PR](https://github.com/facebook/react-native/pull/4738) is merged, we won't need to do this anymore.\n\n- __CodePush(String deploymentKey, Context context, boolean isDebugMode, Integer publicKeyResourceDescriptor)__ - Equivalent to the previous constructor, but allows you to specify the public key resource descriptor needed to read public key content. Please refer to [Code Signing](setup-android.md#code-signing-setup) section for more details about the Code Signing Feature.\n\n- __CodePush(String deploymentKey, Context context, boolean isDebugMode, String serverUrl)__ Constructor allows you to specify CodePush Server Url. The Default value: `\"https://codepush.appcenter.ms/\"` is overridden by value specified in `serverUrl`.\n\n##### Builder\n\nAs an alternative to constructors *you can also use `CodePushBuilder`* to setup a CodePush instance configured with *only parameters you want*.\n\n```java\n    @Override\n    protected List<ReactPackage> getPackages() {\n      return Arrays.<ReactPackage>asList(\n            new MainReactPackage(),\n            new CodePushBuilder(\"deployment-key-here\",getApplicationContext())\n                .setIsDebugMode(BuildConfig.DEBUG)\n                .setPublicKeyResourceDescriptor(R.string.publicKey)\n                .setServerUrl(\"https://yourcodepush.server.com\")\n                .build() //return configured CodePush instance\n      );\n    }\n```\n\n`CodePushBuilder` methods:\n\n* __public CodePushBuilder(String deploymentKey, Context context)__ - setup same parameters as via __CodePush(String deploymentKey, Activity mainActivity)__\n\n* __public CodePushBuilder setIsDebugMode(boolean isDebugMode)__ - allows you to specify whether you want the CodePush runtime to be in debug mode or not. Default value: `false`.\n\n* __public CodePushBuilder setServerUrl(String serverUrl)__ - allows you to specify CodePush Server Url. Default value: `\"https://codepush.appcenter.ms/\"`.\n\n* __public CodePushBuilder setPublicKeyResourceDescriptor(int publicKeyResourceDescriptor)__ - allows you to specify Public Key resource descriptor which will be used for reading Public Key content for `strings.xml` file. Please refer to [Code Signing](setup-android.md#code-signing-setup) section for more detailed information about purpose of this parameter.\n\n* __public CodePush build()__ - return configured `CodePush` instance.\n\n##### Public Methods\n\n- __setDeploymentKey(String deploymentKey)__ - Sets the deployment key that the app should use when querying for updates. This is a dynamic alternative to setting the deployment key in Codepush constructor/builder and/or specifying a deployment key in JS when calling `checkForUpdate` or `sync`.\n\n##### Static Methods\n\n- __getBundleUrl()__ - Returns the path to the most recent version of your app's JS bundle file, assuming that the resource name is `index.android.bundle`. If your app is using a different bundle name, then use the overloaded version of this method which allows specifying it. This method has the same resolution behavior as the Objective-C equivalent described above.\n\n- __getBundleUrl(String bundleName)__ - Returns the path to the most recent version of your app's JS bundle file, using the specified resource name (like `index.android.bundle`). This method has the same resolution behavior as the Objective-C equivalent described above.\n\n- __getPackageFolder()__ - Returns the path to the current update folder.\n\n- __overrideAppVersion(String appVersionOverride)__ - Sets the version of the application's binary interface, which would otherwise default to the Play Store version specified as the `versionName` in the `build.gradle`. This should be called a single time, before the CodePush instance is constructed.\n"
  },
  {
    "path": "docs/api-ios.md",
    "content": "### Objective-C API Reference (iOS)\n\nThe Objective-C API is made available by importing the `CodePush.h` header into your `AppDelegate.m` file, and consists of a single public class named `CodePush`.\n\n#### CodePush\n\nContains static methods for retreiving the `NSURL` that represents the most recent JavaScript bundle file, and can be passed to the `RCTRootView`'s `initWithBundleURL` method when bootstrapping your app in the `AppDelegate.m` file.\n\nThe `CodePush` class' methods can be thought of as composite resolvers which always load the appropriate bundle, in order to accommodate the following scenarios:\n\n1. When an end-user installs your app from the store (like `1.0.0`), they will get the JS bundle that is contained within the binary. This is the behavior you would get without using CodePush, but we make sure it doesn't break :)\n\n2. As soon as you begin releasing CodePush updates, your end-users will get the JS bundle that represents the latest release for the configured deployment. This is the behavior that allows you to iterate beyond what you shipped to the store.\n\n3. As soon as you release an update to the app store (like `1.1.0`), and your end-users update it, they will once again get the JS bundle that is contained within the binary. This behavior ensures that CodePush updates that targetted a previous binary version aren't used (since we don't know if they would work), and your end-users always have a working version of your app.\n\n4. Repeat #2 and #3 as the CodePush releases and app store releases continue on into infinity (and beyond?)\n\nBecause of this behavior, you can safely deploy updates to both the app store(s) and CodePush as necesary, and rest assured that your end-users will always get the most recent version.\n\n##### Methods\n\n- __(NSURL \\*)bundleURL__ - Returns the most recent JS bundle `NSURL` as described above. This method assumes that the name of the JS bundle contained within your app binary is `main.jsbundle`.\n\n- __(NSURL \\*)bundleURLForResource:(NSString \\*)resourceName__ - Equivalent to the `bundleURL` method, but also allows customizing the name of the JS bundle that is looked for within the app binary. This is useful if you aren't naming this file `main` (which is the default convention). This method assumes that the JS bundle's extension is `*.jsbundle`.\n\n- __(NSURL \\*)bundleURLForResource:(NSString \\*)resourceName withExtension:(NSString \\*)resourceExtension__: Equivalent to the `bundleURLForResource:` method, but also allows customizing the extension used by the JS bundle that is looked for within the app binary. This is useful if you aren't naming this file `*.jsbundle` (which is the default convention).\n\n- __(void)overrideAppVersion:(NSString \\*)appVersionOverride__ - Sets the version of the application's binary interface, which would otherwise default to the App Store version specified as the `CFBundleShortVersionString` in the `Info.plist`. This should be called a single time, before the bundle URL is loaded.\n\n- __(void)setDeploymentKey:(NSString \\*)deploymentKey__ - Sets the deployment key that the app should use when querying for updates. This is a dynamic alternative to setting the deployment key in your `Info.plist` and/or specifying a deployment key in JS when calling `checkForUpdate` or `sync`.\n"
  },
  {
    "path": "docs/api-js.md",
    "content": "## API Reference\n\nThe CodePush plugin is made up of two components:\n\n1. A JavaScript module, which can be imported/required, and allows the app to interact with the service during runtime (for example check for updates, inspect the metadata about the currently running app update).\n\n2. A native API (Objective-C and Java) which allows the React Native app host to bootstrap itself with the right JS bundle location.\n\nThe following sections describe the shape and behavior of these APIs in detail:\n\n### JavaScript API Reference\n\nWhen you require `react-native-code-push`, the module object provides the following top-level methods in addition to the root-level [component decorator](#codepush):\n\n* [allowRestart](#codepushallowrestart): Re-allows programmatic restarts to occur as a result of an update being installed, and optionally, immediately restarts the app if a pending update had attempted to restart the app while restarts were disallowed. This is an advanced API and is only necessary if your app explicitly disallowed restarts via the `disallowRestart` method.\n\n* [checkForUpdate](#codepushcheckforupdate): Asks the CodePush service whether the configured app deployment has an update available.\n\n* [disallowRestart](#codepushdisallowrestart): Temporarily disallows any programmatic restarts to occur as a result of a CodePush update being installed. This is an advanced API, and is useful when a component within your app (for example an onboarding process) needs to ensure that no end-user interruptions can occur during its lifetime.\n\n* [getCurrentPackage](#codepushgetcurrentpackage): Retrieves the metadata about the currently installed update (like description, installation time, size). *NOTE: As of `v1.10.3-beta` of the CodePush module, this method is deprecated in favor of [`getUpdateMetadata`](#codepushgetupdatemetadata)*.\n\n* [getUpdateMetadata](#codepushgetupdatemetadata): Retrieves the metadata for an installed update (like description, mandatory).\n\n* [notifyAppReady](#codepushnotifyappready): Notifies the CodePush runtime that an installed update is considered successful. If you are manually checking for and installing updates (i.e. not using the [sync](#codepushsync) method to handle it all for you), then this method **MUST** be called; otherwise CodePush will treat the update as failed and rollback to the previous version when the app next restarts.\n\n* [restartApp](#codepushrestartapp): Immediately restarts the app. If there is an update pending, it will be immediately displayed to the end user. Otherwise, calling this method simply has the same behavior as the end user killing and restarting the process.\n\n* [sync](#codepushsync): Allows checking for an update, downloading it and installing it, all with a single call. Unless you need custom UI and/or behavior, we recommend most developers to use this method when integrating CodePush into their apps\n\n* [clearUpdates](#clearupdates): Clear all downloaded CodePush updates. This is useful when switching to a different deployment which may have an older release than the current package. \n   \n    _Note: we don’t recommend to use this method in scenarios other than that (CodePush will call this method automatically when needed in other cases) as it could lead to unpredictable behavior._\n\n#### codePush\n\n```javascript\n// Wrapper function\ncodePush(rootComponent: React.Component): React.Component;\ncodePush(options: CodePushOptions)(rootComponent: React.Component): React.Component;\n```\n```javascript\n// Decorator; Requires ES7 support\n@codePush\n@codePush(options: CodePushOptions)\n```\n\nUsed to wrap a React component inside a \"higher order\" React component that knows how to synchronize your app's JavaScript bundle and image assets when it is mounted. Internally, the higher-order component calls [`sync`](#codepushsync) inside its `componentDidMount` lifecycle handle, which in turns performs an update check, downloads the update if it exists and installs the update for you.\n\nThis decorator provides support for letting you customize its behaviour to easily enable apps with different requirements. Below are some examples of ways you can use it (you can pick one or even use a combination):\n\n1. **Silent sync on app start** *(the simplest, default behavior)*. Your app will automatically download available updates, and apply them the next time the app restarts (like the OS or end user killed it, or the device was restarted). This way, the entire update experience is \"silent\" to the end user, since they don't see any update prompt and/or \"synthetic\" app restarts.\n\n    ```javascript\n    // Fully silent update which keeps the app in\n    // sync with the server, without ever\n    // interrupting the end user\n    class MyApp extends Component<{}> {}\n    MyApp = codePush(MyApp);\n    export default MyApp;\n    ```\n\n2. **Silent sync every time the app resumes**. Same as 1, except we check for updates, or apply an update if one exists every time the app returns to the foreground after being \"backgrounded\".\n\n    ```javascript\n    // Sync for updates every time the app resumes.\n    class MyApp extends Component<{}> {}\n    MyApp = codePush({ checkFrequency: codePush.CheckFrequency.ON_APP_RESUME, installMode: codePush.InstallMode.ON_NEXT_RESUME })(MyApp);\n    export default MyApp;\n    ```\n\n3. **Interactive**. When an update is available, prompt the end user for permission before downloading it, and then immediately apply the update. If an update was released using the `mandatory` flag, the end user would still be notified about the update, but they wouldn't have the choice to ignore it.\n\n    ```javascript\n    // Active update, which lets the end user know\n    // about each update, and displays it to them\n    // immediately after downloading it\n    class MyApp extends Component<{}> {}\n    MyApp = codePush({ updateDialog: true, installMode: codePush.InstallMode.IMMEDIATE })(MyApp);\n    export default MyApp;\n    ```\n\n4. **Log/display progress**. While the app is syncing with the server for updates, make use of the `codePushStatusDidChange` and/or `codePushDownloadDidProgress` event hooks to log down the different stages of this process, or even display a progress bar to the user.\n\n    ```javascript\n    // Make use of the event hooks to keep track of\n    // the different stages of the sync process.\n    class MyApp extends Component<{}> {\n        codePushStatusDidChange(status) {\n            switch(status) {\n                case codePush.SyncStatus.CHECKING_FOR_UPDATE:\n                    console.log(\"Checking for updates.\");\n                    break;\n                case codePush.SyncStatus.DOWNLOADING_PACKAGE:\n                    console.log(\"Downloading package.\");\n                    break;\n                case codePush.SyncStatus.INSTALLING_UPDATE:\n                    console.log(\"Installing update.\");\n                    break;\n                case codePush.SyncStatus.UP_TO_DATE:\n                    console.log(\"Up-to-date.\");\n                    break;\n                case codePush.SyncStatus.UPDATE_INSTALLED:\n                    console.log(\"Update installed.\");\n                    break;\n            }\n        }\n\n        codePushDownloadDidProgress(progress) {\n            console.log(progress.receivedBytes + \" of \" + progress.totalBytes + \" received.\");\n        }\n    }\n    MyApp = codePush(MyApp);\n    export default MyApp;\n    ```\n\n##### CodePushOptions\n\nThe `codePush` decorator accepts an \"options\" object that allows you to customize numerous aspects of the default behavior mentioned above:\n\n* __checkFrequency__ *(codePush.CheckFrequency)* - Specifies when you would like to check for updates. Defaults to `codePush.CheckFrequency.ON_APP_START`. Refer to the [`CheckFrequency`](#checkfrequency) enum reference for a description of the available options and what they do.\n\n* __deploymentKey__ *(String)* - Specifies the deployment key you want to query for an update against. By default, this value is derived from the `Info.plist` file (iOS) and `MainActivity.java` file (Android), but this option allows you to override it from the script-side if you need to dynamically use a different deployment.\n\n* __installMode__ *(codePush.InstallMode)* - Specifies when you would like to install optional updates (i.e. those that aren't marked as mandatory). Defaults to `codePush.InstallMode.ON_NEXT_RESTART`. Refer to the [`InstallMode`](#installmode) enum reference for a description of the available options and what they do.\n\n* __mandatoryInstallMode__ *(codePush.InstallMode)* - Specifies when you would like to install updates which are marked as mandatory. Defaults to `codePush.InstallMode.IMMEDIATE`. Refer to the [`InstallMode`](#installmode) enum reference for a description of the available options and what they do.\n\n* __minimumBackgroundDuration__ *(Number)* - Specifies the minimum number of seconds that the app needs to have been in the background before restarting the app. This property only applies to updates which are installed using `InstallMode.ON_NEXT_RESUME` or `InstallMode.ON_NEXT_SUSPEND`, and can be useful for getting your update in front of end users sooner, without being too obtrusive. Defaults to `0`, which has the effect of applying the update immediately after a resume or unless the app suspension is long enough to not matter, regardless how long it was in the background.\n\n* __updateDialog__ *(UpdateDialogOptions)* - An \"options\" object used to determine whether a confirmation dialog should be displayed to the end user when an update is available, and if so, what strings to use. Defaults to `null`, which has the effect of disabling the dialog completely. Setting this to any truthy value will enable the dialog with the default strings, and passing an object to this parameter allows enabling the dialog as well as overriding one or more of the default strings. Before enabling this option within an App Store-distributed app, please refer to [this note](https://github.com/microsoft/react-native-code-push#app-store).\n\n    The following list represents the available options and their defaults:\n\n    * __appendReleaseDescription__ *(Boolean)* - Indicates whether you would like to append the description of an available release to the notification message which is displayed to the end user. Defaults to `false`.\n\n    * __descriptionPrefix__ *(String)* - Indicates the string you would like to prefix the release description with, if any, when displaying the update notification to the end user. Defaults to `\" Description: \"`\n\n    * __mandatoryContinueButtonLabel__ *(String)* - The text to use for the button the end user must press in order to install a mandatory update. Defaults to `\"Continue\"`.\n\n    * __mandatoryUpdateMessage__ *(String)* - The text used as the body of an update notification, when the update is specified as mandatory. Defaults to `\"An update is available that must be installed.\"`.\n\n    * __optionalIgnoreButtonLabel__ *(String)* - The text to use for the button the end user can press in order to ignore an optional update that is available. Defaults to `\"Ignore\"`.\n\n    * __optionalInstallButtonLabel__ *(String)* - The text to use for the button the end user can press in order to install an optional update. Defaults to `\"Install\"`.\n\n    * __optionalUpdateMessage__ *(String)* - The text used as the body of an update notification, when the update is optional. Defaults to `\"An update is available. Would you like to install it?\"`.\n\n    * __title__ *(String)* - The text used as the header of an update notification that is displayed to the end user. Defaults to `\"Update available\"`.\n\n* __rollbackRetryOptions__ *(RollbackRetryOptions)* - The rollback retry mechanism allows the application to attempt to reinstall an update that was previously rolled back (with the restrictions specified in the options). It is an \"options\" object used to determine whether a rollback retry should occur, and if so, what settings to use for the rollback retry. This defaults to null, which has the effect of disabling the retry mechanism. Setting this to any truthy value will enable the retry mechanism with the default settings, and passing an object to this parameter allows enabling the rollback retry as well as overriding one or more of the default values.\n\n    The following list represents the available options and their defaults:\n\n    * __delayInHours__ *(Number)* - Specifies the minimum time in hours that the app will wait after the latest rollback before attempting to reinstall the same rolled-back package. Defaults to `24`.\n\n    * __maxRetryAttempts__ *(Number)* - Specifies the maximum number of retry attempts that the app can make before it stops trying. Cannot be less than `1`. Defaults to `1`.\n\n##### codePushStatusDidChange (event hook)\n\nCalled when the sync process moves from one stage to another in the overall update process. The event hook is called with a status code which represents the current state, and can be any of the [`SyncStatus`](#syncstatus) values.\n\n##### codePushDownloadDidProgress (event hook)\n\nCalled periodically when an available update is being downloaded from the CodePush server. The method is called with a `DownloadProgress` object, which contains the following two properties:\n\n* __totalBytes__ *(Number)* - The total number of bytes expected to be received for this update (i.e. the size of the set of files which changed from the previous release).\n\n* __receivedBytes__ *(Number)* - The number of bytes downloaded thus far, which can be used to track download progress.\n\n#### codePush.allowRestart\n\n```javascript\ncodePush.allowRestart(): void;\n```\n\nRe-allows programmatic restarts to occur, that would have otherwise been rejected due to a previous call to `disallowRestart`. If `disallowRestart` was never called in the first place, then calling this method will simply result in a no-op.\n\nIf a CodePush update is currently pending, which attempted to restart the app (for example it used `InstallMode.IMMEDIATE`), but was blocked due to `disallowRestart` having been called, then calling `allowRestart` will result in an immediate restart. This allows the update to be applied as soon as possible, without interrupting the end user during critical workflows (for example an onboarding process).\n\nFor example, calling `allowRestart` would trigger an immediate restart if either of the three scenarios mentioned in the [`disallowRestart` docs](#codepushdisallowrestart) occured after `disallowRestart` was called. However, calling `allowRestart` wouldn't trigger a restart if the following were true:\n\n1. No CodePush updates were installed since the last time `disallowRestart` was called, and therefore, there isn't any need to restart anyways.\n\n2. There is currently a pending CodePush update, but it was installed via `InstallMode.ON_NEXT_RESTART`, and therefore, doesn't require a programmatic restart.\n\n3. There is currently a pending CodePush update, but it was installed via `InstallMode.ON_NEXT_RESUME` and the app hasn't been put into the background yet, and therefore, there isn't a need to programmatically restart yet.\n\n4. No calls to `restartApp` were made since the last time `disallowRestart` was called.\n\nThis behavior ensures that no restarts will be triggered as a result of calling `allowRestart` unless one was explictly requested during the disallowed period. In this way, `allowRestart` is somewhat similar to calling `restartApp(true)`, except the former will only trigger a restart if the currently pending update wanted to restart, whereas the later would restart as long as an update is pending.\n\nSee [disallowRestart](#codepushdisallowrestart) for an example of how this method can be used.\n\n#### codePush.checkForUpdate\n\n```javascript\ncodePush.checkForUpdate(deploymentKey: String = null, handleBinaryVersionMismatchCallback: (update: RemotePackage) => void): Promise<RemotePackage>;\n```\n\nQueries the CodePush service to see whether the configured app deployment has an update available. By default, it will use the deployment key that is configured in your `Info.plist` file (iOS), or `MainActivity.java` file (Android), but you can override that by specifying a value via the optional `deploymentKey` parameter. This can be useful when you want to dynamically \"redirect\" a user to a specific deployment, such as allowing \"early access\" via an easter egg or a user setting switch.\n\nSecond optional parameter `handleBinaryVersionMismatchCallback` is an optional callback function that can be used to notify user if there are any binary update.\nE.g. consider a use-case where currently installed binary version is 1.0.1 with label(codepush label) v1. Later native code was changed in the dev cycle and binary version was updated to 1.0.2. When code-push update check is triggered we ignore updates having binary version mismatch (because the update is not targeting to the binary version of currently installed app). In this case installed app (1.0.1) will ignore the update targeting version 1.0.2. You can use `handleBinaryVersionMismatchCallback` to provide a hook to handle such situations.\n\n**NOTE:**\nBe cautious to use Alerts within this callback if you are developing iOS application, due to [App Store](https://developer.apple.com/app-store/review/guidelines/) review process: \n> Apps must not force users to rate the app, review the app, download other apps, or other similar actions in order to access functionality, content, or use of the app.\n\nThis method returns a `Promise` which resolves to one of two possible values:\n\n1. `null` if there is no update available. This can occur in the following scenarios:\n\n    1. The configured deployment doesn't contain any releases, and therefore, nothing to update.\n    2. The latest release within the configured deployment is targeting a different binary version than what you're currently running (either older or newer).\n    3. The currently running app already has the latest release from the configured deployment, and therefore, doesn't need it again.\n    4. The latest release within the configured deployment is currently marked as disabled, and therefore, isn't allowed to be downloaded.\n    5. The latest release within the configured deployment is in an \"active rollout\" state, and the requesting device doesn't fall within the percentage of users who are eligible for it.\n\n2. A [`RemotePackage`](#remotepackage) instance which represents an available update that can be inspected and/or subsequently downloaded.\n\nExample Usage:\n\n```javascript\ncodePush.checkForUpdate()\n.then((update) => {\n    if (!update) {\n        console.log(\"The app is up to date!\");\n    } else {\n        console.log(\"An update is available! Should we download it?\");\n    }\n});\n```\n\n#### codePush.disallowRestart\n\n```javascript\ncodePush.disallowRestart(): void;\n```\n\nTemporarily disallows programmatic restarts to occur as a result of either of following scenarios:\n\n1. A CodePush update is installed using `InstallMode.IMMEDIATE`\n2. A CodePush update is installed using `InstallMode.ON_NEXT_RESUME` and the app is resumed from the background (optionally being throttled by the `minimumBackgroundDuration` property)\n3. The `restartApp` method was called\n\n*NOTE: #1 and #2 effectively work by calling `restartApp` for you, so you can think of `disallowRestart` as blocking any call to `restartApp`, regardless if your app calls it directly or indirectly.*\n\nAfter calling this method, any calls to `sync` would still be allowed to check for an update, download it and install it, but an attempt to restart the app would be queued until `allowRestart` is called. This way, the restart request is captured and can be \"flushed\" whenever you want to allow it to occur.\n\nThis is an advanced API, and is primarily useful when individual components within your app (like an onboarding process) need to ensure that no end-user interruptions can occur during their lifetime, while continuing to allow the app to keep syncing with the CodePush server at its own pace and using whatever install modes are appropriate. This has the benefit of allowing the app to discover and download available updates as soon as possible, while also preventing any disruptions during key end-user experiences.\n\nAs an alternative, you could also choose to simply use `InstallMode.ON_NEXT_RESTART` whenever calling `sync` (which will never attempt to programmatically restart the app), and then explicity calling `restartApp` at points in your app that you know it is \"safe\" to do so. `disallowRestart` provides an alternative approach to this when the code that synchronizes with the CodePush server is separate from the code/components that want to enforce a no-restart policy.\n\nExample Usage:\n\n```javascript\nclass OnboardingProcess extends Component {\n    ...\n\n    componentWillMount() {\n        // Ensure that any CodePush updates which are\n        // synchronized in the background can't trigger\n        // a restart while this component is mounted.\n        codePush.disallowRestart();\n    }\n\n    componentWillUnmount() {\n        // Reallow restarts, and optionally trigger\n        // a restart if one was currently pending.\n        codePush.allowRestart();\n    }\n\n    ...\n}\n```\n\n#### codePush.getCurrentPackage\n\n*NOTE: This method is considered deprecated as of `v1.10.3-beta` of the CodePush module. If you're running this version (or newer), we would recommend using the [`codePush.getUpdateMetadata`](#codepushgetupdatemetadata) instead, since it has more predictable behavior.*\n\n```javascript\ncodePush.getCurrentPackage(): Promise<LocalPackage>;\n```\n\nRetrieves the metadata about the currently installed \"package\" (like description, installation time). This can be useful for scenarios such as displaying a \"what's new?\" dialog after an update has been applied or checking whether there is a pending update that is waiting to be applied via a resume or restart.\n\nThis method returns a `Promise` which resolves to one of two possible values:\n\n1. `null` if the app is currently running the JS bundle from the binary and not a CodePush update. This occurs in the following scenarios:\n\n    1. The end-user installed the app binary and has yet to install a CodePush update\n    1. The end-user installed an update of the binary (for example from the store), which cleared away the old CodePush updates, and gave precedence back to the JS binary in the binary.\n\n2. A [`LocalPackage`](#localpackage) instance which represents the metadata for the currently running CodePush update.\n\nExample Usage:\n\n```javascript\ncodePush.getCurrentPackage()\n.then((update) => {\n    // If the current app \"session\" represents the first time\n    // this update has run, and it had a description provided\n    // with it upon release, let's show it to the end user\n    if (update.isFirstRun && update.description) {\n        // Display a \"what's new?\" modal\n    }\n});\n```\n\n#### codePush.getUpdateMetadata\n\n```javascript\ncodePush.getUpdateMetadata(updateState: UpdateState = UpdateState.RUNNING): Promise<LocalPackage>;\n```\n\nRetrieves the metadata for an installed update (for example description, mandatory) whose state matches the specified `updateState` parameter. This can be useful for scenarios such as displaying a \"what's new?\" dialog after an update has been applied or checking whether there is a pending update that is waiting to be applied via a resume or restart. For more details about the possible update states, and what they represent, refer to the [UpdateState reference](#updatestate).\n\nThis method returns a `Promise` which resolves to one of two possible values:\n\n1. `null` if an update with the specified state doesn't currently exist. This occurs in the following scenarios:\n\n    1. The end-user hasn't installed any CodePush updates yet, and therefore, no metadata is available for any updates, regardless what you specify as the `updateState` parameter.\n\n    2. The end-user installed an update of the binary (for example from the store), which cleared away the old CodePush updates, and gave precedence back to the JS binary in the binary. Therefore, it would exhibit the same behavior as #1\n\n    3. The `updateState` parameter is set to `UpdateState.RUNNING`, but the app isn't currently running a CodePush update. There may be a pending update, but the app hasn't been restarted yet in order to make it active.\n\n    4. The `updateState` parameter is set to `UpdateState.PENDING`, but the app doesn't have any currently pending updates.\n\n2. A [`LocalPackage`](#localpackage) instance which represents the metadata for the currently requested CodePush update (either the running or pending).\n\nExample Usage:\n\n```javascript\n// Check if there is currently a CodePush update running, and if\n// so, register it with the HockeyApp SDK (https://github.com/slowpath/react-native-hockeyapp)\n// so that crash reports will correctly display the JS bundle version the user was running.\ncodePush.getUpdateMetadata().then((update) => {\n    if (update) {\n        hockeyApp.addMetadata({ CodePushRelease: update.label });\n    }\n});\n\n// Check to see if there is still an update pending.\ncodePush.getUpdateMetadata(UpdateState.PENDING).then((update) => {\n    if (update) {\n        // There's a pending update, do we want to force a restart?\n    }\n});\n```\n\n#### codePush.notifyAppReady\n\n```javascript\ncodePush.notifyAppReady(): Promise<void>;\n```\n\nNotifies the CodePush runtime that a freshly installed update should be considered successful, and therefore, an automatic client-side rollback isn't necessary. It is mandatory to call this function somewhere in the code of the updated bundle. Otherwise, when the app next restarts, the CodePush runtime will assume that the installed update has failed and roll back to the previous version. This behavior exists to help ensure that your end users aren't blocked by a broken update.\n\nIf you are using the `sync` function, and doing your update check on app start, then you don't need to manually call `notifyAppReady` since `sync` will call it for you. This behavior exists due to the assumption that the point at which `sync` is called in your app represents a good approximation of a successful startup.\n\n*NOTE: This method is also aliased as `notifyApplicationReady` (for backwards compatibility).*\n\n#### codePush.restartApp\n\n```javascript\ncodePush.restartApp(onlyIfUpdateIsPending: Boolean = false): void;\n```\n\nImmediately restarts the app. If a truthy value is provided to the `onlyIfUpdateIsPending` parameter, then the app will only restart if there is actually a pending update waiting to be applied.\n\nThis method is for advanced scenarios, and is primarily useful when the following conditions are true:\n\n1. Your app is specifying an install mode value of `ON_NEXT_RESTART` or `ON_NEXT_RESUME` when calling the `sync` or `LocalPackage.install` methods. This has the effect of not applying your update until the app has been restarted (by either the end user or OS)\tor resumed, and therefore, the update won't be immediately displayed to the end user.\n\n2. You have an app-specific user event (like the end user navigated back to the app's home route) that allows you to apply the update in an unobtrusive way, and potentially gets the update in front of the end user sooner then waiting until the next restart or resume.\n\n#### codePush.sync\n\n```javascript\ncodePush.sync(options: Object, syncStatusChangeCallback: function(syncStatus: Number), downloadProgressCallback: function(progress: DownloadProgress), handleBinaryVersionMismatchCallback: function(update: RemotePackage)): Promise<Number>;\n```\n\nSynchronizes your app's JavaScript bundle and image assets with the latest release to the configured deployment. Unlike the [checkForUpdate](#codepushcheckforupdate) method, which simply checks for the presence of an update, and let's you control what to do next, `sync` handles the update check, download and installation experience for you.\n\nThis method provides support for two different (but customizable) \"modes\" to easily enable apps with different requirements:\n\n1. **Silent mode** *(the default behavior)*, which automatically downloads available updates, and applies them the next time the app restarts (for example the OS or end user killed it, or the device was restarted). This way, the entire update experience is \"silent\" to the end user, since they don't see any update prompt and/or \"synthetic\" app restarts.\n\n2. **Active mode**, which when an update is available, prompts the end user for permission before downloading it, and then immediately applies the update. If an update was released using the `mandatory` flag, the end user would still be notified about the update, but they wouldn't have the choice to ignore it.\n\nExample Usage:\n\n```javascript\n// Fully silent update which keeps the app in\n// sync with the server, without ever\n// interrupting the end user\ncodePush.sync();\n\n// Active update, which lets the end user know\n// about each update, and displays it to them\n// immediately after downloading it\ncodePush.sync({ updateDialog: true, installMode: codePush.InstallMode.IMMEDIATE });\n```\n\n*Note: If you want to decide whether you check and/or download an available update based on the end user's device battery level, network conditions, etc. then simply wrap the call to `sync` in a condition that ensures you only call it when desired.*\n\n##### SyncOptions\n\nWhile the `sync` method tries to make it easy to perform silent and active updates with little configuration, it accepts an \"options\" object that allows you to customize numerous aspects of the default behavior mentioned above. The options available are identical to the [CodePushOptions](#codepushoptions), with the exception of the `checkFrequency` option:\n\n* __deploymentKey__ *(String)* - Refer to [`CodePushOptions`](#codepushoptions).\n\n* __installMode__ *(codePush.InstallMode)* - Refer to [`CodePushOptions`](#codepushoptions).\n\n* __mandatoryInstallMode__ *(codePush.InstallMode)* - Refer to [`CodePushOptions`](#codepushoptions).\n\n* __minimumBackgroundDuration__ *(Number)* - Refer to [`CodePushOptions`](#codepushoptions).\n\n* __updateDialog__ *(UpdateDialogOptions)* - Refer to [`CodePushOptions`](#codepushoptions).\n\nExample Usage:\n\n```javascript\n// Use a different deployment key for this\n// specific call, instead of the one configured\n// in the Info.plist file\ncodePush.sync({ deploymentKey: \"KEY\" });\n\n// Download the update silently, but install it on\n// the next resume, as long as at least 5 minutes\n// has passed since the app was put into the background.\ncodePush.sync({ installMode: codePush.InstallMode.ON_NEXT_RESUME, minimumBackgroundDuration: 60 * 5 });\n\n// Download the update silently, and install optional updates\n// on the next restart, but install mandatory updates on the next resume.\ncodePush.sync({ mandatoryInstallMode: codePush.InstallMode.ON_NEXT_RESUME });\n\n// Changing the title displayed in the\n// confirmation dialog of an \"active\" update\ncodePush.sync({ updateDialog: { title: \"An update is available!\" } });\n\n// Displaying an update prompt which includes the\n// description associated with the CodePush release\ncodePush.sync({\n   updateDialog: {\n    appendReleaseDescription: true,\n    descriptionPrefix: \"\\n\\nChange log:\\n\"\n   },\n   installMode: codePush.InstallMode.IMMEDIATE\n});\n```\n\nIn addition to the options, the `sync` method also accepts several optional function parameters which allow you to subscribe to the lifecycle of the `sync` \"pipeline\" in order to display additional UI as needed (like a \"checking for update modal or a download progress modal):\n\n* __syncStatusChangedCallback__ *((syncStatus: Number) => void)* - Called when the sync process moves from one stage to another in the overall update process. The method is called with a status code which represents the current state, and can be any of the [`SyncStatus`](#syncstatus) values.\n\n* __downloadProgressCallback__ *((progress: DownloadProgress) => void)* - Called periodically when an available update is being downloaded from the CodePush server. The method is called with a `DownloadProgress` object, which contains the following two properties:\n\n    * __totalBytes__ *(Number)* - The total number of bytes expected to be received for this update (i.e. the size of the set of files which changed from the previous release).\n\n    * __receivedBytes__ *(Number)* - The number of bytes downloaded thus far, which can be used to track download progress.\n\n* __handleBinaryVersionMismatchCallback__ *((update: RemotePackage) => void)* - \nCalled when there are any binary update available. The method is called with a [`RemotePackage`](#remotepackage) object. Refer to [codePush.checkForUpdate](#codepushcheckforupdate) section for more details.\n\nExample Usage:\n\n```javascript\n// Prompt the user when an update is available\n// and then display a \"downloading\" modal\ncodePush.sync({ updateDialog: true },\n  (status) => {\n      switch (status) {\n          case codePush.SyncStatus.DOWNLOADING_PACKAGE:\n              // Show \"downloading\" modal\n              break;\n          case codePush.SyncStatus.INSTALLING_UPDATE:\n              // Hide \"downloading\" modal\n              break;\n      }\n  },\n  ({ receivedBytes, totalBytes, }) => {\n    /* Update download modal progress */\n  }\n);\n```\n\nThis method returns a `Promise` which is resolved to a `SyncStatus` code that indicates why the `sync` call succeeded. This code can be one of the following `SyncStatus` values:\n\n* __codePush.SyncStatus.UP_TO_DATE__ *(0)* - The app is up-to-date with the CodePush server.\n\n* __codePush.SyncStatus.UPDATE_IGNORED__ *(2)* - The app had an optional update which the end user chose to ignore. (This is only applicable when the `updateDialog` is used)\n\n* __codePush.SyncStatus.UPDATE_INSTALLED__ *(1)* - The update has been installed and will be run either immediately after the `syncStatusChangedCallback` function returns or the next time the app resumes/restarts, depending on the `InstallMode` specified in `SyncOptions`.\n\n* __codePush.SyncStatus.SYNC_IN_PROGRESS__ *(4)* - There is an ongoing `sync` operation running which prevents the current call from being executed.\n\nThe `sync` method can be called anywhere you'd like to check for an update. That could be in the `componentWillMount` lifecycle event of your root component, the onPress handler of a `<TouchableHighlight>` component, in the callback of a periodic timer, or whatever else makes sense for your needs. Just like the `checkForUpdate` method, it will perform the network request to check for an update in the background, so it won't impact your UI thread and/or JavaScript thread's responsiveness.\n\n#### Package objects\n\nThe `checkForUpdate` and `getUpdateMetadata` methods return `Promise` objects, that when resolved, provide acces to \"package\" objects. The package represents your code update as well as any extra metadata (like description, mandatory?). The CodePush API has the distinction between the following types of packages:\n\n* [LocalPackage](#localpackage): Represents a downloaded update that is either already running, or has been installed and is pending an app restart.\n\n* [RemotePackage](#remotepackage): Represents an available update on the CodePush server that hasn't been downloaded yet.\n\n##### LocalPackage\n\nContains details about an update that has been downloaded locally or already installed. You can get a reference to an instance of this object either by calling the module-level `getUpdateMetadata` method, or as the value of the promise returned by the `RemotePackage.download` method.\n\n###### Properties\n- __appVersion__: The app binary version that this update is dependent on. This is the value that was specified via the `appStoreVersion` parameter when calling the CLI's `release` command. *(String)*\n- __deploymentKey__: The deployment key that was used to originally download this update. *(String)*\n- __description__: The description of the update. This is the same value that you specified in the CLI when you released the update. *(String)*\n- __failedInstall__: Indicates whether this update has been previously installed but was rolled back. The `sync` method will automatically ignore updates which have previously failed, so you only need to worry about this property if using `checkForUpdate`. *(Boolean)*\n- __isFirstRun__: Indicates whether this is the first time the update has been run after being installed. This is useful for determining whether you would like to show a \"What's New?\" UI to the end user after installing an update. *(Boolean)*\n- __isMandatory__: Indicates whether the update is considered mandatory.  This is the value that was specified in the CLI when the update was released. *(Boolean)*\n- __isPending__: Indicates whether this update is in a \"pending\" state. When `true`, that means the update has been downloaded and installed, but the app restart needed to apply it hasn't occurred yet, and therefore, it's changes aren't currently visible to the end-user. *(Boolean)*\n- __label__: The internal label automatically given to the update by the CodePush server, such as `v5`. This value uniquely identifies the update within it's deployment. *(String)*\n- __packageHash__: The SHA hash value of the update. *(String)*\n- __packageSize__: The size of the code contained within the update, in bytes. *(Number)*\n\n###### Methods\n\n- __install(installMode: codePush.InstallMode = codePush.InstallMode.ON_NEXT_RESTART, minimumBackgroundDuration = 0): Promise&lt;void&gt;__: Installs the update by saving it to the location on disk where the runtime expects to find the latest version of the app. The `installMode` parameter controls when the changes are actually presented to the end user. The default value is to wait until the next app restart to display the changes, but you can refer to the [`InstallMode`](#installmode) enum reference for a description of the available options and what they do. If the `installMode` parameter is set to `InstallMode.ON_NEXT_RESUME`, then the `minimumBackgroundDuration` parameter allows you to control how long the app must have been in the background before forcing the install after it is resumed.\n\n##### RemotePackage\n\nContains details about an update that is available for download from the CodePush server. You get a reference to an instance of this object by calling the `checkForUpdate` method when an update is available. If you are using the `sync` API, you don't need to worry about the `RemotePackage`, since it will handle the download and installation process automatically for you.\n\n###### Properties\n\nThe `RemotePackage` inherits all of the same properties as the `LocalPackage`, but includes one additional one:\n\n- __downloadUrl__: The URL at which the package is available for download. This property is only needed for advanced usage, since the `download` method will automatically handle the acquisition of updates for you. *(String)*\n\n###### Methods\n\n- __download(downloadProgressCallback?: Function): Promise&lt;LocalPackage&gt;__: Downloads the available update from the CodePush service. If a `downloadProgressCallback` is specified, it will be called periodically with a `DownloadProgress` object (`{ totalBytes: Number, receivedBytes: Number }`) that reports the progress of the download until it completes. Returns a Promise that resolves with the `LocalPackage`.\n\n#### Enums\n\nThe CodePush API includes the following enums which can be used to customize the update experience:\n\n##### InstallMode\n\nThis enum specifies when you would like an installed update to actually be applied, and can be passed to either the `sync` or `LocalPackage.install` methods. It includes the following values:\n\n* __codePush.InstallMode.IMMEDIATE__ *(0)* - Indicates that you want to install the update and restart the app immediately. This value is appropriate for debugging scenarios as well as when displaying an update prompt to the user, since they would expect to see the changes immediately after accepting the installation. Additionally, this mode can be used to enforce mandatory updates, since it removes the potentially undesired latency between the update installation and the next time the end user restarts or resumes the app.\n\n* __codePush.InstallMode.ON_NEXT_RESTART__ *(1)* - Indicates that you want to install the update, but not forcibly restart the app. When the app is \"naturally\" restarted (due the OS or end user killing it), the update will be seamlessly picked up. This value is appropriate when performing silent updates, since it would likely be disruptive to the end user if the app suddenly restarted out of nowhere, since they wouldn't have realized an update was even downloaded. This is the default mode used for both the `sync` and `LocalPackage.install` methods.\n\n* __codePush.InstallMode.ON_NEXT_RESUME__ *(2)* - Indicates that you want to install the update, but don't want to restart the app until the next time the end user resumes it from the background. This way, you don't disrupt their current session, but you can get the update in front of them sooner then having to wait for the next natural restart. This value is appropriate for silent installs that can be applied on resume in a non-invasive way.\n\n* __codePush.InstallMode.ON_NEXT_SUSPEND__ *(3)* - Indicates that you want to install the update _while_ it is in the background, but only after it has been in the background for `minimumBackgroundDuration` seconds (0 by default), so that user context isn't lost unless the app suspension is long enough to not matter.\n\n##### CheckFrequency\n\nThis enum specifies when you would like your app to sync with the server for updates, and can be passed to the `codePushify` decorator. It includes the following values:\n\n* __codePush.CheckFrequency.ON_APP_START__ *(0)* - Indicates that you want to check for updates whenever the app's process is started.\n\n* __codePush.CheckFrequency.ON_APP_RESUME__ *(1)* - Indicates that you want to check for updates whenever the app is brought back to the foreground after being \"backgrounded\" (user pressed the home button, app launches a seperate payment process, etc).\n\n* __codePush.CheckFrequency.MANUAL__ *(2)* - Disable automatic checking for updates, but only check when [`codePush.sync()`](#codepushsync) is called in app code.\n\n##### SyncStatus\n\nThis enum is provided to the `syncStatusChangedCallback` function that can be passed to the `sync` method, in order to hook into the overall update process. It includes the following values:\n\n* __codePush.SyncStatus.UP_TO_DATE__ *(0)* - The app is fully up-to-date with the configured deployment.\n* __codePush.SyncStatus.UPDATE_INSTALLED__ *(1)* - An available update has been installed and will be run either immediately after the `syncStatusChangedCallback` function returns or the next time the app resumes/restarts, depending on the `InstallMode` specified in `SyncOptions`.\n* __codePush.SyncStatus.UPDATE_IGNORED__ *(2)* - The app has an optional update, which the end user chose to ignore. (This is only applicable when the `updateDialog` is used)\n* __codePush.SyncStatus.UNKNOWN_ERROR__ *(3)* - The sync operation encountered an unknown error.\n* __codePush.SyncStatus.SYNC_IN_PROGRESS__ *(4)* - There is an ongoing `sync` operation running which prevents the current call from being executed.\n* __codePush.SyncStatus.CHECKING_FOR_UPDATE__ *(5)* - The CodePush server is being queried for an update.\n* __codePush.SyncStatus.AWAITING_USER_ACTION__ *(6)* - An update is available, and a confirmation dialog was shown to the end user. (This is only applicable when the `updateDialog` is used)\n* __codePush.SyncStatus.DOWNLOADING_PACKAGE__ *(7)* - An available update is being downloaded from the CodePush server.\n* __codePush.SyncStatus.INSTALLING_UPDATE__ *(8)* - An available update was downloaded and is about to be installed.\n\n##### UpdateState\n\nThis enum specifies the state that an update is currently in, and can be specified when calling the `getUpdateMetadata` method. It includes the following values:\n\n* __codePush.UpdateState.RUNNING__ *(0)* - Indicates that an update represents the version of the app that is currently running. This can be useful for identifying attributes about the app, for scenarios such as displaying the release description in a \"what's new?\" dialog or reporting the latest version to an analytics and/or crash reporting service.\n\n* __codePush.UpdateState.PENDING__ *(1)* - Indicates than an update has been installed, but the app hasn't been restarted yet in order to apply it. This can be useful for determining whether there is a pending update, which you may want to force a programmatic restart (via `restartApp`) in order to apply.\n\n* __codePush.UpdateState.LATEST__ *(2)* - Indicates than an update represents the latest available release, and can be either currently running or pending.\n"
  },
  {
    "path": "docs/multi-deployment-testing-android.md",
    "content": "### Android\n\n> NOTE\n>\n> Complete demo configured with \"multi-deployment testing\" feature is [here](https://github.com/microsoft/react-native-code-push/files/1314118/rncp1004.zip).\n\nThe [Android Gradle plugin](https://google.github.io/android-gradle-dsl/current/index.html) allows you to define custom config settings for each \"build type\" (like debug, release). This mechanism allows you to easily configure your debug builds to use your CodePush staging deployment key and your release builds to use your CodePush production deployment key.\n\n*NOTE: As a reminder, you can retrieve these keys by running `appcenter codepush deployment list -a <ownerName>/<appName> -k` from your terminal.*\n\nTo set this up, perform the following steps:\n\n**For React Native >= v0.60**\n\n1. Open the project's app level `build.gradle` file (for example `android/app/build.gradle` in standard React Native projects)\n\n2. Find the `android { buildTypes {} }` section and define `resValue` entries for both your `debug` and `release` build types, which reference your `Staging` and `Production` deployment keys respectively.\n\n    ```groovy\n    android {\n        ...\n        buildTypes {\n            debug {\n                ...\n                // Note: CodePush updates should not be tested in Debug mode as they are overriden by the RN packager. However, because CodePush checks for updates in all modes, we must supply a key.\n                resValue \"string\", \"CodePushDeploymentKey\", '\"\"'\n                ...\n            }\n\n            releaseStaging {\n                ...\n                resValue \"string\", \"CodePushDeploymentKey\", '\"<INSERT_STAGING_KEY>\"'\n\n                // Note: It is a good idea to provide matchingFallbacks for the new buildType you create to prevent build issues\n                // Add the following line if not already there\n                matchingFallbacks = ['release']\n                ...\n            }\n\n            release {\n                ...\n                resValue \"string\", \"CodePushDeploymentKey\", '\"<INSERT_PRODUCTION_KEY>\"'\n                ...\n            }\n        }\n        ...\n    }\n    ```\n    \n    *NOTE: Remember to remove the key from `strings.xml` if you are configuring the deployment key in the build process*\n\n    *NOTE: The naming convention for `releaseStaging` is significant due to [this line](https://github.com/facebook/react-native/blob/e083f9a139b3f8c5552528f8f8018529ef3193b9/react.gradle#L79).*\n\n**For React Native v0.29 - v0.59**\n\n1. Open up your `MainApplication.java` file and make the following changes:\n\n    ```java\n    @Override\n    protected List<ReactPackage> getPackages() {\n         return Arrays.<ReactPackage>asList(\n             ...\n             new CodePush(BuildConfig.CODEPUSH_KEY, MainApplication.this, BuildConfig.DEBUG), // Add/change this line.\n             ...\n         );\n    }\n    ```\n\n2. Open your app's `build.gradle` file (for example `android/app/build.gradle` in standard React Native projects)\n\n3. Find the `android { buildTypes {} }` section and define `buildConfigField` entries for both your `debug` and `release` build types, which reference your `Staging` and `Production` deployment keys respectively. If you prefer, you can define the key literals in your `gradle.properties` file, and then reference them here. Either way will work, and it's just a matter of personal preference.\n\n    ```groovy\n    android {\n        ...\n        buildTypes {\n            debug {\n                ...\n                // Note: CodePush updates should not be tested in Debug mode as they are overriden by the RN packager. However, because CodePush checks for updates in all modes, we must supply a key.\n                buildConfigField \"String\", \"CODEPUSH_KEY\", '\"\"'\n                ...\n            }\n\n            releaseStaging {\n                ...\n                buildConfigField \"String\", \"CODEPUSH_KEY\", '\"<INSERT_STAGING_KEY>\"'\n                // Note: It is a good idea to provide matchingFallbacks for the new buildType you create to prevent build issues\n                // Add the following line if not already there\n                matchingFallbacks = ['release']\n                ...\n            }\n\n            release {\n                ...\n                buildConfigField \"String\", \"CODEPUSH_KEY\", '\"<INSERT_PRODUCTION_KEY>\"'\n                ...\n            }\n        }\n        ...\n    }\n    ```\n\n    *NOTE: The naming convention for `releaseStaging` is significant due to [this line](https://github.com/facebook/react-native/blob/e083f9a139b3f8c5552528f8f8018529ef3193b9/react.gradle#L79).*\n\n4. Pass the deployment key to the `CodePush` constructor via the build config you defined, as opposed to a string literal.\n\n**For React Native v0.19 - v0.28**\n\nOpen up your `MainActivity.java` file and make the following changes:\n\n ```java\n @Override\n protected List<ReactPackage> getPackages() {\n     return Arrays.<ReactPackage>asList(\n         ...\n         new CodePush(BuildConfig.CODEPUSH_KEY, this, BuildConfig.DEBUG), // Add/change this line.\n         ...\n     );\n }\n ```\n\n*Note: If you gave your build setting a different name in your Gradle file, simply make sure to reflect that in your Java code.*\n\nAnd that's it! Now when you run or build your app, your debug builds will automatically be configured to sync with your `Staging` deployment, and your release builds will be configured to sync with your `Production` deployment.\n\n*NOTE: By default, the `react-native run-android` command builds and deploys the debug version of your app, so if you want to test out a release/production build, simply run `react-native run-android --variant release. Refer to the [React Native docs](http://facebook.github.io/react-native/docs/signed-apk-android.html#conten) for details about how to configure and create release builds for your Android apps.*\n\nIf you want to be able to install both debug and release builds simultaneously on the same device (highly recommended!), then you need to ensure that your debug build has a unique identity and icon from your release build. Otherwise, neither the OS nor you will be able to differentiate between the two. You can achieve this by performing the following steps:\n\n1. In your `build.gradle` file, specify the [`applicationIdSuffix`](http://google.github.io/android-gradle-dsl/current/com.android.build.gradle.internal.dsl.BuildType.html#com.android.build.gradle.internal.dsl.BuildType:applicationIdSuffix) field for your debug build type, which gives your debug build a unique identity for the OS (like `com.foo` vs. `com.foo.debug`).\n\n```groovy\nbuildTypes {\n    debug {\n        applicationIdSuffix \".debug\"\n    }\n}\n```\n\n2. Create the `app/src/debug/res` directory structure in your app, which allows overriding resources (like strings, icons, layouts) for your debug builds\n\n3. Create a `values` directory underneath the debug res directory created in #2, and copy the existing `strings.xml` file from the `app/src/main/res/values` directory\n\n4. Open up the new debug `strings.xml` file and change the `<string name=\"app_name\">` element's value to something else (like `foo-debug`). This ensures that your debug build now has a distinct display name, so that you can differentiate it from your release build.\n\n5. Optionally, create \"mirrored\" directories in the `app/src/debug/res` directory for all of your app's icons that you want to change for your debug build. This part isn't technically critical, but it can make it easier to quickly spot your debug builds on a device if its icon is noticeable different.\n\nAnd that's it! View [here](http://tools.android.com/tech-docs/new-build-system/resource-merging) for more details on how resource merging works in Android.\n"
  },
  {
    "path": "docs/multi-deployment-testing-ios.md",
    "content": "### iOS\n\n> NOTE\n>\n> Complete demos configured with \"multi-deployment testing\" feature are [here]:\n> *  **without using cocoa pods**: [link](https://github.com/microsoft/react-native-code-push/files/1259957/rncp976.copy.zip)\n> *  **using cocoa pods**: [link](https://github.com/microsoft/react-native-code-push/files/1172217/rncp893.copy.zip)\n\nXcode allows you to define custom build settings for each \"configuration\" (like debug, release), which can then be referenced as the value of keys within the `Info.plist` file (like the `CodePushDeploymentKey` setting). This mechanism allows you to easily configure your builds to produce binaries, which are configured to synchronize with different CodePush deployments.\n\nTo set this up, perform the following steps:\n\n1. Open up your Xcode project and select your project in the `Project navigator` window\n\n2. Ensure the project node is selected, as opposed to one of your targets\n\n3. Select the `Info` tab\n\n4. Click the `+` button within the `Configurations` section and select `Duplicate \"Release\" Configuration`\n\n   ![Configuration](https://cloud.githubusercontent.com/assets/116461/16101597/088714c0-331c-11e6-9504-5469d9a59d74.png)\n\n5. Name the new configuration `Staging` (or whatever you prefer)\n\n6. Select the `Build Settings` tab\n\n7. Click the `+` button on the toolbar and select `Add User-Defined Setting`\n\n   ![Setting](https://cloud.githubusercontent.com/assets/116461/15764165/a16dbe30-28dd-11e6-94f2-fa3b7eb0c7de.png)\n\n   Name this new setting something like `Multi_Deployment_Config`. Go to the setting and add value `$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)` for Release. After that add value `$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)` for Staging\n\n   ![MultiDeploymentConfig](https://user-images.githubusercontent.com/48414875/87178636-1d6a6500-c2e6-11ea-890d-b7773f07e503.png)\n\n   *NOTE: For Xcode 10 and lower version: Go to Build Location -> Per-configuration Build Products Path -> Staging and change Staging value from $(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) to $(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)*\n\n   ![BuildFilesPath1](https://cloud.githubusercontent.com/assets/4928157/22645377/b1d7df0e-ec77-11e6-83c6-291a27bcdb17.png)\n\n   *NOTE: Due to https://github.com/facebook/react-native/issues/11813, we have to do this step to make it possible to use other configurations than Debug or Release on RN 0.40.0 or higher.*\n\n8. Click the `+` button again on the toolbar and select `Add User-Defined Setting`\n\n   Name this new setting something like `CODEPUSH_KEY`, expand it, and specify your `Staging` deployment key for the `Staging` config and your `Production` deployment key for the `Release` config.\n\n    ![Setting Keys](https://cloud.githubusercontent.com/assets/8598682/16821919/fc1eac4a-490d-11e6-9b11-128129c24b80.png)\n\n    *NOTE: As a reminder, you can retrieve these keys by running `appcenter codepush deployment list -a <ownerName>/<appName> -k` from your terminal.*\n\n9. Open your project's `Info.plist` file and change the value of your `CodePushDeploymentKey` entry to `$(CODEPUSH_KEY)`\n\n    ![Infoplist](https://cloud.githubusercontent.com/assets/116461/15764252/3ac8aed2-28de-11e6-8c19-2270ae9857a7.png)\n\nAnd that's it! Now when you run or build your app, your staging builds will automatically be configured to sync with your `Staging` deployment, and your release builds will be configured to sync with your `Production` deployment.\n\n*NOTE: CocoaPods users may need to run `pod install` before building with their new release configuration.*\n\n*Note: If you encounter the error message `ld: library not found for ...`, please consult [this issue](https://github.com/microsoft/react-native-code-push/issues/426) for a possible solution.*\n\nAdditionally, if you want to give them seperate names and/or icons, you can modify the `Product Bundle Identifier`, `Product Name` and `Asset Catalog App Icon Set Name` build settings, which will allow your staging builds to be distinguishable from release builds when installed on the same device.\n"
  },
  {
    "path": "docs/setup-android.md",
    "content": "## Android Setup\n\n* [Plugin Installation and Configuration for React Native 0.60 version and above](#plugin-installation-and-configuration-for-react-native-060-version-and-above-android)\n* [Plugin Installation for React Native lower than 0.60 (Android)](#plugin-installation-for-react-native-lower-than-060-android)\n  * [Plugin Installation (Android - RNPM)](#plugin-installation-android---rnpm)\n  * [Plugin Installation (Android - Manual)](#plugin-installation-android---manual)\n* [Plugin Configuration for React Native lower than 0.60 (Android)](#plugin-configuration-for-react-native-lower-than-060-android)\n  * [For React Native v0.29 - v0.59](#for-react-native-v029---v059)\n    * [For newly created React Native application](#for-newly-created-react-native-application)\n    * [For existing native application](#for-existing-native-application)\n  * [For React Native v0.19 - v0.28](#for-react-native-v019---v028)\n  * [Background React Instances](#background-react-instances)\n    * [For React Native >= v0.29 (Background React Instances)](#for-react-native--v029-background-react-instances)\n    * [For React Native v0.19 - v0.28 (Background React Instances)](#for-react-native-v019---v028-background-react-instances)\n  * [WIX React Native Navigation applications (ver 1.x)](#wix-react-native-navigation-applications)\n* [Code Signing setup](#code-signing-setup)\n\nIn order to integrate CodePush into your Android project, please perform the following steps:\n\n### Plugin Installation and Configuration for React Native 0.60 version and above (Android)\n\n1. In your `android/settings.gradle` file, make the following additions at the end of the file:\n\n    ```gradle\n    ...\n    include ':app', ':react-native-code-push'\n    project(':react-native-code-push').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-code-push/android/app')\n    ```\n    \n2. In your `android/app/build.gradle` file, add the `codepush.gradle` file as an additional build task definition to the end of the file:\n\n    ```gradle\n    ...\n    apply from: \"../../node_modules/react-native-code-push/android/codepush.gradle\"\n    ...\n    ```\n\n3. Update the `MainApplication` file to use CodePush via the following changes:\n\n    For React Native 0.73 and above: update the `MainApplication.kt`\n\n    ```kotlin\n    ...\n    // 1. Import the plugin class.\n    import com.microsoft.codepush.react.CodePush\n\n    class MainApplication : Application(), ReactApplication {\n\n    override val reactNativeHost: ReactNativeHost =\n        object : DefaultReactNativeHost(this) {\n            ...\n\n            // 2. Override the getJSBundleFile method in order to let\n            // the CodePush runtime determine where to get the JS\n            // bundle location from on each app start\n            override fun getJSBundleFile(): String {\n                return CodePush.getJSBundleFile() \n            }\n        };\n    }\n    ```\n\n    For React Native 0.72 and below: update the `MainApplication.java`\n\n    ```java\n    ...\n    // 1. Import the plugin class.\n    import com.microsoft.codepush.react.CodePush;\n\n    public class MainApplication extends Application implements ReactApplication {\n\n        private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {\n            ...\n\n            // 2. Override the getJSBundleFile method in order to let\n            // the CodePush runtime determine where to get the JS\n            // bundle location from on each app start\n            @Override\n            protected String getJSBundleFile() {\n                return CodePush.getJSBundleFile();\n            }\n        };\n    }\n    ```\n\n4. Add the Deployment key to `strings.xml`:\n\n   To let the CodePush runtime know which deployment it should query for updates, open your app's `strings.xml` file and add a new string named `CodePushDeploymentKey`, whose value is the key of the deployment you want to configure this app against (like the key for the `Staging` deployment for the `FooBar` app). You can retrieve this value by running `appcenter codepush deployment list -a <ownerName>/<appName> -k` in the CodePush CLI (the `-k` flag is necessary since keys aren't displayed by default) and copying the value of the `Key` column which corresponds to the deployment you want to use (see below). Note that using the deployment's name (like Staging) will not work. The \"friendly name\" is intended only for authenticated management usage from the CLI, and not for public consumption within your app.\n\n   ![Deployment list](https://cloud.githubusercontent.com/assets/116461/11601733/13011d5e-9a8a-11e5-9ce2-b100498ffb34.png)\n\n   In order to effectively make use of the `Staging` and `Production` deployments that were created along with your CodePush app, refer to the [multi-deployment testing](../README.md#multi-deployment-testing) docs below before actually moving your app's usage of CodePush into production.\n\n   Your `strings.xml` should looks like this:\n\n   ```xml\n    <resources>\n        <string name=\"app_name\">AppName</string>\n        <string moduleConfig=\"true\" name=\"CodePushDeploymentKey\">DeploymentKey</string>\n    </resources>\n    ```\n\n    *Note: If you need to dynamically use a different deployment, you can also override your deployment key in JS code using [Code-Push options](./api-js.md#CodePushOptions)*\n\n### Plugin Installation for React Native lower than 0.60 (Android)\n\nIn order to accommodate as many developer preferences as possible, the CodePush plugin supports Android installation via two mechanisms:\n\n1. [**RNPM**](#plugin-installation-android---rnpm) - [React Native Package Manager (RNPM)](https://github.com/rnpm/rnpm) is an awesome tool that provides the simplest installation experience possible for React Native plugins. If you're already using it, or you want to use it, then we recommend this approach.\n\n2. [**\"Manual\"**](#plugin-installation-android---manual) - If you don't want to depend on any additional tools or are fine with a few extra installation steps (it's a one-time thing), then go with this approach.\n\n*Note: Due to a code change from the React Native repository, if your installed React Native version ranges from 0.29 to 0.32, we recommend following the manual steps to set up correctly. *\n\n#### Plugin Installation (Android - RNPM)\n\n1. As of v0.27 of React Native, `rnpm link` has already been merged into the React Native CLI. Simply run:\n    ```\n    react-native link react-native-code-push\n    ```\n\n    If your app uses a version of React Native that is lower than v0.27, run the following:\n    ```\n    rnpm link react-native-code-push\n    ```\n\n    *Note: If you don't already have RNPM installed, you can do so by simply running `npm i -g rnpm` and then executing the above command.*\n\n2. If you're using RNPM >=1.6.0, you will be prompted for the deployment key you'd like to use. If you don't already have it, you can retrieve this value by running `appcenter codepush deployment list -a <ownerName>/<appName> -k`, or you can choose to ignore it (by simply hitting `<ENTER>`) and add it in later. To get started, we would recommend just using your `Staging` deployment key, so that you can test out the CodePush end-to-end.\n\nAnd that's it for installation using RNPM! Continue below to the [Plugin Configuration](#plugin-configuration-for-react-native-lower-than-060-android) section to complete the setup.\n\n#### Plugin Installation (Android - Manual)\n\n1. In your `android/settings.gradle` file, make the following additions:\n\n    ```gradle\n    include ':app', ':react-native-code-push'\n    project(':react-native-code-push').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-code-push/android/app')\n    ```\n\n2. In your `android/app/build.gradle` file, add the `:react-native-code-push` project as a compile-time dependency:\n\n    ```gradle\n    ...\n    dependencies {\n        ...\n        compile project(':react-native-code-push')\n    }\n    ```\n\n3. In your `android/app/build.gradle` file, add the `codepush.gradle` file as an additional build task definition underneath `react.gradle`:\n\n    ```gradle\n    ...\n    apply from: \"../../node_modules/react-native/react.gradle\"\n    apply from: \"../../node_modules/react-native-code-push/android/codepush.gradle\"\n    ...\n    ```\n\n### Plugin Configuration for React Native lower than 0.60 (Android)\n\n*NOTE: If you used RNPM or `react-native link` to automatically link the plugin, these steps have already been done for you so you may skip this section.*\n\nAfter installing the plugin and syncing your Android Studio project with Gradle, you need to configure your app to consult CodePush for the location of your JS bundle, since it will \"take control\" of managing the current and all future versions. To do this:\n\n#### For React Native v0.29 - v0.59\n\n##### For newly created React Native application\n\nIf you are integrating Code Push into React Native application please do the following steps:\n\nUpdate the `MainApplication.java` file to use CodePush via the following changes:\n\n```java\n...\n// 1. Import the plugin class.\nimport com.microsoft.codepush.react.CodePush;\n\npublic class MainApplication extends Application implements ReactApplication {\n\n    private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {\n        ...\n        // 2. Override the getJSBundleFile method in order to let\n        // the CodePush runtime determine where to get the JS\n        // bundle location from on each app start\n        @Override\n        protected String getJSBundleFile() {\n            return CodePush.getJSBundleFile();\n        }\n\n        @Override\n        protected List<ReactPackage> getPackages() {\n            // 3. Instantiate an instance of the CodePush runtime and add it to the list of\n            // existing packages, specifying the right deployment key. If you don't already\n            // have it, you can run \"appcenter codepush deployment list -a <ownerName>/<appName> -k\" to retrieve your key.\n            return Arrays.<ReactPackage>asList(\n                new MainReactPackage(),\n                new CodePush(\"deployment-key-here\", MainApplication.this, BuildConfig.DEBUG)\n            );\n        }\n    };\n}\n```\n\n*NOTE: For React Native v0.49+ please be sure that `getJSMainModuleName` function in the `MainApplication.java` file determines correct URL to fetch JS bundle (used when dev support is enabled, see [this](https://github.com/facebook/react-native/blob/c7f37074ac89f7e568ca26a6bad3bdb02812c39f/ReactAndroid/src/main/java/com/facebook/react/ReactNativeHost.java#L124) for more details) e.g.*\n```\n@Override\nprotected String getJSMainModuleName() {\n    return \"index\";\n}\n```\n\n##### For existing native application\n\nIf you are integrating React Native into existing native application please do the following steps:\n\nUpdate `MyReactActivity.java` (it could be named differently in your app) file to use CodePush via the following changes:\n\n```java\n...\n// 1. Import the plugin class.\nimport com.microsoft.codepush.react.CodePush;\n\npublic class MyReactActivity extends Activity {\n    private ReactRootView mReactRootView;\n    private ReactInstanceManager mReactInstanceManager;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        ...\n        mReactInstanceManager = ReactInstanceManager.builder()\n                // ...\n                // Add CodePush package\n                .addPackage(new CodePush(\"deployment-key-here\", getApplicationContext(), BuildConfig.DEBUG))\n                // Get the JS Bundle File via Code Push\n                .setJSBundleFile(CodePush.getJSBundleFile())\n                // ...\n                \n                .build();\n        mReactRootView.startReactApplication(mReactInstanceManager, \"MyReactNativeApp\", null);\n\n        setContentView(mReactRootView);\n    }\n\n    ...\n}\n```\n\n#### For React Native v0.19 - v0.28\n\nUpdate the `MainActivity.java` file to use CodePush via the following changes:\n\n```java\n...\n// 1. Import the plugin class (if you used RNPM to install the plugin, this\n// should already be done for you automatically so you can skip this step).\nimport com.microsoft.codepush.react.CodePush;\n\npublic class MainActivity extends ReactActivity {\n    // 2. Override the getJSBundleFile method in order to let\n    // the CodePush runtime determine where to get the JS\n    // bundle location from on each app start\n    @Override\n    protected String getJSBundleFile() {\n        return CodePush.getJSBundleFile();\n    }\n\n    @Override\n    protected List<ReactPackage> getPackages() {\n        // 3. Instantiate an instance of the CodePush runtime and add it to the list of\n        // existing packages, specifying the right deployment key. If you don't already\n        // have it, you can run \"appcenter codepush deployment list -a <ownerName>/<appName> -k\" to retrieve your key.\n        return Arrays.<ReactPackage>asList(\n            new MainReactPackage(),\n            new CodePush(\"deployment-key-here\", this, BuildConfig.DEBUG)\n        );\n    }\n\n    ...\n}\n```\n\n#### Background React Instances\n\n*This section is only necessary if you're <b>explicitly</b> launching a React Native instance without an `Activity` (for example, from within a native push notification receiver). For these situations, CodePush must be told how to find your React Native instance.*\n\nIn order to update/restart your React Native instance, CodePush must be configured with a `ReactInstanceHolder` before attempting to restart an instance in the background. This is done in your `Application` implementation.\n\n##### For React Native >= v0.29 (Background React Instances)\n\nUpdate the `MainApplication.java` file to use CodePush via the following changes:\n\n```java\n...\n// 1. Declare your ReactNativeHost to extend ReactInstanceHolder. ReactInstanceHolder is a subset of ReactNativeHost, so no additional implementation is needed.\nimport com.microsoft.codepush.react.ReactInstanceHolder;\n\npublic class MyReactNativeHost extends ReactNativeHost implements ReactInstanceHolder {\n  // ... usual overrides\n}\n\n// 2. Provide your ReactNativeHost to CodePush.\n\npublic class MainApplication extends Application implements ReactApplication {\n\n   private final MyReactNativeHost mReactNativeHost = new MyReactNativeHost(this);\n\n   @Override\n   public void onCreate() {\n     CodePush.setReactInstanceHolder(mReactNativeHost);\n     super.onCreate();\n  }\n}\n```\n\n##### For React Native v0.19 - v0.28 (Background React Instances)\n\nBefore v0.29, React Native did not provide a `ReactNativeHost` abstraction. If you're launching a background instance, you'll likely have built your own, which should now implement `ReactInstanceHolder`. Once that's done:\n\n```java\n// 1. Provide your ReactInstanceHolder to CodePush.\n\npublic class MainApplication extends Application {\n\n   @Override\n   public void onCreate() {\n     // ... initialize your instance holder\n     CodePush.setReactInstanceHolder(myInstanceHolder);\n     super.onCreate();\n  }\n}\n```\n\nIn order to effectively make use of the `Staging` and `Production` deployments that were created along with your CodePush app, refer to the [multi-deployment testing](../README.md#multi-deployment-testing) docs below before actually moving your app's usage of CodePush into production.\n\n#### WIX React Native Navigation applications\n\nIf you are using [WIX React Native Navigation **version 1.x**](https://github.com/wix/react-native-navigation) based application, please do the following steps to integrate CodePush:\n\n1. No need to change `MainActivity.java` file, so if you are integrating CodePush to newly created RNN application it might be looking like this:\n\n```java\nimport com.facebook.react.ReactActivity;\nimport com.reactnativenavigation.controllers.SplashActivity;\n\npublic class MainActivity extends SplashActivity {\n\n}\n```\n\n2. Update the `MainApplication.java` file to use CodePush via the following changes:\n\n```java\n// ...\nimport com.facebook.react.ReactInstanceManager;\n\n// Add CodePush imports\nimport com.microsoft.codepush.react.ReactInstanceHolder;\nimport com.microsoft.codepush.react.CodePush;\n\npublic class MainApplication extends NavigationApplication implements ReactInstanceHolder {\n\n\t@Override\n\tpublic boolean isDebug() {\n\t\t// Make sure you are using BuildConfig from your own application\n\t\treturn BuildConfig.DEBUG;\n\t}\n\n\tprotected List<ReactPackage> getPackages() {\n\t\t// Add additional packages you require here\n\t\treturn Arrays.<ReactPackage>asList(\n\t\t\tnew CodePush(\"deployment-key-here\", getApplicationContext(), BuildConfig.DEBUG)\n\t\t);\n\t}\n\n\t@Override\n\tpublic List<ReactPackage> createAdditionalReactPackages() {\n\t\treturn getPackages();\n\t}\n\n\t@Override\n\tpublic String getJSBundleFile() {\n        // Override default getJSBundleFile method with the one CodePush is providing\n\t\treturn CodePush.getJSBundleFile();\n\t}\n\n\t@Override\n\tpublic String getJSMainModuleName() {\n\t\treturn \"index\";\n\t}\n\n    @Override\n    public ReactInstanceManager getReactInstanceManager() {\n        // CodePush must be told how to find React Native instance\n        return getReactNativeHost().getReactInstanceManager();\n    }\n}\n```\nIf you are using [WIX React Native Navigation **version 2.x**](https://github.com/wix/react-native-navigation/tree/v2) based application, please do the following steps to integrate CodePush:\n\n1. As per React Native Navigation's documentation, `MainActivity.java` should extend `NavigationActivity`, no changes required to incorporate CodePush:\n\n```java\nimport com.reactnativenavigation.NavigationActivity;\n\npublic class MainActivity extends NavigationActivity {\n\n}\n```\n\n2. Update the `MainApplication.java` file to use CodePush via the following changes:\n\n```java\n// ...\nimport com.facebook.react.ReactInstanceManager;\n\n// Add CodePush imports\nimport com.microsoft.codepush.react.CodePush;\n\npublic class MainApplication extends NavigationApplication {\n\n    @Override\n    public boolean isDebug() {\n        return BuildConfig.DEBUG;\n    }\n\n    @Override\n    protected ReactGateway createReactGateway() {\n        ReactNativeHost host = new NavigationReactNativeHost(this, isDebug(), createAdditionalReactPackages()) {\n            @javax.annotation.Nullable\n            @Override\n            protected String getJSBundleFile() {\n                return CodePush.getJSBundleFile();\n            }\n            \n        };\n        return new ReactGateway(this, isDebug(), host);\n    }\n\n    @Override\n    public List<ReactPackage> createAdditionalReactPackages() {\n        return Arrays.<ReactPackage>asList(\n\t    new CodePush(\"deployment-key-here\", getApplicationContext(), isDebug())\n\t    //,MainReactPackage , etc...\n    }\n}\n```\n\n### Code Signing setup\n\nStarting with CLI version **2.1.0** you can self sign bundles during release and verify its signature before installation of update. For more info about Code Signing please refer to [relevant code-push documentation section](https://github.com/microsoft/code-push/tree/v3.0.1/cli#code-signing). In order to use Public Key for Code Signing you need to do following steps:\n\n   Add `CodePushPublicKey` string item to `/path_to_your_app/android/app/src/main/res/values/strings.xml`. It may looks like this:\n\n ```xml\n <resources>\n    <string name=\"app_name\">my_app</string>\n    <string name=\"CodePushPublicKey\">-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtPSR9lkGzZ4FR0lxF+ZA\nP6jJ8+Xi5L601BPN4QESoRVSrJM08roOCVrs4qoYqYJy3Of2cQWvNBEh8ti3FhHu\ntiuLFpNdfzM4DjAw0Ti5hOTfTixqVBXTJPYpSjDh7K6tUvp9MV0l5q/Ps3se1vud\nM1/X6g54lIX/QoEXTdMgR+SKXvlUIC13T7GkDHT6Z4RlwxkWkOmf2tGguRcEBL6j\nww7w/3g0kWILz7nNPtXyDhIB9WLH7MKSJWdVCZm+cAqabUfpCFo7sHiyHLnUxcVY\nOTw3sz9ceaci7z2r8SZdsfjyjiDJrq69eWtvKVUpredy9HtyALtNuLjDITahdh8A\nzwIDAQAB\n-----END PUBLIC KEY-----</string>\n</resources>\n ```\n\n#### For React Native <= v0.60 you should configure the `CodePush` instance to use this parameter using one of the following approaches\n\n##### Using constructor\n\n```java\nnew CodePush(\n    \"deployment-key\",\n    getApplicationContext(),\n    BuildConfig.DEBUG,\n    R.string.CodePushPublicKey)\n```\n\n##### Using builder\n\n ```java\nnew CodePushBuilder(\"deployment-key-here\",getApplicationContext())\n    .setIsDebugMode(BuildConfig.DEBUG)\n    .setPublicKeyResourceDescriptor(R.string.CodePushPublicKey)\n    .build()\n```\n"
  },
  {
    "path": "docs/setup-ios.md",
    "content": "## iOS Setup\n\nOnce you've acquired the CodePush plugin, you need to integrate it into the Xcode project of your React Native app and configure it correctly. To do this, take the following steps:\n​\n### Plugin Installation and Configuration for React Native 0.60 version and above (iOS)\n\n1. Run `cd ios && pod install && cd ..` to install all the necessary CocoaPods dependencies.\n​\n2. Open up the `AppDelegate.m` file, and add an import statement for the CodePush headers:\n\n   ```objective-c\n   #import <CodePush/CodePush.h>\n   ```\n\n3. Find the following line of code, which sets the source URL for bridge for production releases:\n\n   ```objective-c\n   return [[NSBundle mainBundle] URLForResource:@\"main\" withExtension:@\"jsbundle\"];\n   ```\n\n4. Replace it with this line:\n   \n   ```objective-c\n   return [CodePush bundleURL];\n   ```\n   This change configures your app to always load the most recent version of your app's JS bundle. On the first launch, this will correspond to the file that was compiled with the app. However, after an update has been pushed via CodePush, this will return the location of the most recently installed update.\n  \n   *NOTE: The `bundleURL` method assumes your app's JS bundle is named `main.jsbundle`. If you have configured your app to use a different file name, simply call the `bundleURLForResource:` method (which assumes you're using the `.jsbundle` extension) or `bundleURLForResource:withExtension:` method instead, in order to overwrite that default behavior*\n\n   Typically, you're only going to want to use CodePush to resolve your JS bundle location within release builds, and therefore, we recommend using the `DEBUG` pre-processor macro to dynamically switch between using the packager server and CodePush, depending on whether you are debugging or not. This will make it much simpler to ensure you get the right behavior you want in production, while still being able to use the Chrome Dev Tools, live reload, etc. at debug-time.\n\n   Your `sourceURLForBridge` method should look like this:\n\n   ```objective-c\n   - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge\n   {\n     #if DEBUG\n       return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@\"index\"];\n     #else\n       return [CodePush bundleURL];\n     #endif\n   }\n   ```\n\n5. Add the Deployment key to `Info.plist`:\n\n   To let the CodePush runtime know which deployment it should query for updates against, open your app's `Info.plist` file and add a new entry named `CodePushDeploymentKey`, whose value is the key of the deployment you want to configure this app against (like the key for the `Staging` deployment for the `FooBar` app). You can retrieve this value by running `appcenter codepush deployment list -a <ownerName>/<appName> -k` in the AppCenter CLI (the `-k` flag is necessary since keys aren't displayed by default) and copying the value of the `Key` column which corresponds to the deployment you want to use (see below). Note that using the deployment's name (like Staging) will not work. That \"friendly name\" is intended only for authenticated management usage from the CLI, and not for public consumption within your app.\n\n   ![Deployment list](https://cloud.githubusercontent.com/assets/116461/11601733/13011d5e-9a8a-11e5-9ce2-b100498ffb34.png)\n\n   In order to effectively make use of the `Staging` and `Production` deployments that were created along with your CodePush app, refer to the [multi-deployment testing](../README.md#multi-deployment-testing) docs below before actually moving your app's usage of CodePush into production.\n\n   *Note: If you need to dynamically use a different deployment, you can also override your deployment key in JS code using [Code-Push options](./api-js.md#CodePushOptions)*\n\n### Plugin Installation for React Native lower than 0.60 (iOS)\n\nIn order to accommodate as many developer preferences as possible, the CodePush plugin supports iOS installation via three mechanisms:\n\n1. [**RNPM**](#plugin-installation-ios---rnpm) - [React Native Package Manager (RNPM)](https://github.com/rnpm/rnpm) is an awesome tool that provides the simplest installation experience possible for React Native plugins. If you're already using it, or you want to use it, then we recommend this approach.\n\n2. [**CocoaPods**](#plugin-installation-ios---cocoapods) - If you're building a native iOS app that is embedding React Native into it, or you simply prefer using [CocoaPods](https://cocoapods.org), then we recommend using the Podspec file that we ship as part of our plugin.\n\n3. [**\"Manual\"**](#plugin-installation-ios---manual) - If you don't want to depend on any additional tools or are fine with a few extra installation steps (it's a one-time thing), then go with this approach.\n\n#### Plugin Installation (iOS - RNPM)\n\n1. As of v0.27 of React Native, `rnpm link` has already been merged into the React Native CLI. Simply run:\n    ```\n    react-native link react-native-code-push\n    ```\n\n    If your app uses a version of React Native that is lower than v0.27, run the following:\n    ```\n    rnpm link react-native-code-push\n    ```\n\n    *Note: If you don't already have RNPM installed, you can do so by simply running `npm i -g rnpm` and then executing the above command. If you already have RNPM installed, make sure you have v1.9.0+ in order to benefit from this one step install.*\n\n2. You will be prompted for the deployment key you'd like to use. If you don't already have it, you can retrieve this value by running `appcenter codepush deployment list -a <ownerName>/<appName> -k`, or you can choose to ignore it (by simply hitting `<ENTER>`) and add it in later. To get started, we would recommend just using your `Staging` deployment key, so that you can test out the CodePush end-to-end.\n\nAnd that's it! Isn't RNPM awesome? :)\n\n#### Plugin Installation (iOS - CocoaPods)\n\n1. Add the ReactNative and CodePush plugin dependencies to your `Podfile`, pointing at the path where NPM installed it\n\n    ```\n    # React Native requirements\n    pod 'React', :path => '../node_modules/react-native', :subspecs => [\n       'Core',\n       'CxxBridge', # Include this for RN >= 0.47\n       'DevSupport', # Include this to enable In-App Devmenu if RN >= 0.43\n       'RCTText',\n       'RCTNetwork',\n       'RCTWebSocket', # Needed for debugging\n       'RCTAnimation', # Needed for FlatList and animations running on native UI thread\n       # Add any other subspecs you want to use in your project\n    ]\n    # Explicitly include Yoga if you are using RN >= 0.42.0\n    pod 'yoga', :path => '../node_modules/react-native/ReactCommon/yoga'\n    pod 'DoubleConversion', :podspec => '../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec'\n    pod 'glog', :podspec => '../node_modules/react-native/third-party-podspecs/glog.podspec'\n    pod 'Folly', :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec'\n      \n    # CodePush plugin dependency\n    pod 'CodePush', :path => '../node_modules/react-native-code-push'\n    ```\n\n    *NOTE: The above path needs to be relative to your app's `Podfile`, so adjust it as necessary.*\n\n    *NOTE: `JWT` library should be >= version 3.0.x*\n\n2. Run `pod install`\n\n*NOTE: The CodePush `.podspec` depends on the `React` pod, and so in order to ensure that it can correctly use the version of React Native that your app is built with, please make sure to define the `React` dependency in your app's `Podfile` as explained [here](https://facebook.github.io/react-native/docs/integration-with-existing-apps.html#podfile).*\n\n#### Plugin Installation (iOS - Manual)\n\n1. Open your app's Xcode project\n\n2. Find the `CodePush.xcodeproj` file within the `node_modules/react-native-code-push/ios` directory (or `node_modules/react-native-code-push` for <=`1.7.3-beta` installations) and drag it into the `Libraries` node in Xcode\n\n    ![Add CodePush to project](https://cloud.githubusercontent.com/assets/8598682/13368613/c5c21422-dca0-11e5-8594-c0ec5bde9d81.png)\n\n3. Select the project node in Xcode and select the \"Build Phases\" tab of your project configuration.\n\n4. Drag `libCodePush.a` from `Libraries/CodePush.xcodeproj/Products` into the \"Link Binary With Libraries\" section of your project's \"Build Phases\" configuration.\n\n    ![Link CodePush during build](https://cloud.githubusercontent.com/assets/516559/10322221/a75ea066-6c31-11e5-9d88-ff6f6a4d6968.png)\n\n5. Click the plus sign underneath the \"Link Binary With Libraries\" list and select the `libz.tbd` library underneath the `iOS 9.1` node.\n\n    ![Libz reference](https://cloud.githubusercontent.com/assets/116461/11605042/6f786e64-9aaa-11e5-8ca7-14b852f808b1.png)\n\n    *Note: Alternatively, if you prefer, you can add the `-lz` flag to the `Other Linker Flags` field in the `Linking` section of the `Build Settings`.*\n\n\n### Plugin Configuration for React Native lower than 0.60 (iOS)\n\n*NOTE: If you used RNPM or `react-native link` to automatically link the plugin, these steps have already been done for you so you may skip this section.*\n\nOnce your Xcode project has been setup to build/link the CodePush plugin, you need to configure your app to consult CodePush for the location of your JS bundle, since it is responsible for synchronizing it with updates that are released to the CodePush server. To do this, perform the following steps:\n\n1. Open up the `AppDelegate.m` file, and add an import statement for the CodePush headers:\n\n    ```objective-c\n    #import <CodePush/CodePush.h>\n    ```\n\nFor React Native 0.59 - 0.59.10:\n\n2. Find the following line of code, which sets the source URL for bridge for production releases:\n\n    ```objective-c\n    return [[NSBundle mainBundle] URLForResource:@\"main\" withExtension:@\"jsbundle\"];\n    ```\n\n3. Replace it with this line:\n\n    ```objective-c\n    return [CodePush bundleURL];\n    ```\n\nFor React Native 0.58 and below:\n\n2. Find the following line of code, which loads your JS Bundle from the app binary for production releases:\n\n    ```objective-c\n    jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@\"index\" fallbackResource:nil];\n    ```\n\n3. Replace it with this line:\n\n    ```objective-c\n    jsCodeLocation = [CodePush bundleURL];\n    ```\n\nThis change configures your app to always load the most recent version of your app's JS bundle. On the first launch, this will correspond to the file that was compiled with the app. However, after an update has been pushed via CodePush, this will return the location of the most recently installed update.\n\n*NOTE: The `bundleURL` method assumes your app's JS bundle is named `main.jsbundle`. If you have configured your app to use a different file name, simply call the `bundleURLForResource:` method (which assumes you're using the `.jsbundle` extension) or `bundleURLForResource:withExtension:` method instead, in order to overwrite that default behavior*\n\nTypically, you're only going to want to use CodePush to resolve your JS bundle location within release builds, and therefore, we recommend using the `DEBUG` pre-processor macro to dynamically switch between using the packager server and CodePush, depending on whether you are debugging or not. This will make it much simpler to ensure you get the right behavior you want in production, while still being able to use the Chrome Dev Tools, live reload, etc. at debug-time.\n\nFor React Native 0.59 - 0.59.10:\n\n```objective-c\n- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge\n{\n  #if DEBUG\n    return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@\"index\" fallbackResource:nil];\n  #else\n    return [CodePush bundleURL];\n  #endif\n}\n```\n\nFor React Native 0.49 - 0.58:\n\n```objective-c\nNSURL *jsCodeLocation;\n\n#ifdef DEBUG\n    jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@\"index\" fallbackResource:nil];\n#else\n    jsCodeLocation = [CodePush bundleURL];\n#endif\n```\n\nFor React Native 0.48 and below:\n\n```objective-c\nNSURL *jsCodeLocation;\n\n#ifdef DEBUG\n    jsCodeLocation = [NSURL URLWithString:@\"http://localhost:8081/index.ios.bundle?platform=ios&dev=true\"];\n#else\n    jsCodeLocation = [CodePush bundleURL];\n#endif\n```\n\nTo let the CodePush runtime know which deployment it should query for updates against, open your app's `Info.plist` file and add a new entry named `CodePushDeploymentKey`, whose value is the key of the deployment you want to configure this app against (like the key for the `Staging` deployment for the `FooBar` app). You can retrieve this value by running `appcenter codepush deployment list -a <ownerName>/<appName> -k` in the AppCenter CLI (the `-k` flag is necessary since keys aren't displayed by default) and copying the value of the `Key` column which corresponds to the deployment you want to use (see below). Note that using the deployment's name (like Staging) will not work. That \"friendly name\" is intended only for authenticated management usage from the CLI, and not for public consumption within your app.\n\n![Deployment list](https://cloud.githubusercontent.com/assets/116461/11601733/13011d5e-9a8a-11e5-9ce2-b100498ffb34.png)\n\nIn order to effectively make use of the `Staging` and `Production` deployments that were created along with your CodePush app, refer to the [multi-deployment testing](../README.md#multi-deployment-testing) docs below before actually moving your app's usage of CodePush into production.\n\n### HTTP exception domains configuration (iOS)\n\nCodePush plugin makes HTTPS requests to the following domains:\n\n- codepush.appcenter.ms\n- codepush.blob.core.windows.net\n- codepushupdates.azureedge.net\n\nIf you want to change the default HTTP security configuration for any of these domains, you have to define the [`NSAppTransportSecurity` (ATS)][ats] configuration inside your __Info.plist__ file:\n\n```xml\n<plist version=\"1.0\">\n  <dict>\n    <!-- ...other configs... -->\n\n    <key>NSAppTransportSecurity</key>\n    <dict>\n      <key>NSExceptionDomains</key>\n      <dict>\n        <key>codepush.appcenter.ms</key>\n        <dict><!-- read the ATS Apple Docs for available options --></dict>\n      </dict>\n    </dict>\n\n    <!-- ...other configs... -->\n  </dict>\n</plist>\n```\n\nBefore doing anything, please [read the docs][ats] first.\n\n[ats]: https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW33\n\n### Code Signing setup\n\nStarting with CLI version **2.1.0** you can self sign bundles during release and verify its signature before installation of update. For more info about Code Signing please refer to [relevant code-push documentation section](https://github.com/microsoft/code-push/tree/v3.0.1/cli#code-signing).\n\nIn order to configure Public Key for bundle verification you need to add record in `Info.plist` with name `CodePushPublicKey` and string value of public key content. Example:\n\n```xml\n<plist version=\"1.0\">\n  <dict>\n    <!-- ...other configs... -->\n\n    <key>CodePushPublicKey</key>\n        <string>-----BEGIN PUBLIC KEY-----\nMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANkWYydPuyOumR/sn2agNBVDnzyRpM16NAUpYPGxNgjSEp0etkDNgzzdzyvyl+OsAGBYF3jCxYOXozum+uV5hQECAwEAAQ==\n-----END PUBLIC KEY-----</string>\n\n    <!-- ...other configs... -->\n  </dict>\n</plist>\n```\n\n"
  },
  {
    "path": "docs/setup-windows.md",
    "content": "## Windows Setup\n\nOnce you've acquired the CodePush plugin, you need to integrate it into the Visual Studio project of your React Native app and configure it correctly. To do this, take the following steps:\n\n### Plugin Installation and Configuration for React Native Windows 0.63.6 version and above\n\n#### Plugin Installation (Windows-npx)\n\nOnce the plugin has been downloaded, run `npx react-native autolink-windows` in your application's root directory to automatically add the CodePush c++ project to your application's windows solution file.\n\n#### Plugin Configuration (Windows)\n\n1. Replace the following files located at `windows/<app name>` with those in the CodePushDemoAppCpp example app in this repo found at `Examples/CodePushDemoAppCpp/windows/CodePushDemoAppCpp`:\n   1. app.h\n   2. app.cpp\n   3. app.xaml\n\n2. In the above files, replace any occurance of `CodePushDemoAppCpp` with the name of your application\n\n3. Enter your application's app version and deployment key to the `configMap` object at the top of your app's `OnLaunched` method in `App.cpp`:\n\n```c++\n...\nvoid App::OnLaunched(activation::LaunchActivatedEventArgs const& e)\n{\n    winrt::Microsoft::CodePush::ReactNative::CodePushConfig::SetHost(Host());\n    auto configMap{ winrt::single_threaded_map<hstring, hstring>() };\n    configMap.Insert(L\"appVersion\", L\"1.0.0\");\n    configMap.Insert(L\"deploymentKey\", L\"<app deployment key>\");\n    winrt::Microsoft::CodePush::ReactNative::CodePushConfig::Init(configMap);\n...\n}\n...\n```\n\n#### Plugin Configuration (Windows) C#\n\n1. add name space `Microsoft.CodePush` to `App.xaml.cs`\n\n2. add app version and deployment key to `configMap` at the start of your app's `OnLaunched` method in `App.xaml.cs`.\n\n```c#\nusing Microsoft.CodePush;\n\n...\nprotected override void OnLaunched(LaunchActivatedEventArgs e)\n{\n    Microsoft.CodePush.ReactNative.CodePushConfig.SetHost(Host);\n    IDictionary<string, string> configMap = new Dictionary<string, string>();\n    configMap.Add(\"appVersion\", \"1.0.0\");\n    configMap.Add(\"deploymentKey\", \"deployment key\");\n    Microsoft.CodePush.ReactNative.CodePushConfig.Init(configMap);\n...\n}\n...\n```\n\n\n### Plugin Installation and Configuration for React Native Windows lower than 0.60\n\n#### Plugin Installation (Windows)\n\n1. Open the Visual Studio solution located at `windows-legacy\\<AppName>\\<AppName>.sln` within your app\n\n2. Right-click the solution node in the `Solution Explorer` window and select the `Add -> Existing Project...` menu item\n\n   ![Add Project](https://cloud.githubusercontent.com/assets/116461/14467164/ddf6312e-008e-11e6-8a10-44a8b44b5dfc.PNG)\n\n3. Browse to the `node_modules\\react-native-code-push\\windows` directory, select the `CodePush.csproj` file and click `OK`\n\n4. Back in the `Solution Explorer`, right-click the project node that is named after your app, and select the `Add -> Reference...` menu item\n\n   ![Add Reference](https://cloud.githubusercontent.com/assets/116461/14467154/d833bc98-008e-11e6-8e95-09864b1f05ef.PNG)\n\n5. Select the `Projects` tab on the left hand side, check the `CodePush` item and then click `OK`\n\n   ![Add Reference Dialog](https://cloud.githubusercontent.com/assets/116461/14467147/cb805b6e-008e-11e6-964f-f856c59b65af.PNG)\n\n#### Plugin Configuration (Windows)\n\nAfter installing the plugin, you need to configure your app to consult CodePush for the location of your JS bundle, since it will \"take control\" of managing the current and all future versions. To do this, update the `MainReactNativeHost.cs` file to use CodePush via the following changes:\n\n```c#\n...\n// 1. Import the CodePush namespace\nusing CodePush.ReactNative;\n...\nclass MainReactNativeHost : ReactNativeHost\n{\n    // 2. Declare a private instance variable for the CodePushModule instance.\n    private CodePushReactPackage codePushReactPackage;\n\n    // 3. Update the JavaScriptBundleFile property to initalize the CodePush runtime,\n    // specifying the right deployment key, then use it to return the bundle URL from\n    // CodePush instead of statically from the binary. If you don't already have your\n    // deployment key, you can run \"appcenter codepush deployment list -a <ownerName>/<appName> -k\" to retrieve it.\n    protected override string JavaScriptBundleFile\n    {\n        get\n        {\n            codePushReactPackage = new CodePushReactPackage(\"deployment-key-here\", this);\n            return codePushReactPackage.GetJavaScriptBundleFile();\n        }\n    }\n\n    // 4. Add the codePushReactPackage instance to the list of existing packages.\n    protected override List<IReactPackage> Packages\n    {\n        get\n        {\n            return new List<IReactPackage>\n            {\n                new MainReactPackage(),\n                ...\n                codePushReactPackage\n            };\n        }\n    }\n    ...\n}\n```\n"
  },
  {
    "path": "ios/CodePush/Base64/Base64/MF_Base64Additions.h",
    "content": "//\n//  MF_Base64Additions.h\n//  Base64 -- RFC 4648 compatible implementation\n//  see http://www.ietf.org/rfc/rfc4648.txt for more details\n//\n//  Designed to be compiled with Automatic Reference Counting\n//\n//  Created by Dave Poirier on 2012-06-14.\n//  Public Domain\n//  Hosted at https://github.com/ekscrypto/Base64\n//\n\n#import <Foundation/Foundation.h>\n\n@interface NSString (Base64Addition)\n+(NSString *)stringFromBase64String:(NSString *)base64String;\n+(NSString *)stringFromBase64UrlEncodedString:(NSString *)base64UrlEncodedString;\n-(NSString *)base64String;\n-(NSString *)base64UrlEncodedString;\n@end\n\n@interface NSData (Base64Addition)\n+(NSData *)dataWithBase64String:(NSString *)base64String;\n+(NSData *)dataWithBase64UrlEncodedString:(NSString *)base64UrlEncodedString;\n-(NSString *)base64String;\n-(NSString *)base64UrlEncodedString;\n@end\n\n@interface MF_Base64Codec : NSObject \n+(NSData *)dataFromBase64String:(NSString *)base64String;\n+(NSString *)base64StringFromData:(NSData *)data;\n+(NSString *)base64UrlEncodedStringFromBase64String:(NSString *)base64String;\n+(NSString *)base64StringFromBase64UrlEncodedString:(NSString *)base64UrlEncodedString;\n@end\n"
  },
  {
    "path": "ios/CodePush/Base64/Base64/MF_Base64Additions.m",
    "content": "//\n//  MF_Base64Additions.m\n//  Base64 -- RFC 4648 compatible implementation\n//  see http://www.ietf.org/rfc/rfc4648.txt for more details\n//\n//  Designed to be compiled with Automatic Reference Counting\n//\n//  Created by Dave Poirier on 2012-06-14.\n//  Public Domain\n//  Hosted at https://github.com/ekscrypto/Base64\n//\n\n#import \"MF_Base64Additions.h\"\n\n@implementation MF_Base64Codec\n\n+(NSString *)base64StringFromBase64UrlEncodedString:(NSString *)base64UrlEncodedString\n{\n    NSString *s = base64UrlEncodedString;\n    s = [s stringByReplacingOccurrencesOfString:@\"-\" withString:@\"+\"];\n    s = [s stringByReplacingOccurrencesOfString:@\"_\" withString:@\"/\"];\n    switch (s.length % 4) {\n        case 2:\n            s = [s stringByAppendingString:@\"==\"];\n            break;\n        case 3:\n            s = [s stringByAppendingString:@\"=\"];\n            break;\n        default:\n            break;\n    }\n    return s;\n}\n\n+(NSString *)base64UrlEncodedStringFromBase64String:(NSString *)base64String\n{\n    NSString *s = base64String;\n    s = [s stringByReplacingOccurrencesOfString:@\"=\" withString:@\"\"];\n    s = [s stringByReplacingOccurrencesOfString:@\"+\" withString:@\"-\"];\n    s = [s stringByReplacingOccurrencesOfString:@\"/\" withString:@\"_\"];\n    return s;\n}\n\n+(NSData *)dataFromBase64String:(NSString *)encoding\n{\n    NSData *data = nil;\n    unsigned char *decodedBytes = NULL;\n    @try {\n#define __ 255\n        static char decodingTable[256] = {\n            __,__,__,__, __,__,__,__, __,__,__,__, __,__,__,__,  // 0x00 - 0x0F\n            __,__,__,__, __,__,__,__, __,__,__,__, __,__,__,__,  // 0x10 - 0x1F\n            __,__,__,__, __,__,__,__, __,__,__,62, __,__,__,63,  // 0x20 - 0x2F\n            52,53,54,55, 56,57,58,59, 60,61,__,__, __, 0,__,__,  // 0x30 - 0x3F\n            __, 0, 1, 2,  3, 4, 5, 6,  7, 8, 9,10, 11,12,13,14,  // 0x40 - 0x4F\n            15,16,17,18, 19,20,21,22, 23,24,25,__, __,__,__,__,  // 0x50 - 0x5F\n            __,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,  // 0x60 - 0x6F\n            41,42,43,44, 45,46,47,48, 49,50,51,__, __,__,__,__,  // 0x70 - 0x7F\n            __,__,__,__, __,__,__,__, __,__,__,__, __,__,__,__,  // 0x80 - 0x8F\n            __,__,__,__, __,__,__,__, __,__,__,__, __,__,__,__,  // 0x90 - 0x9F\n            __,__,__,__, __,__,__,__, __,__,__,__, __,__,__,__,  // 0xA0 - 0xAF\n            __,__,__,__, __,__,__,__, __,__,__,__, __,__,__,__,  // 0xB0 - 0xBF\n            __,__,__,__, __,__,__,__, __,__,__,__, __,__,__,__,  // 0xC0 - 0xCF\n            __,__,__,__, __,__,__,__, __,__,__,__, __,__,__,__,  // 0xD0 - 0xDF\n            __,__,__,__, __,__,__,__, __,__,__,__, __,__,__,__,  // 0xE0 - 0xEF\n            __,__,__,__, __,__,__,__, __,__,__,__, __,__,__,__,  // 0xF0 - 0xFF\n        };\n        encoding = [encoding stringByReplacingOccurrencesOfString:@\"=\" withString:@\"\"];\n        NSData *encodedData = [encoding dataUsingEncoding:NSASCIIStringEncoding];\n        unsigned char *encodedBytes = (unsigned char *)[encodedData bytes];\n        \n        NSUInteger encodedLength = [encodedData length];\n        if( encodedLength >= (NSUIntegerMax - 3) ) return nil; // NSUInteger overflow check\n        NSUInteger encodedBlocks = (encodedLength+3) >> 2;\n        NSUInteger expectedDataLength = encodedBlocks * 3;\n        \n        unsigned char decodingBlock[4];\n        \n        decodedBytes = malloc(expectedDataLength);\n        if( decodedBytes != NULL ) {\n            \n            NSUInteger i = 0;\n            NSUInteger j = 0;\n            NSUInteger k = 0;\n            unsigned char c;\n            while( i < encodedLength ) {\n                c = decodingTable[encodedBytes[i]];\n                i++;\n                if( c != __ ) {\n                    decodingBlock[j] = c;\n                    j++;\n                    if( j == 4 ) {\n                        decodedBytes[k] = (decodingBlock[0] << 2) | (decodingBlock[1] >> 4);                \n                        decodedBytes[k+1] = (decodingBlock[1] << 4) | (decodingBlock[2] >> 2);\n                        decodedBytes[k+2] = (decodingBlock[2] << 6) | (decodingBlock[3]);\n                        j = 0;\n                        k += 3;\n                    }\n                }\n            }\n            \n            // Process left over bytes, if any\n            if( j == 3 ) {\n                decodedBytes[k] = (decodingBlock[0] << 2) | (decodingBlock[1] >> 4);                \n                decodedBytes[k+1] = (decodingBlock[1] << 4) | (decodingBlock[2] >> 2);\n                k += 2;\n            } else if( j == 2 ) {\n                decodedBytes[k] = (decodingBlock[0] << 2) | (decodingBlock[1] >> 4);                \n                k += 1;\n            }\n            data = [[NSData alloc] initWithBytes:decodedBytes length:k];\n        }\n    }\n    @catch (NSException *exception) {\n        data = nil;\n        NSLog(@\"WARNING: error occured while decoding base 32 string: %@\", exception);\n    }\n    @finally {\n        if( decodedBytes != NULL ) {\n            free( decodedBytes );\n        }\n    }\n    return data;\n}\n+(NSString *)base64StringFromData:(NSData *)data\n{\n    NSString *encoding = nil;\n    unsigned char *encodingBytes = NULL;\n    @try {\n        static char encodingTable[64] = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\n        static NSUInteger paddingTable[] = {0,2,1};\n        //                 Table 1: The Base 64 Alphabet\n        //        \n        //    Value Encoding  Value Encoding  Value Encoding  Value Encoding\n        //        0 A            17 R            34 i            51 z\n        //        1 B            18 S            35 j            52 0\n        //        2 C            19 T            36 k            53 1\n        //        3 D            20 U            37 l            54 2\n        //        4 E            21 V            38 m            55 3\n        //        5 F            22 W            39 n            56 4\n        //        6 G            23 X            40 o            57 5\n        //        7 H            24 Y            41 p            58 6\n        //        8 I            25 Z            42 q            59 7\n        //        9 J            26 a            43 r            60 8\n        //       10 K            27 b            44 s            61 9\n        //       11 L            28 c            45 t            62 +\n        //       12 M            29 d            46 u            63 /\n        //       13 N            30 e            47 v\n        //       14 O            31 f            48 w         (pad) =\n        //       15 P            32 g            49 x\n        //       16 Q            33 h            50 y\n        \n        NSUInteger dataLength = [data length];\n        NSUInteger encodedBlocks = dataLength / 3;\n        if( (encodedBlocks + 1) >= (NSUIntegerMax / 4) ) return nil; // NSUInteger overflow check\n        NSUInteger padding = paddingTable[dataLength % 3];\n        if( padding > 0 ) encodedBlocks++;\n        NSUInteger encodedLength = encodedBlocks * 4;\n        \n        encodingBytes = malloc(encodedLength);\n        if( encodingBytes != NULL ) {\n            NSUInteger rawBytesToProcess = dataLength;\n            NSUInteger rawBaseIndex = 0;\n            NSUInteger encodingBaseIndex = 0;\n            unsigned char *rawBytes = (unsigned char *)[data bytes];\n            unsigned char rawByte1, rawByte2, rawByte3;\n            while( rawBytesToProcess >= 3 ) {\n                rawByte1 = rawBytes[rawBaseIndex];\n                rawByte2 = rawBytes[rawBaseIndex+1];\n                rawByte3 = rawBytes[rawBaseIndex+2];\n                encodingBytes[encodingBaseIndex] = encodingTable[((rawByte1 >> 2) & 0x3F)];\n                encodingBytes[encodingBaseIndex+1] = encodingTable[((rawByte1 << 4) & 0x30) | ((rawByte2 >> 4) & 0x0F) ];\n                encodingBytes[encodingBaseIndex+2] = encodingTable[((rawByte2 << 2) & 0x3C) | ((rawByte3 >> 6) & 0x03) ];\n                encodingBytes[encodingBaseIndex+3] = encodingTable[(rawByte3 & 0x3F)];\n                \n                rawBaseIndex += 3;\n                encodingBaseIndex += 4;\n                rawBytesToProcess -= 3;\n            }\n            rawByte2 = 0;\n            switch (dataLength-rawBaseIndex) {\n                case 2:\n                    rawByte2 = rawBytes[rawBaseIndex+1];\n                case 1:\n                    rawByte1 = rawBytes[rawBaseIndex];\n                    encodingBytes[encodingBaseIndex] = encodingTable[((rawByte1 >> 2) & 0x3F)];\n                    encodingBytes[encodingBaseIndex+1] = encodingTable[((rawByte1 << 4) & 0x30) | ((rawByte2 >> 4) & 0x0F) ];\n                    encodingBytes[encodingBaseIndex+2] = encodingTable[((rawByte2 << 2) & 0x3C) ];\n                    // we can skip rawByte3 since we have a partial block it would always be 0\n                    break;\n            }\n            // compute location from where to begin inserting padding, it may overwrite some bytes from the partial block encoding\n            // if their value was 0 (cases 1-2).\n            encodingBaseIndex = encodedLength - padding;\n            while( padding-- > 0 ) {\n                encodingBytes[encodingBaseIndex++] = '=';\n            }\n            encoding = [[NSString alloc] initWithBytes:encodingBytes length:encodedLength encoding:NSASCIIStringEncoding];\n        }\n    }\n    @catch (NSException *exception) {\n        encoding = nil;\n        NSLog(@\"WARNING: error occured while tring to encode base 32 data: %@\", exception);\n    }\n    @finally {\n        if( encodingBytes != NULL ) {\n            free( encodingBytes );\n        }\n    }\n    return encoding;\n}\n@end\n\n@implementation NSString (Base64Addition)\n-(NSString *)base64String\n{\n    NSData *utf8encoding = [self dataUsingEncoding:NSUTF8StringEncoding];\n    return [MF_Base64Codec base64StringFromData:utf8encoding];\n}\n-(NSString *)base64UrlEncodedString\n{\n    return [MF_Base64Codec base64UrlEncodedStringFromBase64String:[self base64String]];\n}\n+(NSString *)stringFromBase64String:(NSString *)base64String\n{\n    NSData *utf8encoding = [MF_Base64Codec dataFromBase64String:base64String];\n    return [[NSString alloc] initWithData:utf8encoding encoding:NSUTF8StringEncoding];\n}\n+(NSString *)stringFromBase64UrlEncodedString:(NSString *)base64UrlEncodedString\n{\n    return [self stringFromBase64String:[MF_Base64Codec base64StringFromBase64UrlEncodedString:base64UrlEncodedString]];\n}\n@end\n\n@implementation NSData (Base64Addition)\n+(NSData *)dataWithBase64String:(NSString *)base64String\n{\n    return [MF_Base64Codec dataFromBase64String:base64String];\n}\n+(NSData *)dataWithBase64UrlEncodedString:(NSString *)base64UrlEncodedString\n{\n    return [self dataWithBase64String:[MF_Base64Codec base64StringFromBase64UrlEncodedString:base64UrlEncodedString]];\n}\n-(NSString *)base64String\n{\n    return [MF_Base64Codec base64StringFromData:self];\n}\n-(NSString *)base64UrlEncodedString\n{\n    return [MF_Base64Codec base64UrlEncodedStringFromBase64String:[self base64String]];\n}\n@end"
  },
  {
    "path": "ios/CodePush/Base64/README.md",
    "content": "[![CI Status](https://travis-ci.org/ekscrypto/Base64.svg?branch=master)](https://github.com/ekscrypto/Base64)\n\nBase64 Additions for Objective-C on Mac OS X and iOS\n=======\n\n\nUsage\n----\nOpen the Xcode project file, and drag MF_Base64Additions.m/.h into your project.\n\nIn files where you want to use Base64 encoding/decoding, simply include the header file and use one of the provided NSData or NSString additions.\n    \nExample use:\n    #import \"MF_Base64Additions.h\"\n    \n    NSString *helloWorld = @\"Hello World\";\n    NSString *helloInBase64 = [helloWorld base64String];\n    NSString *helloDecoded = [NSString stringFromBase64String:helloInBase64];\n\n\n\n\nPerformance\n----\n* Encoding: Approximately 4 to 5 times faster than using the equivalent SecTransform.\n* Encoding: 30% faster than https://github.com/l4u/NSData-Base64\n* Decoding: 5% faster than using the equivalent SecTransform.\n* Decoding: 5% faster than https://github.com/l4u/NSData-Base64\n\n\n\nRequirements\n-----\n* Compile with Automatic Reference Counting\n* Compatible with Mac OSX 10.6+ and iOS 4.0+\n\n\n\nImplementation\n----\n* Implemented as per RFC 4648, see http://www.ietf.org/rfc/rfc4648.txt for more details.\n\n\n\nLicensing\n----\n* Public Domain\n"
  },
  {
    "path": "ios/CodePush/CodePush.h",
    "content": "#if __has_include(<React/RCTEventEmitter.h>)\n#import <React/RCTEventEmitter.h>\n#elif __has_include(\"RCTEventEmitter.h\")\n#import \"RCTEventEmitter.h\"\n#else\n#import \"React/RCTEventEmitter.h\"   // Required when used as a Pod in a Swift project\n#endif\n\n#import <Foundation/Foundation.h>\n\n@interface CodePush : RCTEventEmitter\n\n+ (NSURL *)binaryBundleURL;\n/*\n * This method is used to retrieve the URL for the most recent\n * version of the JavaScript bundle. This could be either the\n * bundle that was packaged with the app binary, or the bundle\n * that was downloaded as part of a CodePush update. The value returned\n * should be used to \"bootstrap\" the React Native bridge.\n *\n * This method assumes that your JS bundle is named \"main.jsbundle\"\n * and therefore, if it isn't, you should use either the bundleURLForResource:\n * or bundleURLForResource:withExtension: methods to override that behavior.\n */\n+ (NSURL *)bundleURL;\n\n+ (NSURL *)bundleURLForResource:(NSString *)resourceName;\n\n+ (NSURL *)bundleURLForResource:(NSString *)resourceName\n                  withExtension:(NSString *)resourceExtension;\n\n+ (NSURL *)bundleURLForResource:(NSString *)resourceName\n                  withExtension:(NSString *)resourceExtension\n                   subdirectory:(NSString *)resourceSubdirectory;\n\n+ (NSURL *)bundleURLForResource:(NSString *)resourceName\n                  withExtension:(NSString *)resourceExtension\n                   subdirectory:(NSString *)resourceSubdirectory\n                         bundle:(NSBundle *)resourceBundle;\n\n+ (NSString *)getApplicationSupportDirectory;\n\n+ (NSString *)bundleAssetsPath;\n\n/*\n * This method allows the version of the app's binary interface\n * to be specified, which would otherwise default to the\n * binary version of the app.\n */\n+ (void)overrideAppVersion:(NSString *)appVersion;\n\n/*\n * This method allows dynamically setting the app's\n * deployment key, in addition to setting it via\n * the Info.plist file's CodePushDeploymentKey setting.\n */\n+ (void)setDeploymentKey:(NSString *)deploymentKey;\n\n/*\n * This method checks to see whether a specific package hash\n * has previously failed installation.\n */\n+ (BOOL)isFailedHash:(NSString*)packageHash;\n\n\n/*\n * This method is used to get information about the latest rollback.\n * This information will be used to decide whether the application\n * should ignore the update or not.\n */\n+ (NSDictionary*)getRollbackInfo;\n/*\n * This method is used to save information about the latest rollback.\n * This information will be used to decide whether the application\n * should ignore the update or not.\n */\n+ (void)setLatestRollbackInfo:(NSString*)packageHash;\n/*\n * This method is used to get the count of rollback for the package\n * using the latest rollback information.\n */\n+ (int)getRollbackCountForPackage:(NSString*) packageHash fromLatestRollbackInfo:(NSMutableDictionary*) latestRollbackInfo;\n\n/*\n * This method checks to see whether a specific package hash\n * represents a downloaded and installed update, that hasn't\n * been applied yet via an app restart.\n */\n+ (BOOL)isPendingUpdate:(NSString*)packageHash;\n\n// The below methods are only used during tests.\n+ (BOOL)isUsingTestConfiguration;\n+ (void)setUsingTestConfiguration:(BOOL)shouldUseTestConfiguration;\n+ (void)clearUpdates;\n\n@end\n\n@interface CodePushConfig : NSObject\n\n@property (copy) NSString *appVersion;\n@property (readonly) NSString *buildVersion;\n@property (readonly) NSDictionary *configuration;\n@property (copy) NSString *deploymentKey;\n@property (copy) NSString *serverURL;\n@property (copy) NSString *publicKey;\n\n+ (instancetype)current;\n\n@end\n\n@interface CodePushDownloadHandler : NSObject <NSURLConnectionDelegate>\n\n@property (strong) NSOutputStream *outputFileStream;\n@property long long expectedContentLength;\n@property long long receivedContentLength;\n@property dispatch_queue_t operationQueue;\n@property (copy) void (^progressCallback)(long long, long long);\n@property (copy) void (^doneCallback)(BOOL);\n@property (copy) void (^failCallback)(NSError *err);\n@property NSString *downloadUrl;\n\n- (id)init:(NSString *)downloadFilePath\noperationQueue:(dispatch_queue_t)operationQueue\nprogressCallback:(void (^)(long long, long long))progressCallback\ndoneCallback:(void (^)(BOOL))doneCallback\nfailCallback:(void (^)(NSError *err))failCallback;\n\n- (void)download:(NSString*)url;\n\n@end\n\n@interface CodePushErrorUtils : NSObject\n\n+ (NSError *)errorWithMessage:(NSString *)errorMessage;\n+ (BOOL)isCodePushError:(NSError *)error;\n\n@end\n\n@interface CodePushPackage : NSObject\n\n+ (void)downloadPackage:(NSDictionary *)updatePackage\n expectedBundleFileName:(NSString *)expectedBundleFileName\n              publicKey:(NSString *)publicKey\n         operationQueue:(dispatch_queue_t)operationQueue\n       progressCallback:(void (^)(long long, long long))progressCallback\n           doneCallback:(void (^)())doneCallback\n           failCallback:(void (^)(NSError *err))failCallback;\n\n+ (NSDictionary *)getCurrentPackage:(NSError **)error;\n+ (NSDictionary *)getPreviousPackage:(NSError **)error;\n+ (NSString *)getCurrentPackageFolderPath:(NSError **)error;\n+ (NSString *)getCurrentPackageBundlePath:(NSError **)error;\n+ (NSString *)getCurrentPackageHash:(NSError **)error;\n\n+ (NSDictionary *)getPackage:(NSString *)packageHash\n                       error:(NSError **)error;\n\n+ (NSString *)getPackageFolderPath:(NSString *)packageHash;\n\n+ (BOOL)installPackage:(NSDictionary *)updatePackage\n   removePendingUpdate:(BOOL)removePendingUpdate\n                 error:(NSError **)error;\n\n+ (void)rollbackPackage;\n\n// The below methods are only used during tests.\n+ (void)clearUpdates;\n+ (void)downloadAndReplaceCurrentBundle:(NSString *)remoteBundleUrl;\n\n@end\n\n@interface CodePushTelemetryManager : NSObject\n\n+ (NSDictionary *)getBinaryUpdateReport:(NSString *)appVersion;\n+ (NSDictionary *)getRetryStatusReport;\n+ (NSDictionary *)getRollbackReport:(NSDictionary *)lastFailedPackage;\n+ (NSDictionary *)getUpdateReport:(NSDictionary *)currentPackage;\n+ (void)recordStatusReported:(NSDictionary *)statusReport;\n+ (void)saveStatusReportForRetry:(NSDictionary *)statusReport;\n\n@end\n\n@interface CodePushUpdateUtils : NSObject\n\n+ (BOOL)copyEntriesInFolder:(NSString *)sourceFolder\n                 destFolder:(NSString *)destFolder\n                      error:(NSError **)error;\n\n+ (NSString *)findMainBundleInFolder:(NSString *)folderPath\n                    expectedFileName:(NSString *)expectedFileName\n                               error:(NSError **)error;\n\n+ (NSString *)assetsFolderName;\n+ (NSString *)getHashForBinaryContents:(NSURL *)binaryBundleUrl\n                                 error:(NSError **)error;\n\n+ (NSString *)manifestFolderPrefix;\n+ (NSString *)modifiedDateStringOfFileAtURL:(NSURL *)fileURL;\n\n+ (BOOL)isHashIgnoredFor:(NSString *) relativePath;\n\n+ (BOOL)verifyFolderHash:(NSString *)finalUpdateFolder\n                   expectedHash:(NSString *)expectedHash\n                          error:(NSError **)error;\n\n// remove BEGIN / END tags and line breaks from public key string\n+ (NSString *)getKeyValueFromPublicKeyString:(NSString *)publicKeyString;\n\n+ (NSString *)getSignatureFilePath:(NSString *)updateFolderPath;\n\n+ (NSDictionary *) verifyAndDecodeJWT:(NSString *) jwt\n               withPublicKey:(NSString *)publicKey\n                       error:(NSError **)error;\n\n+ (BOOL)verifyUpdateSignatureFor:(NSString *)updateFolderPath\n                    expectedHash:(NSString *)newUpdateHash\n                   withPublicKey:(NSString *)publicKeyString\n                           error:(NSError **)error;\n\n@end\n\nvoid CPLog(NSString *formatString, ...);\n\ntypedef NS_ENUM(NSInteger, CodePushInstallMode) {\n    CodePushInstallModeImmediate,\n    CodePushInstallModeOnNextRestart,\n    CodePushInstallModeOnNextResume,\n    CodePushInstallModeOnNextSuspend\n};\n\ntypedef NS_ENUM(NSInteger, CodePushUpdateState) {\n    CodePushUpdateStateRunning,\n    CodePushUpdateStatePending,\n    CodePushUpdateStateLatest\n};\n"
  },
  {
    "path": "ios/CodePush/CodePush.m",
    "content": "#if __has_include(<React/RCTAssert.h>)\n#import <React/RCTAssert.h>\n#import <React/RCTBridgeModule.h>\n#import <React/RCTConvert.h>\n#import <React/RCTEventDispatcher.h>\n#import <React/RCTRootView.h>\n#import <React/RCTUtils.h>\n#import <React/RCTReloadCommand.h>\n#else // back compatibility for RN version < 0.40\n#import \"RCTAssert.h\"\n#import \"RCTBridgeModule.h\"\n#import \"RCTConvert.h\"\n#import \"RCTEventDispatcher.h\"\n#import \"RCTRootView.h\"\n#import \"RCTUtils.h\"\n#endif\n\n#import \"CodePush.h\"\n\n@interface CodePush () <RCTBridgeModule, RCTFrameUpdateObserver>\n@end\n\n@implementation CodePush {\n    BOOL _hasResumeListener;\n    BOOL _isFirstRunAfterUpdate;\n    int _minimumBackgroundDuration;\n    NSDate *_lastResignedDate;\n    CodePushInstallMode _installMode;\n    NSTimer *_appSuspendTimer;\n\n    // Used to coordinate the dispatching of download progress events to JS.\n    long long _latestExpectedContentLength;\n    long long _latestReceivedConentLength;\n    BOOL _didUpdateProgress;\n    \n    BOOL _allowed;\n    BOOL _restartInProgress;\n    NSMutableArray *_restartQueue;\n}\n\nRCT_EXPORT_MODULE()\n\n#pragma mark - Private constants\n\n// These constants represent emitted events\nstatic NSString *const DownloadProgressEvent = @\"CodePushDownloadProgress\";\n\n// These constants represent valid deployment statuses\nstatic NSString *const DeploymentFailed = @\"DeploymentFailed\";\nstatic NSString *const DeploymentSucceeded = @\"DeploymentSucceeded\";\n\n// These keys represent the names we use to store data in NSUserDefaults\nstatic NSString *const FailedUpdatesKey = @\"CODE_PUSH_FAILED_UPDATES\";\nstatic NSString *const PendingUpdateKey = @\"CODE_PUSH_PENDING_UPDATE\";\n\n// These keys are already \"namespaced\" by the PendingUpdateKey, so\n// their values don't need to be obfuscated to prevent collision with app data\nstatic NSString *const PendingUpdateHashKey = @\"hash\";\nstatic NSString *const PendingUpdateIsLoadingKey = @\"isLoading\";\n\n// These keys are used to inspect/augment the metadata\n// that is associated with an update's package.\nstatic NSString *const AppVersionKey = @\"appVersion\";\nstatic NSString *const BinaryBundleDateKey = @\"binaryDate\";\nstatic NSString *const PackageHashKey = @\"packageHash\";\nstatic NSString *const PackageIsPendingKey = @\"isPending\";\n\n#pragma mark - Static variables\n\nstatic BOOL isRunningBinaryVersion = NO;\nstatic BOOL needToReportRollback = NO;\nstatic BOOL testConfigurationFlag = NO;\n\n// These values are used to save the NS bundle, name, extension and subdirectory\n// for the JS bundle in the binary.\nstatic NSBundle *bundleResourceBundle = nil;\nstatic NSString *bundleResourceExtension = @\"jsbundle\";\nstatic NSString *bundleResourceName = @\"main\";\nstatic NSString *bundleResourceSubdirectory = nil;\n\n// These keys represent the names we use to store information about the latest rollback\nstatic NSString *const LatestRollbackInfoKey = @\"LATEST_ROLLBACK_INFO\";\nstatic NSString *const LatestRollbackPackageHashKey = @\"packageHash\";\nstatic NSString *const LatestRollbackTimeKey = @\"time\";\nstatic NSString *const LatestRollbackCountKey = @\"count\";\n\n+ (void)initialize\n{\n    [super initialize];\n    if (self == [CodePush class]) {\n        // Use the mainBundle by default.\n        bundleResourceBundle = [NSBundle mainBundle];\n    }\n}\n\n#pragma mark - Public Obj-C API\n\n+ (NSURL *)binaryBundleURL\n{\n    return [bundleResourceBundle URLForResource:bundleResourceName\n                                  withExtension:bundleResourceExtension\n                                   subdirectory:bundleResourceSubdirectory];\n}\n\n+ (NSString *)bundleAssetsPath\n{\n    NSString *resourcePath = [bundleResourceBundle resourcePath];\n    if (bundleResourceSubdirectory) {\n        resourcePath = [resourcePath stringByAppendingPathComponent:bundleResourceSubdirectory];\n    }\n\n    return [resourcePath stringByAppendingPathComponent:[CodePushUpdateUtils assetsFolderName]];\n}\n\n+ (NSURL *)bundleURL\n{\n    return [self bundleURLForResource:bundleResourceName\n                        withExtension:bundleResourceExtension\n                         subdirectory:bundleResourceSubdirectory\n                               bundle:bundleResourceBundle];\n}\n\n+ (NSURL *)bundleURLForResource:(NSString *)resourceName\n{\n    return [self bundleURLForResource:resourceName\n                        withExtension:bundleResourceExtension\n                         subdirectory:bundleResourceSubdirectory\n                               bundle:bundleResourceBundle];\n}\n\n+ (NSURL *)bundleURLForResource:(NSString *)resourceName\n                  withExtension:(NSString *)resourceExtension\n{\n    return [self bundleURLForResource:resourceName\n                        withExtension:resourceExtension\n                         subdirectory:bundleResourceSubdirectory\n                               bundle:bundleResourceBundle];\n}\n\n+ (NSURL *)bundleURLForResource:(NSString *)resourceName\n                  withExtension:(NSString *)resourceExtension\n                   subdirectory:(NSString *)resourceSubdirectory\n{\n    return [self bundleURLForResource:resourceName\n                        withExtension:resourceExtension\n                         subdirectory:resourceSubdirectory\n                               bundle:bundleResourceBundle];\n}\n\n+ (NSURL *)bundleURLForResource:(NSString *)resourceName\n                  withExtension:(NSString *)resourceExtension\n                   subdirectory:(NSString *)resourceSubdirectory\n                         bundle:(NSBundle *)resourceBundle\n{\n    bundleResourceName = resourceName;\n    bundleResourceExtension = resourceExtension;\n    bundleResourceSubdirectory = resourceSubdirectory;\n    bundleResourceBundle = resourceBundle;\n\n    [self ensureBinaryBundleExists];\n\n    NSString *logMessageFormat = @\"Loading JS bundle from %@\";\n\n    NSError *error;\n    NSString *packageFile = [CodePushPackage getCurrentPackageBundlePath:&error];\n    NSURL *binaryBundleURL = [self binaryBundleURL];\n\n    if (error || !packageFile) {\n        CPLog(logMessageFormat, binaryBundleURL);\n        isRunningBinaryVersion = YES;\n        return binaryBundleURL;\n    }\n\n    NSString *binaryAppVersion = [[CodePushConfig current] appVersion];\n    NSDictionary *currentPackageMetadata = [CodePushPackage getCurrentPackage:&error];\n    if (error || !currentPackageMetadata) {\n        CPLog(logMessageFormat, binaryBundleURL);\n        isRunningBinaryVersion = YES;\n        return binaryBundleURL;\n    }\n\n    NSString *packageDate = [currentPackageMetadata objectForKey:BinaryBundleDateKey];\n    NSString *packageAppVersion = [currentPackageMetadata objectForKey:AppVersionKey];\n\n    if ([[CodePushUpdateUtils modifiedDateStringOfFileAtURL:binaryBundleURL] isEqualToString:packageDate] && ([CodePush isUsingTestConfiguration] ||[binaryAppVersion isEqualToString:packageAppVersion])) {\n        // Return package file because it is newer than the app store binary's JS bundle\n        NSURL *packageUrl = [[NSURL alloc] initFileURLWithPath:packageFile];\n        CPLog(logMessageFormat, packageUrl);\n        isRunningBinaryVersion = NO;\n        return packageUrl;\n    } else {\n        BOOL isRelease = NO;\n#ifndef DEBUG\n        isRelease = YES;\n#endif\n\n        if (isRelease || ![binaryAppVersion isEqualToString:packageAppVersion]) {\n            [CodePush clearUpdates];\n        }\n\n        CPLog(logMessageFormat, binaryBundleURL);\n        isRunningBinaryVersion = YES;\n        return binaryBundleURL;\n    }\n}\n\n+ (NSString *)getApplicationSupportDirectory\n{\n    NSString *applicationSupportDirectory = [NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES) objectAtIndex:0];\n    return applicationSupportDirectory;\n}\n\n+ (void)overrideAppVersion:(NSString *)appVersion\n{\n    [CodePushConfig current].appVersion = appVersion;\n}\n\n+ (void)setDeploymentKey:(NSString *)deploymentKey\n{\n    [CodePushConfig current].deploymentKey = deploymentKey;\n}\n\n/*\n * WARNING: This cleans up all downloaded and pending updates.\n */\n+ (void)clearUpdates\n{\n    [CodePushPackage clearUpdates];\n    [self removePendingUpdate];\n    [self removeFailedUpdates];\n}\n\n#pragma mark - Test-only methods\n\n/*\n * This returns a boolean value indicating whether CodePush has\n * been set to run under a test configuration.\n */\n+ (BOOL)isUsingTestConfiguration\n{\n    return testConfigurationFlag;\n}\n\n/*\n * This is used to enable an environment in which tests can be run.\n * Specifically, it flips a boolean flag that causes bundles to be\n * saved to a test folder and enables the ability to modify\n * installed bundles on the fly from JavaScript.\n */\n+ (void)setUsingTestConfiguration:(BOOL)shouldUseTestConfiguration\n{\n    testConfigurationFlag = shouldUseTestConfiguration;\n}\n\n#pragma mark - Private API methods\n\n@synthesize methodQueue = _methodQueue;\n@synthesize pauseCallback = _pauseCallback;\n@synthesize paused = _paused;\n\n- (void)setPaused:(BOOL)paused\n{\n    if (_paused != paused) {\n        _paused = paused;\n        if (_pauseCallback) {\n            _pauseCallback();\n        }\n    }\n}\n\n/*\n * This method is used to clear updates that are installed\n * under a different app version and hence don't apply anymore,\n * during a debug run configuration and when the bridge is\n * running the JS bundle from the dev server.\n */\n- (void)clearDebugUpdates\n{\n    dispatch_async(dispatch_get_main_queue(), ^{\n        if ([super.bridge.bundleURL.scheme hasPrefix:@\"http\"]) {\n            NSError *error;\n            NSString *binaryAppVersion = [[CodePushConfig current] appVersion];\n            NSDictionary *currentPackageMetadata = [CodePushPackage getCurrentPackage:&error];\n            if (currentPackageMetadata) {\n                NSString *packageAppVersion = [currentPackageMetadata objectForKey:AppVersionKey];\n                if (![binaryAppVersion isEqualToString:packageAppVersion]) {\n                    [CodePush clearUpdates];\n                }\n            }\n        }\n    });\n}\n\n/*\n * This method is used by the React Native bridge to allow\n * our plugin to expose constants to the JS-side. In our case\n * we're simply exporting enum values so that the JS and Native\n * sides of the plugin can be in sync.\n */\n- (NSDictionary *)constantsToExport\n{\n    // Export the values of the CodePushInstallMode and CodePushUpdateState\n    // enums so that the script-side can easily stay in sync\n    return @{\n             @\"codePushInstallModeOnNextRestart\":@(CodePushInstallModeOnNextRestart),\n             @\"codePushInstallModeImmediate\": @(CodePushInstallModeImmediate),\n             @\"codePushInstallModeOnNextResume\": @(CodePushInstallModeOnNextResume),\n             @\"codePushInstallModeOnNextSuspend\": @(CodePushInstallModeOnNextSuspend),\n\n             @\"codePushUpdateStateRunning\": @(CodePushUpdateStateRunning),\n             @\"codePushUpdateStatePending\": @(CodePushUpdateStatePending),\n             @\"codePushUpdateStateLatest\": @(CodePushUpdateStateLatest)\n            };\n};\n\n+ (BOOL)requiresMainQueueSetup\n{\n    return YES;\n}\n\n- (void)dealloc\n{\n    // Ensure the global resume handler is cleared, so that\n    // this object isn't kept alive unnecessarily\n    [[NSNotificationCenter defaultCenter] removeObserver:self];\n}\n\n- (void)dispatchDownloadProgressEvent {\n  // Notify the script-side about the progress\n  [self sendEventWithName:DownloadProgressEvent\n                     body:@{\n                       @\"totalBytes\" : [NSNumber\n                           numberWithLongLong:_latestExpectedContentLength],\n                       @\"receivedBytes\" : [NSNumber\n                           numberWithLongLong:_latestReceivedConentLength]\n                     }];\n}\n\n/*\n * This method ensures that the app was packaged with a JS bundle\n * file, and if not, it throws the appropriate exception.\n */\n+ (void)ensureBinaryBundleExists\n{\n    if (![self binaryBundleURL]) {\n        NSString *errorMessage;\n\n    #ifdef DEBUG\n        #if TARGET_IPHONE_SIMULATOR\n            errorMessage = @\"React Native doesn't generate your app's JS bundle by default when deploying to the simulator. \"\n            \"If you'd like to test CodePush using the simulator, you can do one of the following depending on your \"\n            \"React Native version and/or preferred workflow:\\n\\n\"\n\n            \"1. Update your AppDelegate.m file to load the JS bundle from the packager instead of from CodePush. \"\n            \"You can still test your CodePush update experience using this workflow (Debug builds only).\\n\\n\"\n\n            \"2. Force the JS bundle to be generated in simulator builds by adding 'export FORCE_BUNDLING=true' to the script under \"\n            \"\\\"Build Phases\\\" > \\\"Bundle React Native code and images\\\" (React Native >=0.48 only).\\n\\n\"\n\n            \"3. Force the JS bundle to be generated in simulator builds by removing the if block that echoes \"\n            \"\\\"Skipping bundling for Simulator platform\\\" in the \\\"node_modules/react-native/packager/react-native-xcode.sh\\\" file (React Native <=0.47 only)\\n\\n\"\n\n            \"4. Deploy a Release build to the simulator, which unlike Debug builds, will generate the JS bundle (React Native >=0.22.0 only).\";\n        #else\n            errorMessage = [NSString stringWithFormat:@\"The specified JS bundle file wasn't found within the app's binary. Is \\\"%@\\\" the correct file name?\", [bundleResourceName stringByAppendingPathExtension:bundleResourceExtension]];\n        #endif\n    #else\n        errorMessage = @\"Something went wrong. Please verify if generated JS bundle is correct. \";\n    #endif\n\n        RCTFatal([CodePushErrorUtils errorWithMessage:errorMessage]);\n    }\n}\n\n- (instancetype)init\n{\n    _allowed = YES;\n    _restartInProgress = NO;\n    _restartQueue = [NSMutableArray arrayWithCapacity:1];\n    \n    self = [super init];\n    if (self) {\n        [self initializeUpdateAfterRestart];\n    }\n\n    return self;\n}\n\n/*\n * This method is used when the app is started to either\n * initialize a pending update or rollback a faulty update\n * to the previous version.\n */\n- (void)initializeUpdateAfterRestart\n{\n#ifdef DEBUG\n    [self clearDebugUpdates];\n#endif\n    self.paused = YES;\n    NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults];\n    NSDictionary *pendingUpdate = [preferences objectForKey:PendingUpdateKey];\n    if (pendingUpdate) {\n        _isFirstRunAfterUpdate = YES;\n        BOOL updateIsLoading = [pendingUpdate[PendingUpdateIsLoadingKey] boolValue];\n        if (updateIsLoading) {\n            // Pending update was initialized, but notifyApplicationReady was not called.\n            // Therefore, deduce that it is a broken update and rollback.\n            CPLog(@\"Update did not finish loading the last time, rolling back to a previous version.\");\n            needToReportRollback = YES;\n            [self rollbackPackage];\n        } else {\n            // Mark that we tried to initialize the new update, so that if it crashes,\n            // we will know that we need to rollback when the app next starts.\n            [self savePendingUpdate:pendingUpdate[PendingUpdateHashKey]\n                          isLoading:YES];\n        }\n    }\n}\n\n/*\n * This method is used to get information about the latest rollback.\n * This information will be used to decide whether the application\n * should ignore the update or not.\n */\n+ (NSDictionary *)getLatestRollbackInfo\n{\n    NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults];\n    NSDictionary *latestRollbackInfo = [preferences objectForKey:LatestRollbackInfoKey];\n    return latestRollbackInfo;\n}\n\n/*\n * This method is used to save information about the latest rollback.\n * This information will be used to decide whether the application\n * should ignore the update or not.\n */\n+ (void)setLatestRollbackInfo:(NSString*)packageHash\n{\n    if (packageHash == nil) {\n        return;\n    }\n\n    NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults];\n    NSMutableDictionary *latestRollbackInfo = [preferences objectForKey:LatestRollbackInfoKey];\n    if (latestRollbackInfo == nil) {\n        latestRollbackInfo = [[NSMutableDictionary alloc] init];\n    } else {\n        latestRollbackInfo = [latestRollbackInfo mutableCopy];\n    }\n\n    int initialRollbackCount = [self getRollbackCountForPackage: packageHash fromLatestRollbackInfo: latestRollbackInfo];\n    NSNumber *count = [NSNumber numberWithInt: initialRollbackCount + 1];\n    NSNumber *currentTimeMillis = [NSNumber numberWithDouble: [[NSDate date] timeIntervalSince1970] * 1000];\n\n    [latestRollbackInfo setValue:count forKey:LatestRollbackCountKey];\n    [latestRollbackInfo setValue:currentTimeMillis forKey:LatestRollbackTimeKey];\n    [latestRollbackInfo setValue:packageHash forKey:LatestRollbackPackageHashKey];\n\n    [preferences setObject:latestRollbackInfo forKey:LatestRollbackInfoKey];\n    [preferences synchronize];\n}\n\n/*\n * This method is used to get the count of rollback for the package\n * using the latest rollback information.\n */\n+ (int)getRollbackCountForPackage:(NSString*) packageHash fromLatestRollbackInfo:(NSMutableDictionary*) latestRollbackInfo\n{\n    NSString *oldPackageHash = [latestRollbackInfo objectForKey:LatestRollbackPackageHashKey];\n    if ([packageHash isEqualToString: oldPackageHash]) {\n        NSNumber *oldCount = [latestRollbackInfo objectForKey:LatestRollbackCountKey];\n        return [oldCount intValue];\n    } else {\n        return 0;\n    }\n}\n\n/*\n * This method checks to see whether a specific package hash\n * has previously failed installation.\n */\n+ (BOOL)isFailedHash:(NSString*)packageHash\n{\n    NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults];\n    NSMutableArray *failedUpdates = [preferences objectForKey:FailedUpdatesKey];\n    if (failedUpdates == nil || packageHash == nil) {\n        return NO;\n    } else {\n        for (NSDictionary *failedPackage in failedUpdates)\n        {\n            // Type check is needed for backwards compatibility, where we used to just store\n            // the failed package hash instead of the metadata. This only impacts \"dev\"\n            // scenarios, since in production we clear out old information whenever a new\n            // binary is applied.\n            if ([failedPackage isKindOfClass:[NSDictionary class]]) {\n                NSString *failedPackageHash = [failedPackage objectForKey:PackageHashKey];\n                if ([packageHash isEqualToString:failedPackageHash]) {\n                    return YES;\n                }\n            }\n        }\n\n        return NO;\n    }\n}\n\n/*\n * This method checks to see whether a specific package hash\n * represents a downloaded and installed update, that hasn't\n * been applied yet via an app restart.\n */\n+ (BOOL)isPendingUpdate:(NSString*)packageHash\n{\n    NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults];\n    NSDictionary *pendingUpdate = [preferences objectForKey:PendingUpdateKey];\n\n    // If there is a pending update whose \"state\" isn't loading, then we consider it \"pending\".\n    // Additionally, if a specific hash was provided, we ensure it matches that of the pending update.\n    BOOL updateIsPending = pendingUpdate &&\n                           [pendingUpdate[PendingUpdateIsLoadingKey] boolValue] == NO &&\n                           (!packageHash || [pendingUpdate[PendingUpdateHashKey] isEqualToString:packageHash]);\n\n    return updateIsPending;\n}\n\n/*\n * This method updates the React Native bridge's bundle URL\n * to point at the latest CodePush update, and then restarts\n * the bridge. This isn't meant to be called directly.\n */\n- (void)loadBundle\n{\n    // This needs to be async dispatched because the bridge is not set on init\n    // when the app first starts, therefore rollbacks will not take effect.\n    dispatch_async(dispatch_get_main_queue(), ^{\n        // If the current bundle URL is using http(s), then assume the dev\n        // is debugging and therefore, shouldn't be redirected to a local\n        // file (since Chrome wouldn't support it). Otherwise, update\n        // the current bundle URL to point at the latest update\n        if ([CodePush isUsingTestConfiguration] || ![super.bridge.bundleURL.scheme hasPrefix:@\"http\"]) {\n            [super.bridge setValue:[CodePush bundleURL] forKey:@\"bundleURL\"];\n        }\n\n        RCTTriggerReloadCommandListeners(@\"react-native-code-push: Restart\");\n    });\n}\n\n/*\n * This method is used when an update has failed installation\n * and the app needs to be rolled back to the previous bundle.\n * This method is automatically called when the rollback timer\n * expires without the app indicating whether the update succeeded,\n * and therefore, it shouldn't be called directly.\n */\n- (void)rollbackPackage\n{\n    NSError *error;\n    NSDictionary *failedPackage = [CodePushPackage getCurrentPackage:&error];\n    if (!failedPackage) {\n        if (error) {\n            CPLog(@\"Error getting current update metadata during rollback: %@\", error);\n        } else {\n            CPLog(@\"Attempted to perform a rollback when there is no current update\");\n        }\n    } else {\n        // Write the current package's metadata to the \"failed list\"\n        [self saveFailedUpdate:failedPackage];\n    }\n\n    // Rollback to the previous version and de-register the new update\n    [CodePushPackage rollbackPackage];\n    [CodePush removePendingUpdate];\n    [self loadBundle];\n}\n\n/*\n * When an update failed to apply, this method can be called\n * to store its hash so that it can be ignored on future\n * attempts to check the server for an update.\n */\n- (void)saveFailedUpdate:(NSDictionary *)failedPackage\n{\n    if ([[self class] isFailedHash:[failedPackage objectForKey:PackageHashKey]]) {\n        return;\n    }\n    \n    NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults];\n    NSMutableArray *failedUpdates = [preferences objectForKey:FailedUpdatesKey];\n    if (failedUpdates == nil) {\n        failedUpdates = [[NSMutableArray alloc] init];\n    } else {\n        // The NSUserDefaults sytem always returns immutable\n        // objects, regardless if you stored something mutable.\n        failedUpdates = [failedUpdates mutableCopy];\n    }\n\n    [failedUpdates addObject:failedPackage];\n    [preferences setObject:failedUpdates forKey:FailedUpdatesKey];\n    [preferences synchronize];\n}\n\n/*\n * This method is used to clear away failed updates in the event that\n * a new app store binary is installed.\n */\n+ (void)removeFailedUpdates\n{\n    NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults];\n    [preferences removeObjectForKey:FailedUpdatesKey];\n    [preferences synchronize];\n}\n\n/*\n * This method is used to register the fact that a pending\n * update succeeded and therefore can be removed.\n */\n+ (void)removePendingUpdate\n{\n    NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults];\n    [preferences removeObjectForKey:PendingUpdateKey];\n    [preferences synchronize];\n}\n\n/*\n * When an update is installed whose mode isn't IMMEDIATE, this method\n * can be called to store the pending update's metadata (e.g. packageHash)\n * so that it can be used when the actual update application occurs at a later point.\n */\n- (void)savePendingUpdate:(NSString *)packageHash\n                isLoading:(BOOL)isLoading\n{\n    // Since we're not restarting, we need to store the fact that the update\n    // was installed, but hasn't yet become \"active\".\n    NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults];\n    NSDictionary *pendingUpdate = [[NSDictionary alloc] initWithObjectsAndKeys:\n                                   packageHash,PendingUpdateHashKey,\n                                   [NSNumber numberWithBool:isLoading],PendingUpdateIsLoadingKey, nil];\n\n    [preferences setObject:pendingUpdate forKey:PendingUpdateKey];\n    [preferences synchronize];\n}\n\n- (NSArray<NSString *> *)supportedEvents {\n    return @[DownloadProgressEvent];\n}\n\n// Determine how long the app was in the background\n- (int)getDurationInBackground\n{\n    int duration = 0;\n    if (_lastResignedDate) {\n        duration = [[NSDate date] timeIntervalSinceDate:_lastResignedDate];\n    }\n\n    return duration;\n}\n\n#pragma mark - Application lifecycle event handlers\n\n// These three handlers will only be registered when there is\n// a resume-based update still pending installation.\n- (void)applicationDidBecomeActive\n{\n    if (_installMode == CodePushInstallModeOnNextSuspend) {\n        int durationInBackground = [self getDurationInBackground];\n        // We shouldn't use loadBundle in this case, because _appSuspendTimer will call loadBundleOnTick.\n        // We should cancel timer for _appSuspendTimer because otherwise, we would call loadBundle two times.\n        if (durationInBackground < _minimumBackgroundDuration) {\n            [_appSuspendTimer invalidate];\n            _appSuspendTimer = nil;\n        }\n    }\n}\n\n- (void)applicationWillEnterForeground\n{\n    if (_installMode == CodePushInstallModeOnNextResume) {\n        int durationInBackground = [self getDurationInBackground];\n        if (durationInBackground >= _minimumBackgroundDuration) {\n            [self restartAppInternal:NO];\n        }\n    }\n}\n\n- (void)applicationWillResignActive\n{\n    // Save the current time so that when the app is later\n    // resumed, we can detect how long it was in the background.\n    _lastResignedDate = [NSDate date];\n\n    if (_installMode == CodePushInstallModeOnNextSuspend && [[self class] isPendingUpdate:nil]) {\n        _appSuspendTimer = [NSTimer scheduledTimerWithTimeInterval:_minimumBackgroundDuration\n                                                         target:self\n                                                       selector:@selector(loadBundleOnTick:)\n                                                       userInfo:nil\n                                                        repeats:NO];\n    }\n}\n\n-(void)loadBundleOnTick:(NSTimer *)timer {\n    [self restartAppInternal:NO];\n}\n\n#pragma mark - JavaScript-exported module methods (Public)\n\n/*\n * This is native-side of the RemotePackage.download method\n */\nRCT_EXPORT_METHOD(downloadUpdate:(NSDictionary*)updatePackage\n                  notifyProgress:(BOOL)notifyProgress\n                        resolver:(RCTPromiseResolveBlock)resolve\n                        rejecter:(RCTPromiseRejectBlock)reject)\n{\n    NSDictionary *mutableUpdatePackage = [updatePackage mutableCopy];\n    NSURL *binaryBundleURL = [CodePush binaryBundleURL];\n    if (binaryBundleURL != nil) {\n        [mutableUpdatePackage setValue:[CodePushUpdateUtils modifiedDateStringOfFileAtURL:binaryBundleURL]\n                                forKey:BinaryBundleDateKey];\n    }\n\n    if (notifyProgress) {\n        // Set up and unpause the frame observer so that it can emit\n        // progress events every frame if the progress is updated.\n        _didUpdateProgress = NO;\n        self.paused = NO;\n    }\n\n    NSString * publicKey = [[CodePushConfig current] publicKey];\n\n    [CodePushPackage\n        downloadPackage:mutableUpdatePackage\n        expectedBundleFileName:[bundleResourceName stringByAppendingPathExtension:bundleResourceExtension]\n        publicKey:publicKey\n        operationQueue:_methodQueue\n        // The download is progressing forward\n        progressCallback:^(long long expectedContentLength, long long receivedContentLength) {\n            // Update the download progress so that the frame observer can notify the JS side\n            _latestExpectedContentLength = expectedContentLength;\n            _latestReceivedConentLength = receivedContentLength;\n            _didUpdateProgress = YES;\n\n            // If the download is completed, stop observing frame\n            // updates and synchronously send the last event.\n            if (expectedContentLength == receivedContentLength) {\n                _didUpdateProgress = NO;\n                self.paused = YES;\n                [self dispatchDownloadProgressEvent];\n            }\n        }\n        // The download completed\n        doneCallback:^{\n            NSError *err;\n            NSDictionary *newPackage = [CodePushPackage getPackage:mutableUpdatePackage[PackageHashKey] error:&err];\n\n            if (err) {\n                return reject([NSString stringWithFormat: @\"%lu\", (long)err.code], err.localizedDescription, err);\n            }\n            resolve(newPackage);\n        }\n        // The download failed\n        failCallback:^(NSError *err) {\n            if ([CodePushErrorUtils isCodePushError:err]) {\n                [self saveFailedUpdate:mutableUpdatePackage];\n            }\n\n            // Stop observing frame updates if the download fails.\n            _didUpdateProgress = NO;\n            self.paused = YES;\n            reject([NSString stringWithFormat: @\"%lu\", (long)err.code], err.localizedDescription, err);\n        }];\n}\n\n- (void)restartAppInternal:(BOOL)onlyIfUpdateIsPending\n{\n    if (_restartInProgress) {\n        CPLog(@\"Restart request queued until the current restart is completed.\");\n        [_restartQueue addObject:@(onlyIfUpdateIsPending)];\n        return;\n    } else if (!_allowed) {\n        CPLog(@\"Restart request queued until restarts are re-allowed.\");\n        [_restartQueue addObject:@(onlyIfUpdateIsPending)];\n        return;\n    }\n\n    _restartInProgress = YES;\n    if (!onlyIfUpdateIsPending || [[self class] isPendingUpdate:nil]) {\n        [self loadBundle];\n        CPLog(@\"Restarting app.\");\n        return;\n    }\n\n    _restartInProgress = NO;\n    if ([_restartQueue count] > 0) {\n        BOOL buf = [_restartQueue valueForKey: @\"@firstObject\"];\n        [_restartQueue removeObjectAtIndex:0];\n        [self restartAppInternal:buf];\n    }\n}\n\n/*\n * This is the native side of the CodePush.getConfiguration method. It isn't\n * currently exposed via the \"react-native-code-push\" module, and is used\n * internally only by the CodePush.checkForUpdate method in order to get the\n * app version, as well as the deployment key that was configured in the Info.plist file.\n */\nRCT_EXPORT_METHOD(getConfiguration:(RCTPromiseResolveBlock)resolve\n                          rejecter:(RCTPromiseRejectBlock)reject)\n{\n    NSDictionary *configuration = [[CodePushConfig current] configuration];\n    NSError *error;\n    if (isRunningBinaryVersion) {\n        // isRunningBinaryVersion will not get set to \"YES\" if running against the packager.\n        NSString *binaryHash = [CodePushUpdateUtils getHashForBinaryContents:[CodePush binaryBundleURL] error:&error];\n        if (error) {\n            CPLog(@\"Error obtaining hash for binary contents: %@\", error);\n            resolve(configuration);\n            return;\n        }\n\n        if (binaryHash == nil) {\n            // The hash was not generated either due to a previous unknown error or the fact that\n            // the React Native assets were not bundled in the binary (e.g. during dev/simulator)\n            // builds.\n            resolve(configuration);\n            return;\n        }\n\n        NSMutableDictionary *mutableConfiguration = [configuration mutableCopy];\n        [mutableConfiguration setObject:binaryHash forKey:PackageHashKey];\n        resolve(mutableConfiguration);\n        return;\n    }\n\n    resolve(configuration);\n}\n\n/*\n * This method is the native side of the CodePush.getUpdateMetadata method.\n */\nRCT_EXPORT_METHOD(getUpdateMetadata:(CodePushUpdateState)updateState\n                           resolver:(RCTPromiseResolveBlock)resolve\n                           rejecter:(RCTPromiseRejectBlock)reject)\n{\n    NSError *error;\n    NSMutableDictionary *package = [[CodePushPackage getCurrentPackage:&error] mutableCopy];\n\n    if (error) {\n        return reject([NSString stringWithFormat: @\"%lu\", (long)error.code], error.localizedDescription, error);\n    } else if (package == nil) {\n        // The app hasn't downloaded any CodePush updates yet,\n        // so we simply return nil regardless if the user\n        // wanted to retrieve the pending or running update.\n        return resolve(nil);\n    }\n\n    // We have a CodePush update, so let's see if it's currently in a pending state.\n    BOOL currentUpdateIsPending = [[self class] isPendingUpdate:[package objectForKey:PackageHashKey]];\n\n    if (updateState == CodePushUpdateStatePending && !currentUpdateIsPending) {\n        // The caller wanted a pending update\n        // but there isn't currently one.\n        resolve(nil);\n    } else if (updateState == CodePushUpdateStateRunning && currentUpdateIsPending) {\n        // The caller wants the running update, but the current\n        // one is pending, so we need to grab the previous.\n        resolve([CodePushPackage getPreviousPackage:&error]);\n    } else {\n        // The current package satisfies the request:\n        // 1) Caller wanted a pending, and there is a pending update\n        // 2) Caller wanted the running update, and there isn't a pending\n        // 3) Caller wants the latest update, regardless if it's pending or not\n        if (isRunningBinaryVersion) {\n            // This only matters in Debug builds. Since we do not clear \"outdated\" updates,\n            // we need to indicate to the JS side that somehow we have a current update on\n            // disk that is not actually running.\n            [package setObject:@(YES) forKey:@\"_isDebugOnly\"];\n        }\n\n        // Enable differentiating pending vs. non-pending updates\n        [package setObject:@(currentUpdateIsPending) forKey:PackageIsPendingKey];\n        resolve(package);\n    }\n}\n\n/*\n * This method is the native side of the LocalPackage.install method.\n */\nRCT_EXPORT_METHOD(installUpdate:(NSDictionary*)updatePackage\n                    installMode:(CodePushInstallMode)installMode\n      minimumBackgroundDuration:(int)minimumBackgroundDuration\n                       resolver:(RCTPromiseResolveBlock)resolve\n                       rejecter:(RCTPromiseRejectBlock)reject)\n{\n    NSError *error;\n    [CodePushPackage installPackage:updatePackage\n                removePendingUpdate:[[self class] isPendingUpdate:nil]\n                              error:&error];\n\n    if (error) {\n        reject([NSString stringWithFormat: @\"%lu\", (long)error.code], error.localizedDescription, error);\n    } else {\n        [self savePendingUpdate:updatePackage[PackageHashKey]\n                      isLoading:NO];\n\n        _installMode = installMode;\n        if (_installMode == CodePushInstallModeOnNextResume || _installMode == CodePushInstallModeOnNextSuspend) {\n            _minimumBackgroundDuration = minimumBackgroundDuration;\n\n            if (!_hasResumeListener) {\n                // Ensure we do not add the listener twice.\n                // Register for app resume notifications so that we\n                // can check for pending updates which support \"restart on resume\"\n                [[NSNotificationCenter defaultCenter] addObserver:self\n                                                         selector:@selector(applicationDidBecomeActive)\n                                                             name:UIApplicationDidBecomeActiveNotification\n                                                           object:RCTSharedApplication()];\n                                                           \n                [[NSNotificationCenter defaultCenter] addObserver:self\n                                                         selector:@selector(applicationWillEnterForeground)\n                                                             name:UIApplicationWillEnterForegroundNotification\n                                                           object:RCTSharedApplication()];\n\n                [[NSNotificationCenter defaultCenter] addObserver:self\n                                                         selector:@selector(applicationWillResignActive)\n                                                             name:UIApplicationWillResignActiveNotification\n                                                           object:RCTSharedApplication()];\n\n                _hasResumeListener = YES;\n            }\n        }\n\n        // Signal to JS that the update has been applied.\n        resolve(nil);\n    }\n}\n\n/*\n * This method isn't publicly exposed via the \"react-native-code-push\"\n * module, and is only used internally to populate the RemotePackage.failedInstall property.\n */\nRCT_EXPORT_METHOD(isFailedUpdate:(NSString *)packageHash\n                         resolve:(RCTPromiseResolveBlock)resolve\n                          reject:(RCTPromiseRejectBlock)reject)\n{\n    BOOL isFailedHash = [[self class] isFailedHash:packageHash];\n    resolve(@(isFailedHash));\n}\n\nRCT_EXPORT_METHOD(setLatestRollbackInfo:(NSString *)packageHash\n                  resolve:(RCTPromiseResolveBlock)resolve\n                  reject:(RCTPromiseRejectBlock)reject)\n{\n    [[self class] setLatestRollbackInfo:packageHash];\n    resolve(nil);\n}\n\n\nRCT_EXPORT_METHOD(getLatestRollbackInfo:(RCTPromiseResolveBlock)resolve\n                  rejecter:(RCTPromiseRejectBlock)reject)\n{\n    NSDictionary *latestRollbackInfo = [[self class] getLatestRollbackInfo];\n    resolve(latestRollbackInfo);\n}\n\n/*\n * This method isn't publicly exposed via the \"react-native-code-push\"\n * module, and is only used internally to populate the LocalPackage.isFirstRun property.\n */\nRCT_EXPORT_METHOD(isFirstRun:(NSString *)packageHash\n                     resolve:(RCTPromiseResolveBlock)resolve\n                    rejecter:(RCTPromiseRejectBlock)reject)\n{\n    NSError *error;\n    BOOL isFirstRun = _isFirstRunAfterUpdate\n                        && nil != packageHash\n                        && [packageHash length] > 0\n                        && [packageHash isEqualToString:[CodePushPackage getCurrentPackageHash:&error]];\n\n    resolve(@(isFirstRun));\n}\n\n/*\n * This method is the native side of the CodePush.notifyApplicationReady() method.\n */\nRCT_EXPORT_METHOD(notifyApplicationReady:(RCTPromiseResolveBlock)resolve\n                                rejecter:(RCTPromiseRejectBlock)reject)\n{\n    [CodePush removePendingUpdate];\n    resolve(nil);\n}\n\nRCT_EXPORT_METHOD(allow:(RCTPromiseResolveBlock)resolve\n                    rejecter:(RCTPromiseRejectBlock)reject)\n{\n    CPLog(@\"Re-allowing restarts.\");\n    _allowed = YES;\n\n    if ([_restartQueue count] > 0) {\n        CPLog(@\"Executing pending restart.\");\n        BOOL buf = [_restartQueue valueForKey: @\"@firstObject\"];\n        [_restartQueue removeObjectAtIndex:0];\n        [self restartAppInternal:buf];\n    }\n\n    resolve(nil);\n}\n\nRCT_EXPORT_METHOD(clearPendingRestart:(RCTPromiseResolveBlock)resolve\n                    rejecter:(RCTPromiseRejectBlock)reject)\n{\n    [_restartQueue removeAllObjects];\n    resolve(nil);\n}\n\nRCT_EXPORT_METHOD(disallow:(RCTPromiseResolveBlock)resolve\n                    rejecter:(RCTPromiseRejectBlock)reject)\n{\n    CPLog(@\"Disallowing restarts.\");\n    _allowed = NO;\n    resolve(nil);\n}\n\n/*\n * This method is the native side of the CodePush.restartApp() method.\n */\nRCT_EXPORT_METHOD(restartApp:(BOOL)onlyIfUpdateIsPending\n                     resolve:(RCTPromiseResolveBlock)resolve\n                    rejecter:(RCTPromiseRejectBlock)reject)\n{\n    [self restartAppInternal:onlyIfUpdateIsPending];\n    resolve(nil);\n}\n\n/*\n * This method clears CodePush's downloaded updates.\n * It is needed to switch to a different deployment if the current deployment is more recent.\n * Note: we don’t recommend to use this method in scenarios other than that (CodePush will call this method\n * automatically when needed in other cases) as it could lead to unpredictable behavior.\n */\nRCT_EXPORT_METHOD(clearUpdates) {\n    CPLog(@\"Clearing updates.\");\n    [CodePush clearUpdates];\n}\n\n#pragma mark - JavaScript-exported module methods (Private)\n\n/*\n * This method is the native side of the CodePush.downloadAndReplaceCurrentBundle()\n * method, which replaces the current bundle with the one downloaded from\n * removeBundleUrl. It is only to be used during tests and no-ops if the test\n * configuration flag is not set.\n */\nRCT_EXPORT_METHOD(downloadAndReplaceCurrentBundle:(NSString *)remoteBundleUrl)\n{\n    if ([CodePush isUsingTestConfiguration]) {\n        [CodePushPackage downloadAndReplaceCurrentBundle:remoteBundleUrl];\n    }\n}\n\n/*\n * This method is checks if a new status update exists (new version was installed,\n * or an update failed) and return its details (version label, status).\n */\nRCT_EXPORT_METHOD(getNewStatusReport:(RCTPromiseResolveBlock)resolve\n                            rejecter:(RCTPromiseRejectBlock)reject)\n{\n    if (needToReportRollback) {\n        needToReportRollback = NO;\n        NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults];\n        NSMutableArray *failedUpdates = [preferences objectForKey:FailedUpdatesKey];\n        if (failedUpdates) {\n            NSDictionary *lastFailedPackage = [failedUpdates lastObject];\n            if (lastFailedPackage) {\n                resolve([CodePushTelemetryManager getRollbackReport:lastFailedPackage]);\n                return;\n            }\n        }\n    } else if (_isFirstRunAfterUpdate) {\n        NSError *error;\n        NSDictionary *currentPackage = [CodePushPackage getCurrentPackage:&error];\n        if (!error && currentPackage) {\n            resolve([CodePushTelemetryManager getUpdateReport:currentPackage]);\n            return;\n        }\n    } else if (isRunningBinaryVersion) {\n        NSString *appVersion = [[CodePushConfig current] appVersion];\n        resolve([CodePushTelemetryManager getBinaryUpdateReport:appVersion]);\n        return;\n    } else {\n        NSDictionary *retryStatusReport = [CodePushTelemetryManager getRetryStatusReport];\n        if (retryStatusReport) {\n            resolve(retryStatusReport);\n            return;\n        }\n    }\n\n    resolve(nil);\n}\n\nRCT_EXPORT_METHOD(recordStatusReported:(NSDictionary *)statusReport)\n{\n    [CodePushTelemetryManager recordStatusReported:statusReport];\n}\n\nRCT_EXPORT_METHOD(saveStatusReportForRetry:(NSDictionary *)statusReport)\n{\n    [CodePushTelemetryManager saveStatusReportForRetry:statusReport];\n}\n\n#pragma mark - RCTFrameUpdateObserver Methods\n\n- (void)didUpdateFrame:(RCTFrameUpdate *)update\n{\n    if (!_didUpdateProgress) {\n        return;\n    }\n\n    [self dispatchDownloadProgressEvent];\n    _didUpdateProgress = NO;\n}\n\n@end\n"
  },
  {
    "path": "ios/CodePush/CodePushConfig.m",
    "content": "#import \"CodePush.h\"\n#import <UIKit/UIKit.h>\n\n@implementation CodePushConfig {\n    NSMutableDictionary *_configDictionary;\n}\n\nstatic CodePushConfig *_currentConfig;\n\nstatic NSString * const AppVersionConfigKey = @\"appVersion\";\nstatic NSString * const BuildVersionConfigKey = @\"buildVersion\";\nstatic NSString * const ClientUniqueIDConfigKey = @\"clientUniqueId\";\nstatic NSString * const DeploymentKeyConfigKey = @\"deploymentKey\";\nstatic NSString * const ServerURLConfigKey = @\"serverUrl\";\nstatic NSString * const PublicKeyKey = @\"publicKey\";\n\n+ (instancetype)current\n{\n    return _currentConfig;\n}\n\n+ (void)initialize\n{\n    if (self == [CodePushConfig class]) {\n        _currentConfig = [[CodePushConfig alloc] init];\n    }\n}\n\n- (instancetype)init\n{\n    self = [super init];\n    NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary];\n\n    NSString *appVersion = [infoDictionary objectForKey:@\"CFBundleShortVersionString\"];\n    NSString *buildVersion = [infoDictionary objectForKey:(NSString *)kCFBundleVersionKey];\n    NSString *deploymentKey = [infoDictionary objectForKey:@\"CodePushDeploymentKey\"];\n    NSString *serverURL = [infoDictionary objectForKey:@\"CodePushServerURL\"];\n    NSString *publicKey = [infoDictionary objectForKey:@\"CodePushPublicKey\"];\n    \n    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];\n    NSString *clientUniqueId = [userDefaults stringForKey:ClientUniqueIDConfigKey];\n    if (clientUniqueId == nil) {\n        clientUniqueId = [[[UIDevice currentDevice] identifierForVendor] UUIDString];\n        [userDefaults setObject:clientUniqueId forKey:ClientUniqueIDConfigKey];\n        [userDefaults synchronize];\n    }\n\n    if (!serverURL) {\n        serverURL = @\"https://codepush.appcenter.ms/\";\n    }\n\n    _configDictionary = [NSMutableDictionary dictionary];\n\n    if (appVersion) [_configDictionary setObject:appVersion forKey:AppVersionConfigKey];\n    if (buildVersion) [_configDictionary setObject:buildVersion forKey:BuildVersionConfigKey];\n    if (serverURL) [_configDictionary setObject:serverURL forKey:ServerURLConfigKey];\n    if (clientUniqueId) [_configDictionary setObject:clientUniqueId forKey:ClientUniqueIDConfigKey];\n    if (deploymentKey) [_configDictionary setObject:deploymentKey forKey:DeploymentKeyConfigKey];\n    if (publicKey) [_configDictionary setObject:publicKey forKey:PublicKeyKey];\n\n    return self;\n}\n\n- (NSString *)appVersion\n{\n    return [_configDictionary objectForKey:AppVersionConfigKey];\n}\n\n- (NSString *)buildVersion\n{\n    return [_configDictionary objectForKey:BuildVersionConfigKey];\n}\n\n- (NSDictionary *)configuration\n{\n    return _configDictionary;\n}\n\n- (NSString *)deploymentKey\n{\n    return [_configDictionary objectForKey:DeploymentKeyConfigKey];\n}\n\n- (NSString *)serverURL\n{\n    return [_configDictionary objectForKey:ServerURLConfigKey];\n}\n\n- (NSString *)clientUniqueId\n{\n    return [_configDictionary objectForKey:ClientUniqueIDConfigKey];\n}\n\n- (NSString *)publicKey\n{\n    return [_configDictionary objectForKey:PublicKeyKey];\n}\n\n- (void)setAppVersion:(NSString *)appVersion\n{\n    [_configDictionary setValue:appVersion forKey:AppVersionConfigKey];\n}\n\n- (void)setDeploymentKey:(NSString *)deploymentKey\n{\n    [_configDictionary setValue:deploymentKey forKey:DeploymentKeyConfigKey];\n}\n\n- (void)setServerURL:(NSString *)serverURL\n{\n    [_configDictionary setValue:serverURL forKey:ServerURLConfigKey];\n}\n\n//no setter for PublicKey, because it's need to be hard coded within Info.plist for safety\n\n@end\n"
  },
  {
    "path": "ios/CodePush/CodePushDownloadHandler.m",
    "content": "#import \"CodePush.h\"\n\n@implementation CodePushDownloadHandler {\n    // Header chars used to determine if the file is a zip.\n    char _header[4];\n}\n\n- (id)init:(NSString *)downloadFilePath\noperationQueue:(dispatch_queue_t)operationQueue\nprogressCallback:(void (^)(long long, long long))progressCallback\ndoneCallback:(void (^)(BOOL))doneCallback\nfailCallback:(void (^)(NSError *err))failCallback {\n    self.outputFileStream = [NSOutputStream outputStreamToFileAtPath:downloadFilePath\n                                                              append:NO];\n    self.receivedContentLength = 0;\n    self.operationQueue = operationQueue;\n    self.progressCallback = progressCallback;\n    self.doneCallback = doneCallback;\n    self.failCallback = failCallback;\n    return self;\n}\n\n- (void)download:(NSString *)url {\n    self.downloadUrl = url;\n    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]\n                                             cachePolicy:NSURLRequestUseProtocolCachePolicy\n                                         timeoutInterval:60.0];\n    NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request\n                                                                  delegate:self\n                                                          startImmediately:NO];\n    if ([NSOperationQueue instancesRespondToSelector:@selector(setUnderlyingQueue:)]) {\n        NSOperationQueue *delegateQueue = [NSOperationQueue new];\n        delegateQueue.underlyingQueue = self.operationQueue;\n        [connection setDelegateQueue:delegateQueue];\n    } else {\n        [connection scheduleInRunLoop:[NSRunLoop mainRunLoop]\n                              forMode:NSDefaultRunLoopMode];\n    }\n\n    [connection start];\n}\n\n#pragma mark NSURLConnection Delegate Methods\n\n- (NSCachedURLResponse *)connection:(NSURLConnection *)connection\n                  willCacheResponse:(NSCachedURLResponse*)cachedResponse {\n    // Return nil to indicate not necessary to store a cached response for this connection\n    return nil;\n}\n\n- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {\n    if ([response isKindOfClass:[NSHTTPURLResponse class]]) {\n        NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode];\n        if (statusCode >= 400) {\n            [self.outputFileStream close];\n            [connection cancel];\n            NSError *err = [CodePushErrorUtils errorWithMessage:[NSString stringWithFormat: @\"Received %ld response from %@\", (long)statusCode, self.downloadUrl]];\n            self.failCallback(err);\n            return;\n        }\n    }\n    \n    self.expectedContentLength = response.expectedContentLength;\n    [self.outputFileStream open];\n}\n\n- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {\n    if (self.receivedContentLength < 4) {\n        for (int i = 0; i < [data length]; i++) {\n            int headerOffset = (int)self.receivedContentLength + i;\n            if (headerOffset >= 4) {\n                break;\n            }\n\n            const char *bytes = [data bytes];\n            _header[headerOffset] = bytes[i];\n        }\n    }\n\n    self.receivedContentLength = self.receivedContentLength + [data length];\n\n    NSInteger bytesLeft = [data length];\n\n    do {\n        NSInteger bytesWritten = [self.outputFileStream write:[data bytes]\n                                                     maxLength:bytesLeft];\n        if (bytesWritten == -1) {\n            break;\n        }\n\n        bytesLeft -= bytesWritten;\n    } while (bytesLeft > 0);\n\n    self.progressCallback(self.expectedContentLength, self.receivedContentLength);\n\n    // bytesLeft should not be negative.\n    assert(bytesLeft >= 0);\n\n    if (bytesLeft) {\n        [self.outputFileStream close];\n        [connection cancel];\n        self.failCallback([self.outputFileStream streamError]);\n    }\n}\n\n- (void)connection:(NSURLConnection*)connection didFailWithError:(NSError*)error\n{\n    [self.outputFileStream close];\n    self.failCallback(error);\n}\n\n- (void)connectionDidFinishLoading:(NSURLConnection *)connection {\n    [self.outputFileStream close];\n    if (self.receivedContentLength < 1) {\n        NSError *err = [CodePushErrorUtils errorWithMessage:[NSString stringWithFormat:@\"Received empty response from %@\", self.downloadUrl]];\n        self.failCallback(err);\n        return;\n    }\n    \n    // expectedContentLength might be -1 when NSURLConnection don't know the length(e.g. response encode with gzip)\n    if (self.expectedContentLength > 0) {\n        // We should have received all of the bytes if this is called.\n        assert(self.receivedContentLength == self.expectedContentLength);\n    }\n\n    BOOL isZip = _header[0] == 'P' && _header[1] == 'K' && _header[2] == 3 && _header[3] == 4;\n    self.doneCallback(isZip);\n}\n\n@end\n"
  },
  {
    "path": "ios/CodePush/CodePushErrorUtils.m",
    "content": "#import \"CodePush.h\"\n\n@implementation CodePushErrorUtils\n\nstatic NSString *const CodePushErrorDomain = @\"CodePushError\";\nstatic const int CodePushErrorCode = -1;\n\n+ (NSError *)errorWithMessage:(NSString *)errorMessage\n{\n    return [NSError errorWithDomain:CodePushErrorDomain\n                               code:CodePushErrorCode\n                           userInfo:@{ NSLocalizedDescriptionKey: NSLocalizedString(errorMessage, nil) }];\n}\n\n+ (BOOL)isCodePushError:(NSError *)err\n{\n    return err != nil && [CodePushErrorDomain isEqualToString:err.domain];\n}\n\n@end"
  },
  {
    "path": "ios/CodePush/CodePushPackage.m",
    "content": "#import \"CodePush.h\"\n#if __has_include(<SSZipArchive/SSZipArchive.h>)\n#import <SSZipArchive/SSZipArchive.h>\n#else\n#import \"SSZipArchive.h\"\n#endif\n\n@implementation CodePushPackage\n\n#pragma mark - Private constants\n\nstatic NSString *const DiffManifestFileName = @\"hotcodepush.json\";\nstatic NSString *const DownloadFileName = @\"download.zip\";\nstatic NSString *const RelativeBundlePathKey = @\"bundlePath\";\nstatic NSString *const StatusFile = @\"codepush.json\";\nstatic NSString *const UpdateBundleFileName = @\"app.jsbundle\";\nstatic NSString *const UpdateMetadataFileName = @\"app.json\";\nstatic NSString *const UnzippedFolderName = @\"unzipped\";\n\n#pragma mark - Public methods\n\n+ (void)clearUpdates\n{\n    [[NSFileManager defaultManager] removeItemAtPath:[self getCodePushPath] error:nil];\n}\n\n+ (void)downloadAndReplaceCurrentBundle:(NSString *)remoteBundleUrl\n{\n    NSURL *urlRequest = [NSURL URLWithString:remoteBundleUrl];\n    NSError *error = nil;\n    NSString *downloadedBundle = [NSString stringWithContentsOfURL:urlRequest\n                                                          encoding:NSUTF8StringEncoding\n                                                             error:&error];\n    \n    if (error) {\n        CPLog(@\"Error downloading from URL %@\", remoteBundleUrl);\n    } else {\n        NSString *currentPackageBundlePath = [self getCurrentPackageBundlePath:&error];\n        [downloadedBundle writeToFile:currentPackageBundlePath\n                           atomically:YES\n                             encoding:NSUTF8StringEncoding\n                                error:&error];\n    }\n}\n\n+ (void)downloadPackage:(NSDictionary *)updatePackage\n expectedBundleFileName:(NSString *)expectedBundleFileName\n              publicKey:(NSString *)publicKey\n         operationQueue:(dispatch_queue_t)operationQueue\n       progressCallback:(void (^)(long long, long long))progressCallback\n           doneCallback:(void (^)())doneCallback\n           failCallback:(void (^)(NSError *err))failCallback\n{\n    NSString *newUpdateHash = updatePackage[@\"packageHash\"];\n    NSString *newUpdateFolderPath = [self getPackageFolderPath:newUpdateHash];\n    NSString *newUpdateMetadataPath = [newUpdateFolderPath stringByAppendingPathComponent:UpdateMetadataFileName];\n    NSError *error;\n    \n    if ([[NSFileManager defaultManager] fileExistsAtPath:newUpdateFolderPath]) {\n        // This removes any stale data in newUpdateFolderPath that could have been left\n        // uncleared due to a crash or error during the download or install process.\n        [[NSFileManager defaultManager] removeItemAtPath:newUpdateFolderPath\n                                                   error:&error];\n    } else if (![[NSFileManager defaultManager] fileExistsAtPath:[self getCodePushPath]]) {\n        [[NSFileManager defaultManager] createDirectoryAtPath:[self getCodePushPath]\n                                  withIntermediateDirectories:YES\n                                                   attributes:nil\n                                                        error:&error];\n                                                        \n        // Ensure that none of the CodePush updates we store on disk are\n        // ever included in the end users iTunes and/or iCloud backups\n        NSURL *codePushURL = [NSURL fileURLWithPath:[self getCodePushPath]];\n        [codePushURL setResourceValue:@YES forKey:NSURLIsExcludedFromBackupKey error:nil];\n    }\n    \n    if (error) {\n        return failCallback(error);\n    }\n    \n    NSString *downloadFilePath = [self getDownloadFilePath];\n    NSString *bundleFilePath = [newUpdateFolderPath stringByAppendingPathComponent:UpdateBundleFileName];\n    \n    CodePushDownloadHandler *downloadHandler = [[CodePushDownloadHandler alloc]\n                                                init:downloadFilePath\n                                                operationQueue:operationQueue\n                                                progressCallback:progressCallback\n                                                doneCallback:^(BOOL isZip) {\n                                                    NSError *error = nil;\n                                                    NSString * unzippedFolderPath = [CodePushPackage getUnzippedFolderPath];\n                                                    NSMutableDictionary * mutableUpdatePackage = [updatePackage mutableCopy];\n                                                    if (isZip) {\n                                                        if ([[NSFileManager defaultManager] fileExistsAtPath:unzippedFolderPath]) {\n                                                            // This removes any unzipped download data that could have been left\n                                                            // uncleared due to a crash or error during the download process.\n                                                            [[NSFileManager defaultManager] removeItemAtPath:unzippedFolderPath\n                                                                                                       error:&error];\n                                                            if (error) {\n                                                                failCallback(error);\n                                                                return;\n                                                            }\n                                                        }\n                                                        \n                                                        NSError *nonFailingError = nil;\n                                                        [SSZipArchive unzipFileAtPath:downloadFilePath\n                                                                        toDestination:unzippedFolderPath];\n                                                        [[NSFileManager defaultManager] removeItemAtPath:downloadFilePath\n                                                                                                   error:&nonFailingError];\n                                                        if (nonFailingError) {\n                                                            CPLog(@\"Error deleting downloaded file: %@\", nonFailingError);\n                                                            nonFailingError = nil;\n                                                        }\n                                                        \n                                                        NSString *diffManifestFilePath = [unzippedFolderPath stringByAppendingPathComponent:DiffManifestFileName];\n                                                        BOOL isDiffUpdate = [[NSFileManager defaultManager] fileExistsAtPath:diffManifestFilePath];\n                                                        \n                                                        if (isDiffUpdate) {\n                                                            // Copy the current package to the new package.\n                                                            NSString *currentPackageFolderPath = [self getCurrentPackageFolderPath:&error];\n                                                            if (error) {\n                                                                failCallback(error);\n                                                                return;\n                                                            }\n                                                            \n                                                            if (currentPackageFolderPath == nil) {\n                                                                // Currently running the binary version, copy files from the bundled resources\n                                                                NSString *newUpdateCodePushPath = [newUpdateFolderPath stringByAppendingPathComponent:[CodePushUpdateUtils manifestFolderPrefix]];\n                                                                [[NSFileManager defaultManager] createDirectoryAtPath:newUpdateCodePushPath\n                                                                                          withIntermediateDirectories:YES\n                                                                                                           attributes:nil\n                                                                                                                error:&error];\n                                                                if (error) {\n                                                                    failCallback(error);\n                                                                    return;\n                                                                }\n                                                                \n                                                                [[NSFileManager defaultManager] copyItemAtPath:[CodePush bundleAssetsPath]\n                                                                                                        toPath:[newUpdateCodePushPath stringByAppendingPathComponent:[CodePushUpdateUtils assetsFolderName]]\n                                                                                                         error:&error];\n                                                                if (error) {\n                                                                    failCallback(error);\n                                                                    return;\n                                                                }\n                                                                \n                                                                [[NSFileManager defaultManager] copyItemAtPath:[[CodePush binaryBundleURL] path]\n                                                                                                        toPath:[newUpdateCodePushPath stringByAppendingPathComponent:[[CodePush binaryBundleURL] lastPathComponent]]\n                                                                                                         error:&error];\n                                                                if (error) {\n                                                                    failCallback(error);\n                                                                    return;\n                                                                }\n                                                            } else {\n                                                                [[NSFileManager defaultManager] copyItemAtPath:currentPackageFolderPath\n                                                                                                        toPath:newUpdateFolderPath\n                                                                                                         error:&error];\n                                                                if (error) {\n                                                                    failCallback(error);\n                                                                    return;\n                                                                }\n                                                            }\n                                                            \n                                                            // Delete files mentioned in the manifest.\n                                                            NSString *manifestContent = [NSString stringWithContentsOfFile:diffManifestFilePath\n                                                                                                                  encoding:NSUTF8StringEncoding\n                                                                                                                     error:&error];\n                                                            if (error) {\n                                                                failCallback(error);\n                                                                return;\n                                                            }\n                                                            \n                                                            NSData *data = [manifestContent dataUsingEncoding:NSUTF8StringEncoding];\n                                                            NSDictionary *manifestJSON = [NSJSONSerialization JSONObjectWithData:data\n                                                                                                                         options:kNilOptions\n                                                                                                                           error:&error];\n                                                            NSArray *deletedFiles = manifestJSON[@\"deletedFiles\"];\n                                                            for (NSString *deletedFileName in deletedFiles) {\n                                                                NSString *absoluteDeletedFilePath = [newUpdateFolderPath stringByAppendingPathComponent:deletedFileName];\n                                                                if ([[NSFileManager defaultManager] fileExistsAtPath:absoluteDeletedFilePath]) {\n                                                                    [[NSFileManager defaultManager] removeItemAtPath:absoluteDeletedFilePath\n                                                                                                               error:&error];\n                                                                    if (error) {\n                                                                        failCallback(error);\n                                                                        return;\n                                                                    }\n                                                                }\n                                                            }\n                                                            \n                                                            [[NSFileManager defaultManager] removeItemAtPath:diffManifestFilePath\n                                                                                                       error:&error];\n                                                            if (error) {\n                                                                failCallback(error);\n                                                                return;\n                                                            }\n                                                        }\n                                                        \n                                                        [CodePushUpdateUtils copyEntriesInFolder:unzippedFolderPath\n                                                                                      destFolder:newUpdateFolderPath\n                                                                                           error:&error];\n                                                        if (error) {\n                                                            failCallback(error);\n                                                            return;\n                                                        }\n                                                        \n                                                        [[NSFileManager defaultManager] removeItemAtPath:unzippedFolderPath\n                                                                                                   error:&nonFailingError];\n                                                        if (nonFailingError) {\n                                                            CPLog(@\"Error deleting downloaded file: %@\", nonFailingError);\n                                                            nonFailingError = nil;\n                                                        }\n                                                        \n                                                        NSString *relativeBundlePath = [CodePushUpdateUtils findMainBundleInFolder:newUpdateFolderPath\n                                                                                                                  expectedFileName:expectedBundleFileName\n                                                                                                                             error:&error];\n                                                        \n                                                        if (error) {\n                                                            failCallback(error);\n                                                            return;\n                                                        }\n                                                        \n                                                        if (relativeBundlePath) {\n                                                            [mutableUpdatePackage setValue:relativeBundlePath forKey:RelativeBundlePathKey];\n                                                        } else {\n                                                            NSString *errorMessage = [NSString stringWithFormat:@\"Update is invalid - A JS bundle file named \\\"%@\\\" could not be found within the downloaded contents. Please ensure that your app is syncing with the correct deployment and that you are releasing your CodePush updates using the exact same JS bundle file name that was shipped with your app's binary.\", expectedBundleFileName];\n                                                            \n                                                            error = [CodePushErrorUtils errorWithMessage:errorMessage];\n                                                            \n                                                            failCallback(error);\n                                                            return;\n                                                        }\n                                                        \n                                                        if ([[NSFileManager defaultManager] fileExistsAtPath:newUpdateMetadataPath]) {\n                                                            [[NSFileManager defaultManager] removeItemAtPath:newUpdateMetadataPath\n                                                                                                       error:&error];\n                                                            if (error) {\n                                                                failCallback(error);\n                                                                return;\n                                                            }\n                                                        }\n\n                                                        CPLog((isDiffUpdate) ? @\"Applying diff update.\" : @\"Applying full update.\");\n                                                        \n                                                        BOOL isSignatureVerificationEnabled = (publicKey != nil);\n                                                        \n                                                        NSString *signatureFilePath = [CodePushUpdateUtils getSignatureFilePath:newUpdateFolderPath];\n                                                        BOOL isSignatureAppearedInBundle = [[NSFileManager defaultManager] fileExistsAtPath:signatureFilePath];\n                                                        \n                                                        if (isSignatureVerificationEnabled) {\n                                                            if (isSignatureAppearedInBundle) {\n                                                                if (![CodePushUpdateUtils verifyFolderHash:newUpdateFolderPath\n                                                                                              expectedHash:newUpdateHash\n                                                                                                     error:&error]) {\n                                                                    CPLog(@\"The update contents failed the data integrity check.\");\n                                                                    if (!error) {\n                                                                        error = [CodePushErrorUtils errorWithMessage:@\"The update contents failed the data integrity check.\"];\n                                                                    }\n                                                                    \n                                                                    failCallback(error);\n                                                                    return;\n                                                                } else {\n                                                                    CPLog(@\"The update contents succeeded the data integrity check.\");\n                                                                }\n                                                                BOOL isSignatureValid = [CodePushUpdateUtils verifyUpdateSignatureFor:newUpdateFolderPath\n                                                                                                                         expectedHash:newUpdateHash\n                                                                                                                        withPublicKey:publicKey\n                                                                                                                                error:&error];\n                                                                if (!isSignatureValid) {\n                                                                    CPLog(@\"The update contents failed code signing check.\");\n                                                                    if (!error) {\n                                                                        error = [CodePushErrorUtils errorWithMessage:@\"The update contents failed code signing check.\"];\n                                                                    }\n                                                                    failCallback(error);\n                                                                    return;\n                                                                } else {\n                                                                    CPLog(@\"The update contents succeeded the code signing check.\");\n                                                                }\n                                                            } else {\n                                                                error = [CodePushErrorUtils errorWithMessage:\n                                                                         @\"Error! Public key was provided but there is no JWT signature within app bundle to verify \" \\\n                                                                         \"Possible reasons, why that might happen: \\n\" \\\n                                                                         \"1. You've been released CodePush bundle update using version of CodePush CLI that is not support code signing.\\n\" \\\n                                                                         \"2. You've been released CodePush bundle update without providing --privateKeyPath option.\"];\n                                                                failCallback(error);\n                                                                return;\n                                                            }\n                                                            \n                                                        } else {\n                                                            BOOL needToVerifyHash;\n                                                            if (isSignatureAppearedInBundle) {\n                                                                CPLog(@\"Warning! JWT signature exists in codepush update but code integrity check couldn't be performed\" \\\n                                                                      \" because there is no public key configured. \" \\\n                                                                      \"Please ensure that public key is properly configured within your application.\");\n                                                                needToVerifyHash = true;\n                                                            } else {\n                                                                needToVerifyHash = isDiffUpdate;\n                                                            }\n                                                            if(needToVerifyHash){\n                                                                if (![CodePushUpdateUtils verifyFolderHash:newUpdateFolderPath\n                                                                                              expectedHash:newUpdateHash\n                                                                                                     error:&error]) {\n                                                                    CPLog(@\"The update contents failed the data integrity check.\");\n                                                                    if (!error) {\n                                                                        error = [CodePushErrorUtils errorWithMessage:@\"The update contents failed the data integrity check.\"];\n                                                                    }\n                                                                    \n                                                                    failCallback(error);\n                                                                    return;\n                                                                } else {\n                                                                    CPLog(@\"The update contents succeeded the data integrity check.\");\n                                                                }\n                                                            }\n                                                        }\n                                                    } else {\n                                                        [[NSFileManager defaultManager] createDirectoryAtPath:newUpdateFolderPath\n                                                                                  withIntermediateDirectories:YES\n                                                                                                   attributes:nil\n                                                                                                        error:&error];\n                                                        [[NSFileManager defaultManager] moveItemAtPath:downloadFilePath\n                                                                                                toPath:bundleFilePath\n                                                                                                 error:&error];\n                                                        if (error) {\n                                                            failCallback(error);\n                                                            return;\n                                                        }\n                                                    }\n                                                    \n                                                    NSData *updateSerializedData = [NSJSONSerialization dataWithJSONObject:mutableUpdatePackage\n                                                                                                                   options:0\n                                                                                                                     error:&error];\n                                                    NSString *packageJsonString = [[NSString alloc] initWithData:updateSerializedData\n                                                                                                        encoding:NSUTF8StringEncoding];\n                                                    \n                                                    [packageJsonString writeToFile:newUpdateMetadataPath\n                                                                        atomically:YES\n                                                                          encoding:NSUTF8StringEncoding\n                                                                             error:&error];\n                                                    if (error) {\n                                                        failCallback(error);\n                                                    } else {\n                                                        doneCallback();\n                                                    }\n                                                }\n                                                \n                                                failCallback:failCallback];\n    \n    [downloadHandler download:updatePackage[@\"downloadUrl\"]];\n}\n\n+ (NSString *)getCodePushPath\n{\n    NSString* codePushPath = [[CodePush getApplicationSupportDirectory] stringByAppendingPathComponent:@\"CodePush\"];\n    if ([CodePush isUsingTestConfiguration]) {\n        codePushPath = [codePushPath stringByAppendingPathComponent:@\"TestPackages\"];\n    }\n    \n    return codePushPath;\n}\n\n+ (NSDictionary *)getCurrentPackage:(NSError **)error\n{\n    NSString *packageHash = [CodePushPackage getCurrentPackageHash:error];\n    if (!packageHash) {\n        return nil;\n    }\n\n    return [CodePushPackage getPackage:packageHash error:error];\n}\n\n+ (NSString *)getCurrentPackageBundlePath:(NSError **)error\n{\n    NSString *packageFolder = [self getCurrentPackageFolderPath:error];\n    \n    if (!packageFolder) {\n        return nil;\n    }\n    \n    NSDictionary *currentPackage = [self getCurrentPackage:error];\n    \n    if (!currentPackage) {\n        return nil;\n    }\n    \n    NSString *relativeBundlePath = [currentPackage objectForKey:RelativeBundlePathKey];\n    if (relativeBundlePath) {\n        return [packageFolder stringByAppendingPathComponent:relativeBundlePath];\n    } else {\n        return [packageFolder stringByAppendingPathComponent:UpdateBundleFileName];\n    }\n}\n\n+ (NSString *)getCurrentPackageHash:(NSError **)error\n{\n    NSDictionary *info = [self getCurrentPackageInfo:error];\n    if (!info) {\n        return nil;\n    }\n    \n    return info[@\"currentPackage\"];\n}\n\n+ (NSString *)getCurrentPackageFolderPath:(NSError **)error\n{\n    NSDictionary *info = [self getCurrentPackageInfo:error];\n    \n    if (!info) {\n        return nil;\n    }\n    \n    NSString *packageHash = info[@\"currentPackage\"];\n    \n    if (!packageHash) {\n        return nil;\n    }\n    \n    return [self getPackageFolderPath:packageHash];\n}\n\n+ (NSMutableDictionary *)getCurrentPackageInfo:(NSError **)error\n{\n    NSString *statusFilePath = [self getStatusFilePath];\n    if (![[NSFileManager defaultManager] fileExistsAtPath:statusFilePath]) {\n        return [NSMutableDictionary dictionary];\n    }\n    \n    NSString *content = [NSString stringWithContentsOfFile:statusFilePath\n                                                  encoding:NSUTF8StringEncoding\n                                                     error:error];\n    if (!content) {\n        return nil;\n    }\n    \n    NSData *data = [content dataUsingEncoding:NSUTF8StringEncoding];\n    NSDictionary* json = [NSJSONSerialization JSONObjectWithData:data\n                                                         options:kNilOptions\n                                                           error:error];\n    if (!json) {\n        return nil;\n    }\n    \n    return [json mutableCopy];\n}\n\n+ (NSString *)getDownloadFilePath\n{\n    return [[self getCodePushPath] stringByAppendingPathComponent:DownloadFileName];\n}\n\n+ (NSDictionary *)getPackage:(NSString *)packageHash\n                       error:(NSError **)error\n{\n    NSString *updateDirectoryPath = [self getPackageFolderPath:packageHash];\n    NSString *updateMetadataFilePath = [updateDirectoryPath stringByAppendingPathComponent:UpdateMetadataFileName];\n    \n    if (![[NSFileManager defaultManager] fileExistsAtPath:updateMetadataFilePath]) {\n        return nil;\n    }\n    \n    NSString *updateMetadataString = [NSString stringWithContentsOfFile:updateMetadataFilePath\n                                                               encoding:NSUTF8StringEncoding\n                                                                  error:error];\n    if (!updateMetadataString) {\n        return nil;\n    }\n    \n    NSData *updateMetadata = [updateMetadataString dataUsingEncoding:NSUTF8StringEncoding];\n    return [NSJSONSerialization JSONObjectWithData:updateMetadata\n                                           options:kNilOptions\n                                             error:error];\n}\n\n+ (NSString *)getPackageFolderPath:(NSString *)packageHash\n{\n    return [[self getCodePushPath] stringByAppendingPathComponent:packageHash];\n}\n\n+ (NSDictionary *)getPreviousPackage:(NSError **)error\n{\n    NSString *packageHash = [self getPreviousPackageHash:error];\n    if (!packageHash) {\n        return nil;\n    }\n    \n    return [CodePushPackage getPackage:packageHash error:error];\n}\n\n+ (NSString *)getPreviousPackageHash:(NSError **)error\n{\n    NSDictionary *info = [self getCurrentPackageInfo:error];\n    if (!info) {\n        return nil;\n    }\n    \n    return info[@\"previousPackage\"];\n}\n\n+ (NSString *)getStatusFilePath\n{\n    return [[self getCodePushPath] stringByAppendingPathComponent:StatusFile];\n}\n\n+ (NSString *)getUnzippedFolderPath\n{\n    return [[self getCodePushPath] stringByAppendingPathComponent:UnzippedFolderName];\n}\n\n+ (BOOL)installPackage:(NSDictionary *)updatePackage\n   removePendingUpdate:(BOOL)removePendingUpdate\n                 error:(NSError **)error\n{\n    NSString *packageHash = updatePackage[@\"packageHash\"];\n    NSMutableDictionary *info = [self getCurrentPackageInfo:error];\n    \n    if (!info) {\n        return NO;\n    }\n    \n    if (packageHash && [packageHash isEqualToString:info[@\"currentPackage\"]]) {\n        // The current package is already the one being installed, so we should no-op.\n        return YES;\n    }\n\n    if (removePendingUpdate) {\n        NSString *currentPackageFolderPath = [self getCurrentPackageFolderPath:error];\n        if (currentPackageFolderPath) {\n            // Error in deleting pending package will not cause the entire operation to fail.\n            NSError *deleteError;\n            [[NSFileManager defaultManager] removeItemAtPath:currentPackageFolderPath\n                                                       error:&deleteError];\n            if (deleteError) {\n                CPLog(@\"Error deleting pending package: %@\", deleteError);\n            }\n        }\n    } else {\n        NSString *previousPackageHash = [self getPreviousPackageHash:error];\n        if (previousPackageHash && ![previousPackageHash isEqualToString:packageHash]) {\n            NSString *previousPackageFolderPath = [self getPackageFolderPath:previousPackageHash];\n            // Error in deleting old package will not cause the entire operation to fail.\n            NSError *deleteError;\n            [[NSFileManager defaultManager] removeItemAtPath:previousPackageFolderPath\n                                                       error:&deleteError];\n            if (deleteError) {\n                CPLog(@\"Error deleting old package: %@\", deleteError);\n            }\n        }\n        [info setValue:info[@\"currentPackage\"] forKey:@\"previousPackage\"];\n    }\n    \n    [info setValue:packageHash forKey:@\"currentPackage\"];\n    return [self updateCurrentPackageInfo:info\n                                    error:error];\n}\n\n+ (void)rollbackPackage\n{\n    NSError *error;\n    NSMutableDictionary *info = [self getCurrentPackageInfo:&error];\n    if (!info) {\n        CPLog(@\"Error getting current package info: %@\", error);\n        return;\n    }\n    \n    NSString *currentPackageFolderPath = [self getCurrentPackageFolderPath:&error];        \n    if (!currentPackageFolderPath) {\n        CPLog(@\"Error getting current package folder path: %@\", error);\n        return;\n    }\n    \n    NSError *deleteError;\n    BOOL result = [[NSFileManager defaultManager] removeItemAtPath:currentPackageFolderPath\n                                               error:&deleteError];\n    if (!result) {\n        CPLog(@\"Error deleting current package contents at %@ error %@\", currentPackageFolderPath, deleteError);\n    }\n    \n    [info setValue:info[@\"previousPackage\"] forKey:@\"currentPackage\"];\n    [info removeObjectForKey:@\"previousPackage\"];\n    \n    [self updateCurrentPackageInfo:info error:&error];\n}\n\n+ (BOOL)updateCurrentPackageInfo:(NSDictionary *)packageInfo\n                           error:(NSError **)error\n{\n    NSData *packageInfoData = [NSJSONSerialization dataWithJSONObject:packageInfo\n                                                              options:0\n                                                                error:error];\n    if (!packageInfoData) {\n        return NO;\n    }\n\n    NSString *packageInfoString = [[NSString alloc] initWithData:packageInfoData\n                                                        encoding:NSUTF8StringEncoding];\n    BOOL result = [packageInfoString writeToFile:[self getStatusFilePath]\n                        atomically:YES\n                          encoding:NSUTF8StringEncoding\n                             error:error];\n\n    if (!result) {\n        return NO;\n    }\n    return YES;\n}\n\n@end\n"
  },
  {
    "path": "ios/CodePush/CodePushTelemetryManager.m",
    "content": "#import \"CodePush.h\"\n\nstatic NSString *const AppVersionKey = @\"appVersion\";\nstatic NSString *const DeploymentFailed = @\"DeploymentFailed\";\nstatic NSString *const DeploymentKeyKey = @\"deploymentKey\";\nstatic NSString *const DeploymentSucceeded = @\"DeploymentSucceeded\";\nstatic NSString *const LabelKey = @\"label\";\nstatic NSString *const LastDeploymentReportKey = @\"CODE_PUSH_LAST_DEPLOYMENT_REPORT\";\nstatic NSString *const PackageKey = @\"package\";\nstatic NSString *const PreviousDeploymentKeyKey = @\"previousDeploymentKey\";\nstatic NSString *const PreviousLabelOrAppVersionKey = @\"previousLabelOrAppVersion\";\nstatic NSString *const RetryDeploymentReportKey = @\"CODE_PUSH_RETRY_DEPLOYMENT_REPORT\";\nstatic NSString *const StatusKey = @\"status\";\n\n@implementation CodePushTelemetryManager\n\n+ (NSDictionary *)getBinaryUpdateReport:(NSString *)appVersion\n{\n    NSString *previousStatusReportIdentifier = [self getPreviousStatusReportIdentifier];\n    if (previousStatusReportIdentifier == nil) {\n        [self clearRetryStatusReport];\n        return @{ AppVersionKey: appVersion };\n    } else if (![previousStatusReportIdentifier isEqualToString:appVersion]) {\n        if ([self isStatusReportIdentifierCodePushLabel:previousStatusReportIdentifier]) {\n            NSString *previousDeploymentKey = [self getDeploymentKeyFromStatusReportIdentifier:previousStatusReportIdentifier];\n            NSString *previousLabel = [self getVersionLabelFromStatusReportIdentifier:previousStatusReportIdentifier];\n            [self clearRetryStatusReport];\n            return @{\n                      AppVersionKey: appVersion,\n                      PreviousDeploymentKeyKey: previousDeploymentKey,\n                      PreviousLabelOrAppVersionKey: previousLabel\n                    };\n        } else {\n            [self clearRetryStatusReport];\n            // Previous status report was with a binary app version.\n            return @{\n                      AppVersionKey: appVersion,\n                      PreviousLabelOrAppVersionKey: previousStatusReportIdentifier\n                    };\n        }\n    }\n\n    return nil;\n}\n\n+ (NSDictionary *)getRetryStatusReport\n{\n    NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults];\n    NSDictionary *retryStatusReport = [preferences objectForKey:RetryDeploymentReportKey];\n    if (retryStatusReport) {\n        [self clearRetryStatusReport];\n        return retryStatusReport;\n    } else {\n        return nil;\n    }\n}\n\n+ (NSDictionary *)getRollbackReport:(NSDictionary *)lastFailedPackage\n{\n    return @{\n              PackageKey: lastFailedPackage,\n              StatusKey: DeploymentFailed\n            };\n}\n\n+ (NSDictionary *)getUpdateReport:(NSDictionary *)currentPackage\n{\n    NSString *currentPackageIdentifier = [self getPackageStatusReportIdentifier:currentPackage];\n    NSString *previousStatusReportIdentifier = [self getPreviousStatusReportIdentifier];\n    if (currentPackageIdentifier) {\n        if (previousStatusReportIdentifier == nil) {\n            [self clearRetryStatusReport];\n            return @{\n                      PackageKey: currentPackage,\n                      StatusKey: DeploymentSucceeded\n                    };\n        } else if (![previousStatusReportIdentifier isEqualToString:currentPackageIdentifier]) {\n            [self clearRetryStatusReport];\n            if ([self isStatusReportIdentifierCodePushLabel:previousStatusReportIdentifier]) {\n                NSString *previousDeploymentKey = [self getDeploymentKeyFromStatusReportIdentifier:previousStatusReportIdentifier];\n                NSString *previousLabel = [self getVersionLabelFromStatusReportIdentifier:previousStatusReportIdentifier];\n                return @{\n                          PackageKey: currentPackage,\n                          StatusKey: DeploymentSucceeded,\n                          PreviousDeploymentKeyKey: previousDeploymentKey,\n                          PreviousLabelOrAppVersionKey: previousLabel\n                        };\n            } else {\n                // Previous status report was with a binary app version.\n                return @{\n                          PackageKey: currentPackage,\n                          StatusKey: DeploymentSucceeded,\n                          PreviousLabelOrAppVersionKey: previousStatusReportIdentifier\n                        };\n            }\n        }\n    }\n\n    return nil;\n}\n\n+ (void)recordStatusReported:(NSDictionary *)statusReport\n{\n    // We don't need to record rollback reports, so exit early if that's what was specified.\n    if ([DeploymentFailed isEqualToString:statusReport[StatusKey]]) {\n        return;\n    }\n    \n    if (statusReport[AppVersionKey]) {\n        [self saveStatusReportedForIdentifier:statusReport[AppVersionKey]];\n    } else if (statusReport[PackageKey]) {\n        NSString *packageIdentifier = [self getPackageStatusReportIdentifier:statusReport[PackageKey]];\n        [self saveStatusReportedForIdentifier:packageIdentifier];\n    }\n}\n\n+ (void)saveStatusReportForRetry:(NSDictionary *)statusReport\n{\n    NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults];\n    [preferences setValue:statusReport forKey:RetryDeploymentReportKey];\n    [preferences synchronize];\n}\n\n#pragma mark - private methods\n\n+ (void)clearRetryStatusReport\n{\n    NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults];\n    [preferences setValue:nil forKey:RetryDeploymentReportKey];\n    [preferences synchronize];\n}\n\n+ (NSString *)getDeploymentKeyFromStatusReportIdentifier:(NSString *)statusReportIdentifier\n{\n    return [[statusReportIdentifier componentsSeparatedByString:@\":\"] firstObject];\n}\n\n+ (NSString *)getPackageStatusReportIdentifier:(NSDictionary *)package\n{\n    // Because deploymentKeys can be dynamically switched, we use a\n    // combination of the deploymentKey and label as the packageIdentifier.\n    NSString *deploymentKey = [package objectForKey:DeploymentKeyKey];\n    NSString *label = [package objectForKey:LabelKey];\n    if (deploymentKey && label) {\n        return [[deploymentKey stringByAppendingString:@\":\"] stringByAppendingString:label];\n    } else {\n        return nil;\n    }\n}\n\n+ (NSString *)getPreviousStatusReportIdentifier\n{\n    NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults];\n    NSString *sentStatusReportIdentifier = [preferences objectForKey:LastDeploymentReportKey];\n    return sentStatusReportIdentifier;\n}\n\n+ (NSString *)getVersionLabelFromStatusReportIdentifier:(NSString *)statusReportIdentifier\n{\n    return [[statusReportIdentifier componentsSeparatedByString:@\":\"] lastObject];\n}\n\n+ (BOOL)isStatusReportIdentifierCodePushLabel:(NSString *)statusReportIdentifier\n{\n    return statusReportIdentifier != nil && [statusReportIdentifier rangeOfString:@\":\"].location != NSNotFound;\n}\n\n+ (void)saveStatusReportedForIdentifier:(NSString *)appVersionOrPackageIdentifier\n{\n    NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults];\n    [preferences setValue:appVersionOrPackageIdentifier forKey:LastDeploymentReportKey];\n    [preferences synchronize];\n}\n\n@end\n"
  },
  {
    "path": "ios/CodePush/CodePushUpdateUtils.m",
    "content": "#import \"CodePush.h\"\n#include <CommonCrypto/CommonDigest.h>\n#import \"JWT.h\"\n\n@implementation CodePushUpdateUtils\n\nNSString * const AssetsFolderName = @\"assets\";\nNSString * const BinaryHashKey = @\"CodePushBinaryHash\";\nNSString * const ManifestFolderPrefix = @\"CodePush\";\nNSString * const BundleJWTFile = @\".codepushrelease\";\n\n/*\n Ignore list for hashing\n */\nNSString * const IgnoreMacOSX= @\"__MACOSX/\";\nNSString * const IgnoreDSStore = @\".DS_Store\";\nNSString * const IgnoreCodePushMetadata = @\".codepushrelease\";\n\n+ (BOOL)isHashIgnoredFor:(NSString *) relativePath\n{\n    return [relativePath hasPrefix:IgnoreMacOSX]\n    || [relativePath isEqualToString:IgnoreDSStore]\n    || [relativePath hasSuffix:[NSString stringWithFormat:@\"/%@\", IgnoreDSStore]]\n    || [relativePath isEqualToString:IgnoreCodePushMetadata]\n    || [relativePath hasSuffix:[NSString stringWithFormat:@\"/%@\", IgnoreCodePushMetadata]];\n}\n\n+ (BOOL)addContentsOfFolderToManifest:(NSString *)folderPath\n                           pathPrefix:(NSString *)pathPrefix\n                             manifest:(NSMutableArray *)manifest\n                                error:(NSError **)error\n{\n    NSArray *folderFiles = [[NSFileManager defaultManager]\n                            contentsOfDirectoryAtPath:folderPath\n                            error:error];\n    if (!folderFiles) {\n        return NO;\n    }\n    \n    for (NSString *fileName in folderFiles) {\n\n        NSString *fullFilePath = [folderPath stringByAppendingPathComponent:fileName];\n        NSString *relativePath = [pathPrefix stringByAppendingPathComponent:fileName];\n        \n        if([self isHashIgnoredFor:relativePath]){\n            continue;\n        }\n        \n        BOOL isDir = NO;\n        if ([[NSFileManager defaultManager] fileExistsAtPath:fullFilePath\n                                                 isDirectory:&isDir] && isDir) {\n            BOOL result = [self addContentsOfFolderToManifest:fullFilePath\n                                                   pathPrefix:relativePath\n                                                     manifest:manifest\n                                                        error:error];\n            if (!result) {\n                return NO;\n            }\n        } else {\n            NSData *fileContents = [NSData dataWithContentsOfFile:fullFilePath];\n            NSString *fileContentsHash = [self computeHashForData:fileContents];\n            [manifest addObject:[[relativePath stringByAppendingString:@\":\"] stringByAppendingString:fileContentsHash]];\n        }\n    }\n \n    return YES;\n}\n\n+ (void)addFileToManifest:(NSURL *)fileURL\n                 manifest:(NSMutableArray *)manifest\n{\n    if ([[NSFileManager defaultManager] fileExistsAtPath:[fileURL path]]) {\n        NSData *fileContents = [NSData dataWithContentsOfURL:fileURL];\n        NSString *fileContentsHash = [self computeHashForData:fileContents];\n        [manifest addObject:[NSString stringWithFormat:@\"%@/%@:%@\", [self manifestFolderPrefix], [fileURL lastPathComponent], fileContentsHash]];\n    }\n}\n\n+ (NSString *)computeFinalHashFromManifest:(NSMutableArray *)manifest\n                                     error:(NSError **)error\n{\n    //sort manifest strings to make sure, that they are completely equal with manifest strings has been generated in cli!\n    NSArray *sortedManifest = [manifest sortedArrayUsingSelector:@selector(compare:)];\n    NSData *manifestData = [NSJSONSerialization dataWithJSONObject:sortedManifest\n                                                           options:kNilOptions\n                                                             error:error];\n    if (!manifestData) {\n        return nil;\n    }\n    \n    NSString *manifestString = [[NSString alloc] initWithData:manifestData\n                                                     encoding:NSUTF8StringEncoding];\n    // The JSON serialization turns path separators into \"\\/\", e.g. \"CodePush\\/assets\\/image.png\"\n    manifestString = [manifestString stringByReplacingOccurrencesOfString:@\"\\\\/\"\n                                                               withString:@\"/\"];\n    return [self computeHashForData:[NSData dataWithBytes:manifestString.UTF8String length:[manifestString lengthOfBytesUsingEncoding:NSUTF8StringEncoding]]];\n}\n\n+ (NSString *)computeHashForData:(NSData *)inputData\n{\n    uint8_t digest[CC_SHA256_DIGEST_LENGTH];\n    CC_SHA256(inputData.bytes, (CC_LONG)inputData.length, digest);\n    NSMutableString* inputHash = [NSMutableString stringWithCapacity:CC_SHA256_DIGEST_LENGTH * 2];\n    for (int i = 0; i < CC_SHA256_DIGEST_LENGTH; i++) {\n        [inputHash appendFormat:@\"%02x\", digest[i]];\n    }\n    \n    return inputHash;\n}\n\n+ (BOOL)copyEntriesInFolder:(NSString *)sourceFolder\n                 destFolder:(NSString *)destFolder\n                      error:(NSError **)error\n{\n    NSArray *files = [[NSFileManager defaultManager]\n                      contentsOfDirectoryAtPath:sourceFolder\n                      error:error];\n    if (!files) {\n        return NO;\n    }\n    \n    for (NSString *fileName in files) {\n        NSString * fullFilePath = [sourceFolder stringByAppendingPathComponent:fileName];\n        BOOL isDir = NO;\n        if ([[NSFileManager defaultManager] fileExistsAtPath:fullFilePath\n                                                 isDirectory:&isDir] && isDir) {\n            NSString *nestedDestFolder = [destFolder stringByAppendingPathComponent:fileName];\n            BOOL result = [self copyEntriesInFolder:fullFilePath\n                                         destFolder:nestedDestFolder\n                                              error:error];\n\n            if (!result) {\n                return NO;\n            }\n\n        } else {\n            NSString *destFileName = [destFolder stringByAppendingPathComponent:fileName];\n            if ([[NSFileManager defaultManager] fileExistsAtPath:destFileName]) {\n                BOOL result = [[NSFileManager defaultManager] removeItemAtPath:destFileName error:error];\n                if (!result) {\n                    return NO;\n                }\n            }\n            if (![[NSFileManager defaultManager] fileExistsAtPath:destFolder]) {\n                BOOL result = [[NSFileManager defaultManager] createDirectoryAtPath:destFolder\n                                          withIntermediateDirectories:YES\n                                                           attributes:nil\n                                                                error:error];\n                if (!result) {\n                    return NO;\n                }\n            }\n            \n            BOOL result = [[NSFileManager defaultManager] copyItemAtPath:fullFilePath toPath:destFileName error:error];\n            if (!result) {\n                return NO;\n            }\n        }\n    }\n    return YES;\n}\n\n+ (NSString *)findMainBundleInFolder:(NSString *)folderPath\n                    expectedFileName:(NSString *)expectedFileName\n                               error:(NSError **)error\n{\n    NSArray* folderFiles = [[NSFileManager defaultManager]\n                            contentsOfDirectoryAtPath:folderPath\n                            error:error];\n    if (!folderFiles) {\n        return nil;\n    }\n    \n    for (NSString *fileName in folderFiles) {\n        NSString *fullFilePath = [folderPath stringByAppendingPathComponent:fileName];\n        BOOL isDir = NO;\n        if ([[NSFileManager defaultManager] fileExistsAtPath:fullFilePath\n                                                 isDirectory:&isDir] && isDir) {\n            NSString *mainBundlePathInFolder = [self findMainBundleInFolder:fullFilePath\n                                                           expectedFileName:expectedFileName\n                                                                      error:error];\n            if (mainBundlePathInFolder) {\n                return [fileName stringByAppendingPathComponent:mainBundlePathInFolder];\n            }\n        } else if ([fileName isEqualToString:expectedFileName]) {\n            return fileName;\n        }\n    }\n    \n    return nil;\n}\n\n+ (NSString *)assetsFolderName\n{\n    return AssetsFolderName;\n}\n\n+ (NSString *)getHashForBinaryContents:(NSURL *)binaryBundleUrl\n                                 error:(NSError **)error\n{\n    // Get the cached hash from user preferences if it exists.\n    NSString *binaryModifiedDate = [self modifiedDateStringOfFileAtURL:binaryBundleUrl];\n    NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults];\n    NSMutableDictionary *binaryHashDictionary = [preferences objectForKey:BinaryHashKey];\n    NSString *binaryHash = nil;\n    if (binaryHashDictionary != nil) {\n        binaryHash = [binaryHashDictionary objectForKey:binaryModifiedDate];\n        if (binaryHash == nil) {\n            [preferences removeObjectForKey:BinaryHashKey];\n            [preferences synchronize];\n        } else {\n            return binaryHash;\n        }\n    }\n    \n    binaryHashDictionary = [NSMutableDictionary dictionary];\n    NSMutableArray *manifest = [NSMutableArray array];\n    \n    // If the app is using assets, then add\n    // them to the generated content manifest.\n    NSString *assetsPath = [CodePush bundleAssetsPath];\n    if ([[NSFileManager defaultManager] fileExistsAtPath:assetsPath]) {\n        \n        BOOL result = [self addContentsOfFolderToManifest:assetsPath\n                                               pathPrefix:[NSString stringWithFormat:@\"%@/%@\", [self manifestFolderPrefix], @\"assets\"]\n                                                 manifest:manifest\n                                                    error:error];\n        if (!result) {\n            return nil;\n        }\n    }\n    \n    [self addFileToManifest:binaryBundleUrl manifest:manifest];\n    [self addFileToManifest:[binaryBundleUrl URLByAppendingPathExtension:@\"meta\"] manifest:manifest];\n\n    binaryHash = [self computeFinalHashFromManifest:manifest error:error];\n    \n    // Cache the hash in user preferences. This assumes that the modified date for the\n    // JS bundle changes every time a new bundle is generated by the packager.\n    [binaryHashDictionary setObject:binaryHash forKey:binaryModifiedDate];\n    [preferences setObject:binaryHashDictionary forKey:BinaryHashKey];\n    [preferences synchronize];\n    return binaryHash;\n}\n\n+ (NSString *)manifestFolderPrefix\n{\n    return ManifestFolderPrefix;\n}\n\n+ (NSString *)modifiedDateStringOfFileAtURL:(NSURL *)fileURL\n{\n    if (fileURL != nil) {\n        NSDictionary *fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:[fileURL path] error:nil];\n        NSDate *modifiedDate = [fileAttributes objectForKey:NSFileModificationDate];\n        return [NSString stringWithFormat:@\"%f\", [modifiedDate timeIntervalSince1970]];\n    } else {\n        return nil;\n    }\n}\n\n+ (BOOL)verifyFolderHash:(NSString *)finalUpdateFolder\n                   expectedHash:(NSString *)expectedHash\n                          error:(NSError **)error\n{\n    CPLog(@\"Verifying hash for folder path: %@\", finalUpdateFolder);\n    \n    NSMutableArray *updateContentsManifest = [NSMutableArray array];\n    BOOL result = [self addContentsOfFolderToManifest:finalUpdateFolder\n                                           pathPrefix:@\"\"\n                                             manifest:updateContentsManifest\n                                                error:error];\n    \n    CPLog(@\"Manifest string: %@\", updateContentsManifest);\n    \n    if (!result) {\n        return NO;\n    }\n\n    NSString *updateContentsManifestHash = [self computeFinalHashFromManifest:updateContentsManifest\n                                                                        error:error];\n    if (!updateContentsManifestHash) {\n        return NO;\n    }\n    \n    CPLog(@\"Expected hash: %@, actual hash: %@\", expectedHash, updateContentsManifestHash);\n    \n    return [updateContentsManifestHash isEqualToString:expectedHash];\n}\n\n// remove BEGIN / END tags and line breaks from public key string\n+ (NSString *)getKeyValueFromPublicKeyString:(NSString *)publicKeyString\n{\n    publicKeyString = [publicKeyString stringByReplacingOccurrencesOfString:@\"-----BEGIN PUBLIC KEY-----\\n\"\n                                                                 withString:@\"\"];\n    publicKeyString = [publicKeyString stringByReplacingOccurrencesOfString:@\"-----END PUBLIC KEY-----\"\n                                                                 withString:@\"\"];\n    publicKeyString = [publicKeyString stringByReplacingOccurrencesOfString:@\"\\n\"\n                                                                 withString:@\"\"];\n\n    return publicKeyString;\n}\n\n+ (NSString *)getSignatureFilePath:(NSString *)updateFolderPath\n{\n    return [NSString stringWithFormat:@\"%@/%@/%@\", updateFolderPath, ManifestFolderPrefix, BundleJWTFile];\n}\n\n+ (NSString *)getSignatureFor:(NSString *)folderPath\n                        error:(NSError **)error\n{\n    NSString *signatureFilePath = [self getSignatureFilePath:folderPath];\n    if ([[NSFileManager defaultManager] fileExistsAtPath:signatureFilePath]) {\n        return [NSString stringWithContentsOfFile:signatureFilePath encoding:NSUTF8StringEncoding error:error];\n    } else {\n        *error = [CodePushErrorUtils errorWithMessage:[NSString stringWithFormat: @\"Cannot find signature at %@\", signatureFilePath]];\n        return nil;\n    }\n}\n\n+ (NSDictionary *) verifyAndDecodeJWT:(NSString *)jwt\n     withPublicKey:(NSString *)publicKey\n             error:(NSError **)error\n{\n    id <JWTAlgorithmDataHolderProtocol> verifyDataHolder = [JWTAlgorithmRSFamilyDataHolder new].keyExtractorType([JWTCryptoKeyExtractor publicKeyWithPEMBase64].type).algorithmName(@\"RS256\").secret(publicKey);\n    \n    JWTCodingBuilder *verifyBuilder = [JWTDecodingBuilder decodeMessage:jwt].addHolder(verifyDataHolder);\n    JWTCodingResultType *verifyResult = verifyBuilder.result;\n    if (verifyResult.successResult) {\n        return verifyResult.successResult.payload;\n    }\n    else {\n        *error = verifyResult.errorResult.error;\n        return nil;\n    }\n}\n\n+ (BOOL)verifyUpdateSignatureFor:(NSString *)folderPath\n                    expectedHash:(NSString *)newUpdateHash\n                   withPublicKey:(NSString *)publicKeyString\n                           error:(NSError **)error\n{\n    NSLog(@\"Verifying signature for folder path: %@\", folderPath);\n    \n    NSString *publicKey = [self getKeyValueFromPublicKeyString: publicKeyString];\n    \n    NSError *signatureVerificationError;\n    NSString *signature = [self getSignatureFor: folderPath\n                                          error: &signatureVerificationError];\n    if (signatureVerificationError) {\n        CPLog(@\"The update could not be verified because no signature was found. %@\", signatureVerificationError);\n        *error = signatureVerificationError;\n        return false;\n    }\n    \n    NSError *payloadDecodingError;\n    NSDictionary *envelopedPayload = [self verifyAndDecodeJWT:signature withPublicKey:publicKey error:&payloadDecodingError];\n    if(payloadDecodingError){\n        CPLog(@\"The update could not be verified because it was not signed by a trusted party. %@\", payloadDecodingError);\n        *error = payloadDecodingError;\n        return false;\n    }\n    \n    CPLog(@\"JWT signature verification succeeded, payload content:  %@\", envelopedPayload);\n    \n    if(![envelopedPayload objectForKey:@\"contentHash\"]){\n        CPLog(@\"The update could not be verified because the signature did not specify a content hash.\");\n        return false;\n    }\n    \n    NSString *contentHash = envelopedPayload[@\"contentHash\"];\n    \n    return [contentHash isEqualToString:newUpdateHash];\n}\n\n@end\n"
  },
  {
    "path": "ios/CodePush/CodePushUtils.m",
    "content": "#import \"CodePush.h\"\n\nvoid CPLog(NSString *formatString, ...) {\n    va_list args;\n    va_start(args, formatString);\n    NSString *prependedFormatString = [NSString stringWithFormat:@\"\\n[CodePush] %@\", formatString];\n    NSLogv(prependedFormatString, args);\n    va_end(args);\n}"
  },
  {
    "path": "ios/CodePush/JWT/Core/Algorithms/Base/JWTAlgorithm.h",
    "content": "//\n//  JWTAlgorithm.h\n//  JWT\n//\n//  Created by Klaas Pieter Annema on 31-05-13.\n//  Copyright (c) 2013 Karma. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n#import \"JWTDeprecations.h\"\n\n@protocol JWTAlgorithm <NSObject>\n\n@required\n/**\n Signs data using provided secret data.\n @param hash The data to sign.\n @param key The secret to use for signing.\n @param error The inout error.\n */\n- (NSData *)signHash:(NSData *)hash key:(NSData *)key error:(NSError *__autoreleasing*)error;\n/**\n Verifies data using.\n @param hash The data to sign.\n @param signature The secret to use for signing.\n @param error The inout error.\n */\n- (BOOL)verifyHash:(NSData *)hash signature:(NSData *)signature key:(NSData *)key error:(NSError *__autoreleasing*)error;\n\n//@required\n\n@property (nonatomic, readonly, copy) NSString *name;\n\n/**\n Encodes and encrypts the provided payload using the provided secret key\n @param theString The string to encode\n @param theSecret The secret to use for encryption\n @return An NSData object containing the encrypted payload, or nil if something went wrong.\n */\n- (NSData *)encodePayload:(NSString *)theString withSecret:(NSString *)theSecret __deprecated_and_will_be_removed_in_release_version(JWTVersion_3_0_0);\n\n/**\n Verifies the provided signature using the signed input and verification key\n @param input The header and payload encoded string\n @param signature The JWT provided signature\n @param verificationKey The key to use for verifying the signature\n @return YES if the provided signature is valid, NO otherwise\n */\n- (BOOL)verifySignedInput:(NSString *)input withSignature:(NSString *)signature verificationKey:(NSString *)verificationKey __deprecated_and_will_be_removed_in_release_version(JWTVersion_3_0_0);\n\n@optional\n\n/**\n Encodes and encrypts the provided payload using the provided secret key\n @param theStringData The data to encode\n @param theSecretData The secret data to use for encryption\n @return An NSData object containing the encrypted payload, or nil if something went wrong.\n */\n- (NSData *)encodePayloadData:(NSData *)theStringData withSecret:(NSData *)theSecretData;\n\n/**\n Verifies the provided signature using the signed input and verification key (as data)\n @param input The header and payload encoded string\n @param signature The JWT provided signature\n @param verificationKeyData The key data to use for verifying the signature\n @return YES if the provided signature is valid, NO otherwise\n */\n- (BOOL)verifySignedInput:(NSString *)input withSignature:(NSString *)signature verificationKeyData:(NSData *)verificationKeyData;\n@end\n"
  },
  {
    "path": "ios/CodePush/JWT/Core/Algorithms/Base/JWTAlgorithmFactory.h",
    "content": "//\n//  JWTAlgorithmFactory.h\n//  JWT\n//\n//  Created by Lobanov Dmitry on 07.10.15.\n//  Copyright © 2015 Karma. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n#import \"JWTAlgorithm.h\"\n@interface JWTAlgorithmFactory : NSObject\n\n+ (NSArray *)algorithms;\n+ (id<JWTAlgorithm>)algorithmByName:(NSString *)name;\n\n@end\n"
  },
  {
    "path": "ios/CodePush/JWT/Core/Algorithms/Base/JWTAlgorithmFactory.m",
    "content": "//\n//  JWTAlgorithmFactory.m\n//  JWT\n//\n//  Created by Lobanov Dmitry on 07.10.15.\n//  Copyright © 2015 Karma. All rights reserved.\n//\n\n#import \"JWTAlgorithmFactory.h\"\n#import \"JWTAlgorithmHSBase.h\"\n#import \"JWTAlgorithmRSBase.h\"\n#import \"JWTAlgorithmNone.h\"\n\n// not implemented.\nNSString *const JWTAlgorithmNameES256 = @\"ES256\";\nNSString *const JWTAlgorithmNameES384 = @\"ES384\";\nNSString *const JWTAlgorithmNameES512 = @\"ES512\";\n\n@implementation JWTAlgorithmFactory\n\n+ (NSArray *)algorithms {\n    return @[\n            [JWTAlgorithmNone new],\n            [JWTAlgorithmHSBase algorithm256],\n            [JWTAlgorithmHSBase algorithm384],\n            [JWTAlgorithmHSBase algorithm512],\n            [JWTAlgorithmRSBase algorithm256],\n            [JWTAlgorithmRSBase algorithm384],\n            [JWTAlgorithmRSBase algorithm512]\n            ];\n\n}\n\n+ (id<JWTAlgorithm>)algorithmByName:(NSString *)name {\n    id<JWTAlgorithm> algorithm = nil;\n    \n    NSString *algName = [name copy];\n    \n    NSUInteger index = [[self algorithms] indexOfObjectPassingTest:^BOOL(id<JWTAlgorithm> obj, NSUInteger idx, BOOL *stop) {\n        // lowercase comparison\n        return [obj.name.lowercaseString isEqualToString:algName.lowercaseString];\n    }];\n    \n    if (index != NSNotFound) {\n        algorithm = [self algorithms][index];\n    }\n    \n    return algorithm;\n}\n\n@end"
  },
  {
    "path": "ios/CodePush/JWT/Core/Algorithms/Base/JWTAlgorithmNone.h",
    "content": "//\n//  JWTAlgorithmNone.h\n//  JWT\n//\n//  Created by Lobanov Dmitry on 16.10.15.\n//  Copyright © 2015 Karma. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n#import \"JWTAlgorithm.h\"\nextern NSString *const JWTAlgorithmNameNone;\n\n@interface JWTAlgorithmNone : NSObject <JWTAlgorithm>\n\n@end\n"
  },
  {
    "path": "ios/CodePush/JWT/Core/Algorithms/Base/JWTAlgorithmNone.m",
    "content": "//\n//  JWTAlgorithmNone.m\n//  JWT\n//\n//  Created by Lobanov Dmitry on 16.10.15.\n//  Copyright © 2015 Karma. All rights reserved.\n//\n\n#import \"JWTAlgorithmNone.h\"\nNSString *const JWTAlgorithmNameNone = @\"none\";\n\n@implementation JWTAlgorithmNone\n\n- (NSString *)name {\n    return JWTAlgorithmNameNone;\n}\n\n- (NSData *)signHash:(NSData *)hash key:(NSData *)key error:(NSError *__autoreleasing *)error {\n    return [NSData data];\n}\n\n- (BOOL)verifyHash:(NSData *)hash signature:(NSData *)signature key:(NSData *)key error:(NSError *__autoreleasing *)error {\n    //if a secret is provided, this isn't the None algorithm\n    if (key && key.length > 0) {\n        return NO;\n    }\n    \n    //If the signature isn't blank, this isn't the None algorithm\n    if (signature && signature.length > 0) {\n        return NO;\n    }\n    \n    return YES;\n}\n\n- (NSData *)encodePayload:(NSString *)theString withSecret:(NSString *)theSecret {\n    return [self encodePayloadData:[theSecret dataUsingEncoding:NSUTF8StringEncoding] withSecret:[theSecret dataUsingEncoding:NSUTF8StringEncoding]];\n}\n\n- (NSData *)encodePayloadData:(NSData *)theStringData withSecret:(NSData *)theSecretData\n{\n    return [self signHash:theStringData key:theSecretData error:nil];\n}\n\n- (BOOL)verifySignedInput:(NSString *)input withSignature:(NSString *)signature verificationKey:(NSString *)verificationKey\n{\n    return [self verifySignedInput:input withSignature:signature verificationKeyData:verificationKey];\n}\n\n- (BOOL)verifySignedInput:(NSString *)input withSignature:(NSString *)signature verificationKeyData:(NSData *)verificationKeyData\n{\n    return [self verifyHash:[input dataUsingEncoding:NSUTF8StringEncoding] signature:[signature dataUsingEncoding:NSUTF8StringEncoding] key:verificationKeyData error:nil];\n}\n\n@end\n"
  },
  {
    "path": "ios/CodePush/JWT/Core/Algorithms/ESFamily/JWTAlgorithmESBase.h",
    "content": "//\n//  JWTAlgorithmESBase.h\n//  Pods\n//\n//  Created by Lobanov Dmitry on 12.02.17.\n//\n//\n\n#import <Foundation/Foundation.h>\n#import \"JWTRSAlgorithm.h\"\nextern NSString *const JWTAlgorithmNameES256;\nextern NSString *const JWTAlgorithmNameES384;\nextern NSString *const JWTAlgorithmNameES512;\n@interface JWTAlgorithmESBase : NSObject @end\n\n@interface JWTAlgorithmESBase (JWTAsymmetricKeysAlgorithm) <JWTAsymmetricKeysAlgorithm> @end\n\n@interface JWTAlgorithmESBase (Create)\n\n+ (instancetype)algorithm256;\n+ (instancetype)algorithm384;\n+ (instancetype)algorithm512;\n\n@end\n"
  },
  {
    "path": "ios/CodePush/JWT/Core/Algorithms/ESFamily/JWTAlgorithmESBase.m",
    "content": "//\n//  JWTAlgorithmESBase.m\n//  Pods\n//\n//  Created by Lobanov Dmitry on 12.02.17.\n//\n//\n\n#import \"JWTAlgorithmESBase.h\"\n#import <CommonCrypto/CommonCryptor.h>\n@interface JWTAlgorithmESBase ()\n\n@end\n@implementation JWTAlgorithmESBase\n@synthesize keyExtractorType;\n@synthesize signKey;\n@synthesize verifyKey;\n@end\n\n// thanks! https://github.com/soyersoyer/SwCrypt\n@interface JWTAlgorithmESBase (ImportKeys)\n- (void)importKey;\n//importKey(publicKey, format: .importKeyBinary, keyType: .keyPublic)\n@end\n@implementation JWTAlgorithmESBase (ImportKeys)\n- (void)importKey {\n    return;\n}\n@end\n\n@implementation JWTAlgorithmESBase (JWTAsymmetricKeysAlgorithm)\n- (NSString *)name {\n    return @\"ESBase\";\n}\n- (NSData *)signHash:(NSData *)hash key:(NSData *)key error:(NSError *__autoreleasing *)error {\n    return nil;\n}\n- (BOOL)verifyHash:(NSData *)hash signature:(NSData *)signature key:(NSData *)key error:(NSError *__autoreleasing *)error {\n    return NO;\n}\n@end\n"
  },
  {
    "path": "ios/CodePush/JWT/Core/Algorithms/HSFamily/JWTAlgorithmHSBase.h",
    "content": "//\n//  JWTAlgorithmHSBase.h\n//  JWT\n//\n//  Created by Lobanov Dmitry on 13.03.16.\n//  Copyright © 2016 Karma. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n#import \"JWTAlgorithm.h\"\nextern NSString *const JWTAlgorithmNameHS256;\nextern NSString *const JWTAlgorithmNameHS384;\nextern NSString *const JWTAlgorithmNameHS512;\n\n@interface JWTAlgorithmHSBase : NSObject <JWTAlgorithm>\n\n@property (assign, nonatomic, readonly) size_t ccSHANumberDigestLength;\n@property (assign, nonatomic, readonly) uint32_t ccHmacAlgSHANumber;\n\n@end\n\n@interface JWTAlgorithmHSBase (Create)\n\n+ (instancetype)algorithm256;\n+ (instancetype)algorithm384;\n+ (instancetype)algorithm512;\n\n@end\n"
  },
  {
    "path": "ios/CodePush/JWT/Core/Algorithms/HSFamily/JWTAlgorithmHSBase.m",
    "content": "//\n//  JWTAlgorithmHSBase.m\n//  JWT\n//\n//  Created by Lobanov Dmitry on 13.03.16.\n//  Copyright © 2016 Karma. All rights reserved.\n//\n\n#import \"JWTAlgorithmHSBase.h\"\n#import \"JWTBase64Coder.h\"\n#import <CommonCrypto/CommonCrypto.h>\n#import <CommonCrypto/CommonHMAC.h>\n\nNSString *const JWTAlgorithmNameHS256 = @\"HS256\";\nNSString *const JWTAlgorithmNameHS384 = @\"HS384\";\nNSString *const JWTAlgorithmNameHS512 = @\"HS512\";\n\n@interface JWTAlgorithmHSBase () @end\n\n@implementation JWTAlgorithmHSBase\n\n- (size_t)ccSHANumberDigestLength {\n    @throw [[NSException alloc] initWithName:NSInternalInconsistencyException reason:@\"ccSHANumberDigestLength property should be overriden\" userInfo:nil];\n}\n\n- (uint32_t)ccHmacAlgSHANumber {\n    @throw [[NSException alloc] initWithName:NSInternalInconsistencyException reason:@\"ccHmacAlgSHANumber property should be overriden\" userInfo:nil];\n}\n\n- (NSData *)signHash:(NSData *)hash key:(NSData *)key error:(NSError *__autoreleasing *)error {\n    size_t amount = self.ccSHANumberDigestLength;\n    size_t fullSize = amount * sizeof(unsigned char);\n    unsigned char* cHMAC = malloc(fullSize);\n    CCHmacAlgorithm ccAlg = self.ccHmacAlgSHANumber;\n    \n    CCHmac(ccAlg, key.bytes, key.length, hash.bytes, hash.length, cHMAC);\n    \n    NSData *result = [[NSData alloc] initWithBytes:cHMAC length:fullSize];\n    free(cHMAC);\n    return result;\n}\n\n- (BOOL)verifyHash:(NSData *)hash signature:(NSData *)signature key:(NSData *)key error:(NSError *__autoreleasing *)error {\n    NSData *expectedSignatureData = [self signHash:hash key:key error:error];\n    return [expectedSignatureData isEqualToData:signature];\n}\n\n- (NSString *)name;\n{\n    return @\"HSBase\";\n}\n\n- (NSData *)encodePayload:(NSString *)theString withSecret:(NSString *)theSecret;\n{\n    NSData *inputData = [theString dataUsingEncoding:NSUTF8StringEncoding];\n    NSData *secretData = [theSecret dataUsingEncoding:NSUTF8StringEncoding];\n    //[JWTBase64Coder dataWithBase64UrlEncodedString:theSecret];\n    return [self encodePayloadData:inputData withSecret:secretData];\n//    const char *cString = [theString cStringUsingEncoding:NSUTF8StringEncoding];\n//    const char *cSecret = [theSecret cStringUsingEncoding:NSUTF8StringEncoding];\n//    \n//    size_t amount = self.ccSHANumberDigestLength;\n//    size_t fullSize = amount * sizeof(unsigned char);\n//    unsigned char* cHMAC = malloc(fullSize);\n//    CCHmacAlgorithm ccAlg = self.ccHmacAlgSHANumber;\n//\n//    CCHmac(ccAlg, cSecret, strlen(cSecret), cString, strlen(cString), cHMAC);\n//    \n//    NSData *returnData = [[NSData alloc] initWithBytes:cHMAC length:fullSize];\n//    free(cHMAC);\n//    return returnData;\n}\n\n- (NSData *)encodePayloadData:(NSData *)theStringData withSecret:(NSData *)theSecretData\n{\n    return [self signHash:theStringData key:theSecretData error:nil];\n//    size_t amount = self.ccSHANumberDigestLength;\n//    size_t fullSize = amount * sizeof(unsigned char);\n//    unsigned char* cHMAC = malloc(fullSize);\n//    CCHmacAlgorithm ccAlg = self.ccHmacAlgSHANumber;\n//    \n//    CCHmac(ccAlg, theSecretData.bytes, [theSecretData length], theStringData.bytes, [theStringData length], cHMAC);\n//    \n//    NSData *returnData = [[NSData alloc] initWithBytes:cHMAC length:fullSize];\n//    free(cHMAC);\n//    return returnData;\n}\n\n- (BOOL)verifySignedInput:(NSString *)input withSignature:(NSString *)signature verificationKey:(NSString *)verificationKey\n{\n    NSData *verificationKeyData = [verificationKey dataUsingEncoding:NSUTF8StringEncoding];\n    return [self verifySignedInput:input withSignature:signature verificationKeyData:verificationKeyData];\n//    NSData *expectedSignatureData = [self encodePayload:input withSecret:verificationKey];\n//    NSString *expectedSignature = [JWTBase64Coder base64UrlEncodedStringWithData:expectedSignatureData];\n//    \n//    return [expectedSignature isEqualToString:signature];\n}\n\n- (BOOL)verifySignedInput:(NSString *)input withSignature:(NSString *)signature verificationKeyData:(NSData *)verificationKeyData {\n    NSData *signatureData = [JWTBase64Coder dataWithBase64UrlEncodedString:signature];\n    NSData *inputData = [input dataUsingEncoding:NSUTF8StringEncoding];//[JWTBase64Coder dataWithBase64UrlEncodedString:input];\n    return [self verifyHash:inputData signature:signatureData key:verificationKeyData error:nil ];\n//    const char *cString = [input cStringUsingEncoding:NSUTF8StringEncoding];\n//    NSData *inputData = [NSData dataWithBytes:cString length:strlen(cString)];\n//    \n//    NSData *expectedSignatureData = [self encodePayloadData:inputData withSecret:verificationKeyData];\n//    NSString *expectedSignature = [JWTBase64Coder base64UrlEncodedStringWithData:expectedSignatureData];\n//    \n//    return [expectedSignature isEqualToString:signature];\n}\n\n@end\n\n@interface JWTAlgorithmHSFamilyMember : JWTAlgorithmHSBase @end\n@implementation JWTAlgorithmHSFamilyMember @end\n\n@interface JWTAlgorithmHS256 : JWTAlgorithmHSBase @end\n@interface JWTAlgorithmHS384 : JWTAlgorithmHSBase @end\n@interface JWTAlgorithmHS512 : JWTAlgorithmHSBase @end\n\n@implementation JWTAlgorithmHS256\n\n- (size_t)ccSHANumberDigestLength {\n    return CC_SHA256_DIGEST_LENGTH;\n}\n\n- (uint32_t)ccHmacAlgSHANumber {\n    return kCCHmacAlgSHA256;\n}\n\n- (NSString *)name {\n    return @\"HS256\";\n}\n\n@end\n\n@implementation JWTAlgorithmHS384\n\n- (size_t)ccSHANumberDigestLength {\n    return CC_SHA384_DIGEST_LENGTH;\n}\n\n- (uint32_t)ccHmacAlgSHANumber {\n    return kCCHmacAlgSHA384;\n}\n\n- (NSString *)name {\n    return @\"HS384\";\n}\n\n@end\n\n@implementation JWTAlgorithmHS512\n\n- (size_t)ccSHANumberDigestLength {\n    return CC_SHA512_DIGEST_LENGTH;\n}\n\n- (uint32_t)ccHmacAlgSHANumber {\n    return kCCHmacAlgSHA512;\n}\n\n- (NSString *)name {\n    return @\"HS512\";\n}\n\n@end\n\n@interface JWTAlgorithmHSFamilyMemberMutable : JWTAlgorithmHSFamilyMember\n@property (assign, nonatomic, readwrite) size_t ccSHANumberDigestLength;\n@property (assign, nonatomic, readwrite) uint32_t ccHmacAlgSHANumber;\n@property (copy, nonatomic, readwrite) NSString *name;\n@end\n\n@implementation JWTAlgorithmHSFamilyMemberMutable\n\n@synthesize ccSHANumberDigestLength = _ccSHANumberDigestLength;\n@synthesize ccHmacAlgSHANumber = _ccHmacAlgSHANumber;\n@synthesize name = _name;\n\n- (size_t)ccSHANumberDigestLength {\n    return _ccSHANumberDigestLength;\n}\n\n- (uint32_t)ccHmacAlgSHANumber {\n    return _ccHmacAlgSHANumber;\n}\n\n@end\n\n@implementation JWTAlgorithmHSBase (Create)\n\n+ (instancetype)algorithm256 {\n    return [JWTAlgorithmHS256 new];\n}\n\n+ (instancetype)algorithm384 {\n    return [JWTAlgorithmHS384 new];\n}\n\n+ (instancetype)algorithm512 {\n    return [JWTAlgorithmHS512 new];\n}\n\n@end\n"
  },
  {
    "path": "ios/CodePush/JWT/Core/Algorithms/Holders/JWTAlgorithmDataHolder.h",
    "content": "//\n//  JWTAlgorithmDataHolder.h\n//  JWT\n//\n//  Created by Lobanov Dmitry on 31.08.16.\n//  Copyright © 2016 Karma. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n#import \"JWTAlgorithm.h\"\n#import \"JWTDeprecations.h\"\n#import \"JWTBase64Coder.h\"\n\n// TODO: available in 3.0\n// All methods with secret as NSString in algorithms will be deprecated or removed.\n\n@protocol JWTAlgorithmDataHolderProtocol <NSObject, NSCopying>\n/**\n The verification key to use when encoding/decoding a JWT in data form\n */\n@property (copy, nonatomic, readwrite) NSData *internalSecretData;\n\n/**\n The <JWTAlgorithm> to use for encoding a JWT\n */\n@property (strong, nonatomic, readwrite) id <JWTAlgorithm> internalAlgorithm;\n\n/**\n The <JWTStringCoder__Protocol> string coder. It converts data to string and vice versa.\n */\n@property (strong, nonatomic, readwrite) id <JWTStringCoder__Protocol> internalStringCoder;\n@end\n\n@interface JWTAlgorithmBaseDataHolder : NSObject <JWTAlgorithmDataHolderProtocol>\n\n#pragma mark - Getters\n/**\n The verification key to use when encoding/decoding a JWT\n */\n@property (copy, nonatomic, readonly) NSString *internalSecret;\n\n/**\n The algorithm name to use for decoding the JWT. Required unless force decode is true\n */\n@property (copy, nonatomic, readonly) NSString *internalAlgorithmName;\n\n#pragma mark - Setters\n/**\n Sets jwtSecret and returns the JWTAlgorithmBaseDataHolder to allow for method chaining\n */\n@property (copy, nonatomic, readonly) JWTAlgorithmBaseDataHolder *(^secret)(NSString *secret);\n\n/**\n Sets jwtSecretData and returns the JWTAlgorithmBaseDataHolder to allow for method chaining\n */\n@property (copy, nonatomic, readonly) JWTAlgorithmBaseDataHolder *(^secretData)(NSData *secretData);\n\n/**\n Sets jwtAlgorithm and returns the JWTAlgorithmBaseDataHolder to allow for method chaining\n */\n@property (copy, nonatomic, readonly) JWTAlgorithmBaseDataHolder *(^algorithm)(id<JWTAlgorithm>algorithm);\n\n/**\n Sets jwtAlgorithmName and returns the JWTAlgorithmBaseDataHolder to allow for method chaining. See list of names in appropriate headers.\n */\n@property (copy, nonatomic, readonly) JWTAlgorithmBaseDataHolder *(^algorithmName)(NSString *algorithmName);\n\n/**\n Sets stringCoder and returns the JWTAlgorithmBaseDataHolder to allow for method chaining. See list of names in appropriate headers.\n */\n@property (copy, nonatomic, readonly) JWTAlgorithmBaseDataHolder *(^stringCoder)(id<JWTStringCoder__Protocol> stringCoder);\n@end\n\n@protocol JWTAlgorithmDataHolderCreateProtocol <NSObject>\n\n+ (instancetype)createWithAlgorithm256;\n+ (instancetype)createWithAlgorithm384;\n+ (instancetype)createWithAlgorithm512;\n\n@end\n\n@interface JWTAlgorithmNoneDataHolder : JWTAlgorithmBaseDataHolder @end\n@interface JWTAlgorithmHSFamilyDataHolder : JWTAlgorithmBaseDataHolder <JWTAlgorithmDataHolderCreateProtocol>\n@end\n@protocol JWTCryptoKeyProtocol;\n@interface JWTAlgorithmRSFamilyDataHolder : JWTAlgorithmBaseDataHolder <JWTAlgorithmDataHolderCreateProtocol>\n#pragma mark - Getters\n/**\n The passphrase for the PKCS12 blob, which represents the certificate containing the private key for the RS algorithms.\n */\n@property (copy, nonatomic, readonly) NSString *internalPrivateKeyCertificatePassphrase;\n@property (copy, nonatomic, readonly) NSString *internalKeyExtractorType;\n@property (strong, nonatomic, readonly) id<JWTCryptoKeyProtocol> internalSignKey;\n@property (strong, nonatomic, readonly) id<JWTCryptoKeyProtocol> internalVerifyKey;\n#pragma mark - Setters\n/**\n Sets jwtPrivateKeyCertificatePassphrase and returns the JWTAlgorithmRSFamilyDataHolder to allow for method chaining\n */\n@property (copy, nonatomic, readonly) JWTAlgorithmRSFamilyDataHolder *(^privateKeyCertificatePassphrase)(NSString *privateKeyCertificatePassphrase);\n@property (copy, nonatomic, readonly) JWTAlgorithmRSFamilyDataHolder *(^keyExtractorType)(NSString *keyExtractorType);\n@property (copy, nonatomic, readonly) JWTAlgorithmRSFamilyDataHolder *(^signKey)(id<JWTCryptoKeyProtocol> signKey);\n@property (copy, nonatomic, readonly) JWTAlgorithmRSFamilyDataHolder *(^verifyKey)(id<JWTCryptoKeyProtocol> verifyKey);\n@end\n"
  },
  {
    "path": "ios/CodePush/JWT/Core/Algorithms/Holders/JWTAlgorithmDataHolder.m",
    "content": "//\n//  JWTAlgorithmDataHolder.m\n//  JWT\n//\n//  Created by Lobanov Dmitry on 31.08.16.\n//  Copyright © 2016 Karma. All rights reserved.\n//\n\n#import \"JWTAlgorithmDataHolder.h\"\n#import \"JWTAlgorithmFactory.h\"\n#import \"JWTAlgorithmNone.h\"\n#import \"JWTRSAlgorithm.h\"\n#import \"JWTAlgorithmHSBase.h\"\n#import \"JWTAlgorithmRSBase.h\"\n#import \"JWTBase64Coder.h\"\n\n@interface JWTAlgorithmBaseDataHolder()\n// not needed by algorithm adoption.\n// @property (copy, nonatomic, readwrite) NSData *internalSecretData;\n// @property (strong, nonatomic, readwrite) id <JWTAlgorithm> internalAlgorithm;\n\n#pragma mark - Setters\n/**\n Sets jwtSecret and returns the JWTAlgorithmBaseDataHolder to allow for method chaining\n */\n@property (copy, nonatomic, readwrite) JWTAlgorithmBaseDataHolder *(^secret)(NSString *secret);\n\n/**\n Sets jwtSecretData and returns the JWTAlgorithmBaseDataHolder to allow for method chaining\n */\n@property (copy, nonatomic, readwrite) JWTAlgorithmBaseDataHolder *(^secretData)(NSData *secretData);\n\n/**\n Sets jwtAlgorithm and returns the JWTAlgorithmBaseDataHolder to allow for method chaining\n */\n@property (copy, nonatomic, readwrite) JWTAlgorithmBaseDataHolder *(^algorithm)(id<JWTAlgorithm>algorithm);\n\n/**\n Sets jwtAlgorithmName and returns the JWTAlgorithmBaseDataHolder to allow for method chaining. See list of names in appropriate headers.\n */\n@property (copy, nonatomic, readwrite) JWTAlgorithmBaseDataHolder *(^algorithmName)(NSString *algorithmName);\n\n/**\n Sets stringCoder and returns the JWTAlgorithmBaseDataHolder to allow for method chaining. See list of names in appropriate headers.\n */\n@property (copy, nonatomic, readwrite) JWTAlgorithmBaseDataHolder *(^stringCoder)(id<JWTStringCoder__Protocol> stringCoder);\n@end\n\n@interface JWTAlgorithmBaseDataHolder (Convertions)\n\n- (NSData *)dataFromString:(NSString *)string;\n- (NSString *)stringFromData:(NSData *)data;\n\n@end\n\n@implementation JWTAlgorithmBaseDataHolder (Convertions)\n#pragma mark - Convertions\n- (NSData *)dataFromString:(NSString *)string {\n    NSData *result = [self.internalStringCoder dataWithString:string];\n    \n    if (result == nil) {\n        // tell about it?!\n        NSLog(@\"%@ %@ something went wrong. Data is not base64encoded\", self.debugDescription, NSStringFromSelector(_cmd));\n    }\n    \n    return result;// ?: [string dataUsingEncoding:NSUTF8StringEncoding];\n}\n\n- (NSString *)stringFromData:(NSData *)data {\n    NSString *result = [self.internalStringCoder stringWithData:data];\n    \n    if (result == nil) {\n        NSLog(@\"%@ %@ something went wrong. String is not base64encoded\", self.debugDescription, NSStringFromSelector(_cmd));\n    }\n    return result ?: [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];\n}\n@end\n\n@interface JWTAlgorithmBaseDataHolder (Fluent)\n- (void)setupFluent;\n@end\n\n@implementation JWTAlgorithmBaseDataHolder (Fluent)\n#pragma mark - Fluent\n- (instancetype)secretData:(NSData *)secretData {\n    self.internalSecretData = secretData;\n    return self;\n}\n\n- (instancetype)secret:(NSString *)secret {\n    self.internalSecretData = [self dataFromString:secret];\n    return self;\n}\n\n- (instancetype)algorithm:(id<JWTAlgorithm>)algorithm {\n    self.internalAlgorithm = algorithm;\n    return self;\n}\n\n- (instancetype)algorithmName:(NSString *)algorithmName {\n    self.internalAlgorithm = [JWTAlgorithmFactory algorithmByName:algorithmName];\n    return self;\n}\n\n- (instancetype)stringCoder:(id<JWTStringCoder__Protocol>)stringCoder {\n    self.internalStringCoder = stringCoder;\n    return self;\n}\n\n- (void)setupFluent {\n    __weak typeof(self) weakSelf = self;\n    self.secret = ^(NSString *secret) {\n        return [weakSelf secret:secret];\n    };\n    \n    self.secretData = ^(NSData *secretData) {\n        return [weakSelf secretData:secretData];\n    };\n    \n    self.algorithm = ^(id<JWTAlgorithm> algorithm) {\n        return [weakSelf algorithm:algorithm];\n    };\n    \n    self.algorithmName = ^(NSString *algorithmName) {\n        return [weakSelf algorithmName:algorithmName];\n    };\n\n    self.stringCoder = ^(id <JWTStringCoder__Protocol> stringCoder) {\n        return [weakSelf stringCoder:stringCoder];\n    };\n}\n@end\n\n@interface JWTAlgorithmBaseDataHolder (Debug)\n- (NSDictionary *)debugInformation;\n@end\n@implementation JWTAlgorithmBaseDataHolder (Debug)\n- (NSString *)debugDescription {\n    return [[self debugInformation] debugDescription];\n}\n- (NSDictionary *)debugInformation {\n    return @{\n             @\"algorithmName\" : self.internalAlgorithmName ?: @\"unknown\",\n             @\"algorithm\" : [self.internalAlgorithm debugDescription] ?: @\"unknown\",\n             @\"secretData\" : [self.internalSecretData debugDescription] ?: @\"unknown\",\n             @\"stringCoder\" : [self.internalStringCoder debugDescription] ?: @\"unknown\"\n             };\n}\n\n@end\n\n@implementation JWTAlgorithmBaseDataHolder\n@synthesize internalAlgorithm;\n@synthesize internalSecretData;\n@synthesize internalStringCoder = _internalStringCoder;\n\n- (id<JWTStringCoder__Protocol>)internalStringCoder {\n    return _internalStringCoder ?: [JWTBase64Coder new];\n}\n\n#pragma mark - Custom Getters\n- (NSString *)internalAlgorithmName {\n    return [self.internalAlgorithm name];\n}\n\n- (NSString *)internalSecret {\n    return [self stringFromData:self.internalSecretData];\n}\n\n- (instancetype)init {\n    self = [super init];\n    if (self) {\n        [self setupFluent];\n    }\n    return self;\n}\n\n#pragma mark - Copy\n- (id)copyWithZone:(NSZone *)zone {\n    JWTAlgorithmBaseDataHolder *holder = [self.class new];\n    holder.internalAlgorithm = self.internalAlgorithm;\n    holder.internalSecretData = self.internalSecretData;\n    holder.internalStringCoder = self.internalStringCoder;\n    return holder;\n}\n@end\n\n@interface JWTAlgorithmBaseDataHolder(Create)\n- (instancetype)initWithAlgorithmName:(NSString *)name;\n@end\n\n@implementation JWTAlgorithmBaseDataHolder(Create)\n- (instancetype)initWithAlgorithmName:(NSString *)name {\n    return [self init].algorithmName(name);\n}\n@end\n\n@implementation JWTAlgorithmNoneDataHolder\n- (instancetype)init {\n    if (self = [super init]) {\n        self.internalAlgorithm = [JWTAlgorithmFactory algorithmByName:JWTAlgorithmNameNone];\n        self.internalSecretData = nil;\n    }\n    return self;\n}\n@end\n\n@implementation JWTAlgorithmHSFamilyDataHolder\n+ (instancetype)createWithAlgorithm256 {\n    return [[self alloc] initWithAlgorithmName:JWTAlgorithmNameHS256];\n}\n+ (instancetype)createWithAlgorithm384 {\n    return [[self alloc] initWithAlgorithmName:JWTAlgorithmNameHS384];\n}\n+ (instancetype)createWithAlgorithm512 {\n    return [[self alloc] initWithAlgorithmName:JWTAlgorithmNameHS512];\n}\n@end\n\n@interface JWTAlgorithmRSFamilyDataHolder()\n#pragma mark - Getters\n@property (copy, nonatomic, readwrite) NSString *internalPrivateKeyCertificatePassphrase;\n@property (copy, nonatomic, readwrite) NSString *internalKeyExtractorType;\n@property (strong, nonatomic, readwrite) id<JWTCryptoKeyProtocol> internalSignKey;\n@property (strong, nonatomic, readwrite) id<JWTCryptoKeyProtocol> internalVerifyKey;\n#pragma mark - Setters\n@property (copy, nonatomic, readwrite) JWTAlgorithmRSFamilyDataHolder *(^privateKeyCertificatePassphrase)(NSString *privateKeyCertificatePassphrase);\n@property (copy, nonatomic, readwrite) JWTAlgorithmRSFamilyDataHolder *(^keyExtractorType)(NSString *keyExtractorType);\n@property (copy, nonatomic, readwrite) JWTAlgorithmRSFamilyDataHolder *(^signKey)(id<JWTCryptoKeyProtocol> signKey);\n@property (copy, nonatomic, readwrite) JWTAlgorithmRSFamilyDataHolder *(^verifyKey)(id<JWTCryptoKeyProtocol> verifyKey);\n@end\n\n@implementation JWTAlgorithmRSFamilyDataHolder (Debug)\n- (NSDictionary *)debugInformation {\n    NSDictionary *add = @{@\"privateKeyCertificatePassphrase\" : self.internalPrivateKeyCertificatePassphrase ?: @\"unknown\",\n                          @\"keyExtractorType\" : self.internalKeyExtractorType ?: @\"unknown\",\n                          @\"signKey\" : [self.signKey debugDescription] ?: @\"unknown\",\n                          @\"verifyKey\" : [self.verifyKey debugDescription] ?: @\"unknown\"\n                          };\n    NSMutableDictionary *result = [[super debugInformation] mutableCopy];\n    [result addEntriesFromDictionary:add];\n    return result;\n}\n@end\n\n@implementation JWTAlgorithmRSFamilyDataHolder\n\n#pragma mark - Initialization\n+ (instancetype)createWithAlgorithm256 {\n    return [[self alloc] initWithAlgorithmName:JWTAlgorithmNameRS256];\n}\n\n+ (instancetype)createWithAlgorithm384 {\n    return [[self alloc] initWithAlgorithmName:JWTAlgorithmNameRS384];\n}\n\n+ (instancetype)createWithAlgorithm512 {\n    return [[self alloc] initWithAlgorithmName:JWTAlgorithmNameRS512];\n}\n\n#pragma mark - Getters\n- (id<JWTAlgorithm>)internalAlgorithm {\n    id <JWTAlgorithm> algorithm = [super internalAlgorithm];\n    if ([algorithm conformsToProtocol:@protocol(JWTRSAlgorithm)]) {\n        // copy?\n        id<JWTRSAlgorithm>currentAlgorithm = [(id <JWTRSAlgorithm>)algorithm copyWithZone:nil];\n        currentAlgorithm.privateKeyCertificatePassphrase = self.internalPrivateKeyCertificatePassphrase;\n        currentAlgorithm.keyExtractorType = self.internalKeyExtractorType;\n        currentAlgorithm.signKey = self.internalSignKey;\n        currentAlgorithm.verifyKey = self.internalVerifyKey;\n        algorithm = currentAlgorithm;\n    }\n    return algorithm;\n}\n\n#pragma mark - Setters\n- (instancetype)privateKeyCertificatePassphrase:(NSString *)passphrase {\n    self.internalPrivateKeyCertificatePassphrase = passphrase;\n    return self;\n}\n- (instancetype)keyExtractorType:(NSString *)type {\n    self.internalKeyExtractorType = type;\n    return self;\n}\n- (instancetype)signKey:(id<JWTCryptoKeyProtocol>)key {\n    self.internalSignKey = key;\n    return self;\n}\n- (instancetype)verifyKey:(id<JWTCryptoKeyProtocol>)key {\n    self.internalVerifyKey = key;\n    return self;\n}\n\n#pragma mark - Copy\n- (id)copyWithZone:(NSZone *)zone {\n    JWTAlgorithmRSFamilyDataHolder *holder = [super copyWithZone:zone];\n    holder.internalPrivateKeyCertificatePassphrase = self.internalPrivateKeyCertificatePassphrase;\n    holder.internalKeyExtractorType = self.internalKeyExtractorType;\n    holder.internalSignKey = self.internalSignKey;\n    holder.internalVerifyKey = self.internalVerifyKey;\n    return holder;\n}\n@end\n\n@implementation JWTAlgorithmRSFamilyDataHolder (Fluent)\n- (void)setupFluent {\n    [super setupFluent];\n    __weak typeof(self) weakSelf = self;\n    self.privateKeyCertificatePassphrase = ^(NSString *privateKeyCertificatePassphrase) {\n        return [weakSelf privateKeyCertificatePassphrase:privateKeyCertificatePassphrase];\n    };\n    self.keyExtractorType = ^(NSString *keyExtractorType) {\n        return [weakSelf keyExtractorType:keyExtractorType];\n    };\n    self.signKey = ^(id<JWTCryptoKeyProtocol> key){\n        return [weakSelf signKey:key];\n    };\n    self.verifyKey = ^(id<JWTCryptoKeyProtocol> key){\n        return [weakSelf verifyKey:key];\n    };\n}\n@end\n"
  },
  {
    "path": "ios/CodePush/JWT/Core/Algorithms/Holders/JWTAlgorithmDataHolderChain.h",
    "content": "//\n//  JWTAlgorithmDataHolderChain.h\n//  JWT\n//\n//  Created by Lobanov Dmitry on 02.10.16.\n//  Copyright © 2016 Karma. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n#import \"JWTAlgorithmDataHolder.h\"\n\n@interface JWTAlgorithmDataHolderChain : NSObject\n\n@property (strong, nonatomic, readonly) NSArray *holders;\n\n#pragma mark - Initialization\n- (instancetype)initWithHolders:(NSArray *)holders;\n- (instancetype)initWithHolder:(id<JWTAlgorithmDataHolderProtocol>)holder;\n\n#pragma mark - Appending\n- (instancetype)chainByAppendingChain:(JWTAlgorithmDataHolderChain *)chain;\n- (instancetype)chainByAppendingHolders:(NSArray *)holders;\n- (instancetype)chainByAppendingHolder:(id<JWTAlgorithmDataHolderProtocol>)holder;\n\n#pragma mark - Create\n+ (instancetype)chainWithHolders:(NSArray *)holders;\n+ (instancetype)chainWithHolder:(id<JWTAlgorithmDataHolderProtocol>)holder;\n@end\n\n@interface JWTAlgorithmDataHolderChain (HoldersPopulation)\n- (NSArray *)singleAlgorithm:(id<JWTAlgorithm>)algorithm withManySecretData:(NSArray *)secretsData;\n- (NSArray *)singleSecretData:(NSData *)secretData withManyAlgorithms:(NSArray *)algorithms;\n\n- (instancetype)chainByPopulatingAlgorithm:(id<JWTAlgorithm>)algorithm withManySecretData:(NSArray *)secretsData;\n- (instancetype)chainByPopulatingSecretData:(NSData *)secretData withManyAlgorithms:(NSArray *)algorithms;\n\n@end\n"
  },
  {
    "path": "ios/CodePush/JWT/Core/Algorithms/Holders/JWTAlgorithmDataHolderChain.m",
    "content": "//\n//  JWTAlgorithmDataHolderChain.m\n//  JWT\n//\n//  Created by Lobanov Dmitry on 02.10.16.\n//  Copyright © 2016 Karma. All rights reserved.\n//\n\n#import \"JWTAlgorithmDataHolderChain.h\"\n\n@interface JWTAlgorithmDataHolderChain()\n\n@property (strong, nonatomic, readwrite) NSArray *holders;\n\n@end\n\n@implementation JWTAlgorithmDataHolderChain\n\n- (NSArray *)holders {\n    if (!_holders) {\n        _holders = @[];\n    }\n    return _holders;\n}\n\n#pragma mark - Initialization\n- (instancetype)initWithHolders:(NSArray *)holders {\n    self = [super init];\n    if (holders) {\n        // check that holders conform to protocol\n        NSArray *checkedHolders = [holders filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id  _Nullable evaluatedObject, NSDictionary<NSString *,id> * _Nullable bindings) {\n            return [evaluatedObject conformsToProtocol:@protocol(JWTAlgorithmDataHolderProtocol)];\n        }]];\n        self.holders = checkedHolders;\n    }\n    return self;\n}\n\n- (instancetype)initWithHolder:(id<JWTAlgorithmDataHolderProtocol>)holder {\n    if (holder) {\n        return [self initWithHolders:@[holder]];\n    }\n    return nil;\n}\n\n#pragma mark - Appending\n- (instancetype)chainByAppendingChain:(JWTAlgorithmDataHolderChain *)chain {\n    NSArray *holders = self.holders;\n    if (chain) {\n        holders = [holders arrayByAddingObjectsFromArray:chain.holders];\n    }\n    return [[self.class alloc] initWithHolders:holders];\n}\n\n- (instancetype)chainByAppendingHolders:(NSArray *)holders {\n    // create new chain with holders\n    JWTAlgorithmDataHolderChain *chain = nil;\n    if (holders) {\n        chain = [[self.class alloc] initWithHolders:holders];\n    }\n    return [self chainByAppendingChain:chain];\n}\n\n- (instancetype)chainByAppendingHolder:(id<JWTAlgorithmDataHolderProtocol>)holder {\n    return [self chainByAppendingHolders:holder ? @[holder] : nil];\n}\n\n#pragma mark - Create\n+ (instancetype)chainWithHolders:(NSArray *)holders {\n    return [[self new] chainByAppendingHolders:holders];\n}\n\n+ (instancetype)chainWithHolder:(id<JWTAlgorithmDataHolderProtocol>)holder {\n    return [[self new] chainByAppendingHolder:holder];\n}\n\n#pragma mark - Debug\n- (NSString *)debugDescription {\n    return [NSString stringWithFormat:@\"%@ holders: %@\", self.class, [self.holders valueForKey:@\"debugDescription\"]];\n}\n@end\n\n@implementation JWTAlgorithmDataHolderChain (Convenient)\n- (id<JWTAlgorithmDataHolderProtocol>)firstHolderByAlgorithm:(id<JWTAlgorithm>)algorithm {\n    NSInteger index = [self.holders indexOfObjectPassingTest:^BOOL(id <JWTAlgorithmDataHolderProtocol> _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {\n        return [[[obj internalAlgorithm] name] isEqualToString:[algorithm name]];\n    }];\n    if (index != NSNotFound) {\n        return self.holders[index];\n    }\n\n    return nil;\n}\n- (id<JWTAlgorithmDataHolderProtocol>)firstHolderBySecretData:(NSData *)secretData {\n    NSInteger index = [self.holders indexOfObjectPassingTest:^BOOL(id <JWTAlgorithmDataHolderProtocol> _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {\n        return [[obj internalSecretData] isEqualToData:secretData];\n    }];\n    if (index != NSNotFound) {\n        return self.holders[index];\n    }\n\n    return nil;\n}\n- (NSArray *)singleAlgorithm:(id<JWTAlgorithm>)algorithm withManySecretData:(NSArray *)secretsData {\n    NSArray *holders = @[];\n\n    id holder = [self firstHolderByAlgorithm:algorithm];\n\n    if (!holder) {\n        return holders;\n    }\n\n    for (NSData *secretData in secretsData) {\n        id<JWTAlgorithmDataHolderProtocol> newHolder = [holder copy];\n        [newHolder setInternalSecretData:secretData];\n        holders = [holders arrayByAddingObject:newHolder];\n    }\n    return holders;\n}\n\n- (NSArray *)singleSecretData:(NSData *)secretData withManyAlgorithms:(NSArray *)algorithms {\n    NSArray *holders = @[];\n\n    id holder = [self firstHolderBySecretData:secretData];\n\n    if (!holder) {\n        return holders;\n    }\n\n    for (id<JWTAlgorithm>algorithm in algorithms) {\n        id<JWTAlgorithmDataHolderProtocol> newHolder = [holder copy];\n        [newHolder setInternalAlgorithm:algorithm];\n        [holders arrayByAddingObject:newHolder];\n    }\n    return holders;\n}\n\n- (instancetype)chainByPopulatingAlgorithm:(id<JWTAlgorithm>)algorithm withManySecretData:(NSArray *)secretsData {\n    return [[self.class alloc] initWithHolders:[self singleAlgorithm:algorithm withManySecretData:secretsData]];\n}\n\n- (instancetype)chainByPopulatingSecretData:(NSData *)secretData withManyAlgorithms:(NSArray *)algorithms {\n    return [[self.class alloc] initWithHolders:[self singleSecretData:secretData withManyAlgorithms:algorithms]];\n}\n@end\n"
  },
  {
    "path": "ios/CodePush/JWT/Core/Algorithms/RSFamily/JWTAlgorithmRSBase.h",
    "content": "//\n//  JWTAlgorithmRSBase.h\n//  JWT\n//\n//  Created by Lobanov Dmitry on 13.03.16.\n//  Copyright © 2016 Karma. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n#import \"JWTRSAlgorithm.h\"\nextern NSString *const JWTAlgorithmNameRS256;\nextern NSString *const JWTAlgorithmNameRS384;\nextern NSString *const JWTAlgorithmNameRS512;\n\n@interface JWTAlgorithmRSBase : NSObject <JWTRSAlgorithm>\n\n@property (assign, nonatomic, readonly) size_t ccSHANumberDigestLength;\n@property (assign, nonatomic, readonly) uint32_t secPaddingPKCS1SHANumber;\n- (unsigned char *)CC_SHANumberWithData:(const void *)data withLength:(uint32_t)len withHashBytes:(unsigned char *)hashBytes;\n\n@end\n\n@interface JWTAlgorithmRSBase (Create)\n\n+ (instancetype)algorithm256;\n+ (instancetype)algorithm384;\n+ (instancetype)algorithm512;\n+ (instancetype)mutableAlgorithm __deprecated;\n\n@end\n\n/*\n // when you can't live without mutability, uncomment.\n @class JWTAlgorithmRSFamilyMemberMutable;\n*/"
  },
  {
    "path": "ios/CodePush/JWT/Core/Algorithms/RSFamily/JWTAlgorithmRSBase.m",
    "content": "//\n//  JWTAlgorithmRSBase.m\n//  JWT\n//\n//  Created by Lobanov Dmitry on 13.03.16.\n//  Copyright © 2016 Karma. All rights reserved.\n//\n\n#import \"JWTAlgorithmRSBase.h\"\n#import \"JWTBase64Coder.h\"\n#import \"JWTCryptoSecurity.h\"\n#import \"JWTCryptoKeyExtractor.h\"\n#import \"JWTCryptoKey.h\"\n#import \"JWTAlgorithmFactory.h\"\n#import <CommonCrypto/CommonCrypto.h>\n/*\n*    * Possible inheritence *\n*\n*\n*             RSBase (Public + Create-category)\n*            /      \\\n*           /        \\\n*  RSBaseMac          RSBaseIOS\n*           \\  ifdef /\n*            \\      /\n*         RSFamilyMember\n*                |\n*         RSFamilyMemberMutable\n*\n*/\n\nNSString *const JWTAlgorithmNameRS256 = @\"RS256\";\nNSString *const JWTAlgorithmNameRS384 = @\"RS384\";\nNSString *const JWTAlgorithmNameRS512 = @\"RS512\";\n\n@interface JWTAlgorithmRSBase()\n@property (nonatomic, readonly) id <JWTCryptoKeyExtractorProtocol> keyExtractor;\n@end\n\n@implementation JWTAlgorithmRSBase\n\n#pragma mark - NSCopying\n- (id)copyWithZone:(NSZone *)zone {\n    // create new.\n    id <JWTRSAlgorithm> algorithm = (id<JWTRSAlgorithm>)[JWTAlgorithmFactory algorithmByName:[self name]];\n    algorithm.privateKeyCertificatePassphrase = self.privateKeyCertificatePassphrase;\n    algorithm.keyExtractorType = self.keyExtractorType;\n    algorithm.signKey = self.signKey;\n    algorithm.verifyKey = self.verifyKey;\n    return algorithm;\n}\n\n@synthesize privateKeyCertificatePassphrase;\n@synthesize keyExtractorType;\n@synthesize signKey;\n@synthesize verifyKey;\n- (id<JWTCryptoKeyExtractorProtocol>) keyExtractor {\n    return [JWTCryptoKeyExtractor createWithType:self.keyExtractorType];\n}\n#pragma mark - Override\n- (size_t)ccSHANumberDigestLength {\n    @throw [[NSException alloc] initWithName:NSInternalInconsistencyException reason:@\"ccSHANumberDigestLength property should be overriden\" userInfo:nil];\n}\n\n- (uint32_t)secPaddingPKCS1SHANumber {\n    @throw [[NSException alloc] initWithName:NSInternalInconsistencyException reason:@\"secPaddingPKCS1SHANumber property should be overriden\" userInfo:nil];\n}\n\n- (unsigned char *)CC_SHANumberWithData:(const void *)data withLength:(CC_LONG)len withHashBytes:(unsigned char *)hashBytes {\n    return nil;\n}\n\n- (NSString *)name {\n    return @\"RSBase\";\n}\n\n#pragma mark - JWTAlgorithm\n- (NSData *)signHash:(NSData *)hash key:(NSData *)key error:(NSError *__autoreleasing *)error {\n    NSData *result = nil;\n    if (self.signKey || self.keyExtractor) {\n        NSError *extractKeyError = nil;\n        id <JWTCryptoKeyProtocol> keyItem = self.signKey ?: [self.keyExtractor keyFromData:key parameters:@{ [JWTCryptoKeyExtractor parametersKeyCertificatePassphrase] : self.privateKeyCertificatePassphrase ?: [NSNull null] } error:&extractKeyError];\n        \n        if (extractKeyError || keyItem == nil) {\n            // tell about error\n            if (extractKeyError && error) {\n                *error = extractKeyError;\n            }\n            NSError *removeError = nil;\n            [JWTCryptoSecurity removeKeyByTag:keyItem.tag error:&removeError];\n            if (removeError && error) {                \n                *error = removeError;\n            }\n        }\n        else {\n            result = [self signData:hash withKey:keyItem.key];\n        }\n    }\n    else {\n        SecIdentityRef identity = nil;\n        SecTrustRef trust = nil;\n        \n//        [JWTCryptoSecurity extractIdentityAndTrustFromPKCS12:inPKCS12Data password:keyPassword identity:outIdentity trust:outTrust];\n        [JWTCryptoSecurity extractIdentityAndTrustFromPKCS12:(__bridge CFDataRef)(key) password: (__bridge CFStringRef)(self.privateKeyCertificatePassphrase) identity:&identity trust:&trust];\n        \n        if (identity && trust) {\n            SecKeyRef privateKey;\n            SecIdentityCopyPrivateKey(identity, &privateKey);\n            result = [self signData:hash withKey:privateKey];\n            \n            if (privateKey) {\n                CFRelease(privateKey);\n            }\n        }\n        \n        if (identity) {\n            CFRelease(identity);\n        }\n        \n        if (trust) {\n            CFRelease(trust);\n        }\n    }\n    return result;\n}\n- (BOOL)verifyHash:(NSData *)hash signature:(NSData *)signature key:(NSData *)key error:(NSError *__autoreleasing *)error {\n    if (self.verifyKey || self.keyExtractor) {\n        NSError *extractKeyError = nil;\n        id<JWTCryptoKeyProtocol> keyItem = self.verifyKey?: [self.keyExtractor keyFromData:key parameters:nil error:&extractKeyError];\n        BOOL verified = NO;\n        \n        if (extractKeyError || keyItem == nil) {\n            // error while getting key.\n            // cleanup.\n            // tell about error\n            if (extractKeyError && error) {\n                *error = extractKeyError;\n            }\n            NSError *removeError = nil;\n            [JWTCryptoSecurity removeKeyByTag:keyItem.tag error:&removeError];\n            if (removeError && error) {\n                //???\n                *error = removeError;\n            }\n            return verified;\n        }\n        else {\n            verified = [self verifyData:hash witSignature:signature withKey:keyItem.key];\n        }\n        \n        NSError *removeError = nil;\n        [JWTCryptoSecurity removeKeyByTag:keyItem.tag error:&removeError];\n        \n        if (error && removeError) {\n            *error = removeError;\n        }\n        \n        return verified;\n    }\n    else {\n        SecKeyRef publicKey = [JWTCryptoSecurity publicKeyFromCertificate:key];\n        // TODO: special error handling here.\n        // add error handling later?\n        if (publicKey != NULL) {\n            BOOL verified = [self verifyData:hash witSignature:signature withKey:publicKey];\n            CFRelease(publicKey);\n            return verified;\n        }\n    }\n    return NO;\n}\n\n- (NSData *)encodePayload:(NSString *)theString withSecret:(NSString *)theSecret {\n    return [self encodePayloadData:[theString dataUsingEncoding:NSUTF8StringEncoding] withSecret:[JWTBase64Coder dataWithBase64UrlEncodedString:theSecret]];\n}\n- (NSData *)encodePayloadData:(NSData *)theStringData withSecret:(NSData *)theSecretData {\n    return [self signHash:theStringData key:theSecretData error:nil];\n}\n- (BOOL)verifySignedInput:(NSString *)input withSignature:(NSString *)signature verificationKey:(NSString *)verificationKey {\n    NSData *certificateData = [JWTBase64Coder dataWithBase64UrlEncodedString:verificationKey];\n    return [self verifySignedInput:input withSignature:signature verificationKeyData:certificateData];\n}\n- (BOOL)verifySignedInput:(NSString *)input withSignature:(NSString *)signature verificationKeyData:(NSData *)verificationKeyData {\n    return [self verifyHash:[input dataUsingEncoding:NSUTF8StringEncoding] signature:[JWTBase64Coder dataWithBase64UrlEncodedString:signature] key:verificationKeyData error:nil];\n}\n\n#pragma mark - Private ( Override-part depends on platform )\n- (BOOL)verifyData:(NSData *)plainData witSignature:(NSData *)signature withKey:(SecKeyRef) publicKey {\n    return NO;\n}\n\n- (NSData *)signData:(NSData *)plainData withKey:(SecKeyRef)privateKey {\n    return nil;\n}\n@end\n\n#if TARGET_OS_MAC && TARGET_OS_IPHONE\n@interface JWTAlgorithmRSBaseIOS : JWTAlgorithmRSBase @end\n@implementation JWTAlgorithmRSBaseIOS\n- (BOOL)verifyData:(NSData *)plainData witSignature:(NSData *)signature withKey:(SecKeyRef) publicKey {\n    size_t signedHashBytesSize = SecKeyGetBlockSize(publicKey);\n    const void* signedHashBytes = [signature bytes];\n\n    size_t hashBytesSize = self.ccSHANumberDigestLength;\n    uint8_t* hashBytes = malloc(hashBytesSize);\n    if (![self CC_SHANumberWithData:[plainData bytes] withLength:(CC_LONG)[plainData length] withHashBytes:hashBytes]) {\n        return false;\n    }\n\n    OSStatus status = SecKeyRawVerify(publicKey,\n                                      self.secPaddingPKCS1SHANumber,\n                                      hashBytes,\n                                      hashBytesSize,\n                                      signedHashBytes,\n                                      signedHashBytesSize);\n\n    return status == errSecSuccess;\n}\n\n- (NSData *)signData:(NSData *)plainData withKey:(SecKeyRef)privateKey {\n    size_t signedHashBytesSize = SecKeyGetBlockSize(privateKey);\n    uint8_t* signedHashBytes = malloc(signedHashBytesSize);\n    memset(signedHashBytes, 0x0, signedHashBytesSize);\n\n    size_t hashBytesSize = self.ccSHANumberDigestLength;\n    uint8_t* hashBytes = malloc(hashBytesSize);\n\n    // ([plainData bytes], (CC_LONG)[plainData length], hashBytes)\n    unsigned char *str = [self CC_SHANumberWithData:[plainData bytes] withLength:(CC_LONG)[plainData length] withHashBytes:hashBytes];\n\n    if (!str) {\n        return nil;\n    }\n\n    SecKeyRawSign(privateKey,\n                  self.secPaddingPKCS1SHANumber,\n                  hashBytes,\n                  hashBytesSize,\n                  signedHashBytes,\n                  &signedHashBytesSize);\n\n    NSData* signedHash = [NSData dataWithBytes:signedHashBytes\n                                        length:(NSUInteger)signedHashBytesSize];\n\n    if (hashBytes) {\n        free(hashBytes);\n    }\n\n    if (signedHashBytes) {\n        free(signedHashBytes);\n    }\n\n    return signedHash;\n}\n@end\n#endif\n\n#if TARGET_OS_MAC && !TARGET_OS_IPHONE\n@interface JWTAlgorithmRSBaseMac : JWTAlgorithmRSBase\n@end\n\n@implementation JWTAlgorithmRSBaseMac\n- (NSData *)executeTransform:(SecTransformRef)transform withInput:(NSData *)input withDigestType:(CFStringRef)type withDigestLength:(NSNumber *)length withFalseResult:(CFTypeRef)falseResultRef {\n    CFErrorRef errorRef = NULL;\n\n    CFTypeRef resultRef = NULL;\n    NSData *resultData = nil;\n\n\n    BOOL success = transform != NULL;\n    //TODO: after import algorithm by pem, this code seems not working well.\n    //error: Error Domain=com.apple.security.transforms.error Code=6 \"Invalid digest algorithm for RSA signature, choose one of: SHA1, SHA2 (512bits, 348bits, 256bits, or 224 bits), MD2, or MD5\"\n    //TODO: add error inout parameter to this method.\n    if (success) {\n        // setup digest type\n        success = SecTransformSetAttribute(transform, kSecDigestTypeAttribute, type, &errorRef);\n    }\n\n    if (success) {\n        // digest length\n        success = SecTransformSetAttribute(transform, kSecDigestLengthAttribute, (__bridge CFNumberRef)length, &errorRef);\n    }\n\n    if (success) {\n        // set input\n        success = SecTransformSetAttribute(transform, kSecTransformInputAttributeName, (__bridge CFDataRef)input, &errorRef);\n    }\n\n    if (success) {\n        // execute\n        resultRef = SecTransformExecute(transform, &errorRef);\n        success = (resultRef != falseResultRef);\n    }\n\n    BOOL positiveResult = success; // resultRef != falseResultRef\n\n    // error\n    if (errorRef != NULL) {\n        NSLog(@\"%@ error: %@\", self.debugDescription, (__bridge NSError *)errorRef);\n    }\n    else {\n        if (positiveResult) {\n            resultData = (__bridge NSData *)resultRef;\n        }\n    }\n\n    // release\n    if (transform != NULL) {\n        CFRelease(transform);\n    }\n\n    if (errorRef != NULL) {\n        CFRelease(errorRef);\n    }\n\n    if (resultRef != NULL) {\n        CFRelease(resultRef);\n    }\n\n    return resultData;\n}\n- (BOOL)verifyData:(NSData *)plainData witSignature:(NSData *)signature withKey:(SecKeyRef) publicKey {\n\n    size_t signedHashBytesSize = SecKeyGetBlockSize(publicKey);\n    //const void* signedHashBytes = [signature bytes];\n\n    size_t hashBytesSize = self.ccSHANumberDigestLength;\n    uint8_t* hashBytes = malloc(hashBytesSize);\n    if (![self CC_SHANumberWithData:[plainData bytes] withLength:(CC_LONG)[plainData length] withHashBytes:hashBytes]) {\n        return false;\n    }\n\n    // verify for iOS\n//    OSStatus status = SecKeyRawVerify(publicKey,\n//                                      self.secPaddingPKCS1SHANumber,\n//                                      hashBytes,\n//                                      hashBytesSize,\n//                                      signedHashBytes,\n//                                      signedHashBytesSize);\n//    return status == errSecSuccess;\n\n    CFErrorRef errorRef = NULL;\n    SecTransformRef transform = SecVerifyTransformCreate(publicKey, (__bridge CFDataRef)signature, &errorRef);\n\n    // verification. false result is kCFBooleanFalse\n    BOOL result = [self executeTransform:transform withInput:plainData withDigestType:kSecDigestSHA2 withDigestLength:@(signedHashBytesSize) withFalseResult:kCFBooleanFalse] != nil;\n\n    if (errorRef != NULL) {\n        CFRelease(errorRef);\n    }\n\n    return result;\n}\n\n- (NSData *)signData:(NSData *)plainData withKey:(SecKeyRef)privateKey {\n    size_t signedHashBytesSize = SecKeyGetBlockSize(privateKey);\n    //uint8_t* signedHashBytes = malloc(signedHashBytesSize);\n    //memset(signedHashBytes, 0x0, signedHashBytesSize);\n\n    size_t hashBytesSize = self.ccSHANumberDigestLength;\n    uint8_t* hashBytes = malloc(hashBytesSize);\n\n    /**\n     for sha256\n     CC_SHANumberWithData() is CC_SHA256()\n     self.secPaddingPKCS1SHANumber = kSecPaddingPKCS1SHA256\n     self.ccSHANumberDigestLength  = CC_SHA256_DIGEST_LENGTH\n     */\n    unsigned char *str = [self CC_SHANumberWithData:[plainData bytes] withLength:(CC_LONG)[plainData length] withHashBytes:hashBytes];\n\n    if (!str) {\n        return nil;\n    }\n\n    CFErrorRef errorRef = NULL;\n\n    SecTransformRef transform = SecSignTransformCreate(privateKey, &errorRef);\n\n    /** iOS\n    SecKeyRawSign(privateKey,\n                  self.secPaddingPKCS1SHANumber,\n                  hashBytes,\n                  hashBytesSize,\n                  signedHashBytes,\n                  &signedHashBytesSize);\n\n    NSData* signedHash = [NSData dataWithBytes:signedHashBytes\n                                        length:(NSUInteger)signedHashBytesSize];\n\n     */\n\n    NSData *resultData = nil;\n    // signing: false result is NULL.\n    // it will release error.\n    resultData = [self executeTransform:transform withInput:plainData withDigestType:kSecDigestSHA2 withDigestLength:@(signedHashBytesSize) withFalseResult:NULL];\n\n    if (errorRef != NULL) {\n        CFRelease(errorRef);\n    }\n\n    return resultData;\n}\n@end\n#endif\n\n\n// MacOS OR iOS is Base\n#if TARGET_OS_MAC && !TARGET_OS_IPHONE\n@interface JWTAlgorithmRSFamilyMember : JWTAlgorithmRSBaseMac @end\n#else\n@interface JWTAlgorithmRSFamilyMember : JWTAlgorithmRSBaseIOS @end\n#endif\n\n@interface JWTAlgorithmRS256 : JWTAlgorithmRSFamilyMember @end\n@interface JWTAlgorithmRS384 : JWTAlgorithmRSFamilyMember @end\n@interface JWTAlgorithmRS512 : JWTAlgorithmRSFamilyMember @end\n\n@implementation JWTAlgorithmRSFamilyMember\n- (uint32_t)secPaddingPKCS1SHANumber {\n    return 0;\n}\n@end\n\n@implementation JWTAlgorithmRS256\n\n- (size_t)ccSHANumberDigestLength {\n    return CC_SHA256_DIGEST_LENGTH;\n}\n\n#if TARGET_OS_MAC && TARGET_OS_IPHONE\n- (uint32_t)secPaddingPKCS1SHANumber {\n    return kSecPaddingPKCS1SHA256;\n}\n#endif\n\n- (unsigned char *)CC_SHANumberWithData:(const void *)data withLength:(CC_LONG)len withHashBytes:(unsigned char *)hashBytes {\n    return CC_SHA256(data, len, hashBytes);\n}\n\n- (NSString *)name {\n    return JWTAlgorithmNameRS256;\n}\n\n@end\n\n@implementation JWTAlgorithmRS384\n\n- (size_t)ccSHANumberDigestLength {\n    return CC_SHA384_DIGEST_LENGTH;\n}\n\n#if TARGET_OS_MAC && TARGET_OS_IPHONE\n- (uint32_t)secPaddingPKCS1SHANumber {\n    return kSecPaddingPKCS1SHA384;\n}\n#endif\n\n- (unsigned char *)CC_SHANumberWithData:(const void *)data withLength:(CC_LONG)len withHashBytes:(unsigned char *)hashBytes {\n    return CC_SHA384(data, len, hashBytes);\n}\n\n- (NSString *)name {\n    return JWTAlgorithmNameRS384;\n}\n\n@end\n\n@implementation JWTAlgorithmRS512\n\n- (size_t)ccSHANumberDigestLength {\n    return CC_SHA512_DIGEST_LENGTH;\n}\n\n#if TARGET_OS_MAC && TARGET_OS_IPHONE\n- (uint32_t)secPaddingPKCS1SHANumber {\n    return kSecPaddingPKCS1SHA512;\n}\n#endif\n\n- (unsigned char *)CC_SHANumberWithData:(const void *)data withLength:(CC_LONG)len withHashBytes:(unsigned char *)hashBytes {\n    return CC_SHA512(data, len, hashBytes);\n}\n\n- (NSString *)name {\n    return JWTAlgorithmNameRS512;\n}\n\n@end\n\n\n@interface JWTAlgorithmRSFamilyMemberMutable : JWTAlgorithmRSFamilyMember\n\n@property (assign, nonatomic, readwrite) size_t ccSHANumberDigestLength;\n@property (assign, nonatomic, readwrite) uint32_t secPaddingPKCS1SHANumber;\n@property (copy, nonatomic, readwrite) unsigned char * (^ccShaNumberWithData)(const void *data, CC_LONG len, unsigned char *hashBytes);\n@property (copy, nonatomic, readwrite) NSString *name;\n@end\n\n@implementation JWTAlgorithmRSFamilyMemberMutable\n\n@synthesize ccSHANumberDigestLength = _ccSHANumberDigestLength;\n@synthesize secPaddingPKCS1SHANumber = _secPaddingPKCS1SHANumber;\n@synthesize name = _name;\n\n- (size_t)ccSHANumberDigestLength {\n    return _ccSHANumberDigestLength;\n}\n\n- (uint32_t)secPaddingPKCS1SHANumber {\n    return _secPaddingPKCS1SHANumber;\n}\n\n- (unsigned char *)CC_SHANumberWithData:(const void *)data withLength:(uint32_t)len withHashBytes:(unsigned char *)hashBytes {\n    unsigned char *result = [super CC_SHANumberWithData:data withLength:len withHashBytes:hashBytes];\n    if (!result && self.ccShaNumberWithData) {\n        result = self.ccShaNumberWithData(data, len, hashBytes);\n    }\n    return result;\n}\n\n@end\n\n\n@implementation JWTAlgorithmRSBase (Create)\n\n+ (instancetype)algorithm256 {\n    return [JWTAlgorithmRS256 new];\n}\n\n+ (instancetype)algorithm384 {\n    return [JWTAlgorithmRS384 new];\n}\n\n+ (instancetype)algorithm512 {\n    return [JWTAlgorithmRS512 new];\n}\n\n+ (instancetype)mutableAlgorithm {\n    JWTAlgorithmRSFamilyMemberMutable *base = [JWTAlgorithmRSFamilyMemberMutable new];\n    base.ccSHANumberDigestLength = CC_SHA256_DIGEST_LENGTH;\n\n    //set to something ok\n    //base.secPaddingPKCS1SHANumber = kSecPaddingPKCS1SHA256;\n    base.ccShaNumberWithData = ^unsigned char *(const void *data, CC_LONG len, unsigned char *hashBytes){\n        return CC_SHA256(data, len, hashBytes);\n    };\n    base.name = @\"RS256\";\n    return base;\n}\n\n@end\n"
  },
  {
    "path": "ios/CodePush/JWT/Core/Algorithms/RSFamily/JWTRSAlgorithm.h",
    "content": "//\n// Created by Marcelo Schroeder on 12/03/2016.\n// Copyright (c) 2016 Karma. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n#import \"JWTAlgorithm.h\"\n@protocol JWTCryptoKeyProtocol;\n\n@protocol JWTAsymmetricKeysAlgorithm <JWTAlgorithm>\n\n@optional\n@property(nonatomic, readwrite, copy) NSString *keyExtractorType;\n@property(nonatomic, readwrite, strong) id<JWTCryptoKeyProtocol> signKey;\n@property(nonatomic, readwrite, strong) id<JWTCryptoKeyProtocol> verifyKey;\n\n@end\n\n@protocol JWTRSAlgorithm <JWTAsymmetricKeysAlgorithm, NSCopying>\n\n@required\n@property(nonatomic, readwrite, copy) NSString *privateKeyCertificatePassphrase;\n@end\n"
  },
  {
    "path": "ios/CodePush/JWT/Core/Algorithms/RSFamily/RSKeys/JWTCryptoKey.h",
    "content": "//\n//  JWTCryptoKey.h\n//  JWT\n//\n//  Created by Lobanov Dmitry on 04.02.17.\n//  Copyright © 2017 JWTIO. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n#import <Security/Security.h>\n\n@protocol JWTCryptoKeyProtocol <NSObject>\n@property (copy, nonatomic, readonly) NSString *tag;\n@property (assign, nonatomic, readonly) SecKeyRef key;\n@property (copy, nonatomic, readonly) NSData *rawKey;\n@end\n\n@interface JWTCryptoKeyBuilder : NSObject\n@property (assign, nonatomic, readonly) NSString *keyType;\n- (instancetype)keyTypeRSA;\n- (instancetype)keyTypeEC;\n@end\n\n@interface JWTCryptoKey : NSObject<JWTCryptoKeyProtocol>\n- (instancetype)initWithData:(NSData *)data parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing*)error; //NS_DESIGNATED_INITIALIZER\n- (instancetype)initWithBase64String:(NSString *)base64String parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing*)error;\n- (instancetype)initWithPemEncoded:(NSString *)encoded parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing*)error;\n- (instancetype)initWithPemAtURL:(NSURL *)url parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing*)error;\n@end\n\n@interface JWTCryptoKey (Parameters)\n+ (NSString *)parametersKeyBuilder;\n@end\n\n@interface JWTCryptoKeyPublic : JWTCryptoKey\n- (instancetype)initWithCertificateData:(NSData *)certificateData parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing*)error; //NS_DESIGNATED_INITIALIZER;\n- (instancetype)initWithCertificateBase64String:(NSString *)certificateString parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing*)error;\n@end\n\n@interface JWTCryptoKeyPrivate : JWTCryptoKey\n- (instancetype)initWithP12Data:(NSData *)p12Data withPassphrase:(NSString *)passphrase parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing*)error; //NS_DESIGNATED_INITIALIZER;\n- (instancetype)initWithP12AtURL:(NSURL *)url withPassphrase:(NSString *)passphrase parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing*)error;\n@end\n"
  },
  {
    "path": "ios/CodePush/JWT/Core/Algorithms/RSFamily/RSKeys/JWTCryptoKey.m",
    "content": "//\n//  JWTCryptoKey.m\n//  JWT\n//\n//  Created by Lobanov Dmitry on 04.02.17.\n//  Copyright © 2017 JWTIO. All rights reserved.\n//\n\n#import \"JWTCryptoKey.h\"\n#import \"JWTCryptoSecurity.h\"\n#import \"JWTBase64Coder.h\"\n@interface JWTCryptoKeyBuilder()\n+ (NSString *)keyTypeRSA;\n+ (NSString *)keyTypeEC;\n@property (assign, nonatomic, readwrite) BOOL public;\n@property (assign, nonatomic, readwrite) NSString *keyType;\n@property (nonatomic, readonly) BOOL withKeyTypeRSA;\n@property (nonatomic, readonly) BOOL withKeyTypeEC;\n@end\n@implementation JWTCryptoKeyBuilder\n+ (NSString *)keyTypeRSA {\n    return @\"RSA\";\n}\n+ (NSString *)keyTypeEC {\n    return @\"EC\";\n}\n- (instancetype)keyTypeRSA {\n    self.keyType = [self.class keyTypeRSA];\n    return self;\n}\n- (instancetype)keyTypeEC {\n    self.keyType = [self.class keyTypeEC];\n    return self;\n}\n- (BOOL)withKeyTypeRSA {\n    return [self.keyType isEqualToString:self.class.keyTypeRSA];\n}\n- (BOOL)withKeyTypeEC {\n    return [self.keyType isEqualToString:self.class.keyTypeEC];\n}\n@end\n@interface JWTCryptoKey ()\n@property (copy, nonatomic, readwrite) NSString *tag;\n@property (assign, nonatomic, readwrite) SecKeyRef key;\n@property (copy, nonatomic, readwrite) NSData *rawKey;\n@end\n@interface JWTCryptoKey (Class)\n+ (NSString *)uniqueTag;\n@end\n@implementation JWTCryptoKey (Class)\n+ (NSString *)uniqueTag {\n    return [[NSUUID UUID].UUIDString stringByReplacingOccurrencesOfString:@\"-\" withString:@\"\"].lowercaseString;\n}\n@end\n@implementation JWTCryptoKey (Parameters)\n+ (NSString *)parametersKeyBuilder {\n    return NSStringFromSelector(_cmd);\n}\n@end\n@interface JWTCryptoKey (ParametersExtraction)\n- (NSString *)extractedSecKeyTypeWithParameters:(NSDictionary *)parameters;\n- (JWTCryptoKeyBuilder *)extractedBuilderWithParameters:(NSDictionary *)parameters;\n@end\n// Consider that both methods in this category should return non-nullable values\n@implementation JWTCryptoKey (ParametersExtraction)\n// Parameters are nil at that moment, could be used later for some purposes\n- (JWTCryptoKeyBuilder *)extractedBuilderWithParameters:(NSDictionary *)parameters {\n    return (JWTCryptoKeyBuilder *)parameters[[self.class parametersKeyBuilder]] ?: [JWTCryptoKeyBuilder new].keyTypeRSA;\n}\n// Parameters are nil at that moment, could be used later for some purposes\n- (NSString *)extractedSecKeyTypeWithParameters:(NSDictionary *)parameters {\n    JWTCryptoKeyBuilder *builder = [self extractedBuilderWithParameters:parameters];\n    NSString *result = nil;\n    if (builder.withKeyTypeEC) {\n        result = [JWTCryptoSecurity keyTypeEC];\n    }\n    return result ?: [JWTCryptoSecurity keyTypeRSA];\n}\n@end\n@implementation JWTCryptoKey\n- (instancetype)initWithData:(NSData *)data parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing*)error {\n    return [super init];\n}\n- (instancetype)initWithBase64String:(NSString *)base64String parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing*)error {\n    return [self initWithData:[JWTBase64Coder dataWithBase64UrlEncodedString:base64String] parameters:parameters error:error];\n}\n- (instancetype)initWithPemEncoded:(NSString *)encoded parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing*)error {\n    //TODO: check correctness.\n    //maybe use clean initWithBase64String and remove ?: encoded tail.\n    NSString *clean = [JWTCryptoSecurity keyFromPemFileContent:encoded] ?: encoded;//[JWTCryptoSecurity stringByRemovingPemHeadersFromString:encoded];\n    return [self initWithBase64String:clean parameters:parameters error:error];\n}\n- (instancetype)initWithPemAtURL:(NSURL *)url parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing*)error {\n    // contents of url\n    NSError *contentsExtractingError = nil;\n    NSString *pemEncoded = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:&contentsExtractingError];\n    if (error && contentsExtractingError) {\n        *error = contentsExtractingError;\n        return nil;\n    }\n    return [self initWithPemEncoded:pemEncoded parameters:parameters error:error];\n}\n@end\n@implementation JWTCryptoKeyPublic\n- (instancetype)initWithData:(NSData *)data parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing*)error {\n    self = [super initWithData:data parameters:parameters error:error];\n    if (self) {\n        self.tag = [self.class uniqueTag];\n\n        if (!data) {\n            return nil;\n        }\n\n        NSError *removingHeaderError = nil;\n        // asks builder\n        \n        JWTCryptoKeyBuilder *builder = [self extractedBuilderWithParameters:parameters];\n        NSData *keyData = data;\n        if (builder.withKeyTypeRSA) {\n        keyData = [JWTCryptoSecurity dataByRemovingPublicKeyHeader:data error:&removingHeaderError];\n            if (!keyData || removingHeaderError) {\n                if (error && removingHeaderError != nil) {\n                    *error = removingHeaderError;\n                }\n                return nil;\n            }\n        }\n        \n        if (builder.withKeyTypeEC) {\n            // unknown here.\n            // process keyData before passing it to JWTCryptoSecurity+addKey... method. \n        }\n\n        NSError *addKeyError = nil;\n        \n        self.key = [JWTCryptoSecurity addKeyWithData:keyData asPublic:YES tag:self.tag type:[self extractedSecKeyTypeWithParameters:parameters] error:&addKeyError];\n        if (!self.key || addKeyError) {\n            if (error && addKeyError != nil) {\n                *error = removingHeaderError;\n            }\n            return nil;\n        }\n    }\n    return self;\n}\n- (instancetype)initWithCertificateData:(NSData *)certificateData parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing*)error {\n    SecKeyRef key = [JWTCryptoSecurity publicKeyFromCertificate:certificateData];\n    if (!key) {\n        // error: Public certificate incorrect.\n        return nil;\n    }\n\n    if (self = [super init]) {\n        self.key = key;\n    }\n\n    return self;\n}\n- (instancetype)initWithCertificateBase64String:(NSString *)certificate parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing*)error {\n    // cleanup certificate if needed.\n    // call initWithCertificateData:(NSData *)certificateData\n    NSData *certificateData = nil;\n    return [self initWithCertificateData:certificateData parameters:parameters error:error];\n}\n@end\n\n@implementation JWTCryptoKeyPrivate\n- (instancetype)initWithData:(NSData *)data parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing*)error {\n    self = [super initWithData:data parameters:parameters error:error];\n    if (self) {\n        self.tag = [self.class uniqueTag];\n        NSError *addKeyError = nil;\n        if (!data) {\n            // error: no data?\n            // or put it in superclass?\n            return nil;\n        }\n        self.key = [JWTCryptoSecurity addKeyWithData:data asPublic:NO tag:self.tag type:[self extractedSecKeyTypeWithParameters:parameters] error:&addKeyError];\n        if (!self.key || addKeyError) {\n            if (error && addKeyError) {\n                *error = addKeyError;\n            }\n            return nil;\n        }\n    }\n    return self;\n}\n// Exists\n- (instancetype)initWithP12AtURL:(NSURL *)url withPassphrase:(NSString *)passphrase parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing*)error {\n    // take data.\n    // cleanup if needed.\n    NSData *data = [NSData dataWithContentsOfURL:url];\n    return [self initWithP12Data:data withPassphrase:passphrase parameters:parameters error:error];\n}\n- (instancetype)initWithP12Data:(NSData *)p12Data withPassphrase:(NSString *)passphrase parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing*)error {\n    if (p12Data == nil) {\n        return nil;\n    }\n\n    // cleanup if needed.\n    SecIdentityRef identity = nil;\n    SecTrustRef trust = nil;\n    [JWTCryptoSecurity extractIdentityAndTrustFromPKCS12:(__bridge CFDataRef)p12Data password:(__bridge CFStringRef)passphrase identity:&identity trust:&trust];\n    BOOL identityAndTrust = identity && trust;\n\n    if (identityAndTrust) {\n        self = [super init];\n        SecKeyRef privateKey;\n        SecIdentityCopyPrivateKey(identity, &privateKey);\n        if (self) {\n            self.key = privateKey;\n        }\n    }\n\n    if (identity) {\n        CFRelease(identity);\n    }\n\n    if (trust) {\n        CFRelease(trust);\n    }\n\n    if (!identityAndTrust) {\n        //error: no identity and trust.\n        return nil;\n    }\n\n    return self;\n}\n@end\n"
  },
  {
    "path": "ios/CodePush/JWT/Core/Algorithms/RSFamily/RSKeys/JWTCryptoKeyExtractor.h",
    "content": "//\n//  JWTCryptoKeyExtractor.h\n//  JWT\n//\n//  Created by Lobanov Dmitry on 04.02.17.\n//  Copyright © 2017 JWTIO. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n#import <Security/Security.h>\n\n@protocol JWTCryptoKeyProtocol;\n@protocol JWTCryptoKeyExtractorProtocol <NSObject>\n@optional\n- (id<JWTCryptoKeyProtocol>)keyFromString:(NSString *)string parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing*)error;\n- (id<JWTCryptoKeyProtocol>)keyFromData:(NSData *)data parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing*)error;\n@end\n\n@interface JWTCryptoKeyExtractor : NSObject <JWTCryptoKeyExtractorProtocol>\n@property (copy, nonatomic, readonly) NSString *type;\n+ (NSString *)type;\n+ (NSString *)parametersKeyCertificatePassphrase;\n@end\n\n@interface JWTCryptoKeyExtractor (ClassCluster)\n+ (instancetype)publicKeyWithCertificate;\n+ (instancetype)privateKeyInP12;\n+ (instancetype)publicKeyWithPEMBase64;\n+ (instancetype)privateKeyWithPEMBase64;\n+ (instancetype)createWithType:(NSString *)type;\n@end\n"
  },
  {
    "path": "ios/CodePush/JWT/Core/Algorithms/RSFamily/RSKeys/JWTCryptoKeyExtractor.m",
    "content": "//\n//  JWTCryptoKeyExtractor.m\n//  JWT\n//\n//  Created by Lobanov Dmitry on 04.02.17.\n//  Copyright © 2017 JWTIO. All rights reserved.\n//\n\n#import \"JWTCryptoKeyExtractor.h\"\n#import \"JWTCryptoKey.h\"\n#import \"JWTBase64Coder.h\"\n\n@implementation JWTCryptoKeyExtractor\n- (NSString *)type {\n    return self.class.type;\n}\n+ (NSString *)type {\n\treturn NSStringFromClass(self);\n}\n+ (NSString *)parametersKeyCertificatePassphrase {\n    return NSStringFromSelector(_cmd);\n}\n- (id<JWTCryptoKeyProtocol>)keyFromData:(NSData *)data parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing *)error {\n#pragma message \"Not Implemented\"\n    if (error) {\n        *error = [NSError errorWithDomain:@\"io.jwt.crypto.rsa\" code:-100 userInfo:@{\n                                                                                    NSLocalizedDescriptionKey : @\"Method not implemented\"\n                                                                                    }];\n    }\n    return nil;\n}\n- (id<JWTCryptoKeyProtocol>)keyFromString:(NSString *)string parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing *)error {\n    if (error) {\n        *error = [NSError errorWithDomain:@\"io.jwt.crypto.rsa\" code:-100 userInfo:@{\n                                                                           NSLocalizedDescriptionKey : @\"Method not implemented\"\n                                                                           }];\n    }\n    return nil;\n}\n@end\n\n@interface JWTCryptoKeyExtractor_Public_Pem_Certificate : JWTCryptoKeyExtractor @end\n\n@implementation JWTCryptoKeyExtractor_Public_Pem_Certificate\n- (id<JWTCryptoKeyProtocol>)keyFromData:(NSData *)data parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing *)error {\n    return [[JWTCryptoKeyPublic alloc] initWithCertificateData:data parameters:parameters error:error];\n}\n@end\n\n@interface JWTCryptoKeyExtractor_Private_P12 : JWTCryptoKeyExtractor @end\n\n@implementation JWTCryptoKeyExtractor_Private_P12\n- (id<JWTCryptoKeyProtocol>)keyFromData:(NSData *)data parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing *)error {\n    NSString *certificatePassphrase = parameters[self.class.parametersKeyCertificatePassphrase];\n    if ([certificatePassphrase isEqual:[NSNull null]]) {\n        certificatePassphrase = nil;\n    }\n    return [[JWTCryptoKeyPrivate alloc] initWithP12Data:data withPassphrase:certificatePassphrase parameters:parameters error:error];\n}\n@end\n\n@interface JWTCryptoKeyExtractor_Public_Pem_Key : JWTCryptoKeyExtractor @end\n\n@implementation JWTCryptoKeyExtractor_Public_Pem_Key\n- (id<JWTCryptoKeyProtocol>)keyFromData:(NSData *)data parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing *)error {\n    return [self keyFromString:[JWTBase64Coder base64UrlEncodedStringWithData:data] parameters:parameters error:error];\n}\n- (id<JWTCryptoKeyProtocol>)keyFromString:(NSString *)string parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing *)error {\n    return [[JWTCryptoKeyPublic alloc] initWithPemEncoded:string parameters:parameters error:error];\n}\n@end\n\n@interface JWTCryptoKeyExtractor_Private_Pem_Key : JWTCryptoKeyExtractor @end\n\n@implementation JWTCryptoKeyExtractor_Private_Pem_Key\n- (id<JWTCryptoKeyProtocol>)keyFromData:(NSData *)data parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing *)error {\n    return [self keyFromString:[JWTBase64Coder base64UrlEncodedStringWithData:data] parameters:parameters error:error];\n}\n- (id<JWTCryptoKeyProtocol>)keyFromString:(NSString *)string parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing *)error {\n    return [[JWTCryptoKeyPrivate alloc] initWithPemEncoded:string parameters:parameters error:error];\n}\n@end\n\n@implementation JWTCryptoKeyExtractor (ClassCluster)\n+ (instancetype)publicKeyWithCertificate {\n    return [JWTCryptoKeyExtractor_Public_Pem_Certificate new];\n}\n+ (instancetype)privateKeyInP12 {\n    return [JWTCryptoKeyExtractor_Private_P12 new];\n}\n+ (instancetype)publicKeyWithPEMBase64 {\n    return [JWTCryptoKeyExtractor_Public_Pem_Key new];\n}\n+ (instancetype)privateKeyWithPEMBase64 {\n    return [JWTCryptoKeyExtractor_Private_Pem_Key new];\n}\n+ (NSArray *)availableExtractors {\n    return @[\n             [self publicKeyWithCertificate],\n             [self privateKeyInP12],\n             [self publicKeyWithPEMBase64],\n             [self privateKeyWithPEMBase64]\n             ];\n}\n+ (NSDictionary *)typesAndExtractors {\n    static NSDictionary *dictionary = nil;\n    return dictionary ?: (dictionary = [[NSDictionary alloc] initWithObjects:[self availableExtractors] forKeys:[[self availableExtractors] valueForKey:@\"type\"]],\n                          dictionary);\n}\n+ (instancetype)createWithType:(NSString *)type {\n\treturn [self typesAndExtractors][type];\n}\n@end\n"
  },
  {
    "path": "ios/CodePush/JWT/Core/Algorithms/RSFamily/RSKeys/JWTCryptoSecurity.h",
    "content": "//\n//  JWTCryptoSecurity.h\n//  JWT\n//\n//  Created by Lobanov Dmitry on 04.02.17.\n//  Copyright © 2017 JWTIO. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n#import <Security/Security.h>\n// Thanks for https://github.com/TakeScoop/SwiftyRSA!\n@interface JWTCryptoSecurity : NSObject\n+ (NSString *)keyTypeRSA;\n+ (NSString *)keyTypeEC;\n+ (SecKeyRef)addKeyWithData:(NSData *)data asPublic:(BOOL)public tag:(NSString *)tag type:(NSString *)type error:(NSError *__autoreleasing*)error;\n+ (SecKeyRef)addKeyWithData:(NSData *)data asPublic:(BOOL)public tag:(NSString *)tag error:(NSError *__autoreleasing*)error;\n+ (SecKeyRef)keyByTag:(NSString *)tag error:(NSError *__autoreleasing*)error;\n+ (void)removeKeyByTag:(NSString *)tag error:(NSError *__autoreleasing*)error;\n@end\n\n@interface JWTCryptoSecurity (Certificates)\n+ (OSStatus)extractIdentityAndTrustFromPKCS12:(CFDataRef)inPKCS12Data password:(CFStringRef)password identity:(SecIdentityRef *)outIdentity trust:(SecTrustRef *)outTrust;\n+ (SecKeyRef)publicKeyFromCertificate:(NSData *)certificateData;\n@end\n\n@interface JWTCryptoSecurity (Pem)\n+ (NSString *)certificateFromPemFileContent:(NSString *)content;\n+ (NSString *)keyFromPemFileContent:(NSString *)content;\n+ (NSArray *)itemsFromPemFileContent:(NSString *)content byRegex:(NSRegularExpression *)expression;\n+ (NSString *)certificateFromPemFileWithName:(NSString *)name;\n+ (NSString *)keyFromPemFileWithName:(NSString *)name;\n+ (NSArray *)itemsFromPemFileWithName:(NSString *)name byRegex:(NSRegularExpression *)expression;\n+ (NSString *)stringByRemovingPemHeadersFromString:(NSString *)string;\n@end\n\n@interface JWTCryptoSecurity (PublicKey)\n+ (NSData *)dataByRemovingPublicKeyHeader:(NSData *)data error:(NSError *__autoreleasing*)error;\n@end\n"
  },
  {
    "path": "ios/CodePush/JWT/Core/Algorithms/RSFamily/RSKeys/JWTCryptoSecurity.m",
    "content": "//\n//  JWTCryptoSecurity.m\n//  JWT\n//\n//  Created by Lobanov Dmitry on 04.02.17.\n//  Copyright © 2017 JWTIO. All rights reserved.\n//\n\n#import \"JWTCryptoSecurity.h\"\n@interface JWTMemoryLayout : NSObject\n+ (NSString *)typeUInt8;\n+ (NSString *)typeCUnsignedChar;\n- (instancetype)initWithType:(NSString *)type;\n+ (instancetype)createWithType:(NSString *)type;\n@property (copy, nonatomic, readwrite) NSString *type;\n@property (assign, nonatomic, readonly) NSInteger size;\n@end\n@implementation JWTMemoryLayout\n+ (NSString *)typeUInt8 {\n    return NSStringFromSelector(_cmd);\n}\n+ (NSString *)typeCUnsignedChar {\n    return [self typeUInt8];\n}\n- (instancetype)initWithType:(NSString *)type {\n    self = [super init];\n    if (self) {\n        self.type = type;\n    }\n    return self;\n}\n+ (instancetype)createWithType:(NSString *)type {\n    return [[self alloc] initWithType:type];\n}\n+ (NSDictionary *)sizesAndTypes {\n    static NSDictionary *sizesAndTypes = nil;\n    return sizesAndTypes ?: (sizesAndTypes = @{\n        [self typeUInt8] : @(1) // or 8?\n    }, sizesAndTypes);\n}\n- (NSInteger)size {\n    return [[self.class sizesAndTypes][self.type] integerValue];\n}\n@end\n@implementation JWTCryptoSecurity\n+ (NSDictionary *)dictionaryByCombiningDictionaries:(NSArray *)dictionaries {\n    NSMutableDictionary *result = [@{} mutableCopy];\n    for (NSDictionary *dictionary in dictionaries) {\n        [result addEntriesFromDictionary:dictionary];\n    }\n    return [result copy];\n}\n+ (NSString *)keyTypeRSA {\n    return (__bridge NSString *)kSecAttrKeyTypeRSA;\n}\n+ (NSString *)keyTypeEC {\n//    extern const CFStringRef kSecAttrKeyTypeEC\n//    __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_4_0);\n//    extern const CFStringRef kSecAttrKeyTypeECSECPrimeRandom\n//    __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0);\n    return (__bridge NSString *)kSecAttrKeyTypeEC;\n}\n+ (SecKeyRef)addKeyWithData:(NSData *)data asPublic:(BOOL)public tag:(NSString *)tag type:(NSString *)type error:(NSError *__autoreleasing*)error; {\n    NSString *keyClass = (__bridge NSString *)(public ? kSecAttrKeyClassPublic : kSecAttrKeyClassPrivate);\n    NSInteger sizeInBits = data.length * [JWTMemoryLayout createWithType:[JWTMemoryLayout typeUInt8]].size;\n    NSDictionary *attributes = @{\n        (__bridge NSString*)kSecAttrKeyType : type,\n        (__bridge NSString*)kSecAttrKeyClass : keyClass,\n        (__bridge NSString*)kSecAttrKeySizeInBits : @(sizeInBits)\n    };\n    \n    if (SecKeyCreateWithData != NULL) {\n        CFErrorRef createError = NULL;\n        SecKeyRef key = SecKeyCreateWithData((__bridge CFDataRef)data, (__bridge CFDictionaryRef)attributes, &createError);\n        if (error && createError != nil) {\n            *error = (__bridge NSError*)createError;\n        }\n        return key;\n    }\n    // oh... not avaialbe API :/\n    else {\n\n        CFTypeRef result = NULL;\n        NSData *tagData = [tag dataUsingEncoding:NSUTF8StringEncoding];\n        NSDictionary *commonAttributes = @{\n            (__bridge NSString*)kSecClass: (__bridge NSString*)kSecClassKey,\n            (__bridge NSString*)kSecAttrApplicationTag: tagData,\n            (__bridge NSString*)kSecAttrAccessible: (__bridge NSString*)kSecAttrAccessibleWhenUnlocked\n        };\n\n\n        NSDictionary *addItemAttributes = @{\n           (__bridge NSString*)kSecValueData: data,\n           (__bridge NSString*)kSecReturnPersistentRef: @(YES),\n        };\n\n        OSStatus addItemStatus = SecItemAdd((__bridge CFDictionaryRef)[self dictionaryByCombiningDictionaries:@[attributes, commonAttributes, addItemAttributes]], &result);\n        if (addItemStatus != errSecSuccess && addItemStatus != errSecDuplicateItem) {\n            // add item error\n            // not duplicate and not added to keychain.\n            return NULL;\n        }\n\n        NSDictionary *copyAttributes = @{\n                (__bridge NSString*)kSecReturnRef: @(YES),\n        };\n\n        CFTypeRef key = NULL;\n        // TODO: Add error handling later.\n        OSStatus copyItemStatus = errSecSuccess;\n        SecItemCopyMatching((__bridge CFDictionaryRef)[self dictionaryByCombiningDictionaries:@[attributes, commonAttributes, copyAttributes]], &key);\n        if (key == NULL) {\n            // copy item error\n        }\n        return (SecKeyRef)key;\n    }\n\n    return NULL;\n}\n+ (SecKeyRef)addKeyWithData:(NSData *)data asPublic:(BOOL)public tag:(NSString *)tag error:(NSError *__autoreleasing*)error; {\n    return [self addKeyWithData:data asPublic:public tag:tag type:[self keyTypeRSA] error:error];\n}\n\n+ (SecKeyRef)keyByTag:(NSString *)tag error:(NSError *__autoreleasing*)error; {\n    return NULL;\n}\n\n+ (void)removeKeyByTag:(NSString *)tag error:(NSError *__autoreleasing*)error; {\n    NSData *tagData = [tag dataUsingEncoding:NSUTF8StringEncoding];\n    if (tagData == nil) {\n        // tell that nothing to remove.        \n        return;\n    }\n    NSDictionary *removeAttributes = @{\n            (__bridge NSString*)kSecClass: (__bridge NSString*)kSecClassKey,\n            (__bridge NSString*)kSecAttrKeyType: (__bridge NSString*)kSecAttrKeyTypeRSA,\n            (__bridge NSString*)kSecAttrApplicationTag: tagData,\n    };\n    SecItemDelete((__bridge CFDictionaryRef)removeAttributes);\n}\n@end\n\n@implementation JWTCryptoSecurity (Certificates)\n+ (OSStatus)extractIdentityAndTrustFromPKCS12:(CFDataRef)inPKCS12Data password:(CFStringRef)password identity:(SecIdentityRef *)outIdentity trust:(SecTrustRef *)outTrust {\n\n    OSStatus securityError = errSecSuccess;\n\n\n    const void *keys[] =   { kSecImportExportPassphrase };\n    const void *values[] = { password };\n    CFDictionaryRef optionsDictionary = NULL;\n\n    /* Create a dictionary containing the passphrase if one\n     was specified.  Otherwise, create an empty dictionary. */\n    optionsDictionary = CFDictionaryCreate(\n                                           NULL, keys,\n                                           values, (password ? 1 : 0),\n                                           NULL, NULL);  // 1\n\n    CFArrayRef items = NULL;\n    securityError = SecPKCS12Import(inPKCS12Data,\n                                    optionsDictionary,\n                                    &items);                    // 2\n\n\n    //\n    if (securityError == 0) {                                   // 3\n        CFDictionaryRef myIdentityAndTrust = CFArrayGetValueAtIndex (items, 0);\n        const void *tempIdentity = NULL;\n        tempIdentity = CFDictionaryGetValue (myIdentityAndTrust,\n                                             kSecImportItemIdentity);\n        CFRetain(tempIdentity);\n        *outIdentity = (SecIdentityRef)tempIdentity;\n        const void *tempTrust = NULL;\n        tempTrust = CFDictionaryGetValue (myIdentityAndTrust, kSecImportItemTrust);\n\n        CFRetain(tempTrust);\n        *outTrust = (SecTrustRef)tempTrust;\n    }\n\n    if (optionsDictionary)                                      // 4\n        CFRelease(optionsDictionary);\n\n    if (items)\n        CFRelease(items);\n\n    return securityError;\n}\n\n+ (SecKeyRef)publicKeyFromCertificate:(NSData *)certificateData {\n    SecCertificateRef certificate = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certificateData);\n    if (certificate != NULL) {\n        SecPolicyRef secPolicy = SecPolicyCreateBasicX509();\n        SecTrustRef trust;\n        SecTrustCreateWithCertificates(certificate, secPolicy, &trust);\n        SecTrustResultType resultType;\n        SecTrustEvaluate(trust, &resultType);\n        SecKeyRef publicKey = SecTrustCopyPublicKey(trust);\n        (CFRelease(trust));\n        (CFRelease(secPolicy));\n        (CFRelease(certificate));\n        return publicKey;\n    }\n    return NULL;\n}\n@end\n\n@implementation JWTCryptoSecurity (Pem)\n+ (NSString *)certificateFromPemFileContent:(NSString *)content {\n    NSRegularExpression *expression = [[NSRegularExpression alloc] initWithPattern:@\"-----BEGIN CERTIFICATE-----(.+?)-----END CERTIFICATE-----\" options:NSRegularExpressionDotMatchesLineSeparators error:nil];\n    return [self itemsFromPemFileContent:content byRegex:expression].firstObject;\n}\n+ (NSString *)keyFromPemFileContent:(NSString *)content {\n    NSRegularExpression *expression = [[NSRegularExpression alloc] initWithPattern:@\"-----BEGIN(?:[\\\\w\\\\s]|)+KEY-----(.+?)-----END(?:[\\\\w\\\\s])+KEY-----\" options:NSRegularExpressionDotMatchesLineSeparators error:nil];\n    return [self itemsFromPemFileContent:content byRegex:expression].firstObject;\n}\n+ (NSArray *)itemsFromPemFileContent:(NSString *)content byRegex:(NSRegularExpression *)expression {\n    NSArray *matches = [expression matchesInString:content options:0 range:NSMakeRange(0, content.length)];\n    NSTextCheckingResult *result = matches.firstObject;\n    NSArray *resultArray = @[];\n    \n    if (result) {\n        for (NSUInteger i = 1; i < result.numberOfRanges; ++i) {\n            NSString *extractedString = [content substringWithRange:[result rangeAtIndex:i]];\n            resultArray = [resultArray arrayByAddingObject:extractedString];\n        }\n    }\n    return resultArray;\n}\n+ (NSString *)certificateFromPemFileWithName:(NSString *)name {\n    NSRegularExpression *expression = [[NSRegularExpression alloc] initWithPattern:@\"-----BEGIN CERTIFICATE-----(.+?)-----END CERTIFICATE-----\" options:NSRegularExpressionDotMatchesLineSeparators error:nil];\n    return [self itemsFromPemFileWithName:name byRegex:expression].firstObject;\n}\n+ (NSString *)keyFromPemFileWithName:(NSString *)name {\n    NSRegularExpression *expression = [[NSRegularExpression alloc] initWithPattern:@\"-----BEGIN(?:[\\\\w\\\\s]|)+KEY-----(.+?)-----END(?:[\\\\w\\\\s])+KEY-----\" options:NSRegularExpressionDotMatchesLineSeparators error:nil];\n    return [self itemsFromPemFileWithName:name byRegex:expression].firstObject;\n}\n+ (NSArray *)itemsFromPemFileWithName:(NSString *)name byRegex:(NSRegularExpression *)expression {\n    NSURL *fileURL = [[NSBundle bundleForClass:self.class] URLForResource:name withExtension:@\"pem\"];\n    NSError *error = nil;\n    NSString *fileContent = [NSString stringWithContentsOfURL:fileURL encoding:NSUTF8StringEncoding error:&error];\n    \n    if (error) {\n        NSLog(@\"%@ error: %@\", self.debugDescription, error);\n        return nil;\n    }\n    \n    return [self itemsFromPemFileContent:fileContent byRegex:expression];\n}\n+ (NSString *)stringByRemovingPemHeadersFromString:(NSString *)string {\n    NSArray *lines = [string componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];\n    NSArray *linesWithoutHeaders = [lines filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(NSString *_Nullable evaluatedObject, NSDictionary<NSString *,id> * _Nullable bindings) {\n        return !([evaluatedObject hasPrefix:@\"-----BEGIN\"] || [evaluatedObject hasPrefix:@\"-----END\"]);\n    }]];\n    return [linesWithoutHeaders componentsJoinedByString:@\"\"];\n}\n@end\n\n@implementation JWTCryptoSecurity (PublicKey)\n/**\n This method strips the x509 from a provided ASN.1 DER public key.\n If the key doesn't contain a header, the DER data is returned as is.\n\n Supported formats are:\n\n Headerless:\n SEQUENCE\n    INTEGER (1024 or 2048 bit) -- modulo\n    INTEGER -- public exponent\n\n With x509 header:\n SEQUENCE\n    SEQUENCE\n        OBJECT IDENTIFIER 1.2.840.113549.1.1.1\n        NULL\n    BIT STRING\n        SEQUENCE\n        INTEGER (1024 or 2048 bit) -- modulo\n        INTEGER -- public exponent\n\n Example of headerless key:\n https://lapo.it/asn1js/#3082010A0282010100C1A0DFA367FBC2A5FD6ED5A071E02A4B0617E19C6B5AD11BB61192E78D212F10A7620084A3CED660894134D4E475BAD7786FA1D40878683FD1B7A1AD9C0542B7A666457A270159DAC40CE25B2EAE7CCD807D31AE725CA394F90FBB5C5BA500545B99C545A9FE08EFF00A5F23457633E1DB84ED5E908EF748A90F8DFCCAFF319CB0334705EA012AF15AA090D17A9330159C9AFC9275C610BB9B7C61317876DC7386C723885C100F774C19830F475AD1E9A9925F9CA9A69CE0181A214DF2EB75FD13E6A546B8C8ED699E33A8521242B7E42711066AEC22D25DD45D56F94D3170D6F2C25164D2DACED31C73963BA885ADCB706F40866B8266433ED5161DC50E4B3B0203010001\n\n Example of key with X509 header (notice the additional ASN.1 sequence):\n https://lapo.it/asn1js/#30819F300D06092A864886F70D010101050003818D0030818902818100D0674615A252ED3D75D2A3073A0A8A445F3188FD3BEB8BA8584F7299E391BDEC3427F287327414174997D147DD8CA62647427D73C9DA5504E0A3EED5274A1D50A1237D688486FADB8B82061675ABFA5E55B624095DB8790C6DBCAE83D6A8588C9A6635D7CF257ED1EDE18F04217D37908FD0CBB86B2C58D5F762E6207FF7B92D0203010001\n */\n//static func stripPublicKeyHeader(keyData: Data) throws -> Data {\n//    let count = keyData.count / MemoryLayout<CUnsignedChar>.size\n//\n//    guard count > 0 else {\n//        throw SwiftyRSAError(message: \"Provided public key is empty\")\n//    }\n//\n//    var byteArray = [UInt8](repeating: 0, count: count)\n//    (keyData as NSData).getBytes(&byteArray, length: keyData.count)\n//\n//    var index = 0\n//    guard byteArray[index] == 0x30 else {\n//        throw SwiftyRSAError(message: \"Provided key doesn't have a valid ASN.1 structure (first byte should be 0x30 == SEQUENCE)\")\n//    }\n//\n//    index += 1\n//    if byteArray[index] > 0x80 {\n//        index += Int(byteArray[index]) - 0x80 + 1\n//    } else {\n//        index += 1\n//    }\n//\n//    // If current byte marks an integer (0x02), it means the key doesn't have a X509 header and just\n//    // contains its modulo & public exponent. In this case, we can just return the provided DER data as is.\n//    if Int(byteArray[index]) == 0x02 {\n//        return keyData\n//    }\n//\n//    // Now that we've excluded the possibility of headerless key, we're looking for a valid X509 header sequence.\n//    // It should look like this:\n//    // 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00\n//    guard Int(byteArray[index]) == 0x30 else {\n//        throw SwiftyRSAError(message: \"Provided key doesn't have a valid X509 header\")\n//    }\n//\n//    index += 15\n//    if byteArray[index] != 0x03 {\n//        throw SwiftyRSAError(message: \"Invalid byte at index \\(index - 1) (\\(byteArray[index - 1])) for public key header\")\n//    }\n//\n//    index += 1\n//    if byteArray[index] > 0x80 {\n//        index += Int(byteArray[index]) - 0x80 + 1\n//    } else {\n//        index += 1\n//    }\n//\n//    guard byteArray[index] == 0 else {\n//        throw SwiftyRSAError(message: \"Invalid byte at index \\(index - 1) (\\(byteArray[index - 1])) for public key header\")\n//    }\n//\n//    index += 1\n//\n//    let strippedKeyBytes = [UInt8](byteArray[index...keyData.count - 1])\n//    let data = Data(bytes: UnsafePointer<UInt8>(strippedKeyBytes), count: keyData.count - index)\n//\n//    return data\n//}\ntypedef NS_ENUM(NSInteger, JWTPublicHeaderStrippingError) {\n    JWTPublicHeaderStrippingError_KeyIsEmpty = -200,\n    JWTPublicHeaderStrippingError_Invalid_ASN1_Structure,\n    JWTPublicHeaderStrippingError_Invalid_X509_Header,\n    JWTPublicHeaderStrippingError_Invalid_Byte_At_Index,\n};\n+ (NSDictionary *)publicHeaderStrippingMessagesAndCodes {\n    static NSDictionary *publicHeaderStrippingMessagesAndCodes = nil;\n    return publicHeaderStrippingMessagesAndCodes ?:\n    (publicHeaderStrippingMessagesAndCodes = @{\n        @(JWTPublicHeaderStrippingError_KeyIsEmpty) : @\"Provided public key is empty\",\n        @(JWTPublicHeaderStrippingError_Invalid_ASN1_Structure) : @\"Provided key doesn't have a valid ASN.1 structure (first byte should be 0x30 == SEQUENCE)\",\n        @(JWTPublicHeaderStrippingError_Invalid_X509_Header) : @\"Provided key doesn't have a valid X509 header\",\n        @(JWTPublicHeaderStrippingError_Invalid_Byte_At_Index) : @\"Invalid byte at index (index - 1) ((bytes[index - 1])) for public key header. Access as error.userInfo[Parameters][index] or error.userInfo[Parameters][byte]\"\n    },\n     publicHeaderStrippingMessagesAndCodes);\n}\n+ (NSString *)stringForPublicHeaderStrippingErrorCode:(NSInteger)code {\n    return [self publicHeaderStrippingMessagesAndCodes][@(code)] ?: @\"Unknown Public Header Stripping Error\";\n}\n+ (NSError*)publicHeaderStrippingErrorForCode:(NSInteger)code parameters:(NSDictionary *)parameters {\n    return [NSError errorWithDomain:@\"io.jwt.crypto.stripping_public_header\" code:code userInfo:@{\n                                                                                                  @\"Parameters\" : parameters ?: [NSNull null],NSLocalizedDescriptionKey: [self stringForPublicHeaderStrippingErrorCode:code]\n                                                                                                  }];\n}\n+ (NSError*)publicHeaderStrippingErrorForCode:(NSInteger)code {\n    return [self publicHeaderStrippingErrorForCode:code parameters:nil];\n}\n+ (NSData *)dataByRemovingPublicKeyHeader:(NSData *)data error:(NSError *__autoreleasing *)error {\n    NSError *currentError = nil;\n    NSData *currentData = [data copy];\n    //    let count = keyData.count / MemoryLayout<CUnsignedChar>.size\n    //\n    //    guard count > 0 else {\n    //        throw SwiftyRSAError(message: \"Provided public key is empty\")\n    //    }\n    NSInteger countOfBytes = currentData.length / [JWTMemoryLayout createWithType:[JWTMemoryLayout typeUInt8]].size;\n    if (countOfBytes == 0) {\n        //        throw SwiftyRSAError(message: \"Provided public key is empty\")\n        currentError = [self publicHeaderStrippingErrorForCode:JWTPublicHeaderStrippingError_KeyIsEmpty];\n        if (error) {\n            *error = currentError;\n        }\n        return nil;\n    }\n    //    var byteArray = [UInt8](repeating: 0, count: count)\n    //    (keyData as NSData).getBytes(&byteArray, length: keyData.count)\n//    UInt8 *bytes = (UInt8*)malloc(countOfBytes);\n    UInt8 *bytes = (UInt8 *)[currentData bytes];\n//    memcpy(bytes, [currentData bytes], countOfBytes);\n\n    //    var index = 0\n    //    guard byteArray[index] == 0x30 else {\n    //        throw SwiftyRSAError(message: \"Provided key doesn't have a valid ASN.1 structure (first byte should be 0x30 == SEQUENCE)\")\n    //    }\n\n    UInt8 index = 0;\n    if (bytes[index] != 0x30) {\n        //        throw SwiftyRSAError(message: \"Provided key doesn't have a valid ASN.1 structure (first byte should be 0x30 == SEQUENCE)\")\n        currentError = [self publicHeaderStrippingErrorForCode:JWTPublicHeaderStrippingError_Invalid_ASN1_Structure];\n        if (error) {\n            *error = currentError;\n        }\n        return nil;\n    }\n\n    //    index += 1\n    //    if byteArray[index] > 0x80 {\n    //        index += Int(byteArray[index]) - 0x80 + 1\n    //    } else {\n    //        index += 1\n    //    }\n    index += 1;\n    if (bytes[index] > 0x80) {\n        index += (SInt8)bytes[index] - 0x80 + 1;\n    }\n    else {\n        index += 1;\n    }\n\n    // Headerless!\n    //    // If current byte marks an integer (0x02), it means the key doesn't have a X509 header and just\n    //    // contains its modulo & public exponent. In this case, we can just return the provided DER data as is.\n    //    if Int(byteArray[index]) == 0x02 {\n    //        return keyData\n    //    }\n    if ((SInt8)bytes[index] == 0x02) {\n        return currentData;\n    }\n\n    // Has header.\n\n    //    // Now that we've excluded the possibility of headerless key, we're looking for a valid X509 header sequence.\n    //    // It should look like this:\n    //    // 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00\n    //    guard Int(byteArray[index]) == 0x30 else {\n    //        throw SwiftyRSAError(message: \"Provided key doesn't have a valid X509 header\")\n    //    }\n    if ((SInt8)bytes[index] != 0x30) {\n        //        throw SwiftyRSAError(message: \"Provided key doesn't have a valid X509 header\")\n        currentError = [self publicHeaderStrippingErrorForCode:JWTPublicHeaderStrippingError_Invalid_X509_Header];\n        if (error) {\n            *error = currentError;\n        }\n        return nil;\n    }\n\n    //    index += 15\n    //    if byteArray[index] != 0x03 {\n    //        throw SwiftyRSAError(message: \"Invalid byte at index \\(index - 1) (\\(byteArray[index - 1])) for public key header\")\n    //    }\n    index += 15;\n    if (bytes[index] != 0x03) {\n        //        throw SwiftyRSAError(message: \"Invalid byte at index \\(index - 1) (\\(byteArray[index - 1])) for public key header\")\n        currentError = [self publicHeaderStrippingErrorForCode:JWTPublicHeaderStrippingError_Invalid_Byte_At_Index parameters:@{@\"index\" : @(index - 1), @\"byte\": @(bytes[index - 1] ?: 0)}];\n        if (error) {\n            *error = currentError;\n        }\n        return nil;\n    }\n    //    index += 1\n    //    if byteArray[index] > 0x80 {\n    //        index += Int(byteArray[index]) - 0x80 + 1\n    //    } else {\n    //        index += 1\n    //    }\n    index += 1;\n    if (bytes[index] > 0x80) {\n        index += (SInt8)bytes[index] - 0x80 + 1;\n    }\n    else {\n        index += 1;\n    }\n    //    guard byteArray[index] == 0 else {\n    //        throw SwiftyRSAError(message: \"Invalid byte at index \\(index - 1) (\\(byteArray[index - 1])) for public key header\")\n    //    }\n    if (bytes[index] != 0) {\n        //        throw SwiftyRSAError(message: \"Invalid byte at index \\(index - 1) (\\(byteArray[index - 1])) for public key header\")\n        currentError = [self publicHeaderStrippingErrorForCode:JWTPublicHeaderStrippingError_Invalid_Byte_At_Index parameters:@{@\"index\" : @(index - 1), @\"byte\": @(bytes[index - 1] ?: 0)}];\n        if (error) {\n            *error = currentError;\n        }\n        return nil;\n    }\n    //    index += 1\n    //\n    //    let strippedKeyBytes = [UInt8](byteArray[index...keyData.count - 1])\n    //    let data = Data(bytes: UnsafePointer<UInt8>(strippedKeyBytes), count: keyData.count - index)\n    index += 1;\n    NSInteger countOfStrippedBytes = currentData.length - index;\n    UInt8 *strippedBytes = (UInt8 *)(bytes + index);\n    NSData *resultData = [[NSData alloc] initWithBytes:strippedBytes length:countOfStrippedBytes];\n    //    return data\n    return resultData;\n}\n@end\n"
  },
  {
    "path": "ios/CodePush/JWT/Core/ClaimSet/JWTClaim.h",
    "content": "//\n//  JWTClaim.h\n//  JWT\n//\n//  Created by Lobanov Dmitry on 13.02.16.\n//  Copyright © 2016 Karma. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n\n@interface JWTClaim : NSObject\n\n+ (NSString *)name;\n+ (instancetype)claimByName:(NSString *)name;\n+ (BOOL)verifyValue:(NSObject *)value withTrustedValue:(NSObject *)trustedValue;\n- (BOOL)verifyValue:(NSObject *)value withTrustedValue:(NSObject *)trustedValue;\n\n@end\n"
  },
  {
    "path": "ios/CodePush/JWT/Core/ClaimSet/JWTClaim.m",
    "content": "//\n//  JWTClaim.m\n//  JWT\n//\n//  Created by Lobanov Dmitry on 13.02.16.\n//  Copyright © 2016 Karma. All rights reserved.\n//\n\n#import \"JWTClaim.h\"\n\n// TODO(3.0): Claim aud should check include in collection?\n// Add claims specification tests.\n// \"iss\" (Issuer) Claim\n// \"sub\" (Subject) Claim\n// \"aud\" (Audience) Claim\n// \"exp\" (Expiration Time) Claim\n// \"nbf\" (Not Before) Claim\n// \"iat\" (Issued At) Claim\n// \"jti\" (JWT ID) Claim\n// \"typ\" (Type) Claim\n// \"scope\" (Scope) Claim\n\n@interface JWTClaimIssuer : JWTClaim\n\n@end\n\n@implementation JWTClaimIssuer\n\n+ (NSString *)name {\n\treturn @\"iss\";\n}\n\n+ (BOOL)verifyValue:(NSString *)value withTrustedValue:(NSString *)trustedValue {\n    return [trustedValue isEqualToString:value];\n}\n\n@end\n\n@interface JWTClaimSubject : JWTClaim\n\n@end\n\n@implementation JWTClaimSubject\n\n+ (NSString *)name {\n\treturn @\"sub\";\n}\n\n+ (BOOL)verifyValue:(NSString *)value withTrustedValue:(NSString *)trustedValue {\n    return [trustedValue isEqualToString:value];\n}\n\n@end\n\n@interface JWTClaimAudience : JWTClaim\n\n@end\n\n// TODO: add array support later\n@implementation JWTClaimAudience\n\n+ (NSString *)name {\n\treturn @\"aud\";\n}\n\n+ (BOOL)verifyValue:(NSString *)value withTrustedValue:(NSString *)trustedValue {\n    return [trustedValue isEqualToString:value];\n}\n\n@end\n\n@interface JWTClaimExpirationTime : JWTClaim\n\n@end\n\n@implementation JWTClaimExpirationTime\n\n+ (NSString *)name {\n\treturn @\"exp\";\n}\n\n+ (BOOL)verifyValue:(NSDate *)value withTrustedValue:(NSDate *)trustedValue {\n    // trustedValue - current date\n    // value - expiration date\n    // trustedValue < value, so\n    return [trustedValue compare:value] == NSOrderedAscending;\n}\n\n@end\n\n@interface JWTClaimNotBefore : JWTClaim\n\n@end\n\n@implementation JWTClaimNotBefore\n\n+ (NSString *)name {\n\treturn @\"nbf\";\n}\n\n+ (BOOL)verifyValue:(NSDate *)value withTrustedValue:(NSDate *)trustedValue {\n    // trustedValue - current date\n    // value - start date\n    // value <= trustedValue, so\n    // trustedValue >= value, which means:\n    // !(trustedValue < value) or NOT OrderedAscending\n    return [trustedValue compare:value] != NSOrderedAscending;\n}\n\n@end\n\n@interface JWTClaimIssuedAt : JWTClaim\n\n@end\n\n@implementation JWTClaimIssuedAt\n\n+ (NSString *)name {\n\treturn @\"iat\";\n}\n\n+ (BOOL)verifyValue:(NSDate *)value withTrustedValue:(NSDate *)trustedValue {\n    // trustedValue - current date\n    // value - issued at date\n    // value < trustedValue, so\n    // trustedValue > value\n    return [trustedValue compare:value] == NSOrderedDescending;\n}\n\n@end\n\n@interface JWTClaimJWTID : JWTClaim\n\n@end\n\n@implementation JWTClaimJWTID\n\n+ (NSString *)name {\n\treturn @\"jti\";\n}\n\n+ (BOOL)verifyValue:(NSString *)value withTrustedValue:(NSString *)trustedValue {\n    return [trustedValue isEqualToString:value];\n}\n\n@end\n\n@interface JWTClaimType : JWTClaim\n\n@end\n\n@implementation JWTClaimType\n\n+ (NSString *)name {\n    return @\"typ\";\n}\n\n+ (BOOL)verifyValue:(NSString *)value withTrustedValue:(NSString *)trustedValue {\n    return [trustedValue isEqualToString:value];\n}\n\n@end\n\n@interface JWTClaimScope : JWTClaim\n\n@end\n\n@implementation JWTClaimScope\n\n+ (NSString *)name {\n    return @\"scope\";\n}\n\n+ (BOOL)verifyValue:(NSString *)value withTrustedValue:(NSString *)trustedValue {\n    return [trustedValue isEqualToString:value];\n}\n\n@end\n\n\n@implementation JWTClaim\n+ (NSString *)name {\n    return @\"\";\n}\n\n+ (NSDictionary *)claimsAndNames {\n    static NSDictionary *dictionary = nil;\n    return dictionary ? dictionary : (dictionary = @{\n\t\t[JWTClaimIssuer name] : [JWTClaimIssuer new],\n\t\t[JWTClaimSubject name] : [JWTClaimSubject new],\n\t\t[JWTClaimAudience name] : [JWTClaimAudience new],\n\t\t[JWTClaimExpirationTime name] : [JWTClaimExpirationTime new],\n\t\t[JWTClaimNotBefore name] : [JWTClaimNotBefore new],\n\t\t[JWTClaimIssuedAt name] : [JWTClaimIssuedAt new],\n\t\t[JWTClaimJWTID name] : [JWTClaimJWTID new],\n\t\t[JWTClaimType name] : [JWTClaimType new],\n        [JWTClaimScope name] : [JWTClaimScope new]\n\t}, dictionary);\n}\n\n+ (instancetype)claimByName:(NSString *)name {    \n    return [self claimsAndNames][name];\n}\n\n+ (BOOL)verifyValue:(NSObject *)value withTrustedValue:(NSObject *)trustedValue {\n\treturn NO;\n}\n\n- (BOOL)verifyValue:(NSObject *)value withTrustedValue:(NSObject *)trustedValue {\n    return [self.class verifyValue:value withTrustedValue:trustedValue];\n}\n\n@end\n\n"
  },
  {
    "path": "ios/CodePush/JWT/Core/ClaimSet/JWTClaimsSet.h",
    "content": "//\n//  JWTClaimsSet.h\n//  JWT\n//\n//  Created by Klaas Pieter Annema on 31-05-13.\n//  Copyright (c) 2013 Karma. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n\n@interface JWTClaimsSet : NSObject<NSCopying>\n\n@property (nonatomic, readwrite, copy) NSString *issuer;\n@property (nonatomic, readwrite, copy) NSString *subject;\n@property (nonatomic, readwrite, copy) NSString *audience;\n@property (nonatomic, readwrite, copy) NSDate *expirationDate;\n@property (nonatomic, readwrite, copy) NSDate *notBeforeDate;\n@property (nonatomic, readwrite, copy) NSDate *issuedAt;\n@property (nonatomic, readwrite, copy) NSString *identifier;\n@property (nonatomic, readwrite, copy) NSString *type;\n@property (nonatomic, readwrite, copy) NSString *scope;\n\n@end\n"
  },
  {
    "path": "ios/CodePush/JWT/Core/ClaimSet/JWTClaimsSet.m",
    "content": "//\n//  JWTClaimsSet.m\n//  JWT\n//\n//  Created by Klaas Pieter Annema on 31-05-13.\n//  Copyright (c) 2013 Karma. All rights reserved.\n//\n\n#import \"JWTClaimsSet.h\"\n\n@implementation JWTClaimsSet\n\n- (id)copyWithZone:(NSZone *)zone {\n    JWTClaimsSet *newClaimsSet = [[self.class alloc] init];\n    \n    newClaimsSet.issuer = self.issuer;\n    newClaimsSet.subject = self.subject;\n    newClaimsSet.audience = self.audience;\n    newClaimsSet.expirationDate = self.expirationDate;\n    newClaimsSet.notBeforeDate = self.notBeforeDate;\n    newClaimsSet.issuedAt = self.issuedAt;\n    newClaimsSet.identifier = self.identifier;\n    newClaimsSet.type = self.type;\n    newClaimsSet.scope = self.scope;\n\n    return newClaimsSet;\n}\n\n@end\n"
  },
  {
    "path": "ios/CodePush/JWT/Core/ClaimSet/JWTClaimsSetSerializer.h",
    "content": "//\n//  JWTClaimsSetSerializer.h\n//  JWT\n//\n//  Created by Klaas Pieter Annema on 31-05-13.\n//  Copyright (c) 2013 Karma. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n\n#import \"JWTClaimsSet.h\"\n\n@interface JWTClaimsSetSerializer : NSObject\n\n+ (NSArray *)claimsSetKeys;\n+ (NSDictionary *)dictionaryWithClaimsSet:(JWTClaimsSet *)theClaimsSet;\n+ (JWTClaimsSet *)claimsSetWithDictionary:(NSDictionary *)theDictionary;\n\n@end\n"
  },
  {
    "path": "ios/CodePush/JWT/Core/ClaimSet/JWTClaimsSetSerializer.m",
    "content": "//\n//  JWTClaimsSetSerializer.m\n//  JWT\n//\n//  Created by Klaas Pieter Annema on 31-05-13.\n//  Copyright (c) 2013 Karma. All rights reserved.\n//\n\n#import \"JWTClaimsSetSerializer.h\"\n\n@implementation JWTClaimsSetSerializer\n\n+ (NSArray *)claimsSetKeys\n{\n    return @[@\"iss\", @\"sub\", @\"aud\", @\"exp\", @\"nbf\", @\"iat\", @\"jti\", @\"typ\", @\"scope\"];\n}\n\n+ (NSDictionary *)dictionaryWithClaimsSet:(JWTClaimsSet *)theClaimsSet;\n{\n    NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];\n    [self dictionary:dictionary setObjectIfNotNil:theClaimsSet.issuer forKey:@\"iss\"];\n    [self dictionary:dictionary setObjectIfNotNil:theClaimsSet.subject forKey:@\"sub\"];\n    [self dictionary:dictionary setObjectIfNotNil:theClaimsSet.audience forKey:@\"aud\"];\n    [self dictionary:dictionary setDateIfNotNil:theClaimsSet.expirationDate forKey:@\"exp\"];\n    [self dictionary:dictionary setDateIfNotNil:theClaimsSet.notBeforeDate forKey:@\"nbf\"];\n    [self dictionary:dictionary setDateIfNotNil:theClaimsSet.issuedAt forKey:@\"iat\"];\n    [self dictionary:dictionary setObjectIfNotNil:theClaimsSet.identifier forKey:@\"jti\"];\n    [self dictionary:dictionary setObjectIfNotNil:theClaimsSet.type forKey:@\"typ\"];\n    [self dictionary:dictionary setObjectIfNotNil:theClaimsSet.scope forKey:@\"scope\"];\n\n    return [dictionary copy];\n}\n\n+ (JWTClaimsSet *)claimsSetWithDictionary:(NSDictionary *)theDictionary;\n{\n    JWTClaimsSet *claimsSet = [[JWTClaimsSet alloc] init];\n    claimsSet.issuer = [theDictionary objectForKey:@\"iss\"];\n    claimsSet.subject = [theDictionary objectForKey:@\"sub\"];\n    claimsSet.audience = [theDictionary objectForKey:@\"aud\"];\n    claimsSet.expirationDate = [NSDate dateWithTimeIntervalSince1970:[[theDictionary objectForKey:@\"exp\"] doubleValue]];\n    claimsSet.notBeforeDate = [NSDate dateWithTimeIntervalSince1970:[[theDictionary objectForKey:@\"nbf\"] doubleValue]];\n    claimsSet.issuedAt = [NSDate dateWithTimeIntervalSince1970:[[theDictionary objectForKey:@\"iat\"] doubleValue]];\n    claimsSet.identifier = [theDictionary objectForKey:@\"jti\"];\n    claimsSet.type = [theDictionary objectForKey:@\"typ\"];\n    claimsSet.scope = [theDictionary objectForKey:@\"scope\"];\n\n    return claimsSet;\n}\n\n+ (void)dictionary:(NSMutableDictionary *)theDictionary setObjectIfNotNil:(id)theObject forKey:(id<NSCopying>)theKey;\n{\n    if (!theObject)\n        return;\n    \n    [theDictionary setObject:theObject forKey:theKey];\n}\n\n+ (void)dictionary:(NSMutableDictionary *)theDictionary setDateIfNotNil:(NSDate*)date forKey:(id<NSCopying>)theKey;\n{\n    if (!date)\n        return;\n    NSNumber* value = @((unsigned long)[date timeIntervalSince1970]);\n    \n    [theDictionary setObject:value forKey:theKey];\n}\n\n\n@end\n"
  },
  {
    "path": "ios/CodePush/JWT/Core/ClaimSet/JWTClaimsSetVerifier.h",
    "content": "//\n//  JWTClaimsSetVerifier.h\n//  JWT\n//\n//  Created by Lobanov Dmitry on 13.02.16.\n//  Copyright © 2016 Karma. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n#import \"JWTClaimsSet.h\"\n\n@interface JWTClaimsSetVerifier : NSObject\n\n+ (BOOL)verifyClaimsSet:(JWTClaimsSet *)theClaimsSet withTrustedClaimsSet:(JWTClaimsSet *)trustedClaimsSet;\n\n+ (BOOL)verifyClaimsSetDictionary:(NSDictionary *)theClaimsSetDictionary withTrustedClaimsSet:(JWTClaimsSet *)trustedClaimsSet;\n\n@end\n"
  },
  {
    "path": "ios/CodePush/JWT/Core/ClaimSet/JWTClaimsSetVerifier.m",
    "content": "//\n//  JWTClaimsSetVerifier.m\n//  JWT\n//\n//  Created by Lobanov Dmitry on 13.02.16.\n//  Copyright © 2016 Karma. All rights reserved.\n//\n\n#import \"JWTClaimsSetVerifier.h\"\n#import \"JWTClaimsSetSerializer.h\"\n#import \"JWTClaim.h\"\n\n@implementation JWTClaimsSetVerifier\n\n+ (BOOL)verifyDictionary:(NSDictionary *)dictionary withTrustedDictionary:(NSDictionary *)trustedDictionary byKey:(NSString *)key {\n    NSObject *value = dictionary[key];\n    NSObject *trustedValue = trustedDictionary[key];\n    \n    BOOL result = YES;\n    \n    if (trustedValue) {\n        result = [[JWTClaim claimByName:key] verifyValue:value withTrustedValue:trustedValue];\n    }\n    \n    return result;\n}\n\n+ (BOOL)verifyClaimsSetDictionary:(NSDictionary *)theClaimsSetDictionary withTrustedClaimsSetDictionary:(NSDictionary *)trustedClaimsSetDictionary {\n    \n    NSArray *claimsSets = [JWTClaimsSetSerializer claimsSetKeys];\n    \n    if (!trustedClaimsSetDictionary) {\n        return YES;\n    }\n    \n    if (!theClaimsSetDictionary) {\n        return NO;\n    }\n    \n    BOOL result = YES;\n    \n    for (NSString *key in claimsSets) {\n        result = result && [self verifyDictionary:theClaimsSetDictionary withTrustedDictionary:trustedClaimsSetDictionary byKey:key];\n    }\n    \n    return result;\n}\n\n\n+ (BOOL)verifyClaimsSet:(JWTClaimsSet *)theClaimsSet withTrustedClaimsSet:(JWTClaimsSet *)trustedClaimsSet {\n    \n    NSDictionary *dictionary = [JWTClaimsSetSerializer dictionaryWithClaimsSet:theClaimsSet];\n    \n    NSDictionary *trustedDictionary = [JWTClaimsSetSerializer dictionaryWithClaimsSet:trustedClaimsSet];\n    \n    NSArray *claimsSets = [JWTClaimsSetSerializer claimsSetKeys];\n    \n    BOOL result = YES;\n    for (NSString *key in claimsSets) {\n        result = result && [self verifyDictionary:dictionary withTrustedDictionary:trustedDictionary byKey:key];\n    }\n    \n    return result;\n}\n\n+ (BOOL)verifyClaimsSetDictionary:(NSDictionary *)theClaimsSetDictionary withTrustedClaimsSet:(JWTClaimsSet *)trustedClaimsSet {\n    NSDictionary *trustedDictionary = [JWTClaimsSetSerializer dictionaryWithClaimsSet:trustedClaimsSet];\n\n    return [self verifyClaimsSetDictionary:theClaimsSetDictionary withTrustedClaimsSetDictionary:trustedDictionary];\n}\n\n@end"
  },
  {
    "path": "ios/CodePush/JWT/Core/Coding/JWTCoding+ResultTypes.h",
    "content": "//\n//  JWTCoding+ResultTypes.h\n//  JWT\n//\n//  Created by Lobanov Dmitry on 30.11.16.\n//  Copyright © 2016 JWTIO. All rights reserved.\n//\n\n#import <JWTCoding.h>\n@class JWTClaimsSet;\n\nextern NSString *JWTCodingResultHeaders;\nextern NSString *JWTCodingResultPayload;\n\n@interface JWT (ResultTypes) @end\n\n/*\n            ResultType\n                /\\\n               /  \\\n              /    \\\n          Success  Error\n \n    Protocols: Mutable and Immutable (?!?)\n */\n\n// Public\n@protocol JWTCodingResultTypeSuccessEncodedProtocol <NSObject>\n@property (copy, nonatomic, readonly) NSString *encoded;\n- (instancetype)initWithEncoded:(NSString *)encoded;\n@property (copy, nonatomic, readonly) NSString *token;\n- (instancetype)initWithToken:(NSString *)token;\n@end\n\n// Public\n@protocol JWTCodingResultTypeSuccessDecodedProtocol <NSObject>\n@property (copy, nonatomic, readonly) NSDictionary *headers;\n@property (copy, nonatomic, readonly) NSDictionary *payload;\n\n// dictionary @{\n//  JWTCodingResultHeaders : self.headers,\n//  JWTCodingResultPayload : self.payload\n//}\n@property (copy, nonatomic, readonly) NSDictionary *headerAndPayloadDictionary;\n\n@property (nonatomic, readonly) JWTClaimsSet *claimsSet;\n- (instancetype)initWithHeaders:(NSDictionary *)headers withPayload:(NSDictionary *)payload;\n- (instancetype)initWithClaimsSet:(JWTClaimsSet *)claimsSet;\n@end\n\n// Public\n@interface JWTCodingResultTypeSuccess : NSObject <JWTCodingResultTypeSuccessEncodedProtocol,JWTCodingResultTypeSuccessDecodedProtocol> @end\n\n// Public\n@protocol JWTCodingResultTypeErrorProtocol <NSObject>\n@property (copy, nonatomic, readonly) NSError *error;\n- (instancetype)initWithError:(NSError *)error;\n@end\n\n@interface JWTCodingResultTypeError : NSObject <JWTCodingResultTypeErrorProtocol> @end\n\n@interface JWTCodingResultType : NSObject\n- (instancetype)initWithSuccessResult:(JWTCodingResultTypeSuccess *)success;\n- (instancetype)initWithErrorResult:(JWTCodingResultTypeError *)error;\n@property (strong, nonatomic, readonly) JWTCodingResultTypeSuccess *successResult;\n@property (strong, nonatomic, readonly) JWTCodingResultTypeError *errorResult;\n@end\n"
  },
  {
    "path": "ios/CodePush/JWT/Core/Coding/JWTCoding+ResultTypes.m",
    "content": "//\n//  JWTCoding+ResultTypes.m\n//  JWT\n//\n//  Created by Lobanov Dmitry on 30.11.16.\n//  Copyright © 2016 JWTIO. All rights reserved.\n//\n\n#import \"JWTCoding+ResultTypes.h\"\n\nNSString *JWTCodingResultHeaders = @\"header\";\nNSString *JWTCodingResultPayload = @\"payload\";\n\n@implementation JWT (ResultTypes) @end\n\n// Protected?\n@protocol JWTMutableCodingResultTypeSuccessEncodedProtocol <JWTCodingResultTypeSuccessEncodedProtocol>\n@property (copy, nonatomic, readwrite) NSString *encoded;\n@property (copy, nonatomic, readwrite) NSString *token;\n@end\n\n// Protected?\n@protocol JWTMutableCodingResultTypeSuccessDecodedProtocol <JWTCodingResultTypeSuccessDecodedProtocol>\n@property (copy, nonatomic, readwrite) NSDictionary *headers;\n@property (copy, nonatomic, readwrite) NSDictionary *payload;\n@property (nonatomic, readwrite) JWTClaimsSet *claimsSet;\n@end\n\n// Protected?\n@protocol JWTMutableCodingResultTypeErrorProtocol <JWTCodingResultTypeErrorProtocol>\n@property (copy, nonatomic, readwrite) NSError *error;\n@end\n\n@interface JWTCodingResultTypeSuccess () <JWTMutableCodingResultTypeSuccessEncodedProtocol, JWTMutableCodingResultTypeSuccessDecodedProtocol> @end\n\n@implementation JWTCodingResultTypeSuccess\n@synthesize encoded = _encoded;\n@synthesize headers = _headers;\n@synthesize payload = _payload;\n@synthesize claimsSet = _claimsSet;\n//Not used yet. Could be replacement for _encoded.\n@synthesize token = _token;\n\n- (NSDictionary *)headerAndPayloadDictionary {\n    if (self.headers && self.payload) {\n        return @{\n                 JWTCodingResultHeaders: self.headers,\n                 JWTCodingResultPayload: self.payload\n        };\n    }\n    return nil;\n}\n- (instancetype)initWithEncoded:(NSString *)encoded {\n    if (self = [super init]) {\n        self.encoded = encoded;\n    }\n    return self;\n}\n- (instancetype)initWithToken:(NSString *)token {\n    if (self = [super init]) {\n        self.token = token;\n    }\n    return self;\n}\n- (instancetype)initWithHeaders:(NSDictionary *)headers withPayload:(NSDictionary *)payload {\n    if (self = [super init]) {\n        self.headers = headers;\n        self.payload = payload;\n    }\n    return self;\n}\n- (instancetype)initWithClaimsSet:(JWTClaimsSet *)claimsSet {\n    if (self = [super init]) {\n        self.claimsSet = claimsSet;\n    }\n    return self;\n}\n@end\n\n@interface JWTCodingResultTypeError () <JWTMutableCodingResultTypeErrorProtocol> @end\n\n@implementation JWTCodingResultTypeError\n@synthesize error = _error;\n- (instancetype)initWithError:(NSError *)error {\n    if (self = [super init]) {\n        self.error = error;\n    }\n    return self;\n}\n@end\n\n@interface JWTCodingResultType ()\n@property (strong, nonatomic, readwrite) JWTCodingResultTypeSuccess *successResult;\n@property (strong, nonatomic, readwrite) JWTCodingResultTypeError *errorResult;\n@end\n\n@implementation JWTCodingResultType\n- (instancetype)initWithSuccessResult:(JWTCodingResultTypeSuccess *)success {\n    if (self = [super init]) {\n        self.successResult = success;\n    }\n    return self;\n}\n- (instancetype)initWithErrorResult:(JWTCodingResultTypeError *)error {\n    if (self = [super init]) {\n        self.errorResult = error;\n    }\n    return self;\n}\n\n@end\n"
  },
  {
    "path": "ios/CodePush/JWT/Core/Coding/JWTCoding+VersionOne.h",
    "content": "//\n//  JWTCoding+VersionOne.h\n//  JWT\n//\n//  Created by Lobanov Dmitry on 27.11.16.\n//  Copyright © 2016 JWTIO. All rights reserved.\n//\n\n#import <JWTCoding.h>\n\n@protocol JWTAlgorithm;\n@class JWTClaimsSet;\n\n@interface JWT (VersionOne)\n#pragma mark - Encode\n+ (NSString *)encodeClaimsSet:(JWTClaimsSet *)theClaimsSet withSecret:(NSString *)theSecret;\n+ (NSString *)encodeClaimsSet:(JWTClaimsSet *)theClaimsSet withSecret:(NSString *)theSecret algorithm:(id<JWTAlgorithm>)theAlgorithm;\n\n+ (NSString *)encodePayload:(NSDictionary *)thePayload withSecret:(NSString *)theSecret;\n+ (NSString *)encodePayload:(NSDictionary *)thePayload withSecret:(NSString *)theSecret algorithm:(id<JWTAlgorithm>)theAlgorithm;\n\n+ (NSString *)encodePayload:(NSDictionary *)thePayload withSecret:(NSString *)theSecret withHeaders:(NSDictionary *)theHeaders algorithm:(id<JWTAlgorithm>)theAlgorithm;\n\n+ (NSString *)encodePayload:(NSDictionary *)thePayload withSecret:(NSString *)theSecret withHeaders:(NSDictionary *)theHeaders algorithm:(id<JWTAlgorithm>)theAlgorithm withError:(NSError * __autoreleasing *)theError;\n\n//Will be deprecated in later releases\n#pragma mark - Decode\n\n/**\n Decodes a JWT and returns the decoded Header and Payload\n @param theMessage The encoded JWT\n @param theSecret The verification key to use for validating the JWT signature\n @param theTrustedClaimsSet The JWTClaimsSet to use for verifying the JWT values\n @param theError Error pointer, if there is an error decoding the message, upon return contains an NSError object that describes the problem.\n @param theAlgorithmName The name of the algorithm to use for verifying the signature. Required, unless skipping verification\n @param theForcedOption BOOL indicating if verifying the JWT signature should be skipped. Should only be used for debugging\n @return A dictionary containing the header and payload dictionaries. Keyed to \"header\" and \"payload\", respectively. Or nil if an error occurs.\n */\n+ (NSDictionary *)decodeMessage:(NSString *)theMessage withSecret:(NSString *)theSecret withTrustedClaimsSet:(JWTClaimsSet *)theTrustedClaimsSet withError:(NSError *__autoreleasing *)theError withForcedAlgorithmByName:(NSString *)theAlgorithmName withForcedOption:(BOOL)theForcedOption;\n\n/**\n Decodes a JWT and returns the decoded Header and Payload\n @param theMessage The encoded JWT\n @param theSecret The verification key to use for validating the JWT signature\n @param theTrustedClaimsSet The JWTClaimsSet to use for verifying the JWT values\n @param theError Error pointer, if there is an error decoding the message, upon return contains an NSError object that describes the problem.\n @param theAlgorithmName The name of the algorithm to use for verifying the signature. Required.\n @return A dictionary containing the header and payload dictionaries. Keyed to \"header\" and \"payload\", respectively. Or nil if an error occurs.\n */\n+ (NSDictionary *)decodeMessage:(NSString *)theMessage withSecret:(NSString *)theSecret withTrustedClaimsSet:(JWTClaimsSet *)theTrustedClaimsSet withError:(NSError *__autoreleasing *)theError withForcedAlgorithmByName:(NSString *)theAlgorithmName;\n\n/**\n Decodes a JWT and returns the decoded Header and Payload.\n\n Uses the JWTAlgorithmHS512 for decoding\n\n @param theMessage The encoded JWT\n @param theSecret The verification key to use for validating the JWT signature\n @param theTrustedClaimsSet The JWTClaimsSet to use for verifying the JWT values\n @param theError Error pointer, if there is an error decoding the message, upon return contains an NSError object that describes the problem.\n @param theForcedOption BOOL indicating if verifying the JWT signature should be skipped. Should only be used for debugging\n @return A dictionary containing the header and payload dictionaries. Keyed to \"header\" and \"payload\", respectively. Or nil if an error occurs.\n */\n+ (NSDictionary *)decodeMessage:(NSString *)theMessage withSecret:(NSString *)theSecret withTrustedClaimsSet:(JWTClaimsSet *)theTrustedClaimsSet withError:(NSError *__autoreleasing *)theError withForcedOption:(BOOL)theForcedOption;\n\n/**\n Decodes a JWT and returns the decoded Header and Payload\n @param theMessage The encoded JWT\n @param theSecret The verification key to use for validating the JWT signature\n @param theError Error pointer, if there is an error decoding the message, upon return contains an NSError object that describes the problem.\n @param theAlgorithmName The name of the algorithm to use for verifying the signature. Required, unless skipping verification\n @param skipVerification BOOL indicating if verifying the JWT signature should be skipped. Should only be used for debugging\n @return A dictionary containing the header and payload dictionaries. Keyed to \"header\" and \"payload\", respectively. Or nil if an error occurs.\n */\n+ (NSDictionary *)decodeMessage:(NSString *)theMessage withSecret:(NSString *)theSecret withError:(NSError *__autoreleasing *)theError withForcedAlgorithmByName:(NSString *)theAlgorithmName skipVerification:(BOOL)skipVerification;\n\n/**\n Decodes a JWT and returns the decoded Header and Payload\n @param theMessage The encoded JWT\n @param theSecret The verification key to use for validating the JWT signature\n @param theError Error pointer, if there is an error decoding the message, upon return contains an NSError object that describes the problem.\n @param theAlgorithmName The name of the algorithm to use for verifying the signature. Required.\n @return A dictionary containing the header and payload dictionaries. Keyed to \"header\" and \"payload\", respectively. Or nil if an error occurs.\n */\n+ (NSDictionary *)decodeMessage:(NSString *)theMessage withSecret:(NSString *)theSecret withError:(NSError *__autoreleasing *)theError withForcedAlgorithmByName:(NSString *)theAlgorithmName;\n\n/**\n Decodes a JWT and returns the decoded Header and Payload\n\n Uses the JWTAlgorithmHS512 for decoding\n\n @param theMessage The encoded JWT\n @param theSecret The verification key to use for validating the JWT signature\n @param theError Error pointer, if there is an error decoding the message, upon return contains an NSError object that describes the problem.\n @param theForcedOption BOOL indicating if verifying the JWT signature should be skipped.\n @return A dictionary containing the header and payload dictionaries. Keyed to \"header\" and \"payload\", respectively. Or nil if an error occurs.\n */\n+ (NSDictionary *)decodeMessage:(NSString *)theMessage withSecret:(NSString *)theSecret withError:(NSError *__autoreleasing *)theError withForcedOption:(BOOL)theForcedOption;\n\n/**\n Decodes a JWT and returns the decoded Header and Payload.\n Uses the JWTAlgorithmHS512 for decoding\n @param theMessage The encoded JWT\n @param theSecret The verification key to use for validating the JWT signature\n @param theError Error pointer, if there is an error decoding the message, upon return contains an NSError object that describes the problem.\n @return A dictionary containing the header and payload dictionaries. Keyed to \"header\" and \"payload\", respectively. Or nil if an error occurs.\n */\n+ (NSDictionary *)decodeMessage:(NSString *)theMessage withSecret:(NSString *)theSecret withError:(NSError * __autoreleasing *)theError;\n\n/**\n Decodes a JWT and returns the decoded Header and Payload.\n Uses the JWTAlgorithmHS512 for decoding\n @param theMessage The encoded JWT\n @param theSecret The verification key to use for validating the JWT signature\n @return A dictionary containing the header and payload dictionaries. Keyed to \"header\" and \"payload\", respectively. Or nil if an error occurs.\n */\n+ (NSDictionary *)decodeMessage:(NSString *)theMessage withSecret:(NSString *)theSecret;\n\n@end\n"
  },
  {
    "path": "ios/CodePush/JWT/Core/Coding/JWTCoding+VersionOne.m",
    "content": "//\n//  JWTCoding+VersionOne.m\n//  JWT\n//\n//  Created by Lobanov Dmitry on 27.11.16.\n//  Copyright © 2016 JWTIO. All rights reserved.\n//\n\n#import \"JWTCoding+VersionOne.h\"\n#import \"JWTBase64Coder.h\"\n\n#import \"JWTRSAlgorithm.h\"\n\n#import \"JWTAlgorithmFactory.h\"\n#import \"JWTAlgorithmHSBase.h\"\n\n#import \"JWTAlgorithmDataHolder.h\"\n\n#import \"JWTClaimsSetSerializer.h\"\n#import \"JWTClaimsSetVerifier.h\"\n\n#import \"JWTErrorDescription.h\"\n\n@implementation JWT (VersionOne)\n#pragma mark - Private Methods\n+ (NSString *)encodeSegment:(id)theSegment withError:(NSError **)error\n{\n    NSData *encodedSegmentData = nil;\n    \n    if (theSegment) {\n        encodedSegmentData = [NSJSONSerialization dataWithJSONObject:theSegment options:0 error:error];\n    }\n    else {\n        // error!\n        NSError *generatedError = [JWTErrorDescription errorWithCode:JWTInvalidSegmentSerializationError];\n        if (error) {\n            *error = generatedError;\n        }\n        NSLog(@\"%@ Could not encode segment: %@\", self.class, generatedError.localizedDescription);\n        return nil;\n    }\n    \n    NSString *encodedSegment = nil;\n    \n    if (encodedSegmentData) {\n        encodedSegment = [JWTBase64Coder base64UrlEncodedStringWithData:encodedSegmentData];//[encodedSegmentData base64UrlEncodedString];\n    }\n    \n    return encodedSegment;\n}\n\n+ (NSString *)encodeSegment:(id)theSegment;\n{\n    NSError *error;\n    return [self encodeSegment:theSegment withError:&error];\n}\n\n#pragma mark - Public Methods\n\n+ (NSString *)encodeClaimsSet:(JWTClaimsSet *)theClaimsSet withSecret:(NSString *)theSecret;\n{\n    return [self encodeClaimsSet:theClaimsSet withSecret:theSecret algorithm:[JWTAlgorithmFactory algorithmByName:JWTAlgorithmNameHS512]];\n}\n\n+ (NSString *)encodeClaimsSet:(JWTClaimsSet *)theClaimsSet withSecret:(NSString *)theSecret algorithm:(id<JWTAlgorithm>)theAlgorithm;\n{\n    NSDictionary *payload = [JWTClaimsSetSerializer dictionaryWithClaimsSet:theClaimsSet];\n    return [self encodePayload:payload withSecret:theSecret algorithm:theAlgorithm];\n}\n\n+ (NSString *)encodePayload:(NSDictionary *)thePayload withSecret:(NSString *)theSecret;\n{\n    return [self encodePayload:thePayload withSecret:theSecret algorithm:[JWTAlgorithmFactory algorithmByName:JWTAlgorithmNameHS512]];\n}\n\n+ (NSString *)encodePayload:(NSDictionary *)thePayload withSecret:(NSString *)theSecret algorithm:(id<JWTAlgorithm>)theAlgorithm;\n{\n    return [self encodePayload:thePayload withSecret:theSecret withHeaders:nil algorithm:theAlgorithm];\n}\n\n+ (NSString *)encodePayload:(NSDictionary *)thePayload withSecret:(NSString *)theSecret withHeaders:(NSDictionary *)theHeaders algorithm:(id<JWTAlgorithm>)theAlgorithm;\n{\n    \n    NSError *error = nil;\n    NSString *encodedString = [self encodePayload:thePayload withSecret:theSecret withHeaders:theHeaders algorithm:theAlgorithm withError:&error];\n    \n    if (error) {\n        // do something\n    }\n    \n    return encodedString;\n}\n\n+ (NSString *)encodePayload:(NSDictionary *)thePayload withSecret:(NSString *)theSecret withHeaders:(NSDictionary *)theHeaders algorithm:(id<JWTAlgorithm>)theAlgorithm withError:(NSError * __autoreleasing *)theError;\n{\n    \n    NSDictionary *header = @{@\"typ\": @\"JWT\", @\"alg\": theAlgorithm.name};\n    NSMutableDictionary *allHeaders = [header mutableCopy];\n    \n    if (theHeaders.allKeys.count) {\n        [allHeaders addEntriesFromDictionary:theHeaders];\n    }\n    \n    NSString *headerSegment = [self encodeSegment:[allHeaders copy] withError:theError];\n    \n    if (!headerSegment) {\n        // encode header segment error\n        if (theError) {\n            *theError = [JWTErrorDescription errorWithCode:JWTEncodingHeaderError];\n        }\n        return nil;\n    }\n    \n    NSString *payloadSegment = [self encodeSegment:thePayload withError:theError];\n    \n    if (!payloadSegment) {\n        // encode payment segment error\n        if (theError) {\n            *theError = [JWTErrorDescription errorWithCode:JWTEncodingPayloadError];\n        }\n        return nil;\n    }\n    \n    if (!theAlgorithm) {\n        // error\n        *theError = [JWTErrorDescription errorWithCode:JWTUnsupportedAlgorithmError];\n        return nil;\n    }\n    \n    NSString *signingInput = [@[headerSegment, payloadSegment] componentsJoinedByString:@\".\"];\n    NSData *signedOutputData = [theAlgorithm encodePayload:signingInput withSecret:theSecret];\n    NSString *signedOutput = [JWTBase64Coder base64UrlEncodedStringWithData:signedOutputData];\n    \n    return [@[headerSegment, payloadSegment, signedOutput] componentsJoinedByString:@\".\"];\n}\n\n#pragma mark - Decode\n\n+ (NSDictionary *)decodeMessage:(NSString *)theMessage withSecret:(NSString *)theSecret withTrustedClaimsSet:(JWTClaimsSet *)theTrustedClaimsSet withError:(NSError *__autoreleasing *)theError withForcedAlgorithmByName:(NSString *)theAlgorithmName\n{\n    return [self decodeMessage:theMessage withSecret:theSecret withTrustedClaimsSet:theTrustedClaimsSet withError:theError withForcedAlgorithmByName:theAlgorithmName withForcedOption:NO];\n}\n\n+ (NSDictionary *)decodeMessage:(NSString *)theMessage withSecret:(NSString *)theSecret withTrustedClaimsSet:(JWTClaimsSet *)theTrustedClaimsSet withError:(NSError *__autoreleasing *)theError withForcedOption:(BOOL)theForcedOption\n{\n    return [self decodeMessage:theMessage withSecret:theSecret withTrustedClaimsSet:theTrustedClaimsSet withError:theError withForcedAlgorithmByName:JWTAlgorithmNameHS512 withForcedOption:theForcedOption];\n}\n\n+ (NSDictionary *)decodeMessage:(NSString *)theMessage withSecret:(NSString *)theSecret withTrustedClaimsSet:(JWTClaimsSet *)theTrustedClaimsSet withError:(NSError *__autoreleasing *)theError withForcedAlgorithmByName:(NSString *)theAlgorithmName withForcedOption:(BOOL)theForcedOption\n{\n    return [self decodeMessage:theMessage withSecret:theSecret withTrustedClaimsSet:theTrustedClaimsSet withError:theError withForcedAlgorithmByName:theAlgorithmName withForcedOption:theForcedOption withAlgorithmWhiteList:nil];\n}\n\n+ (NSDictionary *)decodeMessage:(NSString *)theMessage withSecret:(NSString *)theSecret withTrustedClaimsSet:(JWTClaimsSet *)theTrustedClaimsSet withError:(NSError *__autoreleasing *)theError withForcedAlgorithmByName:(NSString *)theAlgorithmName withForcedOption:(BOOL)theForcedOption withAlgorithmWhiteList:(NSSet *)theWhitelist\n{\n    NSDictionary *dictionary = [self decodeMessage:theMessage withSecret:theSecret withError:theError withForcedAlgorithmByName:theAlgorithmName skipVerification:theForcedOption whitelist:theWhitelist];\n    \n    if (*theError) {\n        // do something\n        return dictionary;\n    }\n    \n    if (theTrustedClaimsSet) {\n        BOOL claimVerified = [JWTClaimsSetVerifier verifyClaimsSet:[JWTClaimsSetSerializer claimsSetWithDictionary:dictionary[@\"payload\"]] withTrustedClaimsSet:theTrustedClaimsSet];\n        if (claimVerified) {\n            return dictionary;\n        }\n        else {\n            *theError = [JWTErrorDescription errorWithCode:JWTClaimsSetVerificationFailed];\n            return nil;\n        }\n    }\n    \n    return dictionary;\n}\n\n+ (NSDictionary *)decodeMessage:(NSString *)theMessage withSecret:(NSString *)theSecret withError:(NSError *__autoreleasing *)theError withForcedOption:(BOOL)theForcedOption;\n{\n    return [self decodeMessage:theMessage withSecret:theSecret withError:theError withForcedAlgorithmByName:JWTAlgorithmNameHS512 skipVerification:theForcedOption];\n}\n\n+ (NSDictionary *)decodeMessage:(NSString *)theMessage withSecret:(NSString *)theSecret withError:(NSError *__autoreleasing *)theError withForcedAlgorithmByName:(NSString *)theAlgorithmName;\n{\n    return [self decodeMessage:theMessage withSecret:theSecret withError:theError withForcedAlgorithmByName:theAlgorithmName skipVerification:NO];\n}\n\n+ (NSDictionary *)decodeMessage:(NSString *)theMessage withSecret:(NSString *)theSecret withError:(NSError *__autoreleasing *)theError withForcedAlgorithmByName:(NSString *)theAlgorithmName skipVerification:(BOOL)skipVerification\n{\n    return [self decodeMessage:theMessage withSecret:theSecret withError:theError withForcedAlgorithmByName:theAlgorithmName skipVerification:skipVerification whitelist:nil];\n}\n\n+ (NSDictionary *)decodeMessage:(NSString *)theMessage withSecret:(NSString *)theSecret withError:(NSError *__autoreleasing *)theError withForcedAlgorithmByName:(NSString *)theAlgorithmName skipVerification:(BOOL)skipVerification whitelist:(NSSet *)theWhitelist\n{\n    NSArray *parts = [theMessage componentsSeparatedByString:@\".\"];\n    \n    if (parts.count < 3) {\n        // generate error?\n        if (theError) {\n            *theError = [JWTErrorDescription errorWithCode:JWTInvalidFormatError];\n        }\n        return nil;\n    }\n    \n    NSString *headerPart = parts[0];\n    NSString *payloadPart = parts[1];\n    NSString *signedPart = parts[2];\n    \n    // decode headerPart\n    NSError *jsonError = nil;\n    NSData *headerData = [JWTBase64Coder dataWithBase64UrlEncodedString:headerPart];\n    id headerJSON = [NSJSONSerialization JSONObjectWithData:headerData\n                                                    options:0\n                                                      error:&jsonError];\n    if (jsonError) {\n        *theError = [JWTErrorDescription errorWithCode:JWTDecodingHeaderError];\n        return nil;\n    }\n    NSDictionary *header = (NSDictionary *)headerJSON;\n    if (!header) {\n        *theError = [JWTErrorDescription errorWithCode:JWTNoHeaderError];\n        return nil;\n    }\n    \n    if (!skipVerification) {\n        // find algorithm\n        \n        //It is insecure to trust the header's value for the algorithm, since\n        //the signature hasn't been verified yet, so an algorithm must be provided\n        if (!theAlgorithmName) {\n            *theError = [JWTErrorDescription errorWithCode:JWTUnspecifiedAlgorithmError];\n            return nil;\n        }\n        \n        NSString *headerAlgorithmName = header[@\"alg\"];\n        \n        //If the algorithm in the header doesn't match what's expected, verification fails\n        if (![theAlgorithmName isEqualToString:headerAlgorithmName]) {\n            *theError = [JWTErrorDescription errorWithCode:JWTUnsupportedAlgorithmError];\n            return nil;\n        }\n        \n        //If a whitelist is passed in, ensure the chosen algorithm is allowed\n        if (theWhitelist) {\n            if (![theWhitelist containsObject:theAlgorithmName]) {\n                *theError = [JWTErrorDescription errorWithCode:JWTUnsupportedAlgorithmError];\n                return nil;\n            }\n        }\n        \n        id<JWTAlgorithm> algorithm = [JWTAlgorithmFactory algorithmByName:theAlgorithmName];\n        \n        if (!algorithm) {\n            *theError = [JWTErrorDescription errorWithCode:JWTUnsupportedAlgorithmError];\n            return nil;\n        }\n        \n        // Verify the signed part\n        NSString *signingInput = [@[headerPart, payloadPart] componentsJoinedByString:@\".\"];\n        BOOL signatureValid = [algorithm verifySignedInput:signingInput withSignature:signedPart verificationKey:theSecret];\n        \n        if (!signatureValid) {\n            *theError = [JWTErrorDescription errorWithCode:JWTInvalidSignatureError];\n            return nil;\n        }\n    }\n    \n    // and decode payload\n    jsonError = nil;\n    NSData *payloadData = [JWTBase64Coder dataWithBase64UrlEncodedString:payloadPart];\n    id payloadJSON = [NSJSONSerialization JSONObjectWithData:payloadData\n                                                     options:0\n                                                       error:&jsonError];\n    if (jsonError) {\n        *theError = [JWTErrorDescription errorWithCode:JWTDecodingPayloadError];\n        return nil;\n    }\n    NSDictionary *payload = (NSDictionary *)payloadJSON;\n    \n    if (!payload) {\n        *theError = [JWTErrorDescription errorWithCode:JWTNoPayloadError];\n        return nil;\n    }\n    \n    NSDictionary *result = @{\n                             @\"header\" : header,\n                             @\"payload\" : payload\n                             };\n    \n    return result;\n}\n\n+ (NSDictionary *)decodeMessage:(NSString *)theMessage withSecret:(NSString *)theSecret withError:(NSError * __autoreleasing *)theError;\n{\n    return [self decodeMessage:theMessage withSecret:theSecret withError:theError withForcedAlgorithmByName:JWTAlgorithmNameHS512];\n}\n\n+ (NSDictionary *)decodeMessage:(NSString *)theMessage withSecret:(NSString *)theSecret;\n{\n    NSError *error = nil;\n    NSDictionary *dictionary = [self decodeMessage:theMessage withSecret:theSecret withError:&error];\n    if (error) {\n        // do something\n    }\n    return dictionary;\n}\n\n@end\n"
  },
  {
    "path": "ios/CodePush/JWT/Core/Coding/JWTCoding+VersionThree.h",
    "content": "//\n//  JWTCoding+VersionThree.h\n//  JWT\n//\n//  Created by Lobanov Dmitry on 27.11.16.\n//  Copyright © 2016 JWTIO. All rights reserved.\n//\n\n#import <JWTCoding.h>\n\n// encode and decode options\n@protocol JWTAlgorithm;\n@class JWTClaimsSet;\n@class JWTCodingBuilder;\n@class JWTEncodingBuilder;\n@class JWTDecodingBuilder;\n@class JWTAlgorithmDataHolderChain;\n@protocol JWTAlgorithmDataHolderProtocol;\n@class JWTCodingResultType;\n\n@interface JWT (VersionThree)\n+ (JWTEncodingBuilder *)encodeWithHolders:(NSArray *)holders;\n+ (JWTEncodingBuilder *)encodeWithChain:(JWTAlgorithmDataHolderChain *)chain;\n+ (JWTDecodingBuilder *)decodeWithHolders:(NSArray *)holders;\n+ (JWTDecodingBuilder *)decodeWithChain:(JWTAlgorithmDataHolderChain *)chain;\n@end\n\n@interface JWTCodingBuilder : NSObject\n#pragma mark - Create\n// each element should conform to JWTAlgorithmDataHolderProtocol\n+ (instancetype)createWithHolders:(NSArray *)holders;\n+ (instancetype)createWithChain:(JWTAlgorithmDataHolderChain *)chain;\n+ (instancetype)createWithEmptyChain;\n\n#pragma mark - Internal\n@property (nonatomic, readonly) JWTAlgorithmDataHolderChain *internalChain;\n@property (copy, nonatomic, readonly) NSNumber *internalOptions;\n\n#pragma mark - Fluent\n@property (copy, nonatomic, readonly) JWTCodingBuilder *(^chain)(JWTAlgorithmDataHolderChain *chain);\n@property (copy, nonatomic, readonly) JWTCodingBuilder *(^constructChain)(JWTAlgorithmDataHolderChain *(^block)());\n@property (copy, nonatomic, readonly) JWTCodingBuilder *(^modifyChain)(JWTAlgorithmDataHolderChain *(^block)(JWTAlgorithmDataHolderChain * chain));\n@property (copy, nonatomic, readonly) JWTCodingBuilder *(^options)(NSNumber *options);\n@property (copy, nonatomic, readonly) JWTCodingBuilder *(^addHolder)(id<JWTAlgorithmDataHolderProtocol> holder);\n//@property (copy, nonatomic, readonly) JWTCodingBuilder *(^constructHolder)(id<JWTAlgorithmDataHolderProtocol>(^block)(id<JWTAlgorithmDataHolderProtocol> holder));\n@end\n\n@interface JWTCodingBuilder (Sugar)\n- (instancetype)and;\n- (instancetype)with;\n@end\n\n@interface JWTCodingBuilder (Coding)\n@property (nonatomic, readonly) JWTCodingResultType *result;\n@end\n\n@interface JWTEncodingBuilder : JWTCodingBuilder\n#pragma mark - Create\n+ (instancetype)encodePayload:(NSDictionary *)payload;\n+ (instancetype)encodeClaimsSet:(JWTClaimsSet *)claimsSet;\n\n#pragma mark - Internal\n@property (copy, nonatomic, readonly) NSDictionary *internalPayload;\n@property (copy, nonatomic, readonly) NSDictionary *internalHeaders;\n@property (nonatomic, readonly) JWTClaimsSet *internalClaimsSet;\n\n#pragma mark - Fluent\n@property (copy, nonatomic, readonly) JWTEncodingBuilder *(^payload)(NSDictionary *payload);\n@property (copy, nonatomic, readonly) JWTEncodingBuilder *(^headers)(NSDictionary *headers);\n@property (copy, nonatomic, readonly) JWTEncodingBuilder *(^claimsSet)(JWTClaimsSet *claimsSet);\n\n@end\n\n@interface JWTEncodingBuilder (Coding)\n@property (nonatomic, readonly) JWTCodingResultType *encode;\n@end\n\n@interface JWTDecodingBuilder : JWTCodingBuilder\n#pragma mark - Create\n+ (instancetype)decodeMessage:(NSString *)message;\n\n#pragma mark - Internal\n@property (copy, nonatomic, readonly) NSString *internalMessage;\n@property (nonatomic, readonly) JWTClaimsSet *internalClaimsSet;\n\n#pragma mark - Fluent\n@property (copy, nonatomic, readonly) JWTDecodingBuilder *(^message)(NSString *message);\n@property (copy, nonatomic, readonly) JWTDecodingBuilder *(^claimsSet)(JWTClaimsSet *claimsSet);\n\n@end\n\n@interface JWTDecodingBuilder (Coding)\n@property (nonatomic, readonly) JWTCodingResultType *decode;\n@end\n"
  },
  {
    "path": "ios/CodePush/JWT/Core/Coding/JWTCoding+VersionThree.m",
    "content": "//\n//  JWTCoding+VersionThree.m\n//  JWT\n//\n//  Created by Lobanov Dmitry on 27.11.16.\n//  Copyright © 2016 JWTIO. All rights reserved.\n//\n\n#import \"JWTCoding+VersionThree.h\"\n#import \"JWTAlgorithmDataHolderChain.h\"\n#import \"JWTRSAlgorithm.h\"\n#import \"JWTCoding+ResultTypes.h\"\n#import \"JWTAlgorithmFactory.h\"\n#import \"JWTErrorDescription.h\"\n#import \"JWTBase64Coder.h\"\n#import \"JWTClaimsSetSerializer.h\"\n#import \"JWTClaimsSetVerifier.h\"\n\n@implementation JWT (VersionThree)\n+ (JWTEncodingBuilder *)encodeWithHolders:(NSArray *)holders {\n    return [JWTEncodingBuilder createWithHolders:holders];\n}\n+ (JWTEncodingBuilder *)encodeWithChain:(JWTAlgorithmDataHolderChain *)chain {\n    return [JWTEncodingBuilder createWithChain:chain];\n}\n+ (JWTDecodingBuilder *)decodeWithHolders:(NSArray *)holders {\n    return [JWTDecodingBuilder createWithHolders:holders];\n}\n+ (JWTDecodingBuilder *)decodeWithChain:(JWTAlgorithmDataHolderChain *)chain {\n    return [JWTDecodingBuilder createWithChain:chain];\n}\n@end\n\n@interface JWTCodingBuilder ()\n#pragma mark - Internal\n@property (strong, nonatomic, readwrite) JWTAlgorithmDataHolderChain *internalChain;\n@property (copy, nonatomic, readwrite) NSNumber *internalOptions;\n\n#pragma mark - Fluent\n@property (copy, nonatomic, readwrite) JWTCodingBuilder *(^chain)(JWTAlgorithmDataHolderChain *chain);\n@property (copy, nonatomic, readwrite) JWTCodingBuilder *(^constructChain)(JWTAlgorithmDataHolderChain *(^block)());\n@property (copy, nonatomic, readwrite) JWTCodingBuilder *(^modifyChain)(JWTAlgorithmDataHolderChain *(^block)(JWTAlgorithmDataHolderChain * chain));\n@property (copy, nonatomic, readwrite) JWTCodingBuilder *(^options)(NSNumber *options);\n@property (copy, nonatomic, readwrite) JWTCodingBuilder *(^addHolder)(id<JWTAlgorithmDataHolderProtocol> holder);\n@property (copy, nonatomic, readwrite) JWTCodingBuilder *(^constructHolder)(id<JWTAlgorithmDataHolderProtocol>(^block)(id<JWTAlgorithmDataHolderProtocol> holder));\n\n@end\n@interface JWTCodingBuilder (Fluent_Setup)\n- (instancetype)chain:(JWTAlgorithmDataHolderChain *)chain;\n- (instancetype)options:(NSNumber *)options;\n- (instancetype)addHolder:(id<JWTAlgorithmDataHolderProtocol>)holder;\n- (void)setupFluent;\n@end\n\n@implementation JWTCodingBuilder (Fluent_Setup)\n- (instancetype)chain:(JWTAlgorithmDataHolderChain *)chain {\n    self.internalChain = chain;\n    return self;\n}\n- (instancetype)options:(NSNumber *)options {\n    self.internalOptions = options;\n    return self;\n}\n- (instancetype)addHolder:(id<JWTAlgorithmDataHolderProtocol>)holder {\n    self.internalChain = [self.internalChain chainByAppendingHolder:holder];\n    return self;\n}\n- (void)setupFluent {\n    __weak typeof(self) weakSelf = self;\n    self.chain = ^(JWTAlgorithmDataHolderChain *chain) {\n        return [weakSelf chain:chain];\n    };\n    \n    self.constructChain = ^(JWTAlgorithmDataHolderChain *(^block)()) {\n        if (block) {\n            JWTAlgorithmDataHolderChain *chain = block();\n            return [weakSelf chain:chain];\n        }\n        return weakSelf;\n    };\n    \n    self.modifyChain = ^(JWTAlgorithmDataHolderChain *(^block)(JWTAlgorithmDataHolderChain *chain)) {\n        if (block) {\n            JWTAlgorithmDataHolderChain *chain = block(weakSelf.internalChain);\n            return [weakSelf chain:chain];\n        }\n        return weakSelf;\n    };\n\n\n    self.options = ^(NSNumber *options) {\n        return [weakSelf options:options];\n    };\n    \n    self.addHolder = ^(id<JWTAlgorithmDataHolderProtocol> holder) {\n        return [weakSelf addHolder:holder];\n    };\n    \n    self.constructHolder = ^(id<JWTAlgorithmDataHolderProtocol> (^block)(id<JWTAlgorithmDataHolderProtocol> holder)) {\n        if (block) {\n            [weakSelf addHolder:block([JWTAlgorithmBaseDataHolder new])];\n        }\n        return weakSelf;\n    };\n}\n@end\n\n@implementation JWTCodingBuilder\n#pragma mark - Getters\n// Chain always exists\n- (JWTAlgorithmDataHolderChain *)internalChain {\n    return _internalChain ?: (_internalChain = [JWTAlgorithmDataHolderChain new], _internalChain);\n}\n#pragma mark - Create\n- (instancetype)initWithChain:(JWTAlgorithmDataHolderChain *)chain {\n    if (self = [super init]) {\n        self.internalChain = chain;\n        [self setupFluent];\n    }\n    return self;\n}\n+ (instancetype)createWithHolders:(NSArray *)items {\n    return [self createWithChain:[[JWTAlgorithmDataHolderChain alloc] initWithHolders:items]];\n}\n+ (instancetype)createWithChain:(JWTAlgorithmDataHolderChain *)chain {\n    return [[self alloc] initWithChain:chain];\n}\n+ (instancetype)createWithEmptyChain {\n    return [self createWithChain:nil];\n}\n@end\n\n@implementation JWTCodingBuilder (Sugar)\n- (instancetype)and {\n    return self;\n}\n- (instancetype)with {\n    return self;\n}\n@end\n\n@interface JWTEncodingBuilder ()\n#pragma mark - Internal\n@property (copy, nonatomic, readwrite) NSDictionary *internalPayload;\n@property (copy, nonatomic, readwrite) NSDictionary *internalHeaders;\n@property (strong, nonatomic, readwrite) JWTClaimsSet *internalClaimsSet;\n@property (copy, nonatomic, readwrite) NSDictionary *internalMixingClaimsPayload;\n\n#pragma mark - Fluent\n@property (copy, nonatomic, readwrite) JWTEncodingBuilder *(^payload)(NSDictionary *payload);\n@property (copy, nonatomic, readwrite) JWTEncodingBuilder *(^headers)(NSDictionary *headers);\n@property (copy, nonatomic, readwrite) JWTEncodingBuilder *(^claimsSet)(JWTClaimsSet *claimsSet);\n@end\n\n@interface JWTEncodingBuilder (Fluent_Setup)\n- (instancetype)payload:(NSDictionary *)payload;\n- (instancetype)headers:(NSDictionary *)headers;\n- (instancetype)claimsSet:(JWTClaimsSet *)claimsSet;\n@end\n\n@implementation JWTEncodingBuilder (Fluent_Setup)\n\n- (instancetype)payload:(NSDictionary *)payload {\n    self.internalPayload = payload;\n    return self;\n}\n- (instancetype)headers:(NSDictionary *)headers {\n    self.internalHeaders = headers;\n    return self;\n}\n\n- (instancetype)claimsSet:(JWTClaimsSet *)claimsSet {\n    self.internalClaimsSet = claimsSet;\n    return self;\n}\n\n- (void)setupFluent {\n    [super setupFluent];\n    __weak typeof(self) weakSelf = self;\n    self.payload = ^(NSDictionary *payload) {\n        return [weakSelf payload:payload];\n    };\n    self.headers = ^(NSDictionary *headers) {\n        return [weakSelf headers:headers];\n    };\n    self.claimsSet = ^(JWTClaimsSet *claimsSet) {\n        return [weakSelf claimsSet:claimsSet];\n    };\n}\n\n@end\n\n@implementation JWTEncodingBuilder\n#pragma mark - Getters\n- (NSDictionary *)internalMixingClaimsPayload {\n    NSMutableDictionary *dictionary = [@{} mutableCopy];\n    if (_internalPayload) {\n        [dictionary addEntriesFromDictionary:_internalPayload];\n    }\n    \n    if (_internalClaimsSet) {\n        [dictionary addEntriesFromDictionary:[JWTClaimsSetSerializer dictionaryWithClaimsSet:_internalClaimsSet]];\n    }\n    \n    return dictionary;\n}\n\n#pragma mark - Create\n+ (instancetype)encodePayload:(NSDictionary *)payload {\n    return ((JWTEncodingBuilder *)[self createWithEmptyChain]).payload(payload);\n}\n\n+ (instancetype)encodeClaimsSet:(JWTClaimsSet *)claimsSet {\n    return ((JWTEncodingBuilder *)[self createWithEmptyChain]).claimsSet(claimsSet);\n}\n\n@end\n\n@implementation JWTEncodingBuilder (Coding)\n- (JWTCodingResultType *)encode {\n    \n    NSDictionary *headers = self.internalHeaders;\n    NSDictionary *payload = self.internalMixingClaimsPayload;\n    \n    NSString *encodedMessage = nil;\n    NSError *error = nil;\n    \n    NSArray *holders = self.internalChain.holders;\n    // ERROR: HOLDERS ARE EMPTY.\n    if (holders.count == 0) {\n        error = [JWTErrorDescription errorWithCode:JWTDecodingHoldersChainEmptyError];\n    }\n    \n    for (id <JWTAlgorithmDataHolderProtocol>holder in holders) {\n        id <JWTAlgorithm>algorithm = holder.internalAlgorithm;\n        NSData *secretData = holder.internalSecretData;\n        encodedMessage = [self encodeWithAlgorithm:algorithm withHeaders:headers withPayload:payload withSecretData:secretData withError:&error];\n        if (encodedMessage && (error == nil)) {\n            break;\n        }\n    }\n    \n    JWTCodingResultType *result = nil;\n    \n    if (error) {\n        result = [[JWTCodingResultType alloc] initWithErrorResult:[[JWTCodingResultTypeError alloc] initWithError:error]];\n    }\n    else if (encodedMessage) {\n        result = [[JWTCodingResultType alloc] initWithSuccessResult:[[JWTCodingResultTypeSuccess alloc] initWithEncoded:encodedMessage]];\n    }\n    else {\n        NSLog(@\"%@ something went wrong! result is nil!\", self.debugDescription);\n    }\n    \n    return result;\n}\n- (NSString *)encodeWithAlgorithm:(id<JWTAlgorithm>)theAlgorithm withHeaders:(NSDictionary *)theHeaders withPayload:(NSDictionary *)thePayload withSecretData:(NSData *)theSecretData withError:(NSError *__autoreleasing *)theError {\n    // do it!\n    \n    if (!theAlgorithm) {\n        if (theError) {\n            *theError = [JWTErrorDescription errorWithCode:JWTUnspecifiedAlgorithmError];\n        }\n        return nil;\n    }\n\n    NSString *theAlgorithmName = [theAlgorithm name];\n    \n    if (!theAlgorithmName) {\n        if (theError) {\n            *theError = [JWTErrorDescription errorWithCode:JWTUnsupportedAlgorithmError];\n        }\n        return nil;\n    }\n    \n    NSDictionary *header = @{\n                             @\"alg\": theAlgorithmName,\n                             @\"typ\": @\"JWT\"\n                             };\n    NSMutableDictionary *allHeaders = [header mutableCopy];\n\n    if (theHeaders.allKeys.count > 0) {\n        [allHeaders addEntriesFromDictionary:theHeaders];\n    }\n\n    NSString *headerSegment = [self encodeSegment:[allHeaders copy] withError:nil];\n    \n    if (!headerSegment) {\n        // encode header segment error\n        if (theError) {\n            *theError = [JWTErrorDescription errorWithCode:JWTEncodingHeaderError];\n        }\n        return nil;\n    }\n    \n    NSString *payloadSegment = [self encodeSegment:thePayload withError:nil];\n    \n    if (!payloadSegment) {\n        // encode payment segment error\n        if (theError) {\n            *theError = [JWTErrorDescription errorWithCode:JWTEncodingPayloadError];\n        }\n        return nil;\n    }\n\n    NSString *signingInput = [@[headerSegment, payloadSegment] componentsJoinedByString:@\".\"];\n\n    NSString *signedOutput = nil;\n\n    // this happens somewhere outside.\n\n    NSError *algorithmError = nil;\n    if (theSecretData && [theAlgorithm respondsToSelector:@selector(signHash:key:error:)]) {\n          NSData *signedOutputData = [theAlgorithm signHash:[signingInput dataUsingEncoding:NSUTF8StringEncoding] key:theSecretData error:&algorithmError];\n        signedOutput = [JWTBase64Coder base64UrlEncodedStringWithData:signedOutputData];\n    }\n//    if (theSecretData && [theAlgorithm respondsToSelector:@selector(encodePayloadData:withSecret:)]) {\n//        // not sure that it is correct.\n//        NSData *signedOutputData = [theAlgorithm encodePayloadData:[signingInput dataUsingEncoding:NSUTF8StringEncoding] withSecret:theSecretData];\n//        signedOutput = [JWTBase64Coder base64UrlEncodedStringWithData:signedOutputData];\n//    }\n    // not used now.\n//    else {\n//        NSData *signedOutputData = [theAlgorithm encodePayload:signingInput withSecret:self.jwtSecret];\n//        signedOutput = [JWTBase64Coder base64UrlEncodedStringWithData:signedOutputData];\n//    }\n\n    if (algorithmError) {\n        // algorithmError\n        if (theError) {\n            *theError = algorithmError;\n        }\n        return nil;\n    }\n    if (!signedOutput) {\n        // Make sure signing worked (e.g. we may have issues extracting the key from the PKCS12 bundle if passphrase is incorrect)\n        if (theError) {\n            *theError = [JWTErrorDescription errorWithCode:JWTEncodingSigningError];\n        }\n        return nil;\n    }\n    \n    return [@[headerSegment, payloadSegment, signedOutput] componentsJoinedByString:@\".\"];\n}\n\n- (NSString *)encodeSegment:(id)theSegment withError:(NSError *__autoreleasing*)error {\n    NSData *encodedSegmentData = nil;\n    \n    if (theSegment) {\n        encodedSegmentData = [NSJSONSerialization dataWithJSONObject:theSegment options:0 error:error];\n    }\n    else {\n        // error!\n        NSError *generatedError = [JWTErrorDescription errorWithCode:JWTInvalidSegmentSerializationError];\n        if (error) {\n            *error = generatedError;\n        }\n        NSLog(@\"%@ Could not encode segment: %@\", self.class, generatedError.localizedDescription);\n        return nil;\n    }\n    \n    NSString *encodedSegment = nil;\n    \n    if (encodedSegmentData) {\n        encodedSegment = [JWTBase64Coder base64UrlEncodedStringWithData:encodedSegmentData];\n    }\n    \n    return encodedSegment;\n}\n\n- (JWTCodingResultType *)result {\n    return self.encode;\n}\n@end\n\n@interface JWTDecodingBuilder ()\n#pragma mark - Internal\n@property (copy, nonatomic, readwrite) NSString *internalMessage;\n@property (nonatomic, readwrite) JWTClaimsSet *internalClaimsSet;\n\n#pragma mark - Fluent\n@property (copy, nonatomic, readwrite) JWTDecodingBuilder *(^message)(NSString *message);\n@property (copy, nonatomic, readwrite) JWTDecodingBuilder *(^claimsSet)(JWTClaimsSet *claimsSet);\n\n@end\n\n@interface JWTDecodingBuilder (Fluent_Setup)\n- (instancetype)message:(NSString *)message;\n- (instancetype)claimsSet:(JWTClaimsSet *)claimsSet;\n@end\n@implementation JWTDecodingBuilder (Fluent_Setup)\n- (instancetype)message:(NSString *)message {\n    self.internalMessage = message;\n    return self;\n}\n- (instancetype)claimsSet:(JWTClaimsSet *)claimsSet {\n    self.internalClaimsSet = claimsSet;\n    return self;\n}\n- (void)setupFluent {\n    [super setupFluent];\n    __weak typeof(self) weakSelf = self;\n    self.message = ^(NSString *message) {\n        return [weakSelf message:message];\n    };\n    self.claimsSet = ^(JWTClaimsSet *claimsSet) {\n        return [weakSelf claimsSet:claimsSet];\n    };\n}\n@end\n\n@implementation JWTDecodingBuilder\n#pragma mark - Create\n+ (instancetype)decodeMessage:(NSString *)message {\n    return ((JWTDecodingBuilder *)[self createWithEmptyChain]).message(message);\n}\n@end\n\n@implementation JWTDecodingBuilder (Coding)\n- (JWTCodingResultType *)decode {\n    // do!\n    // iterate over items in chain!\n    // and return if everything ok!\n    // or return error!\n    NSError *error = nil;\n    NSDictionary *decodedDictionary = nil;\n    NSString *message = self.internalMessage;\n    NSNumber *options = self.internalOptions;\n    NSArray *holders = self.internalChain.holders;\n    JWTClaimsSet *claimsSet = self.internalClaimsSet;\n    \n    // ERROR: HOLDERS ARE EMPTY.\n    if (holders.count == 0) {\n        error = [JWTErrorDescription errorWithCode:JWTDecodingHoldersChainEmptyError];\n    }\n    \n    for (id <JWTAlgorithmDataHolderProtocol>holder in self.internalChain.holders) {\n        // try decode!\n        id <JWTAlgorithm> algorithm = holder.internalAlgorithm;\n        NSData *secretData = holder.internalSecretData;\n        // try to retrieve passphrase.\n        decodedDictionary = [self decodeMessage:message secretData:secretData algorithm:algorithm options:options error:&error];\n        if (decodedDictionary && (error == nil)) {\n            break;\n        }\n    }\n    \n    // claimsSet verification.\n    JWTCodingResultType *result = nil;\n    if (error) {\n        return [[JWTCodingResultType alloc] initWithErrorResult:[[JWTCodingResultTypeError alloc] initWithError:error]];\n    }\n    \n    if (claimsSet) {\n        BOOL claimsVerified = [JWTClaimsSetVerifier verifyClaimsSet:[JWTClaimsSetSerializer claimsSetWithDictionary:decodedDictionary[JWTCodingResultPayload]] withTrustedClaimsSet:claimsSet];\n        if (!claimsVerified){\n            error = [JWTErrorDescription errorWithCode:JWTClaimsSetVerificationFailed];\n            return [[JWTCodingResultType alloc] initWithErrorResult:[[JWTCodingResultTypeError alloc] initWithError:error]];\n        }\n    }\n    \n    if (decodedDictionary) {\n        NSDictionary *headers = decodedDictionary[JWTCodingResultHeaders];\n        NSDictionary *payload = decodedDictionary[JWTCodingResultPayload];\n        result = [[JWTCodingResultType alloc] initWithSuccessResult:[[JWTCodingResultTypeSuccess alloc] initWithHeaders:headers withPayload:payload]];\n    }\n    else {\n        NSLog(@\"%@ something went wrong! result is nil!\", self.debugDescription);\n    }\n    \n    return result;\n}\n\n// Maybe later add algorithmName\n- (NSDictionary *)decodeMessage:(NSString *)theMessage secretData:(NSData *)theSecretData algorithm:(id<JWTAlgorithm>)theAlgorithm options:(NSNumber *)theOptions error:(NSError *__autoreleasing *)theError {\n    \n    BOOL skipVerification = [theOptions boolValue];\n    NSString *theAlgorithmName = [theAlgorithm name];\n    \n    NSArray *parts = [theMessage componentsSeparatedByString:@\".\"];\n    \n    if (parts.count < 3) {\n        // generate error?\n        if (theError) {\n            *theError = [JWTErrorDescription errorWithCode:JWTInvalidFormatError];\n        }\n        return nil;\n    }\n    \n    NSString *headerPart = parts[0];\n    NSString *payloadPart = parts[1];\n    NSString *signedPart = parts[2];\n    \n    // decode headerPart\n    NSError *jsonError = nil;\n    NSData *headerData = [JWTBase64Coder dataWithBase64UrlEncodedString:headerPart];\n    id headerJSON = [NSJSONSerialization JSONObjectWithData:headerData\n                                                    options:0\n                                                      error:&jsonError];\n    if (jsonError) {\n        if (theError) {\n            *theError = [JWTErrorDescription errorWithCode:JWTDecodingHeaderError];\n        }\n        return nil;\n    }\n    NSDictionary *header = (NSDictionary *)headerJSON;\n    if (!header) {\n        if (theError) {\n            *theError = [JWTErrorDescription errorWithCode:JWTNoHeaderError];\n        }\n        return nil;\n    }\n    \n    if (!skipVerification) {\n        // find algorithm\n        \n        //It is insecure to trust the header's value for the algorithm, since\n        //the signature hasn't been verified yet, so an algorithm must be provided\n        if (!theAlgorithmName) {\n            if (theError) {\n                *theError = [JWTErrorDescription errorWithCode:JWTUnspecifiedAlgorithmError];\n            }\n            return nil;\n        }\n        \n        NSString *headerAlgorithmName = header[@\"alg\"];\n        \n        //If the algorithm in the header doesn't match what's expected, verification fails\n        if (![theAlgorithmName isEqualToString:headerAlgorithmName]) {\n            if (theError) {\n                *theError = [JWTErrorDescription errorWithCode:JWTAlgorithmNameMismatchError];\n            }\n            return nil;\n        }\n        \n        // A shit logic, but...\n        // You should copy algorithm if this algorithm conforms to RSAlgorithm (NSCopying).\n        // Now RS Algorithm holds too much. ( All data about keys :/ )\n        // Need further investigation.\n        id<JWTAlgorithm> algorithm = nil;\n        if ([theAlgorithm conformsToProtocol:@protocol(JWTRSAlgorithm)]) {\n            algorithm = [(id<JWTRSAlgorithm>)theAlgorithm copyWithZone:nil];\n        }\n        else {\n            algorithm = [JWTAlgorithmFactory algorithmByName:theAlgorithmName];\n        }\n        \n        if (!algorithm) {\n            if (theError) {\n                *theError = [JWTErrorDescription errorWithCode:JWTUnsupportedAlgorithmError];\n            }\n            return nil;\n        }\n        \n        // Verify the signed part\n        NSString *signingInput = [@[headerPart, payloadPart] componentsJoinedByString:@\".\"];\n        BOOL signatureValid = NO;\n\n        NSError *algorithmError = nil;\n        if (theSecretData && [algorithm respondsToSelector:@selector(verifyHash:signature:key:error:)]) {\n            signatureValid =\n            //[algorithm verifySignedInput:signingInput withSignature:signedPart verificationKeyData:theSecretData];\n            [algorithm verifyHash:[signingInput dataUsingEncoding:NSUTF8StringEncoding] signature:[JWTBase64Coder dataWithBase64UrlEncodedString:signedPart] key:theSecretData error:&algorithmError];\n        }\n//        if (theSecretData && [algorithm respondsToSelector:@selector(verifySignedInput:withSignature:verificationKeyData:)]) {\n//            signatureValid = [algorithm verifySignedInput:signingInput withSignature:signedPart verificationKeyData:theSecretData];\n//\n//            // Not used now.\n////        } else {\n////            signatureValid = [algorithm verifySignedInput:signingInput withSignature:signedPart verificationKey:theSecret];\n//        }\n        \n        if (algorithmError) {\n            if (theError) {\n                *theError = algorithmError;\n            }\n            return nil;\n        }\n        if (!signatureValid) {\n            if (theError) {\n                *theError = [JWTErrorDescription errorWithCode:JWTInvalidSignatureError];\n            }\n            return nil;\n        }\n    }\n    \n    // and decode payload\n    jsonError = nil;\n    NSData *payloadData = [JWTBase64Coder dataWithBase64UrlEncodedString:payloadPart];\n    id payloadJSON = [NSJSONSerialization JSONObjectWithData:payloadData\n                                                     options:0\n                                                       error:&jsonError];\n    if (jsonError) {\n        if (theError) {\n            *theError = [JWTErrorDescription errorWithCode:JWTDecodingPayloadError];\n        }\n        return nil;\n    }\n    NSDictionary *payload = (NSDictionary *)payloadJSON;\n    \n    if (!payload) {\n        if (theError) {\n            *theError = [JWTErrorDescription errorWithCode:JWTNoPayloadError];\n        }\n        return nil;\n    }\n    \n    NSDictionary *result = @{\n                             JWTCodingResultHeaders : header,\n                             JWTCodingResultPayload : payload\n                             };\n    \n    return result;\n}\n\n- (JWTCodingResultType *)result {\n    return self.decode;\n}\n@end\n"
  },
  {
    "path": "ios/CodePush/JWT/Core/Coding/JWTCoding+VersionTwo.h",
    "content": "//\n//  JWTCoding+VersionTwo.h\n//  JWT\n//\n//  Created by Lobanov Dmitry on 27.11.16.\n//  Copyright © 2016 JWTIO. All rights reserved.\n//\n\n#import <JWTCoding.h>\n\n@protocol JWTAlgorithm;\n@class JWTClaimsSet;\n@class JWTBuilder;\n\n@interface JWT (VersionTwo)\n#pragma mark - Builder\n+ (JWTBuilder *)encodePayload:(NSDictionary *)payload;\n+ (JWTBuilder *)encodeClaimsSet:(JWTClaimsSet *)claimsSet;\n+ (JWTBuilder *)decodeMessage:(NSString *)message;\n@end\n\n@interface JWTBuilder : NSObject\n\n+ (JWTBuilder *)encodePayload:(NSDictionary *)payload;\n+ (JWTBuilder *)encodeClaimsSet:(JWTClaimsSet *)claimsSet;\n+ (JWTBuilder *)decodeMessage:(NSString *)message;\n\n/**\n The JWT in it's encoded form. Will be decoded and verified\n */\n@property (copy, nonatomic, readonly) NSString *jwtMessage;\n\n/**\n The payload dictionary to encode\n */\n@property (copy, nonatomic, readonly) NSDictionary *jwtPayload;\n\n/**\n The header dictionary to encode\n */\n@property (copy, nonatomic, readonly) NSDictionary *jwtHeaders;\n\n/**\n The expected JWTClaimsSet to compare against a decoded JWT\n */\n@property (copy, nonatomic, readonly) JWTClaimsSet *jwtClaimsSet;\n\n/**\n The algorithm data holders. They contain necessary information about algorithms.\n */\n@property (copy, nonatomic, readonly) NSArray *jwtDataHolders;\n\n/**\n The verification key to use when encoding/decoding a JWT\n */\n@property (copy, nonatomic, readonly) NSString *jwtSecret;\n\n/**\n The verification key to use when encoding/decoding a JWT in data form\n */\n@property (copy, nonatomic, readonly) NSData *jwtSecretData;\n\n/**\n The passphrase for the PKCS12 blob, which represents the certificate containing the private key for the RS algorithms.\n */\n@property (copy, nonatomic, readonly) NSString *jwtPrivateKeyCertificatePassphrase;\n\n/**\n Contains the error that occured during an operation, or nil if no error occured\n */\n@property (copy, nonatomic, readonly) NSError *jwtError;\n\n/**\n The <JWTAlgorithm> to use for encoding a JWT\n */\n@property (strong, nonatomic, readonly) id<JWTAlgorithm> jwtAlgorithm;\n\n/**\n The algorithm name to use for decoding the JWT. Required unless force decode is true\n */\n@property (copy, nonatomic, readonly) NSString *jwtAlgorithmName;\n\n/**\n The force decode option. If set to true, a JWT won't be validated before decoding.\n Should only be used for debugging\n */\n@property (copy, nonatomic, readonly) NSNumber *jwtOptions;\n\n/*\n Optional algorithm name whitelist. If non-null, a JWT can only be decoded using an algorithm\n specified on this list.\n */\n@property (copy, nonatomic, readonly) NSSet *algorithmWhitelist;\n\n/**\n Sets jwtMessage and returns the JWTBuilder to allow for method chaining\n */\n@property (copy, nonatomic, readonly) JWTBuilder *(^message)(NSString *message);\n\n/**\n Sets jwtPayload and returns the JWTBuilder to allow for method chaining\n */\n@property (copy, nonatomic, readonly) JWTBuilder *(^payload)(NSDictionary *payload);\n\n/**\n Sets jwtHeaders and returns the JWTBuilder to allow for method chaining\n */\n@property (copy, nonatomic, readonly) JWTBuilder *(^headers)(NSDictionary *headers);\n\n/**\n Sets jwtClaimsSet and returns the JWTBuilder to allow for method chaining\n */\n@property (copy, nonatomic, readonly) JWTBuilder *(^claimsSet)(JWTClaimsSet *claimsSet);\n\n/**\n Sets jwtSecret and returns the JWTBuilder to allow for method chaining\n */\n@property (copy, nonatomic, readonly) JWTBuilder *(^secret)(NSString *secret);\n\n/**\n Sets jwtSecretData and returns the JWTBuilder to allow for method chaining\n */\n@property (copy, nonatomic, readonly) JWTBuilder *(^secretData)(NSData *secretData);\n\n/**\n Sets jwtPrivateKeyCertificatePassphrase and returns the JWTBuilder to allow for method chaining\n */\n@property (copy, nonatomic, readonly) JWTBuilder *(^privateKeyCertificatePassphrase)(NSString *privateKeyCertificatePassphrase);\n\n/**\n Sets jwtAlgorithm and returns the JWTBuilder to allow for method chaining\n */\n@property (copy, nonatomic, readonly) JWTBuilder *(^algorithm)(id<JWTAlgorithm>algorithm);\n\n/**\n Sets jwtAlgorithmName and returns the JWTBuilder to allow for method chaining. See list of names in appropriate headers.\n */\n@property (copy, nonatomic, readonly) JWTBuilder *(^algorithmName)(NSString *algorithmName);\n\n/**\n Sets jwtOptions and returns the JWTBuilder to allow for method chaining\n */\n@property (copy, nonatomic, readonly) JWTBuilder *(^options)(NSNumber *options);\n\n/**\n Sets algorithmWhitelist and returns the JWTBuilder to allow for method chaining\n */\n@property (copy, nonatomic, readonly) JWTBuilder *(^whitelist)(NSArray *whitelist);\n\n/**\n Creates the encoded JWT string based on the currently set properties, or nil if an\n error occured\n */\n@property (copy, nonatomic, readonly) NSString *encode;\n\n/**\n Decodes and returns the JWT as a dictionary, based on the JWTBuilder's currently set\n properties, or nil, if an error occured.\n */\n@property (copy, nonatomic, readonly) NSDictionary *decode;\n\n//@property (copy, nonatomic, readonly) JWTBuilder * (^addDataHolder)(JWTAlgorithmBaseDataHolder *dataHolder) __available_in_release_version(JWTVersion_3_0_0);\n//@property (copy, nonatomic, readonly) JWTBuilder * (^constructDataHolder)(id<JWTAlgorithmDataHolderProtocol> (^block)()) __available_in_release_version(JWTVersion_3_0_0);\n@end\n"
  },
  {
    "path": "ios/CodePush/JWT/Core/Coding/JWTCoding+VersionTwo.m",
    "content": "//\n//  JWTCoding+VersionTwo.m\n//  JWT\n//\n//  Created by Lobanov Dmitry on 27.11.16.\n//  Copyright © 2016 JWTIO. All rights reserved.\n//\n\n#import \"JWTCoding+VersionTwo.h\"\n#import \"JWTBase64Coder.h\"\n\n#import \"JWTRSAlgorithm.h\"\n\n#import \"JWTAlgorithmFactory.h\"\n\n#import \"JWTAlgorithmDataHolder.h\"\n\n#import \"JWTClaimsSetSerializer.h\"\n#import \"JWTClaimsSetVerifier.h\"\n\n#import \"JWTErrorDescription.h\"\n\n@implementation JWT (VersionTwo)\n#pragma mark - Builder\n\n+ (JWTBuilder *)encodePayload:(NSDictionary *)payload {\n    return [JWTBuilder encodePayload:payload];\n}\n\n+ (JWTBuilder *)encodeClaimsSet:(JWTClaimsSet *)claimsSet {\n    return [JWTBuilder encodeClaimsSet:claimsSet];\n}\n\n+ (JWTBuilder *)decodeMessage:(NSString *)message {\n    return [JWTBuilder decodeMessage:message];\n}\n@end\n\n@interface JWTBuilder()\n\n@property (copy, nonatomic, readwrite) NSString *jwtMessage;\n@property (copy, nonatomic, readwrite) NSDictionary *jwtPayload;\n@property (copy, nonatomic, readwrite) NSDictionary *jwtHeaders;\n@property (copy, nonatomic, readwrite) JWTClaimsSet *jwtClaimsSet;\n@property (copy, nonatomic, readwrite) NSArray *jwtDataHolders;\n\n@property (copy, nonatomic, readwrite) NSString *jwtSecret;\n@property (copy, nonatomic, readwrite) NSData *jwtSecretData;\n@property (copy, nonatomic, readwrite) NSString *jwtPrivateKeyCertificatePassphrase;\n@property (copy, nonatomic, readwrite) NSError *jwtError;\n@property (strong, nonatomic, readwrite) id<JWTAlgorithm> jwtAlgorithm;\n@property (copy, nonatomic, readwrite) NSString *jwtAlgorithmName;\n@property (copy, nonatomic, readwrite) NSNumber *jwtOptions;\n@property (copy, nonatomic, readwrite) NSSet *algorithmWhitelist;\n\n@property (copy, nonatomic, readwrite) JWTBuilder *(^message)(NSString *message);\n@property (copy, nonatomic, readwrite) JWTBuilder *(^payload)(NSDictionary *payload);\n@property (copy, nonatomic, readwrite) JWTBuilder *(^headers)(NSDictionary *headers);\n@property (copy, nonatomic, readwrite) JWTBuilder *(^claimsSet)(JWTClaimsSet *claimsSet);\n@property (copy, nonatomic, readwrite) JWTBuilder *(^secret)(NSString *secret);\n@property (copy, nonatomic, readwrite) JWTBuilder *(^secretData)(NSData *secretData);\n@property (copy, nonatomic, readwrite) JWTBuilder *(^privateKeyCertificatePassphrase)(NSString *privateKeyCertificatePassphrase);\n@property (copy, nonatomic, readwrite) JWTBuilder *(^algorithm)(id<JWTAlgorithm>algorithm);\n@property (copy, nonatomic, readwrite) JWTBuilder *(^algorithmName)(NSString *algorithmName);\n@property (copy, nonatomic, readwrite) JWTBuilder *(^options)(NSNumber *options);\n@property (copy, nonatomic, readwrite) JWTBuilder *(^whitelist)(NSArray *whitelist);\n@property (copy, nonatomic, readwrite) JWTBuilder * (^addDataHolder)(JWTAlgorithmBaseDataHolder *dataHolder);\n@property (copy, nonatomic, readwrite) JWTBuilder * (^constructDataHolder)(id<JWTAlgorithmDataHolderProtocol> (^block)());\n@end\n\n@implementation JWTBuilder\n\n#pragma mark - Getters\n- (id<JWTAlgorithm>)jwtAlgorithm {\n    if (!_jwtAlgorithm) {\n        _jwtAlgorithm = [JWTAlgorithmFactory algorithmByName:_jwtAlgorithmName];\n    }\n    return _jwtAlgorithm;\n}\n\n- (NSDictionary *)jwtPayload {\n    return _jwtClaimsSet ? [JWTClaimsSetSerializer dictionaryWithClaimsSet:_jwtClaimsSet] : _jwtPayload;\n}\n\n#pragma mark - Fluent\n- (instancetype)message:(NSString *)message {\n    self.jwtMessage = message;\n    return self;\n}\n\n- (instancetype)payload:(NSDictionary *)payload {\n    self.jwtPayload = payload;\n    return self;\n}\n\n- (instancetype)headers:(NSDictionary *)headers {\n    self.jwtHeaders = headers;\n    return self;\n}\n\n- (instancetype)claimSet:(JWTClaimsSet *)claimSet {\n    self.jwtClaimsSet = claimSet;\n    return self;\n}\n\n- (instancetype)secret:(NSString *)secret {\n    self.jwtSecret = secret;\n    return self;\n}\n\n- (instancetype)secretData:(NSData *)secretData {\n    self.jwtSecretData = secretData;\n    return self;\n}\n\n- (instancetype)privateKeyCertificatePassphrase:(NSString *)privateKeyCertificatePassphrase {\n    self.jwtPrivateKeyCertificatePassphrase = privateKeyCertificatePassphrase;\n    return self;\n}\n\n- (instancetype)algorithm:(id<JWTAlgorithm>)algorithm {\n    self.jwtAlgorithm = algorithm;\n    return self;\n}\n\n- (instancetype)algorithmName:(NSString *)algorithmName {\n    self.jwtAlgorithmName = algorithmName;\n    return self;\n}\n\n- (instancetype)options:(NSNumber *)options {\n    self.jwtOptions = options;\n    return self;\n}\n\n- (instancetype)whitelist:(NSArray *)whitelist {\n    if (whitelist) {\n        self.algorithmWhitelist = [NSSet setWithArray:whitelist];\n    } else {\n        self.algorithmWhitelist = nil;\n    }\n    return self;\n}\n\n- (instancetype)addDataHolder:(JWTAlgorithmBaseDataHolder *)dataHolder {\n    if (dataHolder) {\n        \n    }\n    return self;\n}\n\n#pragma mark - Initialization\n+ (JWTBuilder *)encodePayload:(NSDictionary *)payload {\n    return [[JWTBuilder alloc] init].payload(payload);\n}\n\n+ (JWTBuilder *)encodeClaimsSet:(JWTClaimsSet *)claimsSet {\n    return [[JWTBuilder alloc] init].claimsSet(claimsSet);\n}\n\n+ (JWTBuilder *)decodeMessage:(NSString *)message {\n    return [[JWTBuilder alloc] init].message(message);\n}\n\n- (instancetype)init {\n    self = [super init];\n    if (self) {\n        __weak typeof(self) weakSelf = self;\n        self.message = ^(NSString *message) {\n            return [weakSelf message:message];\n        };\n        \n        self.payload = ^(NSDictionary *payload) {\n            return [weakSelf payload:payload];\n        };\n        \n        self.headers = ^(NSDictionary *headers) {\n            return [weakSelf headers:headers];\n        };\n        \n        self.claimsSet = ^(JWTClaimsSet *claimSet) {\n            return [weakSelf claimSet:claimSet];\n        };\n        \n        self.secret = ^(NSString *secret) {\n            return [weakSelf secret:secret];\n        };\n        \n        self.secretData = ^(NSData *secretData) {\n            return [weakSelf secretData:secretData];\n        };\n        \n        self.privateKeyCertificatePassphrase = ^(NSString *privateKeyCertificatePassphrase) {\n            return [weakSelf privateKeyCertificatePassphrase:privateKeyCertificatePassphrase];\n        };\n        \n        self.algorithm = ^(id<JWTAlgorithm> algorithm) {\n            return [weakSelf algorithm:algorithm];\n        };\n        \n        self.algorithmName = ^(NSString *algorithmName) {\n            return [weakSelf algorithmName:algorithmName];\n        };\n        \n        self.options = ^(NSNumber *options) {\n            return [weakSelf options:options];\n        };\n        \n        self.whitelist = ^(NSArray *whitelist) {\n            return [weakSelf whitelist:whitelist];\n        };\n        \n        self.addDataHolder = ^(JWTAlgorithmBaseDataHolder *holder) {\n            return [weakSelf addDataHolder:holder];\n        };\n        \n        self.constructDataHolder = ^(id<JWTAlgorithmDataHolderProtocol> (^block)()) {\n            if (block) {\n                return [weakSelf addDataHolder:block()];\n            }\n            return weakSelf;\n        };\n    }\n    \n    return self;\n}\n\n#pragma mark - Encoding/Decoding\n\n- (NSString *)encode {\n    NSString *result = nil;\n    self.jwtError = nil;\n    result = [self encodeHelper];\n    return result;\n}\n\n- (NSDictionary *)decode {\n    NSDictionary *result = nil;\n    self.jwtError = nil;\n    result = [self decodeHelper];\n    \n    return result;\n}\n\n#pragma mark - Private\n\n#pragma mark - Encode Helpers\n\n- (NSString *)encodeHelper\n{\n    if (!self.jwtAlgorithm) {\n        self.jwtError = [JWTErrorDescription errorWithCode:JWTUnspecifiedAlgorithmError];\n        return nil;\n    }\n    \n    NSDictionary *header = @{@\"typ\": @\"JWT\", @\"alg\": self.jwtAlgorithm.name};\n    NSMutableDictionary *allHeaders = [header mutableCopy];\n    \n    if (self.jwtHeaders.allKeys.count > 0) {\n        [allHeaders addEntriesFromDictionary:self.jwtHeaders];\n    }\n    \n    NSString *headerSegment = [self encodeSegment:[allHeaders copy] withError:nil];\n    \n    if (!headerSegment) {\n        // encode header segment error\n        self.jwtError = [JWTErrorDescription errorWithCode:JWTEncodingHeaderError];\n        return nil;\n    }\n    \n    NSString *payloadSegment = [self encodeSegment:self.jwtPayload withError:nil];\n    \n    if (!payloadSegment) {\n        // encode payment segment error\n        self.jwtError = [JWTErrorDescription errorWithCode:JWTEncodingPayloadError];\n        return nil;\n    }\n    \n    NSString *signingInput = [@[headerSegment, payloadSegment] componentsJoinedByString:@\".\"];\n    \n    NSString *signedOutput;\n    \n    if ([self.jwtAlgorithm conformsToProtocol:@protocol(JWTRSAlgorithm)]) {\n        id<JWTRSAlgorithm> jwtRsAlgorithm = (id <JWTRSAlgorithm>) self.jwtAlgorithm;\n        jwtRsAlgorithm.privateKeyCertificatePassphrase = self.jwtPrivateKeyCertificatePassphrase;\n    }\n    if (self.jwtSecretData && [self.jwtAlgorithm respondsToSelector:@selector(encodePayloadData:withSecret:)]) {\n        NSData *signedOutputData = [self.jwtAlgorithm encodePayloadData:[signingInput dataUsingEncoding:NSUTF8StringEncoding] withSecret:self.jwtSecretData];\n        \n        signedOutput = [JWTBase64Coder base64UrlEncodedStringWithData:signedOutputData];\n    } else {\n        NSData *signedOutputData = [self.jwtAlgorithm encodePayload:signingInput withSecret:self.jwtSecret];\n        signedOutput = [JWTBase64Coder base64UrlEncodedStringWithData:signedOutputData];\n    }\n    \n    if (signedOutput) { // Make sure signing worked (e.g. we may have issues extracting the key from the PKCS12 bundle if passphrase is incorrect)\n        return [@[headerSegment, payloadSegment, signedOutput] componentsJoinedByString:@\".\"];\n    } else {\n        self.jwtError = [JWTErrorDescription errorWithCode:JWTEncodingSigningError];\n        return nil;\n    }\n}\n\n- (NSString *)encodeSegment:(id)theSegment withError:(NSError **)error\n{\n    NSData *encodedSegmentData = nil;\n    \n    if (theSegment) {\n        encodedSegmentData = [NSJSONSerialization dataWithJSONObject:theSegment options:0 error:error];\n    }\n    else {\n        // error!\n        NSError *generatedError = [JWTErrorDescription errorWithCode:JWTInvalidSegmentSerializationError];\n        if (error) {\n            *error = generatedError;\n        }\n        NSLog(@\"%@ Could not encode segment: %@\", self.class, generatedError.localizedDescription);\n        return nil;\n    }\n    \n    NSString *encodedSegment = nil;\n    \n    if (encodedSegmentData) {\n        encodedSegment = [JWTBase64Coder base64UrlEncodedStringWithData:encodedSegmentData];\n    }\n    \n    return encodedSegment;\n}\n\n#pragma mark - Decode Helpers\n\n- (NSDictionary *)decodeHelper\n{\n    NSError *error = nil;\n    NSDictionary *dictionary = [self decodeMessage:self.jwtMessage withSecret:self.jwtSecret withSecretData:self.jwtSecretData withError:&error withForcedAlgorithmByName:self.jwtAlgorithmName skipVerification:[self.jwtOptions boolValue] whitelist:self.algorithmWhitelist];\n    \n    if (error) {\n        self.jwtError = error;\n        return nil;\n    }\n    \n    if (self.jwtClaimsSet) {\n        BOOL claimVerified = [JWTClaimsSetVerifier verifyClaimsSet:[JWTClaimsSetSerializer claimsSetWithDictionary:dictionary[@\"payload\"]] withTrustedClaimsSet:self.jwtClaimsSet];\n        if (claimVerified) {\n            return dictionary;\n        }\n        else {\n            self.jwtError = [JWTErrorDescription errorWithCode:JWTClaimsSetVerificationFailed];\n            return nil;\n        }\n    }\n    \n    return dictionary;\n}\n\n- (NSDictionary *)decodeMessage:(NSString *)theMessage withSecret:(NSString *)theSecret withSecretData:(NSData *)secretData withError:(NSError *__autoreleasing *)theError withForcedAlgorithmByName:(NSString *)theAlgorithmName skipVerification:(BOOL)skipVerification {\n    NSArray *parts = [theMessage componentsSeparatedByString:@\".\"];\n    \n    if (parts.count < 3) {\n        // generate error?\n        if (theError) {\n            *theError = [JWTErrorDescription errorWithCode:JWTInvalidFormatError];\n        }\n        return nil;\n    }\n    \n    NSString *headerPart = parts[0];\n    NSString *payloadPart = parts[1];\n    NSString *signedPart = parts[2];\n    \n    // decode headerPart\n    NSError *jsonError = nil;\n    NSData *headerData = [JWTBase64Coder dataWithBase64UrlEncodedString:headerPart];\n    id headerJSON = [NSJSONSerialization JSONObjectWithData:headerData\n                                                    options:0\n                                                      error:&jsonError];\n    if (jsonError) {\n        *theError = [JWTErrorDescription errorWithCode:JWTDecodingHeaderError];\n        return nil;\n    }\n    NSDictionary *header = (NSDictionary *)headerJSON;\n    if (!header) {\n        *theError = [JWTErrorDescription errorWithCode:JWTNoHeaderError];\n        return nil;\n    }\n    \n    if (!skipVerification) {\n        // find algorithm\n        \n        //It is insecure to trust the header's value for the algorithm, since\n        //the signature hasn't been verified yet, so an algorithm must be provided\n        if (!theAlgorithmName) {\n            *theError = [JWTErrorDescription errorWithCode:JWTUnspecifiedAlgorithmError];\n            return nil;\n        }\n        \n        NSString *headerAlgorithmName = header[@\"alg\"];\n        \n        //If the algorithm in the header doesn't match what's expected, verification fails\n        if (![theAlgorithmName isEqualToString:headerAlgorithmName]) {\n            *theError = [JWTErrorDescription errorWithCode:JWTAlgorithmNameMismatchError];\n            return nil;\n        }\n        \n        id<JWTAlgorithm> algorithm = [JWTAlgorithmFactory algorithmByName:theAlgorithmName];\n        \n        if (!algorithm) {\n            *theError = [JWTErrorDescription errorWithCode:JWTUnsupportedAlgorithmError];\n            return nil;\n            //    NSAssert(!algorithm, @\"Can't decode segment!, %@\", header);\n        }\n        \n        // Verify the signed part\n        NSString *signingInput = [@[headerPart, payloadPart] componentsJoinedByString:@\".\"];\n        BOOL signatureValid = NO;\n        \n        \n        if (secretData && [algorithm respondsToSelector:@selector(verifySignedInput:withSignature:verificationKeyData:)]) {\n            signatureValid = [algorithm verifySignedInput:signingInput withSignature:signedPart verificationKeyData:secretData];\n        } else {\n            signatureValid = [algorithm verifySignedInput:signingInput withSignature:signedPart verificationKey:theSecret];\n        }\n        \n        if (!signatureValid) {\n            *theError = [JWTErrorDescription errorWithCode:JWTInvalidSignatureError];\n            return nil;\n        }\n    }\n    \n    // and decode payload\n    jsonError = nil;\n    NSData *payloadData = [JWTBase64Coder dataWithBase64UrlEncodedString:payloadPart];\n    id payloadJSON = [NSJSONSerialization JSONObjectWithData:payloadData\n                                                     options:0\n                                                       error:&jsonError];\n    if (jsonError) {\n        *theError = [JWTErrorDescription errorWithCode:JWTDecodingPayloadError];\n        return nil;\n    }\n    NSDictionary *payload = (NSDictionary *)payloadJSON;\n    \n    if (!payload) {\n        *theError = [JWTErrorDescription errorWithCode:JWTNoPayloadError];\n        return nil;\n    }\n    \n    NSDictionary *result = @{\n                             @\"header\" : header,\n                             @\"payload\" : payload\n                             };\n    \n    return result;\n}\n\n- (NSDictionary *)decodeMessage:(NSString *)theMessage withSecret:(NSString *)theSecret withSecretData:(NSData *)secretData withError:(NSError *__autoreleasing *)theError withForcedAlgorithmByName:(NSString *)theAlgorithmName skipVerification:(BOOL)skipVerification whitelist:(NSSet *)theWhitelist\n{\n    /*\n     many cases:\n     1. whitelist 1, algorithm 1, match 1\n     everything fine, match exists. just decode by algorithm name.\n     2. whitelist 1, algorithm 0 // match not needed.\n     use every algorithm and try to decode.\n     3. whitelist 1, algorithm 1, match 0\n     throw black list error.\n     4. whitelist 0\n     normal decode by algorithm.\n     */\n    if (theWhitelist) {\n        if (!theAlgorithmName) {\n            // name -> decoding\n            NSMutableArray *tries = [@[] mutableCopy];\n            NSMutableDictionary *result = nil;\n            for (NSString *name in theWhitelist) {\n                // special case for none algorithm.\n                // none algorithm uses\n                // maybe remove later?\n                NSDictionary *try = nil;\n                if ([name isEqualToString:@\"none\"]) {\n                    try = [self decodeMessage:theMessage withSecret:nil withSecretData:nil withError:theError withForcedAlgorithmByName:name skipVerification:skipVerification];\n                }\n                else {\n                    try = [self decodeMessage:theMessage withSecret:theSecret withSecretData:secretData withError:theError withForcedAlgorithmByName:name skipVerification:skipVerification];\n                }\n                if (try) {\n                    result = [try mutableCopy];\n                    result[@\"tries\"] = [tries copy];\n                    if (theError) {\n                        *theError = nil;\n                    }\n                    break;\n                }\n                else {\n                    if (theError && *theError) {\n                        [tries addObject:*theError];\n                    }\n                }\n            }\n            return [result copy];\n        }\n        else {\n            //If a whitelist is passed in, ensure the chosen algorithm is allowed\n            if (![theWhitelist containsObject:theAlgorithmName]) {\n                if (theError) {\n                    *theError = [JWTErrorDescription errorWithCode:JWTBlacklistedAlgorithmError];\n                }\n                return nil;\n            }\n        }\n    }\n    \n    return [self decodeMessage:theMessage withSecret:theSecret withSecretData:secretData withError:theError withForcedAlgorithmByName:theAlgorithmName skipVerification:skipVerification];\n}\n\n@end\n"
  },
  {
    "path": "ios/CodePush/JWT/Core/Coding/JWTCoding.h",
    "content": "//\n//  JWT.h\n//  JWT\n//\n//  Created by Klaas Pieter Annema on 31-05-13.\n//  Copyright (c) 2013 Karma. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n/**\n @discussion JWT is a general interface for decoding and encoding.\n Now it is to complex and fat to support.\n Possible solution: split interface into several pieces.\n \n JWT_1_0 -> JWT with plain old functions.\n JWT_2_0 -> JWT with builder usage.\n JWT_3_0 -> JWT with splitted apart algorithm data and payload data.\n */\n@interface JWT : NSObject @end\n\ntypedef NS_OPTIONS(NSInteger, JWTCodingDecodingOptions) {\n    JWTCodingDecodingOptionsNone = 0,\n    JWTCodingDecodingOptionsSkipVerification = 1\n};\n"
  },
  {
    "path": "ios/CodePush/JWT/Core/Coding/JWTCoding.m",
    "content": "//\n//  JWT.m\n//  JWT\n//\n//  Created by Klaas Pieter Annema on 31-05-13.\n//  Copyright (c) 2013 Karma. All rights reserved.\n//\n\n#import \"JWTCoding.h\"\n\n@implementation JWT @end\n"
  },
  {
    "path": "ios/CodePush/JWT/Core/FrameworkSupplement/JWT.h",
    "content": "//\n//  JWT.h\n//  JWT\n//\n//  Created by Lobanov Dmitry on 23.10.16.\n//  Copyright © 2016 Karma. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n\n//! Project version number for JWT.\nFOUNDATION_EXPORT double JWTVersionNumber;\n\n//! Project version string for JWT.\nFOUNDATION_EXPORT const unsigned char JWTVersionString[];\n\n// In this header, you should import all the public headers of your framework using statements like #import <PublicHeader.h>\n\n// Coding\n#import <JWTCoding.h>\n#import <JWTCoding+ResultTypes.h>\n#import <JWTCoding+VersionOne.h>\n#import <JWTCoding+VersionTwo.h>\n#import <JWTCoding+VersionThree.h>\n\n// Algorithms\n#import <JWTAlgorithm.h>\n#import <JWTRSAlgorithm.h>\n#import <JWTAlgorithmFactory.h>\n#import <JWTAlgorithmNone.h>\n#import <JWTAlgorithmHSBase.h>\n#import <JWTAlgorithmRSBase.h>\n\n// Holders\n#import <JWTAlgorithmDataHolder.h>\n#import <JWTAlgorithmDataHolderChain.h>\n\n// Claims\n#import <JWTClaimsSet.h>\n#import <JWTClaim.h>\n#import <JWTClaimsSetSerializer.h>\n#import <JWTClaimsSetVerifier.h>\n\n// Supplement\n#import <JWTDeprecations.h>\n#import <JWTBase64Coder.h>\n#import <JWTErrorDescription.h>\n\n// Crypto\n#import <JWTCryptoKey.h>\n#import <JWTCryptoKeyExtractor.h>\n#import <JWTCryptoSecurity.h>\n"
  },
  {
    "path": "ios/CodePush/JWT/Core/FrameworkSupplement/Map.modulemap",
    "content": "framework module JWT {\n\tumbrella header \"JWT.h\"\n\texport *\n\tmodule * { export * }\n}"
  },
  {
    "path": "ios/CodePush/JWT/Core/Supplement/JWTBase64Coder.h",
    "content": "//\n//  JWTBase64Coder.h\n//  Pods\n//\n//  Created by Lobanov Dmitry on 05.10.16.\n//\n//\n\n#import <Foundation/Foundation.h>\n\n@protocol JWTStringCoder__Protocol <NSObject>\n- (NSString *)stringWithData:(NSData *)data;\n- (NSData *)dataWithString:(NSString *)string;\n@end\n\n@interface JWTBase64Coder : NSObject\n+ (NSString *)base64UrlEncodedStringWithData:(NSData *)data;\n+ (NSData *)dataWithBase64UrlEncodedString:(NSString *)urlEncodedString;\n@end\n\n@interface JWTBase64Coder (JWTStringCoder__Protocol) <JWTStringCoder__Protocol> @end\n\n\n@interface JWTStringCoder__For__Encoding : NSObject\n@property (assign, nonatomic, readwrite) NSStringEncoding stringEncoding;\n+ (instancetype)utf8Encoding;\n@end\n@interface JWTStringCoder__For__Encoding (JWTStringCoder__Protocol) <JWTStringCoder__Protocol> @end\n"
  },
  {
    "path": "ios/CodePush/JWT/Core/Supplement/JWTBase64Coder.m",
    "content": "//\n//  JWTBase64Coder.m\n//  Pods\n//\n//  Created by Lobanov Dmitry on 05.10.16.\n//\n//\n\n#import \"JWTBase64Coder.h\"\n\n@interface JWTBase64Coder (ConditionLinking)\n+ (BOOL)isBase64AddtionsAvailable;\n@end\n\n@implementation JWTBase64Coder (ConditionLinking)\n+ (BOOL)isBase64AddtionsAvailable {\n    return [[NSData class] respondsToSelector:@selector(dataWithBase64UrlEncodedString:)];\n}\n@end\n\n#if __has_include(\"MF_Base64Additions.h\")\n#import <MF_Base64Additions.h>\n#endif\n\n@implementation JWTBase64Coder\n\n+ (NSString *)base64UrlEncodedStringWithData:(NSData *)data {\n    if ([self isBase64AddtionsAvailable] && [data respondsToSelector:@selector(base64UrlEncodedString)]) {\n        return [data performSelector:@selector(base64UrlEncodedString)];\n    }\n    else {\n        return [data base64EncodedStringWithOptions:0];\n    }\n}\n\n+ (NSData *)dataWithBase64UrlEncodedString:(NSString *)urlEncodedString {\n    if ([self isBase64AddtionsAvailable] && [[NSData class] respondsToSelector:@selector(dataWithBase64UrlEncodedString:)]) {\n        return [[NSData class] performSelector:@selector(dataWithBase64UrlEncodedString:) withObject:urlEncodedString];\n    }\n    else {\n        return [[NSData alloc] initWithBase64EncodedString:urlEncodedString options:0];\n    }\n}\n\n@end\n\n@implementation JWTBase64Coder (JWTStringCoder__Protocol)\n- (NSString *)stringWithData:(NSData *)data {\n    return [self.class base64UrlEncodedStringWithData:data];\n}\n- (NSData *)dataWithString:(NSString *)string {\n    return [self.class dataWithBase64UrlEncodedString:string];\n}\n@end\n\n@implementation JWTStringCoder__For__Encoding\n+ (instancetype)utf8Encoding {\n    JWTStringCoder__For__Encoding *coding = [self new];\n    coding.stringEncoding = NSUTF8StringEncoding;\n    return coding;\n}\n@end\n@implementation JWTStringCoder__For__Encoding (JWTStringCoder__Protocol)\n- (NSString *)stringWithData:(NSData *)data {\n    return [[NSString alloc] initWithData:data encoding:self.stringEncoding];\n}\n- (NSData *)dataWithString:(NSString *)string {\n    return [string dataUsingEncoding:self.stringEncoding];\n}\n@end\n"
  },
  {
    "path": "ios/CodePush/JWT/Core/Supplement/JWTDeprecations.h",
    "content": "//\n//  JWTDeprecations.h\n//  JWT\n//\n//  Created by Lobanov Dmitry on 31.08.16.\n//  Copyright © 2016 Karma. All rights reserved.\n//\n\n#ifndef JWTDeprecations_h\n#define JWTDeprecations_h\n\n#define STR(str) #str\n#define JWTVersion_2_1_0 2.1\n#define JWTVersion_2_2_0 2.2\n#define JWTVersion_3_0_0 3.0\n#define __first_deprecated_in_release_version(version) __deprecated_msg(\"first deprecated in release version: \" STR(version))\n#define __deprecated_and_will_be_removed_in_release_version(version) __deprecated_msg(\"deprecated. will be removed in release version: \"STR(version))\n#define __available_in_release_version(version) __deprecated_msg(\"will be introduced in release version: \" STR(version))\n\n#define __jwt_technical_debt(debt) __deprecated_msg(\"Don't forget to inspect it later.\" STR(debt))\n\n#endif /* JWTDeprecations_h */\n"
  },
  {
    "path": "ios/CodePush/JWT/Core/Supplement/JWTErrorDescription.h",
    "content": "//\n//  JWTErrorDescription.h\n//  JWT\n//\n//  Created by Lobanov Dmitry on 27.11.16.\n//  Copyright © 2016 JWTIO. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n\nextern NSString *JWTErrorDomain;\n\ntypedef NS_ENUM(NSInteger, JWTError) {\n    JWTInvalidFormatError = -100,\n    JWTUnsupportedAlgorithmError,\n    JWTAlgorithmNameMismatchError,\n    JWTInvalidSignatureError,\n    JWTNoPayloadError,\n    JWTNoHeaderError,\n    JWTEncodingHeaderError,\n    JWTEncodingPayloadError,\n    JWTEncodingSigningError,\n    JWTClaimsSetVerificationFailed,\n    JWTInvalidSegmentSerializationError,\n    JWTUnspecifiedAlgorithmError,\n    JWTBlacklistedAlgorithmError,\n    JWTDecodingHeaderError,\n    JWTDecodingPayloadError,\n    JWTDecodingHoldersChainEmptyError\n};\n\n@interface JWTErrorDescription : NSObject\n+ (NSError *)errorWithCode:(JWTError)code;\n@end\n"
  },
  {
    "path": "ios/CodePush/JWT/Core/Supplement/JWTErrorDescription.m",
    "content": "//\n//  JWTErrorDescription.m\n//  JWT\n//\n//  Created by Lobanov Dmitry on 27.11.16.\n//  Copyright © 2016 JWTIO. All rights reserved.\n//\n\n#import \"JWTErrorDescription.h\"\nNSString *JWTErrorDomain = @\"io.jwt\";\n@implementation JWTErrorDescription\n+ (NSDictionary *)userDescriptionsAndCodes {\n    static NSDictionary *userDescriptionsAndCodes = nil;\n    return userDescriptionsAndCodes ?: (userDescriptionsAndCodes = @{\n        @(JWTInvalidFormatError): @\"Invalid format! Try to check your encoding algorithm. Maybe you put too many dots as delimiters?\",\n        @(JWTUnsupportedAlgorithmError): @\"Unsupported algorithm! You could implement it by yourself\",\n        @(JWTAlgorithmNameMismatchError) : @\"Algorithm doesn't match name in header.\",\n        @(JWTInvalidSignatureError): @\"Invalid signature! It seems that signed part of jwt mismatch generated part by algorithm provided in header.\",\n        @(JWTNoPayloadError): @\"No payload! Hey, forget payload?\",\n        @(JWTNoHeaderError): @\"No header! Hmm\",\n        @(JWTEncodingHeaderError): @\"It seems that header encoding failed\",\n        @(JWTEncodingPayloadError): @\"It seems that payload encoding failed\",\n        @(JWTEncodingSigningError): @\"It seems that signing output corrupted. Make sure signing worked (e.g. we may have issues extracting the key from the PKCS12 bundle if passphrase is incorrect).\",\n        @(JWTClaimsSetVerificationFailed): @\"It seems that claims verification failed\",\n        @(JWTInvalidSegmentSerializationError): @\"It seems that json serialization failed for segment\",\n        @(JWTUnspecifiedAlgorithmError): @\"Unspecified algorithm! You must explicitly choose an algorithm to decode with.\",\n        @(JWTBlacklistedAlgorithmError): @\"Algorithm in blacklist? Try to check whitelist parameter\",\n        @(JWTDecodingHeaderError): @\"Error decoding the JWT Header segment.\",\n        @(JWTDecodingPayloadError): @\"Error decoding the JWT Payload segment.\",\n        @(JWTDecodingHoldersChainEmptyError) : @\"Error decoding the JWT algorithm and data holders chain is empty!\"\n    }, userDescriptionsAndCodes);\n}\n\n+ (NSDictionary *)errorDescriptionsAndCodes {\n    static NSDictionary *errorDescriptionsAndCodes = nil;\n    return errorDescriptionsAndCodes ?: (errorDescriptionsAndCodes = @{\n        @(JWTInvalidFormatError): @\"JWTInvalidFormatError\",\n        @(JWTUnsupportedAlgorithmError): @\"JWTUnsupportedAlgorithmError\",\n        @(JWTAlgorithmNameMismatchError) :@\"JWTAlgorithmNameMismatchError\",\n        @(JWTInvalidSignatureError): @\"JWTInvalidSignatureError\",\n        @(JWTNoPayloadError): @\"JWTNoPayloadError\",\n        @(JWTNoHeaderError): @\"JWTNoHeaderError\",\n        @(JWTEncodingHeaderError): @\"JWTEncodingHeaderError\",\n        @(JWTEncodingPayloadError): @\"JWTEncodingPayloadError\",\n        @(JWTEncodingSigningError): @\"JWTEncodingSigningError\",\n        @(JWTClaimsSetVerificationFailed): @\"JWTClaimsSetVerificationFailed\",\n        @(JWTInvalidSegmentSerializationError): @\"JWTInvalidSegmentSerializationError\",\n        @(JWTUnspecifiedAlgorithmError): @\"JWTUnspecifiedAlgorithmError\",\n        @(JWTBlacklistedAlgorithmError): @\"JWTBlacklistedAlgorithmError\",\n        @(JWTDecodingHeaderError): @\"JWTDecodingHeaderError\",\n        @(JWTDecodingPayloadError): @\"JWTDecodingPayloadError\",\n        @(JWTDecodingHoldersChainEmptyError) :@\"JWTDecodingHoldersChainEmptyError\"\n    }, errorDescriptionsAndCodes);\n}\n\n+ (NSString *)userDescriptionForCode:(JWTError)code {\n    NSString *resultString = [self userDescriptionsAndCodes][@(code)];\n    return resultString ?: @\"Unexpected error\";\n}\n\n+ (NSString *)errorDescriptionForCode:(JWTError)code {\n    NSString *resultString = [self errorDescriptionsAndCodes][@(code)];\n    return resultString ?: @\"JWTUnexpectedError\";\n}\n\n+ (NSError *)errorWithCode:(JWTError)code {\n    return [self errorWithCode:code withUserDescription:[self userDescriptionForCode:code] withErrorDescription:[self errorDescriptionForCode:code]];\n}\n\n+ (NSError *)errorWithCode:(NSInteger)code withUserDescription:(NSString *)userDescription withErrorDescription:(NSString *)errorDescription {\n    return [NSError errorWithDomain:JWTErrorDomain code:code userInfo:@{NSLocalizedDescriptionKey: userDescription, @\"errorDescription\": errorDescription}];\n}\n@end\n"
  },
  {
    "path": "ios/CodePush/JWT/LICENSE",
    "content": "Copyright (c) 2013 Karma Mobility, Inc.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "ios/CodePush/JWT/README.md",
    "content": "[![JWT](http://jwt.io/assets/logo.svg)](https://jwt.io/)\n\n[![Build Status](https://travis-ci.org/yourkarma/JWT.svg?branch=master)](https://travis-ci.org/yourkarma/JWT)\n[![Pod Version](http://img.shields.io/cocoapods/v/JWT.svg?style=flat)](http://cocoadocs.org/docsets/JWT)\n[![Pod Platform](http://img.shields.io/cocoapods/p/JWT.svg?style=flat)](http://cocoadocs.org/docsets/JWT)\n[![Reference Status](https://www.versioneye.com/objective-c/jwt/reference_badge.svg?style=flat)](https://www.versioneye.com/objective-c/jwt/references)\n\n# JWT\n\nA [JSON Web Token][] implementation in Objective-C.\n\n[JSON Web Token]: http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html\n\n# What's new in master and bleeding edge.\nNothing here.\n\n# What's new in Version 3.0\n\n* Fluent style expanded.\n* Coding result types added.\n* Algorithms and data holders.\n* Algorithms and data holders chain.\n* Keys loaded from Pem files.\n\n## Introduction to Algorithms data holders and chain.\nYou have algorithm, secret data and unknown jwt token.\nLet's try to decode it.\n\n```objective-c\n// create token\nNSString *token = @\"...\";\n\n// possible that algorithm could return error.\n// you could try use algorithm and data chain.\n\nNSString *firstSecret = @\"first\";\nNSString *firstAlgorithmName = JWTAlgorithmNameHS384;\n\nid <JWTAlgorithmDataHolderProtocol> firstHolder = [JWTAlgorithmHSFamilyDataHolder new].algorithmName(firstAlgorithmName).secret(firstSecret);\n\nid <JWTAlgorithmDataHolderProtocol> errorHolder = [JWTAlgorithmNoneDataHolder new];\n\n// chain together.\nJWTAlgorithmDataHolderChain *chain = [[JWTAlgorithmDataHolderChain alloc] initWithHolders:@[firstHolder, errorHolder]];\n\n// or add them in builder\n[JWTDecodingBuilder decodeMessage:token].addHolder(firstHolder).addHolder(errorHolder);\n\n// or add them as chain\n[JWTDecodingBuilder decodeMessage:token].chain(chain);\n```\n\nMaybe you would like to try different secrets.\n\n```objective-c\n// possible that your algorithm has several secrets.\n// you don't know which secret to use.\n// but you want to decode it.\nNSString *firstSecret = @\"first\";\nNSArray *manySecrets = @[@\"second\", @\"third\", @\"forty two\"];\n// translate to data\nNSArray *manySecretsData = @[];\nfor (NSString *secret in manySecrets) {\n    NSData *secretData = [JWTBase64Coder dataWithBase64UrlEncodedString:secret];\n    if (secret) {\n        manySecretsData = [manySecretsData arrayByAddingObject:secretData];\n    }\n}\n\nNSString *algorithmName = JWTAlgorithmNameHS384;\n\nid <JWTAlgorithmDataHolderProtocol> firstHolder = [JWTAlgorithmHSFamilyDataHolder new].algorithmName(algorithmName).secret(firstSecret);\n\n// lets create chain\nJWTAlgorithmDataHolderChain *chain = [JWTAlgorithmDataHolderChain chainWithHolder:firstHolder];\n\n// and lets populate chain with secrets.\nNSLog(@\"chain has: %@\", chain.debugDescription);\n\nJWTAlgorithmDataHolderChain *expandedChain = [chain chainByPopulatingAlgorithm:firstHolder.currentAlgorithm withManySecretData:manySecretsData];\n\n// now we have expanded chain with many secrets and one algorithm.\nNSLog(@\"expanded chain has: %@\", expandedChain.debugDescription);\n```\n\n## Decode and encode with chain.\n\n```objective-c\nJWTClaimsSet *claimsSet = [[JWTClaimsSet alloc] init];\n// fill it\nclaimsSet.issuer = @\"Facebook\";\nclaimsSet.subject = @\"Token\";\nclaimsSet.audience = @\"https://jwt.io\";\n\n// encode it\nNSString *secret = @\"secret\";\nNSString *algorithmName = @\"HS384\";\nNSDictionary *headers = @{@\"custom\":@\"value\"};\n\nid<JWTAlgorithmDataHolderProtocol>holder = [JWTAlgorithmHSFamilyDataHolder new].algorithmName(algorithmName).secret(secret);\n\nJWTCodingResultType *result = [JWTEncodingBuilder encodeClaimsSet:claimsSet].headers(headers).addHolder(holder).result;\n\nNSString *encodedToken = result.successResult.encoded;\nif (result.successResult) {\n    // handle encoded result\n    NSLog(@\"encoded result: %@\", result.successResult.encoded);\n}\nelse {\n    // handle error\n    NSLog(@\"encode failed, error: %@\", result.errorResult.error);\n}\n\n// decode it\n// you can set any property that you want, all properties are optional\nJWTClaimsSet *trustedClaimsSet = [claimsSet copy];\n\nNSNumber *options = @(JWTCodingDecodingOptionsNone);\nNSString *yourJwt = encodedToken; // from previous example\nJWTCodingResultType *decodedResult = [JWTDecodingBuilder decodeMessage:yourJwt].claimsSet(claimsSet).addHolder(holder).options(options).and.result;\n\nif (decodedResult.successResult) {\n    // handle decoded result\n    NSLog(@\"decoded result: %@\", decodedResult.successResult.headerAndPayloadDictionary);\n    NSLog(@\"headers: %@\", decodedResult.successResult.headers);\n    NSLog(@\"payload: %@\", decodedResult.successResult.payload);\n}\nelse {\n    // handle error\n    NSLog(@\"decode failed, error: %@\", decodedResult.errorResult.error);\n}\n```\n\n## Keys loaded from Pem files.\n\nYou have a key in pem file. And you want to use it directly for sign/verify.\nSuppose, that \"public_rsa.pem\" and \"private_rsa.pem\" are public and private keys in pem format.\n```objective-c\n// Load keys\n- (NSString *)pemKeyStringFromFileWithName:(NSString *)string inBundle:(NSBundle *)bundle {\n    NSURL *fileURL = [bundle URLForResource:name withExtension:@\"pem\"];\n    NSError *error = nil;\n    NSString *fileContent = [NSString stringWithContentsOfURL:fileURL encoding:NSUTF8StringEncoding error:&error];\n    if (error) {\n        NSLog(@\"%@ error: %@\", self.debugDescription, error);\n        return nil;\n    }\n}\n\n// Sign and verify\n- (void)signAndVerifyWithPrivateKeyPemString:(NSString *)privateKey publicKeyPemString:(NSString *)publicKey privateKeyPassphrase:(NSString *)passphrase {\n    NSString *algorithmName = @\"RS256\";\n\n    id <JWTAlgorithmDataHolderProtocol> signDataHolder = [JWTAlgorithmRSFamilyDataHolder new].keyExtractorType([JWTCryptoKeyExtractor privateKeyWithPEMBase64].type).privateKeyCertificatePassphrase(passphrase).algorithmName(algorithmName).secret(privateKey);\n\n    id <JWTAlgorithmDataHolderProtocol> verifyDataHolder = [JWTAlgorithmRSFamilyDataHolder new].keyExtractorType([JWTCryptoKeyExtractor publicKeyWithPEMBase64].type).algorithmName(algorithmName).secret(publicKey);\n\n    // sign\n    NSDictionary *payloadDictionary = @{@\"hello\": @\"world\"};\n\n    JWTCodingBuilder *signBuilder = [JWTEncodingBuilder encodePayload:payloadDictionary].addHolder(signDataHolder);\n    JWTCodingResultType *signResult = signBuilder.result;\n    NSString *token = nil;\n    if (signResult.successResult) {\n        // success\n        NSLog(@\"%@ success: %@\", self.debugDescription, signResult.successResult.encoded);\n        token = signResult.successResult.encoded;\n    }\n    else {\n        // error\n        NSLog(@\"%@ error: %@\", self.debugDescription, signResult.errorResult.error);\n    }\n\n    // verify\n    if (token == nil) {\n        NSLog(@\"something wrong\");\n    }\n\n    JWTCodingBuilder *verifyBuilder = [JWTDecodingBuilder decodeMessage:token].addHolder(verifyDataHolder);\n    JWTCodingResultType *verifyResult = verifyBuilder.result;\n    if (verifyResult.successResult) {\n        // success\n        NSLog(@\"%@ success: %@\", self.debugDescription, verifyResult.successResult.payload);\n        token = verifyResult.successResult.encoded;\n    }\n    else {\n        // error\n        NSLog(@\"%@ error: %@\", self.debugDescription, verifyResult.errorResult.error);\n    }\n}\n```\n\n# Experiments in Version 2.0\n## Whitelists possible algorithms.\nWhen you need to decode jwt by several algorithms you could specify their names in whitelist.\nLater this feature possible will migrate to options.\nFor example, someone returns result or error.\n### Limitations\nRestricted to pair (algorithm or none) due to limitations of unique `secret`.\n\n```objective-c\nNSString *jwtResultOrError = /*...*/;\nNSString *secret = @\"secret\";\nJWTBuilder *builder = [JWT decodeMessage:jwtResultOrError].secret(@\"secret\").whitelist(@[@\"HS256\", @\"none\"]);\nNSDictionary *decoded = builder.decode;\nif (builder.jwtError) {\n    // oh!\n}\nelse {\n    NSDictionary *payload = decoded[@\"payload\"];\n    NSDictionary *header = decoded[@\"header\"];\n    NSArray *tries = decoded[@\"tries\"]; // will be evolded into something appropriate later.\n}\n```\n\n# What's new in Version 2.0\n\n* Old plain style deprecated.\n* Use modern fluent style instead.\n\n```objective-c\nNSDictionary *payload = @{@\"foo\" : @\"bar\"};\nNSString *secret = @\"secret\";\nid<JWTAlgorithm> algorithm = [JWTAlgorithmFactory algorithmByName:@\"HS256\"];\n// Deprecated\n[JWT encodePayload:payload withSecret:secret algorithm:algorithm];\n\n// Modern\n[JWTBuilder encodePayload:payload].secret(secret).algorithm(algorithm).encode;\n```\n\n# Installation\n\nAdd the following to your [CocoaPods][] Podfile:\n\n    pod \"JWT\"\n\n[CocoaPods]: http://cocoapods.org\n\nInstall via Cartfile:\n\n    github \"yourkarma/JWT\" \"master\"\n\nand `import JWT`\n\n# Documentation\n# Usage\n\n## JWTBuilder\n\nTo encode & decode JWTs, use fluent style with the `JWTBuilder` interface\n\n```objective-c\n+ (JWTBuilder *)encodePayload:(NSDictionary *)payload;\n+ (JWTBuilder *)encodeClaimsSet:(JWTClaimsSet *)claimsSet;\n+ (JWTBuilder *)decodeMessage:(NSString *)message;\n```\n\nAs you can see, JWTBuilder has interface from both decoding and encoding.\n\nNote: some attributes are encode-only or decode-only.\n\n    #pragma mark - Encode only\n    *payload;\n    *headers;\n    *algorithm;\n\n    #pragma mark - Decode only\n    *message\n    *options // as forcedOption from jwt decode functions interface.\n    *whitelist  //optional array of algorithm names to whitelist for decoding\n\nYou can inspect JWTBuilder by `jwt`-prefixed attributes.\n\nYou can set JWTBuilder attributes by fluent style (block interface).\n\nYou can encode arbitrary payloads like so:\n\n```objective-c\nNSDictionary *payload = @{@\"foo\" : @\"bar\"};\nNSString *secret = @\"secret\";\nid<JWTAlgorithm> algorithm = [JWTAlgorithmFactory algorithmByName:@\"HS256\"];\n\n[JWTBuilder encodePayload:payload].secret(@\"secret\").algorithm(algorithm).encode;\n```\n\nIf you're using reserved claim names you can encode your claim set like so (all properties are optional):\n\n```objective-c\nJWTClaimsSet *claimsSet = [[JWTClaimsSet alloc] init];\nclaimsSet.issuer = @\"Facebook\";\nclaimsSet.subject = @\"Token\";\nclaimsSet.audience = @\"http://yourkarma.com\";\nclaimsSet.expirationDate = [NSDate distantFuture];\nclaimsSet.notBeforeDate = [NSDate distantPast];\nclaimsSet.issuedAt = [NSDate date];\nclaimsSet.identifier = @\"thisisunique\";\nclaimsSet.type = @\"test\";\n\nNSString *secret = @\"secret\";\nid<JWTAlgorithm> algorithm = [JWTAlgorithmFactory algorithmByName:@\"HS256\"];\n\n[JWTBuilder encodeClaimsSet:claimsSet].secret(secret).algorithm(algorithm).encode;\n```\n\nYou can decode a JWT like so:\n\n```objective-c\nNSString *jwtToken = @\"header.payload.signature\";\nNSString *secret = @\"secret\";\nNSString *algorithmName = @\"HS256\"; //Must specify an algorithm to use\n\nNSDictionary *payload = [JWTBuilder decodeMessage:jwtToken].secret(secret).algorithmName(algorithmName).decode;\n```\n\nIf you want to check claims while decoding, you could use next sample of code (all properties are optional):\n\n```objective-c\n// Trusted Claims Set\nJWTClaimsSet *trustedClaimsSet = [[JWTClaimsSet alloc] init];\ntrustedClaimsSet.issuer = @\"Facebook\";\ntrustedClaimsSet.subject = @\"Token\";\ntrustedClaimsSet.audience = @\"http://yourkarma.com\";\ntrustedClaimsSet.expirationDate = [NSDate date];\ntrustedClaimsSet.notBeforeDate = [NSDate date];\ntrustedClaimsSet.issuedAt = [NSDate date];\ntrustedClaimsSet.identifier = @\"thisisunique\";\ntrustedClaimsSet.type = @\"test\";\n\nNSString *message = @\"encodedJwt\";\nNSString *secret = @\"secret\";\nNSString *algorithmName = @\"chosenAlgorithm\"\n\nJWTBuilder *builder = [JWTBuilder decodeMessage:jwt].secret(secret).algorithmName(algorithmName).claimsSet(trustedClaimsSet);\nNSDictionary *payload = builder.decode;\n\nif (builder.jwtError == nil) {\n    // do your work here\n}\nelse {\n    // handle error\n}\n```\n\nIf you want to enforce a whitelist of valid algorithms:\n\n```objective-c\nNSArray *whitelist = @[@\"HS256\", @\"HS512\"];\nNSString *jwtToken = @\"header.payload.signature\";\nNSString *secret = @\"secret\";\nNSString *algorithmName = @\"HS256\";\n\n//Returns nil\nNSDictionary *payload = [JWTBuilder decodeMessage:jwtToken].secret(secret).algorithmName(algorithmName).whitelist(@[]).decode;\n\n//Returns the decoded payload\nNSDictionary *payload = [JWTBuilder decodeMessage:jwtToken].secret(secret).algorithmName(algorithmName).whitelist(whitelist).decode;\n```\n\n### Encode / Decode Example\n\n```objective-c\n// suppose, that you create ClaimsSet\nJWTClaimsSet *claimsSet = [[JWTClaimsSet alloc] init];\n// fill it\nclaimsSet.issuer = @\"Facebook\";\nclaimsSet.subject = @\"Token\";\nclaimsSet.audience = @\"http://yourkarma.com\";\n\n// encode it\nNSString *secret = @\"secret\";\nNSString *algorithmName = @\"HS384\";\nNSDictionary *headers = @{@\"custom\":@\"value\"};\nid<JWTAlgorithm> algorithm = [JWTAlgorithmFactory algorithmByName:algorithmName];\n\nJWTBuilder *encodeBuilder = [JWT encodeClaimsSet:claimsSet];\nNSString *encodedResult = encodeBuilder.secret(secret).algorithm(algorithm).headers(headers).encode;\n\nif (encodeBuilder.jwtError == nil) {\n    // handle encoded result\n    NSLog(@\"encoded result: %@\", encodedResult);\n}\nelse {\n    // handle error\n    NSLog(@\"encode failed, error: %@\", encodeBuilder.jwtError);\n}\n\n// decode it\n// you can set any property that you want, all properties are optional\nJWTClaimsSet *trustedClaimsSet = [claimsSet copy];\n\n// decode forced ? try YES\nBOOL decodeForced = NO;\nNSNumber *options = @(decodeForced);\nNSString *yourJwt = encodedResult; // from previous example\nNSString *yourSecret = secret; // from previous example\nNSString *yourAlgorithm = algorithmName; // from previous example\nJWTBuilder *decodeBuilder = [JWT decodeMessage:yourJwt];\nNSDictionary *decodedResult = decodeBuilder.message(yourJwt).secret(yourSecret).algorithmName(yourAlgorithm).claimsSet(trustedClaimsSet).options(options).decode;\nif (decodeBuilder.jwtError == nil) {\n    // handle decoded result\n    NSLog(@\"decoded result: %@\", decodedResult);\n}\nelse {\n    // handle error\n    NSLog(@\"decode failed, error: %@\", decodeBuilder.jwtError);\n}\n```\n\n#### NSData\nYou can also encode/decode using a secret that is represented as an NSData object\n\n```objective-c\n//Encode\nNSData *secretData = \"<your data>\";\nNSString *algorithmName = @\"HS384\";\nNSDictionary *headers = @{@\"custom\":@\"value\"};\nid<JWTAlgorithm> algorithm = [JWTAlgorithmFactory algorithmByName:algorithmName];\n\nJWTBuilder *encodeBuilder = [JWT encodeClaimsSet:claimsSet];\nNSString *encodedResult = encodeBuilder.secretData(secretData).algorithm(algorithm).headers(headers).encode;\n\n//Decode\nNSString *jwtToken = @\"header.payload.signature\";\nNSData *secretData = \"<your data>\"\nNSString *algorithmName = @\"HS256\"; //Must specify an algorithm to use\n\nNSDictionary *payload = [JWTBuilder decodeMessage:jwtToken].secretData(secretData).algorithmName(algorithmName).decode;\n```\n\n# Algorithms\n\nThe following algorithms are supported:\n\n* RS256\n* HS512 - HMAC using SHA-512.\n* HS256 / HS384 / HS512\n* None\n\n## RS256 usage.\nFor example, you have your file with privateKey: `file.p12`.\nAnd you have a secret passphrase for that file: `secret`.\n\n```objective-c\n// Encode\nNSDictionary *payload = @{@\"payload\" : @\"hidden_information\"};\nNSString *algorithmName = @\"RS256\";\n\nNSString *filePath = [[NSBundle mainBundle] pathForResource:@\"secret_key\" ofType:@\"p12\"];\nNSData *privateKeySecretData = [NSData dataWithContentsOfFile:filePath];\n\nNSString *passphraseForPrivateKey = @\"secret\";\n\nJWTBuilder *builder = [JWTBuilder encodePayload:payload].secretData(privateKeySecretData).privateKeyCertificatePassphrase(passphraseForPrivateKey).algorithmName(algorithmName);\nNSString *token = builder.encode;\n\n// check error\nif (builder.jwtError == nil) {\n    // handle result\n}\nelse {\n    // error occurred.\n}\n\n// Decode\n// Suppose, that you get token from previous example. You need a valid public key for a private key in previous example.\n// Private key stored in @\"secret_key.p12\". So, you need public key for that private key.\nNSString *publicKey = @\"...\"; // load public key. Or use it as raw string.\n\nalgorithmName = @\"RS256\";\n\nJWTBuilder *decodeBuilder = [JWTBuilder decodeMessage:token].secret(publicKey).algorithmName(algorithmName);\nNSDictionary *envelopedPayload = decodeBuilder.decode;\n\n// check error\nif (decodeBuilder.jwtError == nil) {\n    // handle result\n}\nelse {\n    // error occurred.\n}\n```\n\n\nAdditional algorithms can be added by implementing the `JWTAlgorithm` protocol.\n\n## Before pull request\n\nPlease, read [Contribution notes](https://github.com/yourkarma/JWT/blob/master/.github/CONTRIBUTING.md) before make pull request."
  },
  {
    "path": "ios/CodePush/RCTConvert+CodePushInstallMode.m",
    "content": "#import \"CodePush.h\"\n\n#if __has_include(<React/RCTConvert.h>)\n#import <React/RCTConvert.h>\n#else\n#import \"RCTConvert.h\"\n#endif\n\n// Extending the RCTConvert class allows the React Native\n// bridge to handle args of type \"CodePushInstallMode\"\n@implementation RCTConvert (CodePushInstallMode)\n\nRCT_ENUM_CONVERTER(CodePushInstallMode, (@{ @\"codePushInstallModeImmediate\": @(CodePushInstallModeImmediate),\n                                            @\"codePushInstallModeOnNextRestart\": @(CodePushInstallModeOnNextRestart),\n                                            @\"codePushInstallModeOnNextResume\": @(CodePushInstallModeOnNextResume),\n                                            @\"codePushInstallModeOnNextSuspend\": @(CodePushInstallModeOnNextSuspend) }),\n                   CodePushInstallModeImmediate, // Default enum value\n                   integerValue)\n\n@end\n"
  },
  {
    "path": "ios/CodePush/RCTConvert+CodePushUpdateState.m",
    "content": "#import \"CodePush.h\"\n\n#if __has_include(<React/RCTConvert.h>)\n#import <React/RCTConvert.h>\n#else\n#import \"RCTConvert.h\"\n#endif\n\n// Extending the RCTConvert class allows the React Native\n// bridge to handle args of type \"CodePushUpdateState\"\n@implementation RCTConvert (CodePushUpdateState)\n\nRCT_ENUM_CONVERTER(CodePushUpdateState, (@{ @\"codePushUpdateStateRunning\": @(CodePushUpdateStateRunning),\n                                            @\"codePushUpdateStatePending\": @(CodePushUpdateStatePending),\n                                            @\"codePushUpdateStateLatest\": @(CodePushUpdateStateLatest)\n                                          }),\n                   CodePushUpdateStateRunning, // Default enum value\n                   integerValue)\n\n@end\n"
  },
  {
    "path": "ios/CodePush/SSZipArchive/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>FMWK</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>$(CURRENT_PROJECT_VERSION)</string>\n\t<key>NSPrincipalClass</key>\n\t<string></string>\n</dict>\n</plist>\n"
  },
  {
    "path": "ios/CodePush/SSZipArchive/README.md",
    "content": "The source code in this folder is taken from [https://github.com/ZipArchive/ZipArchive/tree/2.5.5/SSZipArchive](https://github.com/ZipArchive/ZipArchive/tree/2.5.5/SSZipArchive) which is [MIT licensed](https://github.com/ZipArchive/ZipArchive/blob/2.5.5/LICENSE.txt)."
  },
  {
    "path": "ios/CodePush/SSZipArchive/SSZipArchive.h",
    "content": "//\n//  SSZipArchive.h\n//  SSZipArchive\n//\n//  Created by Sam Soffes on 7/21/10.\n//\n\n#ifndef _SSZIPARCHIVE_H\n#define _SSZIPARCHIVE_H\n\n#import <Foundation/Foundation.h>\n\n#import \"SSZipCommon.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\nextern NSString *const SSZipArchiveErrorDomain;\ntypedef NS_ENUM(NSInteger, SSZipArchiveErrorCode) {\n    SSZipArchiveErrorCodeFailedOpenZipFile             = -1,\n    SSZipArchiveErrorCodeFailedOpenFileInZip           = -2,\n    SSZipArchiveErrorCodeFileInfoNotLoadable           = -3,\n    SSZipArchiveErrorCodeFileContentNotReadable        = -4,\n    SSZipArchiveErrorCodeFailedToWriteFile             = -5,\n    SSZipArchiveErrorCodeInvalidArguments              = -6,\n    SSZipArchiveErrorCodeSymlinkEscapesTargetDirectory = -7,\n};\n\n@protocol SSZipArchiveDelegate;\n\n@interface SSZipArchive : NSObject\n\n// Password check\n+ (BOOL)isFilePasswordProtectedAtPath:(NSString *)path;\n+ (BOOL)isPasswordValidForArchiveAtPath:(NSString *)path password:(NSString *)pw error:(NSError * _Nullable * _Nullable)error NS_SWIFT_NOTHROW;\n\n// Total payload size\n+ (NSNumber *)payloadSizeForArchiveAtPath:(NSString *)path error:(NSError **)error;\n\n// Unzip\n+ (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination;\n+ (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination delegate:(nullable id<SSZipArchiveDelegate>)delegate;\n\n+ (BOOL)unzipFileAtPath:(NSString *)path\n          toDestination:(NSString *)destination\n              overwrite:(BOOL)overwrite\n               password:(nullable NSString *)password\n                  error:(NSError * *)error;\n\n+ (BOOL)unzipFileAtPath:(NSString *)path\n          toDestination:(NSString *)destination\n              overwrite:(BOOL)overwrite\n               password:(nullable NSString *)password\n                  error:(NSError * *)error\n               delegate:(nullable id<SSZipArchiveDelegate>)delegate NS_REFINED_FOR_SWIFT;\n\n+ (BOOL)unzipFileAtPath:(NSString *)path\n          toDestination:(NSString *)destination\n     preserveAttributes:(BOOL)preserveAttributes\n              overwrite:(BOOL)overwrite\n               password:(nullable NSString *)password\n                  error:(NSError * *)error\n               delegate:(nullable id<SSZipArchiveDelegate>)delegate;\n\n+ (BOOL)unzipFileAtPath:(NSString *)path\n          toDestination:(NSString *)destination\n        progressHandler:(void (^_Nullable)(NSString *entry, unz_file_info zipInfo, long entryNumber, long total))progressHandler\n      completionHandler:(void (^_Nullable)(NSString *path, BOOL succeeded, NSError * _Nullable error))completionHandler;\n\n+ (BOOL)unzipFileAtPath:(NSString *)path\n          toDestination:(NSString *)destination\n              overwrite:(BOOL)overwrite\n               password:(nullable NSString *)password\n        progressHandler:(void (^_Nullable)(NSString *entry, unz_file_info zipInfo, long entryNumber, long total))progressHandler\n      completionHandler:(void (^_Nullable)(NSString *path, BOOL succeeded, NSError * _Nullable error))completionHandler;\n\n+ (BOOL)unzipFileAtPath:(NSString *)path\n          toDestination:(NSString *)destination\n     preserveAttributes:(BOOL)preserveAttributes\n              overwrite:(BOOL)overwrite\n         nestedZipLevel:(NSInteger)nestedZipLevel\n               password:(nullable NSString *)password\n                  error:(NSError **)error\n               delegate:(nullable id<SSZipArchiveDelegate>)delegate\n        progressHandler:(void (^_Nullable)(NSString *entry, unz_file_info zipInfo, long entryNumber, long total))progressHandler\n      completionHandler:(void (^_Nullable)(NSString *path, BOOL succeeded, NSError * _Nullable error))completionHandler;\n\n+ (BOOL)unzipFileAtPath:(NSString *)path\n          toDestination:(NSString *)destination\n     preserveAttributes:(BOOL)preserveAttributes\n              overwrite:(BOOL)overwrite\n    symlinksValidWithin:(nullable NSString *)symlinksValidWithin\n         nestedZipLevel:(NSInteger)nestedZipLevel\n               password:(nullable NSString *)password\n                  error:(NSError **)error\n               delegate:(nullable id<SSZipArchiveDelegate>)delegate\n        progressHandler:(void (^_Nullable)(NSString *entry, unz_file_info zipInfo, long entryNumber, long total))progressHandler\n      completionHandler:(void (^_Nullable)(NSString *path, BOOL succeeded, NSError * _Nullable error))completionHandler;\n\n// Zip\n// default compression level is Z_DEFAULT_COMPRESSION (from \"zlib.h\")\n// keepParentDirectory: if YES, then unzipping will give `directoryName/fileName`. If NO, then unzipping will just give `fileName`. Default is NO.\n\n// without password\n+ (BOOL)createZipFileAtPath:(NSString *)path withFilesAtPaths:(NSArray<NSString *> *)paths;\n+ (BOOL)createZipFileAtPath:(NSString *)path withContentsOfDirectory:(NSString *)directoryPath;\n\n+ (BOOL)createZipFileAtPath:(NSString *)path withContentsOfDirectory:(NSString *)directoryPath keepParentDirectory:(BOOL)keepParentDirectory;\n\n// with optional password, default encryption is AES\n// don't use AES if you need compatibility with native macOS unzip and Archive Utility\n+ (BOOL)createZipFileAtPath:(NSString *)path withFilesAtPaths:(NSArray<NSString *> *)paths withPassword:(nullable NSString *)password;\n+ (BOOL)createZipFileAtPath:(NSString *)path withFilesAtPaths:(NSArray<NSString *> *)paths withPassword:(nullable NSString *)password progressHandler:(void(^ _Nullable)(NSUInteger entryNumber, NSUInteger total))progressHandler;\n+ (BOOL)createZipFileAtPath:(NSString *)path withContentsOfDirectory:(NSString *)directoryPath withPassword:(nullable NSString *)password;\n+ (BOOL)createZipFileAtPath:(NSString *)path withContentsOfDirectory:(NSString *)directoryPath keepParentDirectory:(BOOL)keepParentDirectory withPassword:(nullable NSString *)password;\n+ (BOOL)createZipFileAtPath:(NSString *)path\n    withContentsOfDirectory:(NSString *)directoryPath\n        keepParentDirectory:(BOOL)keepParentDirectory\n               withPassword:(nullable NSString *)password\n         andProgressHandler:(void(^ _Nullable)(NSUInteger entryNumber, NSUInteger total))progressHandler;\n+ (BOOL)createZipFileAtPath:(NSString *)path\n    withContentsOfDirectory:(NSString *)directoryPath\n        keepParentDirectory:(BOOL)keepParentDirectory\n           compressionLevel:(int)compressionLevel\n                   password:(nullable NSString *)password\n                        AES:(BOOL)aes\n            progressHandler:(void(^ _Nullable)(NSUInteger entryNumber, NSUInteger total))progressHandler;\n//suport symlink compress --file\n+ (BOOL)createZipFileAtPath:(NSString *)path withFilesAtPaths:(NSArray<NSString *> *)paths withPassword:(nullable NSString *)password keepSymlinks:(BOOL)keeplinks;\n//suport symlink compress --directory\n+ (BOOL)createZipFileAtPath:(NSString *)path\n    withContentsOfDirectory:(NSString *)directoryPath\n        keepParentDirectory:(BOOL)keepParentDirectory\n           compressionLevel:(int)compressionLevel\n                   password:(nullable NSString *)password\n                        AES:(BOOL)aes\n            progressHandler:(void(^ _Nullable)(NSUInteger entryNumber, NSUInteger total))progressHandler\n               keepSymlinks:(BOOL)keeplinks;\n\n- (instancetype)init NS_UNAVAILABLE;\n- (instancetype)initWithPath:(NSString *)path NS_DESIGNATED_INITIALIZER;\n- (BOOL)open;\n- (BOOL)openForAppending;\n\n/// write empty folder\n- (BOOL)writeFolderAtPath:(NSString *)path withFolderName:(NSString *)folderName withPassword:(nullable NSString *)password;\n/// write file\n- (BOOL)writeFile:(NSString *)path withPassword:(nullable NSString *)password;\n- (BOOL)writeFileAtPath:(NSString *)path withFileName:(nullable NSString *)fileName withPassword:(nullable NSString *)password;\n- (BOOL)writeFileAtPath:(NSString *)path withFileName:(nullable NSString *)fileName compressionLevel:(int)compressionLevel password:(nullable NSString *)password AES:(BOOL)aes;\n///write symlink files\n- (BOOL)writeSymlinkFileAtPath:(NSString *)path withFileName:(nullable NSString *)fileName compressionLevel:(int)compressionLevel password:(nullable NSString *)password AES:(BOOL)aes;\n/// write data\n- (BOOL)writeData:(NSData *)data filename:(nullable NSString *)filename withPassword:(nullable NSString *)password;\n- (BOOL)writeData:(NSData *)data filename:(nullable NSString *)filename compressionLevel:(int)compressionLevel password:(nullable NSString *)password AES:(BOOL)aes;\n\n- (BOOL)close;\n\n@end\n\n@protocol SSZipArchiveDelegate <NSObject>\n\n@optional\n\n- (void)zipArchiveWillUnzipArchiveAtPath:(NSString *)path zipInfo:(unz_global_info)zipInfo;\n- (void)zipArchiveDidUnzipArchiveAtPath:(NSString *)path zipInfo:(unz_global_info)zipInfo unzippedPath:(NSString *)unzippedPath;\n\n- (BOOL)zipArchiveShouldUnzipFileAtIndex:(NSInteger)fileIndex totalFiles:(NSInteger)totalFiles archivePath:(NSString *)archivePath fileInfo:(unz_file_info)fileInfo;\n- (void)zipArchiveWillUnzipFileAtIndex:(NSInteger)fileIndex totalFiles:(NSInteger)totalFiles archivePath:(NSString *)archivePath fileInfo:(unz_file_info)fileInfo;\n- (void)zipArchiveDidUnzipFileAtIndex:(NSInteger)fileIndex totalFiles:(NSInteger)totalFiles archivePath:(NSString *)archivePath fileInfo:(unz_file_info)fileInfo;\n- (void)zipArchiveDidUnzipFileAtIndex:(NSInteger)fileIndex totalFiles:(NSInteger)totalFiles archivePath:(NSString *)archivePath unzippedFilePath:(NSString *)unzippedFilePath;\n\n- (void)zipArchiveProgressEvent:(unsigned long long)loaded total:(unsigned long long)total;\n\n@end\n\nNS_ASSUME_NONNULL_END\n\n#endif /* _SSZIPARCHIVE_H */\n"
  },
  {
    "path": "ios/CodePush/SSZipArchive/SSZipArchive.m",
    "content": "//\n//  SSZipArchive.m\n//  SSZipArchive\n//\n//  Created by Sam Soffes on 7/21/10.\n//\n\n#import \"SSZipArchive.h\"\n#include \"minizip/mz_compat.h\"\n#include \"minizip/mz_zip.h\"\n#include \"minizip/mz_os.h\"\n#include <zlib.h>\n#include <sys/stat.h>\n\nNSString *const SSZipArchiveErrorDomain = @\"SSZipArchiveErrorDomain\";\n\n#define CHUNK 16384\n\nint _zipOpenEntry(zipFile entry, NSString *name, const zip_fileinfo *zipfi, int level, NSString *password, BOOL aes);\nBOOL _fileIsSymbolicLink(const unz_file_info *fileInfo);\n\n#ifndef API_AVAILABLE\n// Xcode 7- compatibility\n#define API_AVAILABLE(...)\n#endif\n\n@interface NSData(SSZipArchive)\n- (NSString *)_base64RFC4648 API_AVAILABLE(macos(10.9), ios(7.0), watchos(2.0), tvos(9.0));\n- (NSString *)_hexString;\n@end\n\n@interface NSString (SSZipArchive)\n- (NSString *)_sanitizedPath;\n- (BOOL)_escapesTargetDirectory:(NSString *)targetDirectory;\n@end\n\n@interface SSZipArchive ()\n- (instancetype)init NS_DESIGNATED_INITIALIZER;\n@end\n\n@implementation SSZipArchive\n{\n    /// path for zip file\n    NSString *_path;\n    zipFile _zip;\n}\n\n#pragma mark - Password check\n\n+ (BOOL)isFilePasswordProtectedAtPath:(NSString *)path {\n    // Begin opening\n    zipFile zip = unzOpen(path.fileSystemRepresentation);\n    if (zip == NULL) {\n        return NO;\n    }\n    \n    BOOL passwordProtected = NO;\n    int ret = unzGoToFirstFile(zip);\n    if (ret == UNZ_OK) {\n        do {\n            ret = unzOpenCurrentFile(zip);\n            if (ret != UNZ_OK) {\n                // attempting with an arbitrary password to workaround `unzOpenCurrentFile` limitation on AES encrypted files\n                ret = unzOpenCurrentFilePassword(zip, \"\");\n                unzCloseCurrentFile(zip);\n                if (ret == UNZ_OK || ret == MZ_PASSWORD_ERROR) {\n                    passwordProtected = YES;\n                }\n                break;\n            }\n            unz_file_info fileInfo = {};\n            ret = unzGetCurrentFileInfo(zip, &fileInfo, NULL, 0, NULL, 0, NULL, 0);\n            unzCloseCurrentFile(zip);\n            if (ret != UNZ_OK) {\n                break;\n            } else if ((fileInfo.flag & MZ_ZIP_FLAG_ENCRYPTED) == 1) {\n                passwordProtected = YES;\n                break;\n            }\n            \n            ret = unzGoToNextFile(zip);\n        } while (ret == UNZ_OK);\n    }\n    \n    unzClose(zip);\n    return passwordProtected;\n}\n\n+ (BOOL)isPasswordValidForArchiveAtPath:(NSString *)path password:(NSString *)pw error:(NSError **)error {\n    if (error) {\n        *error = nil;\n    }\n\n    zipFile zip = unzOpen(path.fileSystemRepresentation);\n    if (zip == NULL) {\n        if (error) {\n            *error = [NSError errorWithDomain:SSZipArchiveErrorDomain\n                                         code:SSZipArchiveErrorCodeFailedOpenZipFile\n                                     userInfo:@{NSLocalizedDescriptionKey: @\"failed to open zip file\"}];\n        }\n        return NO;\n    }\n\n    // Initialize passwordValid to YES (No password required)\n    BOOL passwordValid = YES;\n    int ret = unzGoToFirstFile(zip);\n    if (ret == UNZ_OK) {\n        do {\n            if (pw.length == 0) {\n                ret = unzOpenCurrentFile(zip);\n            } else {\n                ret = unzOpenCurrentFilePassword(zip, [pw cStringUsingEncoding:NSUTF8StringEncoding]);\n            }\n            if (ret != UNZ_OK) {\n                if (ret != MZ_PASSWORD_ERROR) {\n                    if (error) {\n                        *error = [NSError errorWithDomain:SSZipArchiveErrorDomain\n                                                     code:SSZipArchiveErrorCodeFailedOpenFileInZip\n                                                 userInfo:@{NSLocalizedDescriptionKey: @\"failed to open file in zip archive\"}];\n                    }\n                }\n                passwordValid = NO;\n                break;\n            }\n            unz_file_info fileInfo = {};\n            ret = unzGetCurrentFileInfo(zip, &fileInfo, NULL, 0, NULL, 0, NULL, 0);\n            if (ret != UNZ_OK) {\n                if (error) {\n                    *error = [NSError errorWithDomain:SSZipArchiveErrorDomain\n                                                 code:SSZipArchiveErrorCodeFileInfoNotLoadable\n                                             userInfo:@{NSLocalizedDescriptionKey: @\"failed to retrieve info for file\"}];\n                }\n                passwordValid = NO;\n                break;\n            } else if ((fileInfo.flag & 1) == 1) {\n                unsigned char buffer[10] = {0};\n                int readBytes = unzReadCurrentFile(zip, buffer, (unsigned)MIN(10UL,fileInfo.uncompressed_size));\n                if (readBytes < 0) {\n                    // Let's assume error Z_DATA_ERROR is caused by an invalid password\n                    // Let's assume other errors are caused by Content Not Readable\n                    if (readBytes != Z_DATA_ERROR) {\n                        if (error) {\n                            *error = [NSError errorWithDomain:SSZipArchiveErrorDomain\n                                                         code:SSZipArchiveErrorCodeFileContentNotReadable\n                                                     userInfo:@{NSLocalizedDescriptionKey: @\"failed to read contents of file entry\"}];\n                        }\n                    }\n                    passwordValid = NO;\n                    break;\n                }\n                passwordValid = YES;\n                break;\n            }\n            \n            unzCloseCurrentFile(zip);\n            ret = unzGoToNextFile(zip);\n        } while (ret == UNZ_OK);\n    }\n    \n    unzClose(zip);\n    return passwordValid;\n}\n\n+ (NSNumber *)payloadSizeForArchiveAtPath:(NSString *)path error:(NSError **)error {\n    if (error) {\n        *error = nil;\n    }\n\n    zipFile zip = unzOpen(path.fileSystemRepresentation);\n    if (zip == NULL) {\n        if (error) {\n            *error = [NSError errorWithDomain:SSZipArchiveErrorDomain\n                                         code:SSZipArchiveErrorCodeFailedOpenZipFile\n                                     userInfo:@{NSLocalizedDescriptionKey: @\"failed to open zip file\"}];\n        }\n        return @0;\n    }\n\n    unsigned long long totalSize = 0;\n    int ret = unzGoToFirstFile(zip);\n    if (ret == UNZ_OK) {\n        do {\n            ret = unzOpenCurrentFile(zip);\n            if (ret != UNZ_OK) {\n                if (error) {\n                    *error = [NSError errorWithDomain:SSZipArchiveErrorDomain\n                                                 code:SSZipArchiveErrorCodeFailedOpenFileInZip\n                                             userInfo:@{NSLocalizedDescriptionKey: @\"failed to open file in zip archive\"}];\n                }\n                break;\n            }\n            unz_file_info fileInfo = {};\n            ret = unzGetCurrentFileInfo(zip, &fileInfo, NULL, 0, NULL, 0, NULL, 0);\n            if (ret != UNZ_OK) {\n                if (error) {\n                    *error = [NSError errorWithDomain:SSZipArchiveErrorDomain\n                                                 code:SSZipArchiveErrorCodeFileInfoNotLoadable\n                                             userInfo:@{NSLocalizedDescriptionKey: @\"failed to retrieve info for file\"}];\n                }\n                break;\n            }\n\n            totalSize += fileInfo.uncompressed_size;\n\n            unzCloseCurrentFile(zip);\n            ret = unzGoToNextFile(zip);\n        } while (ret == UNZ_OK);\n    }\n\n    unzClose(zip);\n\n    return [NSNumber numberWithUnsignedLongLong:totalSize];\n}\n\n#pragma mark - Unzipping\n\n+ (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination\n{\n    return [self unzipFileAtPath:path toDestination:destination delegate:nil];\n}\n\n+ (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination overwrite:(BOOL)overwrite password:(nullable NSString *)password error:(NSError **)error\n{\n    return [self unzipFileAtPath:path toDestination:destination preserveAttributes:YES overwrite:overwrite password:password error:error delegate:nil progressHandler:nil completionHandler:nil];\n}\n\n+ (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination delegate:(nullable id<SSZipArchiveDelegate>)delegate\n{\n    return [self unzipFileAtPath:path toDestination:destination preserveAttributes:YES overwrite:YES password:nil error:nil delegate:delegate progressHandler:nil completionHandler:nil];\n}\n\n+ (BOOL)unzipFileAtPath:(NSString *)path\n          toDestination:(NSString *)destination\n              overwrite:(BOOL)overwrite\n               password:(nullable NSString *)password\n                  error:(NSError **)error\n               delegate:(nullable id<SSZipArchiveDelegate>)delegate\n{\n    return [self unzipFileAtPath:path toDestination:destination preserveAttributes:YES overwrite:overwrite password:password error:error delegate:delegate progressHandler:nil completionHandler:nil];\n}\n\n+ (BOOL)unzipFileAtPath:(NSString *)path\n          toDestination:(NSString *)destination\n              overwrite:(BOOL)overwrite\n               password:(NSString *)password\n        progressHandler:(void (^)(NSString *entry, unz_file_info zipInfo, long entryNumber, long total))progressHandler\n      completionHandler:(void (^)(NSString *path, BOOL succeeded, NSError * _Nullable error))completionHandler\n{\n    return [self unzipFileAtPath:path toDestination:destination preserveAttributes:YES overwrite:overwrite password:password error:nil delegate:nil progressHandler:progressHandler completionHandler:completionHandler];\n}\n\n+ (BOOL)unzipFileAtPath:(NSString *)path\n          toDestination:(NSString *)destination\n        progressHandler:(void (^_Nullable)(NSString *entry, unz_file_info zipInfo, long entryNumber, long total))progressHandler\n      completionHandler:(void (^_Nullable)(NSString *path, BOOL succeeded, NSError * _Nullable error))completionHandler\n{\n    return [self unzipFileAtPath:path toDestination:destination preserveAttributes:YES overwrite:YES password:nil error:nil delegate:nil progressHandler:progressHandler completionHandler:completionHandler];\n}\n\n+ (BOOL)unzipFileAtPath:(NSString *)path\n          toDestination:(NSString *)destination\n     preserveAttributes:(BOOL)preserveAttributes\n              overwrite:(BOOL)overwrite\n               password:(nullable NSString *)password\n                  error:(NSError * *)error\n               delegate:(nullable id<SSZipArchiveDelegate>)delegate\n{\n    return [self unzipFileAtPath:path toDestination:destination preserveAttributes:preserveAttributes overwrite:overwrite password:password error:error delegate:delegate progressHandler:nil completionHandler:nil];\n}\n\n+ (BOOL)unzipFileAtPath:(NSString *)path\n          toDestination:(NSString *)destination\n     preserveAttributes:(BOOL)preserveAttributes\n              overwrite:(BOOL)overwrite\n               password:(nullable NSString *)password\n                  error:(NSError **)error\n               delegate:(nullable id<SSZipArchiveDelegate>)delegate\n        progressHandler:(void (^_Nullable)(NSString *entry, unz_file_info zipInfo, long entryNumber, long total))progressHandler\n      completionHandler:(void (^_Nullable)(NSString *path, BOOL succeeded, NSError * _Nullable error))completionHandler\n{\n    return [self unzipFileAtPath:path toDestination:destination preserveAttributes:preserveAttributes overwrite:overwrite nestedZipLevel:0 password:password error:error delegate:delegate progressHandler:progressHandler completionHandler:completionHandler];\n}\n\n+ (BOOL)unzipFileAtPath:(NSString *)path\n          toDestination:(NSString *)destination\n     preserveAttributes:(BOOL)preserveAttributes\n              overwrite:(BOOL)overwrite\n         nestedZipLevel:(NSInteger)nestedZipLevel\n               password:(nullable NSString *)password\n                  error:(NSError **)error\n               delegate:(nullable id<SSZipArchiveDelegate>)delegate\n        progressHandler:(void (^_Nullable)(NSString *entry, unz_file_info zipInfo, long entryNumber, long total))progressHandler\n      completionHandler:(void (^_Nullable)(NSString *path, BOOL succeeded, NSError * _Nullable error))completionHandler\n{\n    return [self unzipFileAtPath:path\n                   toDestination:destination\n              preserveAttributes:preserveAttributes\n                       overwrite:overwrite\n         symlinksValidWithin:destination\n                  nestedZipLevel:nestedZipLevel\n                        password:password\n                           error:error\n                        delegate:delegate\n                 progressHandler:progressHandler\n               completionHandler:completionHandler];\n}\n\n\n+ (BOOL)unzipFileAtPath:(NSString *)path\n          toDestination:(NSString *)destination\n     preserveAttributes:(BOOL)preserveAttributes\n              overwrite:(BOOL)overwrite\n    symlinksValidWithin:(nullable NSString *)symlinksValidWithin\n         nestedZipLevel:(NSInteger)nestedZipLevel\n               password:(nullable NSString *)password\n                  error:(NSError **)error\n               delegate:(nullable id<SSZipArchiveDelegate>)delegate\n        progressHandler:(void (^_Nullable)(NSString *entry, unz_file_info zipInfo, long entryNumber, long total))progressHandler\n      completionHandler:(void (^_Nullable)(NSString *path, BOOL succeeded, NSError * _Nullable error))completionHandler\n{\n    // Guard against empty strings\n    if (path.length == 0 || destination.length == 0)\n    {\n        NSDictionary *userInfo = @{NSLocalizedDescriptionKey: @\"received invalid argument(s)\"};\n        NSError *err = [NSError errorWithDomain:SSZipArchiveErrorDomain code:SSZipArchiveErrorCodeInvalidArguments userInfo:userInfo];\n        if (error)\n        {\n            *error = err;\n        }\n        if (completionHandler)\n        {\n            completionHandler(nil, NO, err);\n        }\n        return NO;\n    }\n    \n    // Begin opening\n    zipFile zip = unzOpen(path.fileSystemRepresentation);\n    if (zip == NULL)\n    {\n        NSDictionary *userInfo = @{NSLocalizedDescriptionKey: @\"failed to open zip file\"};\n        NSError *err = [NSError errorWithDomain:SSZipArchiveErrorDomain code:SSZipArchiveErrorCodeFailedOpenZipFile userInfo:userInfo];\n        if (error)\n        {\n            *error = err;\n        }\n        if (completionHandler)\n        {\n            completionHandler(nil, NO, err);\n        }\n        return NO;\n    }\n    \n    NSDictionary * fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:path error:nil];\n    unsigned long long fileSize = [[fileAttributes objectForKey:NSFileSize] unsignedLongLongValue];\n    unsigned long long currentPosition = 0;\n    \n    unz_global_info globalInfo = {};\n    unzGetGlobalInfo(zip, &globalInfo);\n    \n    // Begin unzipping\n    int ret = 0;\n    ret = unzGoToFirstFile(zip);\n    if (ret != UNZ_OK && ret != MZ_END_OF_LIST)\n    {\n        NSDictionary *userInfo = @{NSLocalizedDescriptionKey: @\"failed to open first file in zip file\"};\n        NSError *err = [NSError errorWithDomain:SSZipArchiveErrorDomain code:SSZipArchiveErrorCodeFailedOpenFileInZip userInfo:userInfo];\n        if (error)\n        {\n            *error = err;\n        }\n        if (completionHandler)\n        {\n            completionHandler(nil, NO, err);\n        }\n        unzClose(zip);\n        return NO;\n    }\n    \n    BOOL success = YES;\n    BOOL canceled = NO;\n    int crc_ret = 0;\n    unsigned char buffer[4096] = {0};\n    NSFileManager *fileManager = [NSFileManager defaultManager];\n    NSMutableArray<NSDictionary *> *directoriesModificationDates = [[NSMutableArray alloc] init];\n    \n    // Message delegate\n    if ([delegate respondsToSelector:@selector(zipArchiveWillUnzipArchiveAtPath:zipInfo:)]) {\n        [delegate zipArchiveWillUnzipArchiveAtPath:path zipInfo:globalInfo];\n    }\n    if ([delegate respondsToSelector:@selector(zipArchiveProgressEvent:total:)]) {\n        [delegate zipArchiveProgressEvent:currentPosition total:fileSize];\n    }\n    \n    NSInteger currentFileNumber = -1;\n    NSError *unzippingError;\n    do {\n        currentFileNumber++;\n        if (ret == MZ_END_OF_LIST) {\n            break;\n        }\n        @autoreleasepool {\n            if (password.length == 0) {\n                ret = unzOpenCurrentFile(zip);\n            } else {\n                ret = unzOpenCurrentFilePassword(zip, [password cStringUsingEncoding:NSUTF8StringEncoding]);\n            }\n            \n            if (ret != UNZ_OK) {\n                unzippingError = [NSError errorWithDomain:@\"SSZipArchiveErrorDomain\" code:SSZipArchiveErrorCodeFailedOpenFileInZip userInfo:@{NSLocalizedDescriptionKey: @\"failed to open file in zip file\"}];\n                success = NO;\n                break;\n            }\n            \n            // Reading data and write to file\n            unz_file_info fileInfo;\n            memset(&fileInfo, 0, sizeof(unz_file_info));\n            \n            ret = unzGetCurrentFileInfo(zip, &fileInfo, NULL, 0, NULL, 0, NULL, 0);\n            if (ret != UNZ_OK) {\n                unzippingError = [NSError errorWithDomain:@\"SSZipArchiveErrorDomain\" code:SSZipArchiveErrorCodeFileInfoNotLoadable userInfo:@{NSLocalizedDescriptionKey: @\"failed to retrieve info for file\"}];\n                success = NO;\n                unzCloseCurrentFile(zip);\n                break;\n            }\n            \n            currentPosition += fileInfo.compressed_size;\n            \n            // Message delegate\n            if ([delegate respondsToSelector:@selector(zipArchiveShouldUnzipFileAtIndex:totalFiles:archivePath:fileInfo:)]) {\n                if (![delegate zipArchiveShouldUnzipFileAtIndex:currentFileNumber\n                                                     totalFiles:(NSInteger)globalInfo.number_entry\n                                                    archivePath:path\n                                                       fileInfo:fileInfo]) {\n                    success = NO;\n                    canceled = YES;\n                    break;\n                }\n            }\n            if ([delegate respondsToSelector:@selector(zipArchiveWillUnzipFileAtIndex:totalFiles:archivePath:fileInfo:)]) {\n                [delegate zipArchiveWillUnzipFileAtIndex:currentFileNumber totalFiles:(NSInteger)globalInfo.number_entry\n                                             archivePath:path fileInfo:fileInfo];\n            }\n            if ([delegate respondsToSelector:@selector(zipArchiveProgressEvent:total:)]) {\n                [delegate zipArchiveProgressEvent:(NSInteger)currentPosition total:(NSInteger)fileSize];\n            }\n            \n            char *filename = (char *)malloc(fileInfo.size_filename + 1);\n            if (filename == NULL)\n            {\n                success = NO;\n                break;\n            }\n            \n            unzGetCurrentFileInfo(zip, &fileInfo, filename, fileInfo.size_filename + 1, NULL, 0, NULL, 0);\n            filename[fileInfo.size_filename] = '\\0';\n            \n            BOOL fileIsSymbolicLink = _fileIsSymbolicLink(&fileInfo);\n            \n            NSString * strPath = [SSZipArchive _filenameStringWithCString:filename\n                                                          version_made_by:fileInfo.version\n                                                     general_purpose_flag:fileInfo.flag\n                                                                     size:fileInfo.size_filename];\n            if ([strPath hasPrefix:@\"__MACOSX/\"]) {\n                // ignoring resource forks: https://superuser.com/questions/104500/what-is-macosx-folder\n                unzCloseCurrentFile(zip);\n                ret = unzGoToNextFile(zip);\n                free(filename);\n                continue;\n            }\n            \n            // Check if it contains directory\n            BOOL isDirectory = NO;\n            if (filename[fileInfo.size_filename-1] == '/' || filename[fileInfo.size_filename-1] == '\\\\') {\n                isDirectory = YES;\n            }\n            free(filename);\n            \n            // Sanitize paths in the file name.\n            strPath = [strPath _sanitizedPath];\n            if (!strPath.length) {\n                // if filename data is unsalvageable, we default to currentFileNumber\n                strPath = @(currentFileNumber).stringValue;\n            }\n            \n            NSString *fullPath = [destination stringByAppendingPathComponent:strPath];\n            NSError *err = nil;\n            NSDictionary *directoryAttr;\n            if (preserveAttributes) {\n                NSDate *modDate = [[self class] _dateWithMSDOSFormat:(UInt32)fileInfo.mz_dos_date];\n                directoryAttr = @{NSFileCreationDate: modDate, NSFileModificationDate: modDate};\n                [directoriesModificationDates addObject: @{@\"path\": fullPath, @\"modDate\": modDate}];\n            }\n            if (isDirectory) {\n                [fileManager createDirectoryAtPath:fullPath withIntermediateDirectories:YES attributes:directoryAttr error:&err];\n            } else {\n                [fileManager createDirectoryAtPath:fullPath.stringByDeletingLastPathComponent withIntermediateDirectories:YES attributes:directoryAttr error:&err];\n            }\n            if (err != nil) {\n                if ([err.domain isEqualToString:NSCocoaErrorDomain] &&\n                    err.code == 640) {\n                    unzippingError = err;\n                    unzCloseCurrentFile(zip);\n                    success = NO;\n                    break;\n                }\n                NSLog(@\"[SSZipArchive] Error: %@\", err.localizedDescription);\n            }\n            \n            if ([fileManager fileExistsAtPath:fullPath] && !isDirectory && !overwrite) {\n                //FIXME: couldBe CRC Check?\n                unzCloseCurrentFile(zip);\n                ret = unzGoToNextFile(zip);\n                continue;\n            }\n            \n            if (isDirectory && !fileIsSymbolicLink) {\n                // nothing to read/write for a directory\n            } else if (!fileIsSymbolicLink) {\n                // ensure we are not creating stale file entries\n                int readBytes = unzReadCurrentFile(zip, buffer, 4096);\n                if (readBytes >= 0) {\n                    FILE *fp = fopen(fullPath.fileSystemRepresentation, \"wb\");\n                    while (fp) {\n                        if (readBytes > 0) {\n                            if (0 == fwrite(buffer, readBytes, 1, fp)) {\n                                if (ferror(fp)) {\n                                    NSString *message = [NSString stringWithFormat:@\"Failed to write file (check your free space)\"];\n                                    NSLog(@\"[SSZipArchive] %@\", message);\n                                    success = NO;\n                                    unzippingError = [NSError errorWithDomain:@\"SSZipArchiveErrorDomain\" code:SSZipArchiveErrorCodeFailedToWriteFile userInfo:@{NSLocalizedDescriptionKey: message}];\n                                    break;\n                                }\n                            }\n                        } else {\n                            break;\n                        }\n                        readBytes = unzReadCurrentFile(zip, buffer, 4096);\n                        if (readBytes < 0) {\n                            // Let's assume error Z_DATA_ERROR is caused by an invalid password\n                            // Let's assume other errors are caused by Content Not Readable\n                            success = NO;\n                        }\n                    }\n                    \n                    if (fp) {\n                        fclose(fp);\n                        \n                        if (nestedZipLevel\n                            && [fullPath.pathExtension.lowercaseString isEqualToString:@\"zip\"]\n                            && [self unzipFileAtPath:fullPath\n                                       toDestination:fullPath.stringByDeletingLastPathComponent\n                                  preserveAttributes:preserveAttributes\n                                           overwrite:overwrite\n                                 symlinksValidWithin:symlinksValidWithin\n                                      nestedZipLevel:nestedZipLevel - 1\n                                            password:password\n                                               error:nil\n                                            delegate:nil\n                                     progressHandler:nil\n                                   completionHandler:nil]) {\n                            [directoriesModificationDates removeLastObject];\n                            [[NSFileManager defaultManager] removeItemAtPath:fullPath error:nil];\n                        } else if (preserveAttributes) {\n                            \n                            // Set the original datetime property\n                            if (fileInfo.mz_dos_date != 0) {\n                                NSDate *orgDate = [[self class] _dateWithMSDOSFormat:(UInt32)fileInfo.mz_dos_date];\n                                NSDictionary *attr = @{NSFileModificationDate: orgDate};\n                                \n                                if (attr) {\n                                    if (![fileManager setAttributes:attr ofItemAtPath:fullPath error:nil]) {\n                                        // Can't set attributes\n                                        NSLog(@\"[SSZipArchive] Failed to set attributes - whilst setting modification date\");\n                                    }\n                                }\n                            }\n                            \n                            // Set the original permissions on the file (+read/write to solve #293)\n                            uLong permissions = fileInfo.external_fa >> 16 | 0b110000000;\n                            if (permissions != 0) {\n                                // Store it into a NSNumber\n                                NSNumber *permissionsValue = @(permissions);\n                                \n                                // Retrieve any existing attributes\n                                NSMutableDictionary *attrs = [[NSMutableDictionary alloc] initWithDictionary:[fileManager attributesOfItemAtPath:fullPath error:nil]];\n                                \n                                // Set the value in the attributes dict\n                                [attrs setObject:permissionsValue forKey:NSFilePosixPermissions];\n                                \n                                // Update attributes\n                                if (![fileManager setAttributes:attrs ofItemAtPath:fullPath error:nil]) {\n                                    // Unable to set the permissions attribute\n                                    NSLog(@\"[SSZipArchive] Failed to set attributes - whilst setting permissions\");\n                                }\n                            }\n                        }\n                    }\n                    else\n                    {\n                        // if we couldn't open file descriptor we can validate global errno to see the reason\n                        int errnoSave = errno;\n                        BOOL isSeriousError = NO;\n                        switch (errnoSave) {\n                            case EISDIR:\n                                // Is a directory\n                                // assumed case\n                                break;\n                                \n                            case ENOSPC:\n                            case EMFILE:\n                                // No space left on device\n                                //  or\n                                // Too many open files\n                                isSeriousError = YES;\n                                break;\n                                \n                            default:\n                                // ignore case\n                                // Just log the error\n                            {\n                                NSError *errorObject = [NSError errorWithDomain:NSPOSIXErrorDomain\n                                                                           code:errnoSave\n                                                                       userInfo:nil];\n                                NSLog(@\"[SSZipArchive] Failed to open file on unzipping.(%@)\", errorObject);\n                            }\n                                break;\n                        }\n                        \n                        if (isSeriousError) {\n                            // serious case\n                            unzippingError = [NSError errorWithDomain:NSPOSIXErrorDomain\n                                                                 code:errnoSave\n                                                             userInfo:nil];\n                            unzCloseCurrentFile(zip);\n                            // Log the error\n                            NSLog(@\"[SSZipArchive] Failed to open file on unzipping.(%@)\", unzippingError);\n\n                            // Break unzipping\n                            success = NO;\n                            break;\n                        }\n                    }\n                } else {\n                    // Let's assume error Z_DATA_ERROR is caused by an invalid password\n                    // Let's assume other errors are caused by Content Not Readable\n                    success = NO;\n                    break;\n                }\n            }\n            else\n            {\n                // Assemble the path for the symbolic link\n                NSMutableString *destinationPath = [NSMutableString string];\n                int bytesRead = 0;\n                while ((bytesRead = unzReadCurrentFile(zip, buffer, 4096)) > 0)\n                {\n                    buffer[bytesRead] = 0;\n                    [destinationPath appendString:@((const char *)buffer)];\n                }\n                if (bytesRead < 0) {\n                    // Let's assume error Z_DATA_ERROR is caused by an invalid password\n                    // Let's assume other errors are caused by Content Not Readable\n                    success = NO;\n                    break;\n                }\n                \n                // compose symlink full path\n                NSString *symlinkFullDestinationPath = destinationPath;\n                if (![symlinkFullDestinationPath isAbsolutePath]) {\n                    symlinkFullDestinationPath = [[fullPath stringByDeletingLastPathComponent] stringByAppendingPathComponent:destinationPath];\n                }\n                \n                if (symlinksValidWithin != nil && [symlinkFullDestinationPath _escapesTargetDirectory: symlinksValidWithin]) {\n                    NSString *message = [NSString stringWithFormat:@\"Symlink escapes target directory \\\"~%@ -> %@\\\"\", strPath, destinationPath];\n                    NSLog(@\"[SSZipArchive] %@\", message);\n                    success = NO;\n                    unzippingError = [NSError errorWithDomain:SSZipArchiveErrorDomain code:SSZipArchiveErrorCodeSymlinkEscapesTargetDirectory userInfo:@{NSLocalizedDescriptionKey: message}];\n                } else {\n                    // Check if the symlink exists and delete it if we're overwriting\n                    if (overwrite)\n                    {\n                        if ([fileManager fileExistsAtPath:fullPath])\n                        {\n                            NSError *localError = nil;\n                            BOOL removeSuccess = [fileManager removeItemAtPath:fullPath error:&localError];\n                            if (!removeSuccess)\n                            {\n                                NSString *message = [NSString stringWithFormat:@\"Failed to delete existing symbolic link at \\\"%@\\\"\", localError.localizedDescription];\n                                NSLog(@\"[SSZipArchive] %@\", message);\n                                success = NO;\n                                unzippingError = [NSError errorWithDomain:SSZipArchiveErrorDomain code:localError.code userInfo:@{NSLocalizedDescriptionKey: message}];\n                            }\n                        }\n                    }\n                    \n                    // Create the symbolic link (making sure it stays relative if it was relative before)\n                    int symlinkError = symlink([destinationPath cStringUsingEncoding:NSUTF8StringEncoding],\n                                               [fullPath cStringUsingEncoding:NSUTF8StringEncoding]);\n                    \n                    if (symlinkError != 0)\n                    {\n                        // Bubble the error up to the completion handler\n                        NSString *message = [NSString stringWithFormat:@\"Failed to create symbolic link at \\\"%@\\\" to \\\"%@\\\" - symlink() error code: %d\", fullPath, destinationPath, errno];\n                        NSLog(@\"[SSZipArchive] %@\", message);\n                        success = NO;\n                        unzippingError = [NSError errorWithDomain:NSPOSIXErrorDomain code:symlinkError userInfo:@{NSLocalizedDescriptionKey: message}];\n                    }\n                }\n            }\n            \n            crc_ret = unzCloseCurrentFile(zip);\n            if (crc_ret == MZ_CRC_ERROR) {\n                // CRC ERROR\n                success = NO;\n                break;\n            }\n            ret = unzGoToNextFile(zip);\n            \n            // Message delegate\n            if ([delegate respondsToSelector:@selector(zipArchiveDidUnzipFileAtIndex:totalFiles:archivePath:fileInfo:)]) {\n                [delegate zipArchiveDidUnzipFileAtIndex:currentFileNumber totalFiles:(NSInteger)globalInfo.number_entry\n                                            archivePath:path fileInfo:fileInfo];\n            } else if ([delegate respondsToSelector: @selector(zipArchiveDidUnzipFileAtIndex:totalFiles:archivePath:unzippedFilePath:)]) {\n                [delegate zipArchiveDidUnzipFileAtIndex: currentFileNumber totalFiles: (NSInteger)globalInfo.number_entry\n                                            archivePath:path unzippedFilePath: fullPath];\n            }\n            \n            if (progressHandler)\n            {\n                progressHandler(strPath, fileInfo, currentFileNumber, globalInfo.number_entry);\n            }\n        }\n    } while (ret == UNZ_OK && success);\n    \n    // Close\n    unzClose(zip);\n    \n    // The process of decompressing the .zip archive causes the modification times on the folders\n    // to be set to the present time. So, when we are done, they need to be explicitly set.\n    // set the modification date on all of the directories.\n    if (success && preserveAttributes) {\n        NSError * err = nil;\n        for (NSDictionary * d in directoriesModificationDates) {\n            if (![[NSFileManager defaultManager] setAttributes:@{NSFileModificationDate: [d objectForKey:@\"modDate\"]} ofItemAtPath:[d objectForKey:@\"path\"] error:&err]) {\n                NSLog(@\"[SSZipArchive] Set attributes failed for directory: %@.\", [d objectForKey:@\"path\"]);\n            }\n            if (err) {\n                NSLog(@\"[SSZipArchive] Error setting directory file modification date attribute: %@\", err.localizedDescription);\n            }\n        }\n    }\n    \n    // Message delegate\n    if (success && [delegate respondsToSelector:@selector(zipArchiveDidUnzipArchiveAtPath:zipInfo:unzippedPath:)]) {\n        [delegate zipArchiveDidUnzipArchiveAtPath:path zipInfo:globalInfo unzippedPath:destination];\n    }\n    // final progress event = 100%\n    if (!canceled && [delegate respondsToSelector:@selector(zipArchiveProgressEvent:total:)]) {\n        [delegate zipArchiveProgressEvent:fileSize total:fileSize];\n    }\n    \n    NSError *retErr = nil;\n    if (crc_ret == MZ_CRC_ERROR)\n    {\n        NSDictionary *userInfo = @{NSLocalizedDescriptionKey: @\"crc check failed for file\"};\n        retErr = [NSError errorWithDomain:SSZipArchiveErrorDomain code:SSZipArchiveErrorCodeFileInfoNotLoadable userInfo:userInfo];\n    }\n    \n    if (error) {\n        if (unzippingError) {\n            *error = unzippingError;\n        }\n        else {\n            *error = retErr;\n        }\n    }\n    if (completionHandler)\n    {\n        if (unzippingError) {\n            completionHandler(path, success, unzippingError);\n        }\n        else\n        {\n            completionHandler(path, success, retErr);\n        }\n    }\n    return success;\n}\n\n#pragma mark - Zipping\n+ (BOOL)createZipFileAtPath:(NSString *)path withFilesAtPaths:(NSArray<NSString *> *)paths\n{\n    return [SSZipArchive createZipFileAtPath:path withFilesAtPaths:paths withPassword:nil];\n}\n+ (BOOL)createZipFileAtPath:(NSString *)path withContentsOfDirectory:(NSString *)directoryPath {\n    return [SSZipArchive createZipFileAtPath:path withContentsOfDirectory:directoryPath withPassword:nil];\n}\n\n+ (BOOL)createZipFileAtPath:(NSString *)path withContentsOfDirectory:(NSString *)directoryPath keepParentDirectory:(BOOL)keepParentDirectory {\n    return [SSZipArchive createZipFileAtPath:path withContentsOfDirectory:directoryPath keepParentDirectory:keepParentDirectory withPassword:nil];\n}\n\n+ (BOOL)createZipFileAtPath:(NSString *)path withFilesAtPaths:(NSArray<NSString *> *)paths withPassword:(NSString *)password {\n    return [self createZipFileAtPath:path withFilesAtPaths:paths withPassword:password progressHandler:nil];\n}\n\n+ (BOOL)createZipFileAtPath:(NSString *)path withFilesAtPaths:(NSArray<NSString *> *)paths withPassword:(NSString *)password progressHandler:(void(^ _Nullable)(NSUInteger entryNumber, NSUInteger total))progressHandler\n{\n    SSZipArchive *zipArchive = [[SSZipArchive alloc] initWithPath:path];\n    BOOL success = [zipArchive open];\n    if (success) {\n        NSUInteger total = paths.count, complete = 0;\n        for (NSString *filePath in paths) {\n            success &= [zipArchive writeFile:filePath withPassword:password];\n            if (progressHandler) {\n                complete++;\n                progressHandler(complete, total);\n            }\n        }\n        success &= [zipArchive close];\n    }\n    return success;\n}\n\n+ (BOOL)createZipFileAtPath:(NSString *)path withContentsOfDirectory:(NSString *)directoryPath withPassword:(nullable NSString *)password {\n    return [SSZipArchive createZipFileAtPath:path withContentsOfDirectory:directoryPath keepParentDirectory:NO withPassword:password];\n}\n\n\n+ (BOOL)createZipFileAtPath:(NSString *)path withContentsOfDirectory:(NSString *)directoryPath keepParentDirectory:(BOOL)keepParentDirectory withPassword:(nullable NSString *)password {\n    return [SSZipArchive createZipFileAtPath:path\n                     withContentsOfDirectory:directoryPath\n                         keepParentDirectory:keepParentDirectory\n                                withPassword:password\n                          andProgressHandler:nil\n            ];\n}\n\n+ (BOOL)createZipFileAtPath:(NSString *)path\n    withContentsOfDirectory:(NSString *)directoryPath\n        keepParentDirectory:(BOOL)keepParentDirectory\n               withPassword:(nullable NSString *)password\n         andProgressHandler:(void(^ _Nullable)(NSUInteger entryNumber, NSUInteger total))progressHandler {\n    return [self createZipFileAtPath:path withContentsOfDirectory:directoryPath keepParentDirectory:keepParentDirectory compressionLevel:Z_DEFAULT_COMPRESSION password:password AES:YES progressHandler:progressHandler];\n}\n\n+ (BOOL)createZipFileAtPath:(NSString *)path\n    withContentsOfDirectory:(NSString *)directoryPath\n        keepParentDirectory:(BOOL)keepParentDirectory\n           compressionLevel:(int)compressionLevel\n                   password:(nullable NSString *)password\n                        AES:(BOOL)aes\n            progressHandler:(void(^ _Nullable)(NSUInteger entryNumber, NSUInteger total))progressHandler {\n    \n    SSZipArchive *zipArchive = [[SSZipArchive alloc] initWithPath:path];\n    BOOL success = [zipArchive open];\n    if (success) {\n        // use a local fileManager (queue/thread compatibility)\n        NSFileManager *fileManager = [[NSFileManager alloc] init];\n        NSDirectoryEnumerator *dirEnumerator = [fileManager enumeratorAtPath:directoryPath];\n        NSArray<NSString *> *allObjects = dirEnumerator.allObjects;\n        NSUInteger total = allObjects.count, complete = 0;\n        if (keepParentDirectory && !total) {\n            allObjects = @[@\"\"];\n            total = 1;\n        }\n        for (__strong NSString *fileName in allObjects) {\n            NSString *fullFilePath = [directoryPath stringByAppendingPathComponent:fileName];\n            if ([fullFilePath isEqualToString:path]) {\n                NSLog(@\"[SSZipArchive] the archive path and the file path: %@ are the same, which is forbidden.\", fullFilePath);\n                continue;\n            }\n\t\t\t\n            if (keepParentDirectory) {\n                fileName = [directoryPath.lastPathComponent stringByAppendingPathComponent:fileName];\n            }\n            \n            BOOL isDir;\n            [fileManager fileExistsAtPath:fullFilePath isDirectory:&isDir];\n            if (!isDir) {\n                // file\n                success &= [zipArchive writeFileAtPath:fullFilePath withFileName:fileName compressionLevel:compressionLevel password:password AES:aes];\n            } else {\n                // directory\n                if (![fileManager enumeratorAtPath:fullFilePath].nextObject) {\n                    // empty directory\n                    success &= [zipArchive writeFolderAtPath:fullFilePath withFolderName:fileName withPassword:password];\n                }\n            }\n            if (progressHandler) {\n                complete++;\n                progressHandler(complete, total);\n            }\n        }\n        success &= [zipArchive close];\n    }\n    return success;\n}\n\n+ (BOOL)createZipFileAtPath:(NSString *)path withFilesAtPaths:(NSArray<NSString *> *)paths withPassword:(nullable NSString *)password keepSymlinks:(BOOL)keeplinks {\n    if (!keeplinks) {\n        return [SSZipArchive createZipFileAtPath:path withFilesAtPaths:paths withPassword:password];\n    } else {\n        SSZipArchive *zipArchive = [[SSZipArchive alloc] initWithPath:path];\n        BOOL success = [zipArchive open];\n        if (success) {\n            for (NSString *filePath in paths) {\n                //is symlink\n                if (mz_os_is_symlink(filePath.fileSystemRepresentation) == MZ_OK) {\n                    success &= [zipArchive writeSymlinkFileAtPath:filePath withFileName:nil compressionLevel:Z_DEFAULT_COMPRESSION password:password AES:YES];\n                } else {\n                    success &= [zipArchive writeFile:filePath withPassword:password];\n                }                  \n            }\n            success &= [zipArchive close];\n        }\n        return success;\n    }    \n}\n\n+ (BOOL)createZipFileAtPath:(NSString *)path\n    withContentsOfDirectory:(NSString *)directoryPath\n        keepParentDirectory:(BOOL)keepParentDirectory\n           compressionLevel:(int)compressionLevel\n                   password:(nullable NSString *)password\n                        AES:(BOOL)aes\n            progressHandler:(void(^ _Nullable)(NSUInteger entryNumber, NSUInteger total))progressHandler\n               keepSymlinks:(BOOL)keeplinks {\n    if (!keeplinks) {\n        return [SSZipArchive createZipFileAtPath:path\n                         withContentsOfDirectory:directoryPath\n                             keepParentDirectory:keepParentDirectory\n                                compressionLevel:compressionLevel\n                                        password:password\n                                             AES:aes\n                                 progressHandler:progressHandler];\n    } else {\n        SSZipArchive *zipArchive = [[SSZipArchive alloc] initWithPath:path];\n        BOOL success = [zipArchive open];\n        if (success) {\n            // use a local fileManager (queue/thread compatibility)\n            NSFileManager *fileManager = [[NSFileManager alloc] init];\n            NSDirectoryEnumerator *dirEnumerator = [fileManager enumeratorAtPath:directoryPath];\n            NSArray<NSString *> *allObjects = dirEnumerator.allObjects;\n            NSUInteger total = allObjects.count, complete = 0;\n            if (keepParentDirectory && !total) {\n                allObjects = @[@\"\"];\n                total = 1;\n            }\n            for (__strong NSString *fileName in allObjects) {\n                NSString *fullFilePath = [directoryPath stringByAppendingPathComponent:fileName];\n                \n                if (keepParentDirectory) {\n                    fileName = [directoryPath.lastPathComponent stringByAppendingPathComponent:fileName];\n                }\n                //is symlink\n                BOOL isSymlink = NO;\n                if (mz_os_is_symlink(fullFilePath.fileSystemRepresentation) == MZ_OK)\n                    isSymlink = YES;\n                BOOL isDir;\n                [fileManager fileExistsAtPath:fullFilePath isDirectory:&isDir];\n                if (!isDir || isSymlink) {\n                    // file or symlink\n                    if (!isSymlink) {\n                        success &= [zipArchive writeFileAtPath:fullFilePath withFileName:fileName compressionLevel:compressionLevel password:password AES:aes];\n                    } else {\n                        success &= [zipArchive writeSymlinkFileAtPath:fullFilePath withFileName:fileName compressionLevel:compressionLevel password:password AES:aes];\n                    }                  \n                } else {\n                    // directory\n                    if (![fileManager enumeratorAtPath:fullFilePath].nextObject) {\n                        // empty directory\n                        success &= [zipArchive writeFolderAtPath:fullFilePath withFolderName:fileName withPassword:password];\n                    }\n                }\n                if (progressHandler) {\n                    complete++;\n                    progressHandler(complete, total);\n                }\n            }\n            success &= [zipArchive close];\n        }\n        return success;\n    }    \n}\n\n- (BOOL)writeSymlinkFileAtPath:(NSString *)path withFileName:(nullable NSString *)fileName compressionLevel:(int)compressionLevel password:(nullable NSString *)password AES:(BOOL)aes\n{\n    NSAssert((_zip != NULL), @\"Attempting to write to an archive which was never opened\");\n    //read symlink\n    char link_path[1024];\n    int32_t err = MZ_OK;\n    err = mz_os_read_symlink(path.fileSystemRepresentation, link_path, sizeof(link_path));\n    if (err != MZ_OK) {\n        NSLog(@\"[SSZipArchive] Failed to read sylink\");\n        return NO;\n    }\n\n    if (!fileName) {\n        fileName = path.lastPathComponent;\n    }\n    \n    zip_fileinfo zipInfo = {};    \n    [SSZipArchive zipInfo:&zipInfo setAttributesOfItemAtPath:path];\n    \n    //unpdate zipInfo.external_fa\n    uint32_t target_attrib = 0;\n    uint32_t src_attrib = 0;\n    uint32_t src_sys = 0;\n    mz_os_get_file_attribs(path.fileSystemRepresentation, &src_attrib);\n    src_sys = MZ_HOST_SYSTEM(MZ_VERSION_MADEBY);\n\n    if ((src_sys != MZ_HOST_SYSTEM_MSDOS) && (src_sys != MZ_HOST_SYSTEM_WINDOWS_NTFS)) {\n        /* High bytes are OS specific attributes, low byte is always DOS attributes */\n        if (mz_zip_attrib_convert(src_sys, src_attrib, MZ_HOST_SYSTEM_MSDOS, &target_attrib) == MZ_OK)\n            zipInfo.external_fa = target_attrib;\n        zipInfo.external_fa |= (src_attrib << 16);\n    } else {\n        zipInfo.external_fa = src_attrib;\n    }\n\n    uint16_t version_madeby = 3 << 8;//UNIX\n    int error = zipOpenNewFileInZip5(_zip, fileName.fileSystemRepresentation, &zipInfo, NULL, 0, NULL, 0, NULL, Z_DEFLATED, compressionLevel, 0, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, password.UTF8String, 0, aes, version_madeby, 0, 0);\n    zipWriteInFileInZip(_zip, link_path, (uint32_t)strlen(link_path));\n    zipCloseFileInZip(_zip);\n    return error == ZIP_OK;\n}\n\n// disabling `init` because designated initializer is `initWithPath:`\n- (instancetype)init { @throw nil; }\n\n// designated initializer\n- (instancetype)initWithPath:(NSString *)path\n{\n    if ((self = [super init])) {\n        _path = [path copy];\n    }\n    return self;\n}\n\n\n- (BOOL)open\n{\n    NSAssert((_zip == NULL), @\"Attempting to open an archive which is already open\");\n    _zip = zipOpen(_path.fileSystemRepresentation, APPEND_STATUS_CREATE);\n    return (NULL != _zip);\n}\n\n- (BOOL)openForAppending\n{\n    NSAssert((_zip == NULL), @\"Attempting to open an archive which is already open\");\n    _zip = zipOpen(_path.fileSystemRepresentation, APPEND_STATUS_ADDINZIP);\n    return (NULL != _zip);\n}\n\n- (BOOL)writeFolderAtPath:(NSString *)path withFolderName:(NSString *)folderName withPassword:(nullable NSString *)password\n{\n    NSAssert((_zip != NULL), @\"Attempting to write to an archive which was never opened\");\n    \n    zip_fileinfo zipInfo = {};\n    \n    [SSZipArchive zipInfo:&zipInfo setAttributesOfItemAtPath:path];\n    \n    int error = _zipOpenEntry(_zip, [folderName stringByAppendingString:@\"/\"], &zipInfo, Z_NO_COMPRESSION, password, NO);\n    const void *buffer = NULL;\n    zipWriteInFileInZip(_zip, buffer, 0);\n    zipCloseFileInZip(_zip);\n    return error == ZIP_OK;\n}\n\n- (BOOL)writeFile:(NSString *)path withPassword:(nullable NSString *)password\n{\n    return [self writeFileAtPath:path withFileName:nil withPassword:password];\n}\n\n- (BOOL)writeFileAtPath:(NSString *)path withFileName:(nullable NSString *)fileName withPassword:(nullable NSString *)password\n{\n    return [self writeFileAtPath:path withFileName:fileName compressionLevel:Z_DEFAULT_COMPRESSION password:password AES:YES];\n}\n\n// supports writing files with logical folder/directory structure\n// *path* is the absolute path of the file that will be compressed\n// *fileName* is the relative name of the file how it is stored within the zip e.g. /folder/subfolder/text1.txt\n- (BOOL)writeFileAtPath:(NSString *)path withFileName:(nullable NSString *)fileName compressionLevel:(int)compressionLevel password:(nullable NSString *)password AES:(BOOL)aes\n{\n    NSAssert((_zip != NULL), @\"Attempting to write to an archive which was never opened\");\n    \n    FILE *input = fopen(path.fileSystemRepresentation, \"r\");\n    if (NULL == input) {\n        return NO;\n    }\n    \n    if (!fileName) {\n        fileName = path.lastPathComponent;\n    }\n    \n    zip_fileinfo zipInfo = {};\n    \n    [SSZipArchive zipInfo:&zipInfo setAttributesOfItemAtPath:path];\n    \n    void *buffer = malloc(CHUNK);\n    if (buffer == NULL)\n    {\n        fclose(input);\n        return NO;\n    }\n    \n    int error = _zipOpenEntry(_zip, fileName, &zipInfo, compressionLevel, password, aes);\n    \n    while (!feof(input) && !ferror(input))\n    {\n        unsigned int len = (unsigned int) fread(buffer, 1, CHUNK, input);\n        zipWriteInFileInZip(_zip, buffer, len);\n    }\n    \n    zipCloseFileInZip(_zip);\n    free(buffer);\n    fclose(input);\n    return error == ZIP_OK;\n}\n\n- (BOOL)writeData:(NSData *)data filename:(nullable NSString *)filename withPassword:(nullable NSString *)password\n{\n    return [self writeData:data filename:filename compressionLevel:Z_DEFAULT_COMPRESSION password:password AES:YES];\n}\n\n- (BOOL)writeData:(NSData *)data filename:(nullable NSString *)filename compressionLevel:(int)compressionLevel password:(nullable NSString *)password AES:(BOOL)aes\n{\n    if (!_zip) {\n        return NO;\n    }\n    if (!data) {\n        return NO;\n    }\n    zip_fileinfo zipInfo = {};\n    [SSZipArchive zipInfo:&zipInfo setDate:[NSDate date]];\n    \n    int error = _zipOpenEntry(_zip, filename, &zipInfo, compressionLevel, password, aes);\n    \n    zipWriteInFileInZip(_zip, data.bytes, (unsigned int)data.length);\n    \n    zipCloseFileInZip(_zip);\n    return error == ZIP_OK;\n}\n\n- (BOOL)close\n{\n    NSAssert((_zip != NULL), @\"[SSZipArchive] Attempting to close an archive which was never opened\");\n    int error = zipClose(_zip, NULL);\n    _zip = nil;\n    return error == ZIP_OK;\n}\n\n#pragma mark - Private\n\n+ (NSString *)_filenameStringWithCString:(const char *)filename\n                         version_made_by:(uint16_t)version_made_by\n                    general_purpose_flag:(uint16_t)flag\n                                    size:(uint16_t)size_filename {\n    \n    // Respect Language encoding flag only reading filename as UTF-8 when this is set\n    // when file entry created on dos system.\n    //\n    // https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT\n    //   Bit 11: Language encoding flag (EFS).  If this bit is set,\n    //           the filename and comment fields for this file\n    //           MUST be encoded using UTF-8. (see APPENDIX D)\n    uint16_t made_by = version_made_by >> 8;\n    BOOL made_on_dos = made_by == 0;\n    BOOL languageEncoding = (flag & (1 << 11)) != 0;\n    if (!languageEncoding && made_on_dos) {\n        // APPNOTE.TXT D.1:\n        //   D.2 If general purpose bit 11 is unset, the file name and comment should conform\n        //   to the original ZIP character encoding.  If general purpose bit 11 is set, the\n        //   filename and comment must support The Unicode Standard, Version 4.1.0 or\n        //   greater using the character encoding form defined by the UTF-8 storage\n        //   specification.  The Unicode Standard is published by the The Unicode\n        //   Consortium (www.unicode.org).  UTF-8 encoded data stored within ZIP files\n        //   is expected to not include a byte order mark (BOM).\n        \n        //  Code Page 437 corresponds to kCFStringEncodingDOSLatinUS\n        NSStringEncoding encoding = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingDOSLatinUS);\n        NSString* strPath = [NSString stringWithCString:filename encoding:encoding];\n        if (strPath) {\n            return strPath;\n        }\n    }\n    \n    // attempting unicode encoding\n    NSString * strPath = @(filename);\n    if (strPath) {\n        return strPath;\n    }\n    \n    // if filename is non-unicode, detect and transform Encoding\n    NSData *data = [NSData dataWithBytes:(const void *)filename length:sizeof(unsigned char) * size_filename];\n// Testing availability of @available (https://stackoverflow.com/a/46927445/1033581)\n#if __clang_major__ < 9\n    // Xcode 8-\n    if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber10_9_2) {\n#else\n    // Xcode 9+\n    if (@available(macOS 10.10, iOS 8.0, watchOS 2.0, tvOS 9.0, *)) {\n#endif\n        // supported encodings are in [NSString availableStringEncodings]\n        [NSString stringEncodingForData:data encodingOptions:nil convertedString:&strPath usedLossyConversion:nil];\n    } else {\n        // fallback to a simple manual detect for macOS 10.9 or older\n        NSArray<NSNumber *> *encodings = @[@(kCFStringEncodingGB_18030_2000), @(kCFStringEncodingShiftJIS)];\n        for (NSNumber *encoding in encodings) {\n            strPath = [NSString stringWithCString:filename encoding:(NSStringEncoding)CFStringConvertEncodingToNSStringEncoding(encoding.unsignedIntValue)];\n            if (strPath) {\n                break;\n            }\n        }\n    }\n    if (strPath) {\n        return strPath;\n    }\n    \n    // if filename encoding is non-detected, we default to something based on data\n    // _hexString is more readable than _base64RFC4648 for debugging unknown encodings\n    strPath = [data _hexString];\n    return strPath;\n}\n\n+ (void)zipInfo:(zip_fileinfo *)zipInfo setAttributesOfItemAtPath:(NSString *)path\n{\n    NSDictionary *attr = [[NSFileManager defaultManager] attributesOfItemAtPath:path error: nil];\n    if (attr)\n    {\n        NSDate *fileDate = (NSDate *)[attr objectForKey:NSFileModificationDate];\n        if (fileDate)\n        {\n            [self zipInfo:zipInfo setDate:fileDate];\n        }\n        \n        // Write permissions into the external attributes, for details on this see here: https://unix.stackexchange.com/a/14727\n        // Get the permissions value from the files attributes\n        NSNumber *permissionsValue = (NSNumber *)[attr objectForKey:NSFilePosixPermissions];\n        if (permissionsValue != nil) {\n            // Get the short value for the permissions\n            short permissionsShort = permissionsValue.shortValue;\n            \n            // Convert this into an octal by adding 010000, 010000 being the flag for a regular file\n            NSInteger permissionsOctal = 0100000 + permissionsShort;\n            \n            // Convert this into a long value\n            uLong permissionsLong = @(permissionsOctal).unsignedLongValue;\n            \n            // Store this into the external file attributes once it has been shifted 16 places left to form part of the second from last byte\n            \n            // Casted back to an unsigned int to match type of external_fa in minizip\n            zipInfo->external_fa = (unsigned int)(permissionsLong << 16L);\n        }\n    }\n}\n\n+ (void)zipInfo:(zip_fileinfo *)zipInfo setDate:(NSDate *)date\n{\n    NSCalendar *currentCalendar = SSZipArchive._gregorian;\n    NSCalendarUnit flags = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond;\n    NSDateComponents *components = [currentCalendar components:flags fromDate:date];\n    struct tm tmz_date;\n    tmz_date.tm_sec = (unsigned int)components.second;\n    tmz_date.tm_min = (unsigned int)components.minute;\n    tmz_date.tm_hour = (unsigned int)components.hour;\n    tmz_date.tm_mday = (unsigned int)components.day;\n    // ISO/IEC 9899 struct tm is 0-indexed for January but NSDateComponents for gregorianCalendar is 1-indexed for January\n    tmz_date.tm_mon = (unsigned int)components.month - 1;\n    // ISO/IEC 9899 struct tm is 0-indexed for AD 1900 but NSDateComponents for gregorianCalendar is 1-indexed for AD 1\n    tmz_date.tm_year = (unsigned int)components.year - 1900;\n    zipInfo->mz_dos_date = mz_zip_tm_to_dosdate(&tmz_date);\n}\n\n+ (NSCalendar *)_gregorian\n{\n    static NSCalendar *gregorian;\n    static dispatch_once_t onceToken;\n    dispatch_once(&onceToken, ^{\n        gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];\n    });\n    \n    return gregorian;\n}\n\n// Format from http://newsgroups.derkeiler.com/Archive/Comp/comp.os.msdos.programmer/2009-04/msg00060.html\n// Two consecutive words, or a longword, YYYYYYYMMMMDDDDD hhhhhmmmmmmsssss\n// YYYYYYY is years from 1980 = 0\n// sssss is (seconds/2).\n//\n// 3658 = 0011 0110 0101 1000 = 0011011 0010 11000 = 27 2 24 = 2007-02-24\n// 7423 = 0111 0100 0010 0011 - 01110 100001 00011 = 14 33 3 = 14:33:06\n+ (NSDate *)_dateWithMSDOSFormat:(UInt32)msdosDateTime\n{\n    // the whole `_dateWithMSDOSFormat:` method is equivalent but faster than this one line,\n    // essentially because `mktime` is slow:\n    //NSDate *date = [NSDate dateWithTimeIntervalSince1970:dosdate_to_time_t(msdosDateTime)];\n    static const UInt32 kYearMask = 0xFE000000;\n    static const UInt32 kMonthMask = 0x1E00000;\n    static const UInt32 kDayMask = 0x1F0000;\n    static const UInt32 kHourMask = 0xF800;\n    static const UInt32 kMinuteMask = 0x7E0;\n    static const UInt32 kSecondMask = 0x1F;\n    \n    NSAssert(0xFFFFFFFF == (kYearMask | kMonthMask | kDayMask | kHourMask | kMinuteMask | kSecondMask), @\"[SSZipArchive] MSDOS date masks don't add up\");\n    \n    NSDateComponents *components = [[NSDateComponents alloc] init];\n    components.year = 1980 + ((msdosDateTime & kYearMask) >> 25);\n    components.month = (msdosDateTime & kMonthMask) >> 21;\n    components.day = (msdosDateTime & kDayMask) >> 16;\n    components.hour = (msdosDateTime & kHourMask) >> 11;\n    components.minute = (msdosDateTime & kMinuteMask) >> 5;\n    components.second = (msdosDateTime & kSecondMask) * 2;\n    \n    NSDate *date = [self._gregorian dateFromComponents:components];\n    return date;\n}\n\n@end\n\nint _zipOpenEntry(zipFile entry, NSString *name, const zip_fileinfo *zipfi, int level, NSString *password, BOOL aes)\n{\n    // https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT\n    uint16_t made_on_darwin = 19 << 8;\n    //MZ_ZIP_FLAG_UTF8\n    uint16_t flag_base = 1 << 11;\n    return zipOpenNewFileInZip5(entry, name.fileSystemRepresentation, zipfi, NULL, 0, NULL, 0, NULL, Z_DEFLATED, level, 0, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, password.UTF8String, 0, aes, made_on_darwin, flag_base, 1);\n}\n\n#pragma mark - Private tools for file info\n\nBOOL _fileIsSymbolicLink(const unz_file_info *fileInfo)\n{\n    //\n    // Determine whether this is a symbolic link:\n    // - File is stored with 'version made by' value of UNIX (3),\n    //   as per https://www.pkware.com/documents/casestudies/APPNOTE.TXT\n    //   in the upper byte of the version field.\n    // - BSD4.4 st_mode constants are stored in the high 16 bits of the\n    //   external file attributes (defacto standard, verified against libarchive)\n    //\n    // The original constants can be found here:\n    //    https://minnie.tuhs.org/cgi-bin/utree.pl?file=4.4BSD/usr/include/sys/stat.h\n    //\n    const uLong ZipUNIXVersion = 3;\n    const uLong BSD_SFMT = 0170000;\n    const uLong BSD_IFLNK = 0120000;\n    \n    BOOL fileIsSymbolicLink = ((fileInfo->version >> 8) == ZipUNIXVersion) && BSD_IFLNK == (BSD_SFMT & (fileInfo->external_fa >> 16));\n    return fileIsSymbolicLink;\n}\n\n#pragma mark - Private tools for unreadable encodings\n\n@implementation NSData (SSZipArchive)\n\n// `base64EncodedStringWithOptions` uses a base64 alphabet with '+' and '/'.\n// we got those alternatives to make it compatible with filenames: https://en.wikipedia.org/wiki/Base64\n// * modified Base64 encoding for IMAP mailbox names (RFC 3501): uses '+' and ','\n// * modified Base64 for URL and filenames (RFC 4648): uses '-' and '_'\n- (NSString *)_base64RFC4648\n{\n    NSString *strName = [self base64EncodedStringWithOptions:0];\n    strName = [strName stringByReplacingOccurrencesOfString:@\"+\" withString:@\"-\"];\n    strName = [strName stringByReplacingOccurrencesOfString:@\"/\" withString:@\"_\"];\n    return strName;\n}\n\n// initWithBytesNoCopy from NSProgrammer, Jan 25 '12: https://stackoverflow.com/a/9009321/1033581\n// hexChars from Peter, Aug 19 '14: https://stackoverflow.com/a/25378464/1033581\n// not implemented as too lengthy: a potential mapping improvement from Moose, Nov 3 '15: https://stackoverflow.com/a/33501154/1033581\n- (NSString *)_hexString\n{\n    const char *hexChars = \"0123456789ABCDEF\";\n    NSUInteger length = self.length;\n    const unsigned char *bytes = self.bytes;\n    char *chars = malloc(length * 2);\n    if (chars == NULL) {\n        // we directly raise an exception instead of using NSAssert to make sure assertion is not disabled as this is irrecoverable\n        [NSException raise:@\"NSInternalInconsistencyException\" format:@\"failed malloc\" arguments:nil];\n        return nil;\n    }\n    char *s = chars;\n    NSUInteger i = length;\n    while (i--) {\n        *s++ = hexChars[*bytes >> 4];\n        *s++ = hexChars[*bytes & 0xF];\n        bytes++;\n    }\n    NSString *str = [[NSString alloc] initWithBytesNoCopy:chars\n                                                   length:length * 2\n                                                 encoding:NSASCIIStringEncoding\n                                             freeWhenDone:YES];\n    return str;\n}\n\n@end\n\n#pragma mark Private tools for security\n\n@implementation NSString (SSZipArchive)\n\n// One implementation alternative would be to use the algorithm found at mz_path_resolve from https://github.com/nmoinvaz/minizip/blob/dev/mz_os.c,\n// but making sure to work with unichar values and not ascii values to avoid breaking Unicode characters containing 2E ('.') or 2F ('/') in their decomposition\n/// Sanitize path traversal characters to prevent directory backtracking. Ignoring these characters mimicks the default behavior of the Unarchiving tool on macOS.\n- (NSString *)_sanitizedPath\n{\n    // Change Windows paths to Unix paths: https://en.wikipedia.org/wiki/Path_(computing)\n    // Possible improvement: only do this if the archive was created on a non-Unix system\n    NSString *strPath = [self stringByReplacingOccurrencesOfString:@\"\\\\\" withString:@\"/\"];\n    \n    // Percent-encode file path (where path is defined by https://tools.ietf.org/html/rfc8089)\n    // The key part is to allow characters \".\" and \"/\" and disallow \"%\".\n    // CharacterSet.urlPathAllowed seems to do the job\n#if (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1090 || __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000 || __WATCH_OS_VERSION_MIN_REQUIRED >= 20000 || __TV_OS_VERSION_MIN_REQUIRED >= 90000)\n    strPath = [strPath stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLPathAllowedCharacterSet];\n#else\n    // Testing availability of @available (https://stackoverflow.com/a/46927445/1033581)\n#if __clang_major__ < 9\n    // Xcode 8-\n    if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber10_8_4) {\n#else\n    // Xcode 9+\n    if (@available(macOS 10.9, iOS 7.0, watchOS 2.0, tvOS 9.0, *)) {\n#endif\n        strPath = [strPath stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLPathAllowedCharacterSet];\n    } else {\n        strPath = [strPath stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];\n    }\n#endif\n    \n    // `NSString.stringByAddingPercentEncodingWithAllowedCharacters:` may theorically fail: https://stackoverflow.com/questions/33558933/\n    // But because we auto-detect encoding using `NSString.stringEncodingForData:encodingOptions:convertedString:usedLossyConversion:`,\n    // we likely already prevent UTF-16, UTF-32 and invalid Unicode in the form of unpaired surrogate chars: https://stackoverflow.com/questions/53043876/\n    // To be on the safe side, we will still perform a guard check.\n    if (strPath == nil) {\n        return nil;\n    }\n    \n    // Add scheme \"file:///\" to support sanitation on names with a colon like \"file:a/../../../usr/bin\"\n    strPath = [@\"file:///\" stringByAppendingString:strPath];\n    \n    // Sanitize path traversal characters to prevent directory backtracking. Ignoring these characters mimicks the default behavior of the Unarchiving tool on macOS.\n    // \"../../../../../../../../../../../tmp/test.txt\" -> \"tmp/test.txt\"\n    // \"a/b/../c.txt\" -> \"a/c.txt\"\n    strPath = [NSURL URLWithString:strPath].standardizedURL.absoluteString;\n    \n    // Remove the \"file:///\" scheme\n    strPath = strPath.length < 8 ? @\"\" : [strPath substringFromIndex:8];\n    \n    // Remove the percent-encoding\n#if (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1090 || __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000 || __WATCH_OS_VERSION_MIN_REQUIRED >= 20000 || __TV_OS_VERSION_MIN_REQUIRED >= 90000)\n    strPath = strPath.stringByRemovingPercentEncoding;\n#else\n    // Testing availability of @available (https://stackoverflow.com/a/46927445/1033581)\n#if __clang_major__ < 9\n    // Xcode 8-\n    if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber10_8_4) {\n#else\n    // Xcode 9+\n    if (@available(macOS 10.9, iOS 7.0, watchOS 2.0, tvOS 9.0, *)) {\n#endif\n        strPath = strPath.stringByRemovingPercentEncoding;\n    } else {\n        strPath = [strPath stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];\n    }\n#endif\n    \n    return strPath;\n}\n\n/// Detects if the path represented in this string is pointing outside of the targetDirectory passed as argument.\n///\n/// Helps detecting and avoiding a security vulnerability described here:\n/// https://nvd.nist.gov/vuln/detail/CVE-2022-36943\n- (BOOL)_escapesTargetDirectory:(NSString *)targetDirectory {\n    NSString *standardizedPath = [[self stringByStandardizingPath] stringByResolvingSymlinksInPath];\n    NSString *standardizedTargetPath = [[targetDirectory stringByStandardizingPath] stringByResolvingSymlinksInPath];\n    \n    NSArray *targetPathComponents = [standardizedTargetPath pathComponents];\n    NSArray *pathComponents = [standardizedPath pathComponents];\n    \n    if (pathComponents.count < targetPathComponents.count) return YES;\n    \n    for (int idx = 0; idx < targetPathComponents.count; idx++) {\n        if (![pathComponents[idx] isEqual: targetPathComponents[idx]]) {\n            return YES;\n        }\n    }\n    \n    return NO;\n}\n\n@end\n"
  },
  {
    "path": "ios/CodePush/SSZipArchive/SSZipCommon.h",
    "content": "#ifndef SSZipCommon\n#define SSZipCommon\n\n// typedefs moved from mz_compat.h to here for public access\n\n/* unz_global_info structure contain global data about the ZIPfile\n These data comes from the end of central dir */\ntypedef struct unz_global_info64_s\n{\n    uint64_t number_entry;          /* total number of entries in the central dir on this disk */\n    uint32_t number_disk_with_CD;   /* number the the disk with central dir, used for spanning ZIP */\n    uint16_t size_comment;          /* size of the global comment of the zipfile */\n} unz_global_info64;\n\n\ntypedef struct unz_global_info_s\n{\n    uint32_t number_entry;          /* total number of entries in the central dir on this disk */\n    uint32_t number_disk_with_CD;   /* number the the disk with central dir, used for spanning ZIP */\n    uint16_t size_comment;          /* size of the global comment of the zipfile */\n} unz_global_info;\n\n/* unz_file_info contain information about a file in the zipfile */\n/* https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT */\ntypedef struct unz_file_info64_s\n{\n    uint16_t version;               /* version made by                 2 bytes */\n    uint16_t version_needed;        /* version needed to extract       2 bytes */\n    uint16_t flag;                  /* general purpose bit flag        2 bytes */\n    uint16_t compression_method;    /* compression method              2 bytes */\n    uint32_t dos_date;              /* last mod file date in Dos fmt   4 bytes */\n    struct tm tmu_date;\n    uint32_t crc;                   /* crc-32                          4 bytes */\n    uint64_t compressed_size;       /* compressed size                 8 bytes */\n    uint64_t uncompressed_size;     /* uncompressed size               8 bytes */\n    uint16_t size_filename;         /* filename length                 2 bytes */\n    uint16_t size_file_extra;       /* extra field length              2 bytes */\n    uint16_t size_file_comment;     /* file comment length             2 bytes */\n\n    uint32_t disk_num_start;        /* disk number start               4 bytes */\n    uint16_t internal_fa;           /* internal file attributes        2 bytes */\n    uint32_t external_fa;           /* external file attributes        4 bytes */\n\n    uint64_t disk_offset;\n\n    uint16_t size_file_extra_internal;\n} unz_file_info64;\n\ntypedef struct unz_file_info_s\n{\n    uint16_t version;               /* version made by                 2 bytes */\n    uint16_t version_needed;        /* version needed to extract       2 bytes */\n    uint16_t flag;                  /* general purpose bit flag        2 bytes */\n    uint16_t compression_method;    /* compression method              2 bytes */\n    uint32_t dos_date;              /* last mod file date in Dos fmt   4 bytes */\n    struct tm tmu_date;\n    uint32_t crc;                   /* crc-32                          4 bytes */\n    uint32_t compressed_size;       /* compressed size                 4 bytes */\n    uint32_t uncompressed_size;     /* uncompressed size               4 bytes */\n    uint16_t size_filename;         /* filename length                 2 bytes */\n    uint16_t size_file_extra;       /* extra field length              2 bytes */\n    uint16_t size_file_comment;     /* file comment length             2 bytes */\n\n    uint16_t disk_num_start;        /* disk number start               2 bytes */\n    uint16_t internal_fa;           /* internal file attributes        2 bytes */\n    uint32_t external_fa;           /* external file attributes        4 bytes */\n\n    uint64_t disk_offset;\n} unz_file_info;\n\n#endif\n"
  },
  {
    "path": "ios/CodePush/SSZipArchive/Supporting Files/PrivacyInfo.xcprivacy",
    "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>NSPrivacyTracking</key>\n\t<false/>\n\t<key>NSPrivacyCollectedDataTypes</key>\n\t<array/>\n\t<key>NSPrivacyTrackingDomains</key>\n\t<array/>\n\t<key>NSPrivacyAccessedAPITypes</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>NSPrivacyAccessedAPIType</key>\n\t\t\t<string>NSPrivacyAccessedAPICategoryFileTimestamp</string>\n\t\t\t<key>NSPrivacyAccessedAPITypeReasons</key>\n\t\t\t<array>\n\t\t\t\t<string>C617.1</string>\n\t\t\t</array>\n\t\t</dict>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "ios/CodePush/SSZipArchive/include/ZipArchive.h",
    "content": "//\n//  ZipArchive.h\n//  ZipArchive\n//\n//  Created by Serhii Mumriak on 12/1/15.\n//\n\n#import <Foundation/Foundation.h>\n\n//! Project version number for ZipArchive.\nFOUNDATION_EXPORT double ZipArchiveVersionNumber;\n\n//! Project version string for ZipArchive.\nFOUNDATION_EXPORT const unsigned char ZipArchiveVersionString[];\n\n// In this header, you should import all the public headers of your framework using statements like #import <SSZipArchive.h>\n\n// This is to account for the many different ways this library gets imported.\n#if __has_include(<SSZipArchive/SSZipArchive.h>)\n#import <SSZipArchive/SSZipArchive.h>\n#elif __has_include(\"../SSZipArchive.h\")\n#import \"../SSZipArchive.h\"\n#else\n#import \"SSZipArchive.h\"\n#endif\n"
  },
  {
    "path": "ios/CodePush/SSZipArchive/minizip/LICENSE",
    "content": "Condition of use and distribution are the same as zlib:\n\nThis software is provided 'as-is', without any express or implied\nwarranty.  In no event will the authors be held liable for any damages\narising from the use of this software.\n\nPermission is granted to anyone to use this software for any purpose,\nincluding commercial applications, and to alter it and redistribute it\nfreely, subject to the following restrictions:\n\n1. The origin of this software must not be misrepresented; you must not\n   claim that you wrote the original software. If you use this software\n   in a product, an acknowledgement in the product documentation would be\n   appreciated but is not required.\n2. Altered source versions must be plainly marked as such, and must not be\n   misrepresented as being the original software.\n3. This notice may not be removed or altered from any source distribution.\n"
  },
  {
    "path": "ios/CodePush/SSZipArchive/minizip/mz.h",
    "content": "/* mz.h -- Errors codes, zip flags and magic\n   part of the minizip-ng project\n\n   Copyright (C) Nathan Moinvaziri\n     https://github.com/zlib-ng/minizip-ng\n\n   This program is distributed under the terms of the same license as zlib.\n   See the accompanying LICENSE file for the full text of the license.\n*/\n\n#ifndef MZ_H\n#define MZ_H\n\n/***************************************************************************/\n\n/* MZ_VERSION */\n#define MZ_VERSION                      (\"3.0.9\")\n#define MZ_VERSION_BUILD                (030009)\n\n/* MZ_ERROR */\n#define MZ_OK                           (0)  /* zlib */\n#define MZ_STREAM_ERROR                 (-1) /* zlib */\n#define MZ_DATA_ERROR                   (-3) /* zlib */\n#define MZ_MEM_ERROR                    (-4) /* zlib */\n#define MZ_BUF_ERROR                    (-5) /* zlib */\n#define MZ_VERSION_ERROR                (-6) /* zlib */\n\n#define MZ_END_OF_LIST                  (-100)\n#define MZ_END_OF_STREAM                (-101)\n\n#define MZ_PARAM_ERROR                  (-102)\n#define MZ_FORMAT_ERROR                 (-103)\n#define MZ_INTERNAL_ERROR               (-104)\n#define MZ_CRC_ERROR                    (-105)\n#define MZ_CRYPT_ERROR                  (-106)\n#define MZ_EXIST_ERROR                  (-107)\n#define MZ_PASSWORD_ERROR               (-108)\n#define MZ_SUPPORT_ERROR                (-109)\n#define MZ_HASH_ERROR                   (-110)\n#define MZ_OPEN_ERROR                   (-111)\n#define MZ_CLOSE_ERROR                  (-112)\n#define MZ_SEEK_ERROR                   (-113)\n#define MZ_TELL_ERROR                   (-114)\n#define MZ_READ_ERROR                   (-115)\n#define MZ_WRITE_ERROR                  (-116)\n#define MZ_SIGN_ERROR                   (-117)\n#define MZ_SYMLINK_ERROR                (-118)\n\n/* MZ_OPEN */\n#define MZ_OPEN_MODE_READ               (0x01)\n#define MZ_OPEN_MODE_WRITE              (0x02)\n#define MZ_OPEN_MODE_READWRITE          (MZ_OPEN_MODE_READ | MZ_OPEN_MODE_WRITE)\n#define MZ_OPEN_MODE_APPEND             (0x04)\n#define MZ_OPEN_MODE_CREATE             (0x08)\n#define MZ_OPEN_MODE_EXISTING           (0x10)\n\n/* MZ_SEEK */\n#define MZ_SEEK_SET                     (0)\n#define MZ_SEEK_CUR                     (1)\n#define MZ_SEEK_END                     (2)\n\n/* MZ_COMPRESS */\n#define MZ_COMPRESS_METHOD_STORE        (0)\n#define MZ_COMPRESS_METHOD_DEFLATE      (8)\n#define MZ_COMPRESS_METHOD_BZIP2        (12)\n#define MZ_COMPRESS_METHOD_LZMA         (14)\n#define MZ_COMPRESS_METHOD_ZSTD         (93)\n#define MZ_COMPRESS_METHOD_XZ           (95)\n#define MZ_COMPRESS_METHOD_AES          (99)\n\n#define MZ_COMPRESS_LEVEL_DEFAULT       (-1)\n#define MZ_COMPRESS_LEVEL_FAST          (2)\n#define MZ_COMPRESS_LEVEL_NORMAL        (6)\n#define MZ_COMPRESS_LEVEL_BEST          (9)\n\n/* MZ_ZIP_FLAG */\n#define MZ_ZIP_FLAG_ENCRYPTED           (1 << 0)\n#define MZ_ZIP_FLAG_LZMA_EOS_MARKER     (1 << 1)\n#define MZ_ZIP_FLAG_DEFLATE_MAX         (1 << 1)\n#define MZ_ZIP_FLAG_DEFLATE_NORMAL      (0)\n#define MZ_ZIP_FLAG_DEFLATE_FAST        (1 << 2)\n#define MZ_ZIP_FLAG_DEFLATE_SUPER_FAST  (MZ_ZIP_FLAG_DEFLATE_FAST | \\\n                                         MZ_ZIP_FLAG_DEFLATE_MAX)\n#define MZ_ZIP_FLAG_DATA_DESCRIPTOR     (1 << 3)\n#define MZ_ZIP_FLAG_UTF8                (1 << 11)\n#define MZ_ZIP_FLAG_MASK_LOCAL_INFO     (1 << 13)\n\n/* MZ_ZIP_EXTENSION */\n#define MZ_ZIP_EXTENSION_ZIP64          (0x0001)\n#define MZ_ZIP_EXTENSION_NTFS           (0x000a)\n#define MZ_ZIP_EXTENSION_AES            (0x9901)\n#define MZ_ZIP_EXTENSION_UNIX1          (0x000d)\n#define MZ_ZIP_EXTENSION_SIGN           (0x10c5)\n#define MZ_ZIP_EXTENSION_HASH           (0x1a51)\n#define MZ_ZIP_EXTENSION_CDCD           (0xcdcd)\n\n/* MZ_ZIP64 */\n#define MZ_ZIP64_AUTO                   (0)\n#define MZ_ZIP64_FORCE                  (1)\n#define MZ_ZIP64_DISABLE                (2)\n\n/* MZ_HOST_SYSTEM */\n#define MZ_HOST_SYSTEM(VERSION_MADEBY)  ((uint8_t)(VERSION_MADEBY >> 8))\n#define MZ_HOST_SYSTEM_MSDOS            (0)\n#define MZ_HOST_SYSTEM_UNIX             (3)\n#define MZ_HOST_SYSTEM_WINDOWS_NTFS     (10)\n#define MZ_HOST_SYSTEM_RISCOS           (13)\n#define MZ_HOST_SYSTEM_OSX_DARWIN       (19)\n\n/* MZ_PKCRYPT */\n#define MZ_PKCRYPT_HEADER_SIZE          (12)\n\n/* MZ_AES */\n#define MZ_AES_VERSION                  (1)\n#define MZ_AES_ENCRYPTION_MODE_128      (0x01)\n#define MZ_AES_ENCRYPTION_MODE_192      (0x02)\n#define MZ_AES_ENCRYPTION_MODE_256      (0x03)\n#define MZ_AES_KEY_LENGTH(MODE)         (8 * (MODE & 3) + 8)\n#define MZ_AES_KEY_LENGTH_MAX           (32)\n#define MZ_AES_BLOCK_SIZE               (16)\n#define MZ_AES_HEADER_SIZE(MODE)        ((4 * (MODE & 3) + 4) + 2)\n#define MZ_AES_FOOTER_SIZE              (10)\n\n/* MZ_HASH */\n#define MZ_HASH_MD5                     (10)\n#define MZ_HASH_MD5_SIZE                (16)\n#define MZ_HASH_SHA1                    (20)\n#define MZ_HASH_SHA1_SIZE               (20)\n#define MZ_HASH_SHA224                  (22)\n#define MZ_HASH_SHA224_SIZE             (28)\n#define MZ_HASH_SHA256                  (23)\n#define MZ_HASH_SHA256_SIZE             (32)\n#define MZ_HASH_SHA384                  (24)\n#define MZ_HASH_SHA384_SIZE             (48)\n#define MZ_HASH_SHA512                  (25)\n#define MZ_HASH_SHA512_SIZE             (64)\n#define MZ_HASH_MAX_SIZE                (256)\n\n/* MZ_ENCODING */\n#define MZ_ENCODING_CODEPAGE_437        (437)\n#define MZ_ENCODING_CODEPAGE_932        (932)\n#define MZ_ENCODING_CODEPAGE_936        (936)\n#define MZ_ENCODING_CODEPAGE_950        (950)\n#define MZ_ENCODING_UTF8                (65001)\n\n/* MZ_UTILITY */\n#define MZ_UNUSED(SYMBOL)               ((void)SYMBOL)\n\n#if defined(_WIN32) && defined(MZ_EXPORTS)\n#define MZ_EXPORT __declspec(dllexport)\n#else\n#define MZ_EXPORT\n#endif\n\n/***************************************************************************/\n\n#include <stdlib.h> /* size_t, NULL, malloc */\n#include <time.h>   /* time_t, time() */\n#include <string.h> /* memset, strncpy, strlen */\n#include <limits.h>\n\n#if defined(HAVE_STDINT_H)\n#  include <stdint.h>\n#elif defined(__has_include)\n#  if __has_include(<stdint.h>)\n#    include <stdint.h>\n#  endif\n#endif\n\n#ifndef INT8_MAX\ntypedef signed char int8_t;\n#endif\n#ifndef INT16_MAX\ntypedef short int16_t;\n#endif\n#ifndef INT32_MAX\ntypedef int int32_t;\n#endif\n#ifndef INT64_MAX\ntypedef long long int64_t;\n#endif\n#ifndef UINT8_MAX\ntypedef unsigned char uint8_t;\n#endif\n#ifndef UINT16_MAX\ntypedef unsigned short uint16_t;\n#endif\n#ifndef UINT32_MAX\ntypedef unsigned int uint32_t;\n#endif\n#ifndef UINT64_MAX\ntypedef unsigned long long uint64_t;\n#endif\n\n#if defined(HAVE_INTTYPES_H)\n#  include <inttypes.h>\n#elif defined(__has_include)\n#  if __has_include(<inttypes.h>)\n#    include <inttypes.h>\n#  endif\n#endif\n\n#ifndef PRId8\n#  define PRId8 \"hhd\"\n#endif\n#ifndef PRIu8\n#  define PRIu8 \"hhu\"\n#endif\n#ifndef PRIx8\n#  define PRIx8 \"hhx\"\n#endif\n#ifndef PRId16\n#  define PRId16 \"hd\"\n#endif\n#ifndef PRIu16\n#  define PRIu16 \"hu\"\n#endif\n#ifndef PRIx16\n#  define PRIx16 \"hx\"\n#endif\n#ifndef PRId32\n#  define PRId32 \"d\"\n#endif\n#ifndef PRIu32\n#  define PRIu32 \"u\"\n#endif\n#ifndef PRIx32\n#  define PRIx32 \"x\"\n#endif\n#if ULONG_MAX == 0xfffffffful\n#  ifndef PRId64\n#    define PRId64 \"ld\"\n#  endif\n#  ifndef PRIu64\n#    define PRIu64 \"lu\"\n#  endif\n#  ifndef PRIx64\n#    define PRIx64 \"lx\"\n#  endif\n#else\n#  ifndef PRId64\n#    define PRId64 \"lld\"\n#  endif\n#  ifndef PRIu64\n#    define PRIu64 \"llu\"\n#  endif\n#  ifndef PRIx64\n#    define PRIx64 \"llx\"\n#  endif\n#endif\n\n#ifndef INT16_MAX\n#  define INT16_MAX 32767\n#endif\n#ifndef INT32_MAX\n#  define INT32_MAX 2147483647L\n#endif\n#ifndef INT64_MAX\n#  define INT64_MAX 9223372036854775807LL\n#endif\n#ifndef UINT16_MAX\n#  define UINT16_MAX 65535U\n#endif\n#ifndef UINT32_MAX\n#  define UINT32_MAX 4294967295UL\n#endif\n#ifndef UINT64_MAX\n#  define UINT64_MAX 18446744073709551615ULL\n#endif\n\n/***************************************************************************/\n\n#endif\n"
  },
  {
    "path": "ios/CodePush/SSZipArchive/minizip/mz_compat.c",
    "content": "/* mz_compat.c -- Backwards compatible interface for older versions\n   part of the minizip-ng project\n\n   Copyright (C) Nathan Moinvaziri\n     https://github.com/zlib-ng/minizip-ng\n   Copyright (C) 1998-2010 Gilles Vollant\n     https://www.winimage.com/zLibDll/minizip.html\n\n   This program is distributed under the terms of the same license as zlib.\n   See the accompanying LICENSE file for the full text of the license.\n \n WARNING: Be very careful updating/overwriting this file.\n It has specific changes for SSZipArchive support with some structs moved to SSZipCommon for public access\n*/\n\n#include \"mz.h\"\n#include \"mz_os.h\"\n#include \"mz_strm.h\"\n#include \"mz_strm_mem.h\"\n#include \"mz_strm_os.h\"\n#include \"mz_strm_zlib.h\"\n#include \"mz_zip.h\"\n\n#include <stdio.h> /* SEEK */\n\n#include \"mz_compat.h\"\n\n/***************************************************************************/\n\ntypedef struct mz_compat_s {\n    void     *stream;\n    void     *handle;\n    uint64_t entry_index;\n    int64_t  entry_pos;\n    int64_t  total_out;\n} mz_compat;\n\n/***************************************************************************/\n\ntypedef struct mz_stream_ioapi_s {\n    mz_stream           stream;\n    void                *handle;\n    zlib_filefunc_def   filefunc;\n    zlib_filefunc64_def filefunc64;\n} mz_stream_ioapi;\n\n/***************************************************************************/\n\nstatic int32_t mz_stream_ioapi_open(void *stream, const char *path, int32_t mode);\nstatic int32_t mz_stream_ioapi_is_open(void *stream);\nstatic int32_t mz_stream_ioapi_read(void *stream, void *buf, int32_t size);\nstatic int32_t mz_stream_ioapi_write(void *stream, const void *buf, int32_t size);\nstatic int64_t mz_stream_ioapi_tell(void *stream);\nstatic int32_t mz_stream_ioapi_seek(void *stream, int64_t offset, int32_t origin);\nstatic int32_t mz_stream_ioapi_close(void *stream);\nstatic int32_t mz_stream_ioapi_error(void *stream);\nstatic void *mz_stream_ioapi_create(void **stream);\nstatic void mz_stream_ioapi_delete(void **stream);\n\n/***************************************************************************/\n\nstatic mz_stream_vtbl mz_stream_ioapi_vtbl = {\n    mz_stream_ioapi_open,\n    mz_stream_ioapi_is_open,\n    mz_stream_ioapi_read,\n    mz_stream_ioapi_write,\n    mz_stream_ioapi_tell,\n    mz_stream_ioapi_seek,\n    mz_stream_ioapi_close,\n    mz_stream_ioapi_error,\n    mz_stream_ioapi_create,\n    mz_stream_ioapi_delete,\n    NULL,\n    NULL\n};\n\n/***************************************************************************/\n\nstatic int32_t mz_stream_ioapi_open(void *stream, const char *path, int32_t mode) {\n    mz_stream_ioapi *ioapi = (mz_stream_ioapi *)stream;\n    int32_t ioapi_mode = 0;\n\n    if ((mode & MZ_OPEN_MODE_READWRITE) == MZ_OPEN_MODE_READ)\n        ioapi_mode = ZLIB_FILEFUNC_MODE_READ;\n    else if (mode & MZ_OPEN_MODE_APPEND)\n        ioapi_mode = ZLIB_FILEFUNC_MODE_EXISTING;\n    else if (mode & MZ_OPEN_MODE_CREATE)\n        ioapi_mode = ZLIB_FILEFUNC_MODE_CREATE;\n    else\n        return MZ_OPEN_ERROR;\n\n    if (ioapi->filefunc64.zopen64_file)\n        ioapi->handle = ioapi->filefunc64.zopen64_file(ioapi->filefunc64.opaque, path, ioapi_mode);\n    else if (ioapi->filefunc.zopen_file)\n        ioapi->handle = ioapi->filefunc.zopen_file(ioapi->filefunc.opaque, path, ioapi_mode);\n\n    if (!ioapi->handle)\n        return MZ_PARAM_ERROR;\n\n    return MZ_OK;\n}\n\nstatic int32_t mz_stream_ioapi_is_open(void *stream) {\n    mz_stream_ioapi *ioapi = (mz_stream_ioapi *)stream;\n    if (!ioapi->handle)\n        return MZ_OPEN_ERROR;\n    return MZ_OK;\n}\n\nstatic int32_t mz_stream_ioapi_read(void *stream, void *buf, int32_t size) {\n    mz_stream_ioapi *ioapi = (mz_stream_ioapi *)stream;\n    read_file_func zread = NULL;\n    void *opaque = NULL;\n\n    if (mz_stream_ioapi_is_open(stream) != MZ_OK)\n        return MZ_OPEN_ERROR;\n\n    if (ioapi->filefunc64.zread_file) {\n        zread = ioapi->filefunc64.zread_file;\n        opaque = ioapi->filefunc64.opaque;\n    } else if (ioapi->filefunc.zread_file) {\n        zread = ioapi->filefunc.zread_file;\n        opaque = ioapi->filefunc.opaque;\n    } else\n        return MZ_PARAM_ERROR;\n\n    return (int32_t)zread(opaque, ioapi->handle, buf, size);\n}\n\nstatic int32_t mz_stream_ioapi_write(void *stream, const void *buf, int32_t size) {\n    mz_stream_ioapi *ioapi = (mz_stream_ioapi *)stream;\n    write_file_func zwrite = NULL;\n    int32_t written = 0;\n    void *opaque = NULL;\n\n    if (mz_stream_ioapi_is_open(stream) != MZ_OK)\n        return MZ_OPEN_ERROR;\n\n    if (ioapi->filefunc64.zwrite_file) {\n        zwrite = ioapi->filefunc64.zwrite_file;\n        opaque = ioapi->filefunc64.opaque;\n    } else if (ioapi->filefunc.zwrite_file) {\n        zwrite = ioapi->filefunc.zwrite_file;\n        opaque = ioapi->filefunc.opaque;\n    } else\n        return MZ_PARAM_ERROR;\n\n    written = (int32_t)zwrite(opaque, ioapi->handle, buf, size);\n    return written;\n}\n\nstatic int64_t mz_stream_ioapi_tell(void *stream) {\n    mz_stream_ioapi *ioapi = (mz_stream_ioapi *)stream;\n\n    if (mz_stream_ioapi_is_open(stream) != MZ_OK)\n        return MZ_OPEN_ERROR;\n\n    if (ioapi->filefunc64.ztell64_file)\n        return ioapi->filefunc64.ztell64_file(ioapi->filefunc64.opaque, ioapi->handle);\n    else if (ioapi->filefunc.ztell_file)\n        return ioapi->filefunc.ztell_file(ioapi->filefunc.opaque, ioapi->handle);\n\n    return MZ_INTERNAL_ERROR;\n}\n\nstatic int32_t mz_stream_ioapi_seek(void *stream, int64_t offset, int32_t origin) {\n    mz_stream_ioapi *ioapi = (mz_stream_ioapi *)stream;\n\n    if (mz_stream_ioapi_is_open(stream) != MZ_OK)\n        return MZ_OPEN_ERROR;\n\n    if (ioapi->filefunc64.zseek64_file) {\n        if (ioapi->filefunc64.zseek64_file(ioapi->filefunc64.opaque, ioapi->handle, offset, origin) != 0)\n            return MZ_INTERNAL_ERROR;\n    } else if (ioapi->filefunc.zseek_file) {\n        if (ioapi->filefunc.zseek_file(ioapi->filefunc.opaque, ioapi->handle, (int32_t)offset, origin) != 0)\n            return MZ_INTERNAL_ERROR;\n    } else\n        return MZ_PARAM_ERROR;\n\n    return MZ_OK;\n}\n\nstatic int32_t mz_stream_ioapi_close(void *stream) {\n    mz_stream_ioapi *ioapi = (mz_stream_ioapi *)stream;\n    close_file_func zclose = NULL;\n    void *opaque = NULL;\n\n    if (mz_stream_ioapi_is_open(stream) != MZ_OK)\n        return MZ_OPEN_ERROR;\n\n    if (ioapi->filefunc.zclose_file) {\n        zclose = ioapi->filefunc.zclose_file;\n        opaque = ioapi->filefunc.opaque;\n    } else if (ioapi->filefunc64.zclose_file) {\n        zclose = ioapi->filefunc64.zclose_file;\n        opaque = ioapi->filefunc64.opaque;\n    } else\n        return MZ_PARAM_ERROR;\n\n    if (zclose(opaque, ioapi->handle) != 0)\n        return MZ_CLOSE_ERROR;\n    ioapi->handle = NULL;\n    return MZ_OK;\n}\n\nstatic int32_t mz_stream_ioapi_error(void *stream) {\n    mz_stream_ioapi *ioapi = (mz_stream_ioapi *)stream;\n    testerror_file_func zerror = NULL;\n    void *opaque = NULL;\n\n    if (mz_stream_ioapi_is_open(stream) != MZ_OK)\n        return MZ_OPEN_ERROR;\n\n    if (ioapi->filefunc.zerror_file) {\n        zerror = ioapi->filefunc.zerror_file;\n        opaque = ioapi->filefunc.opaque;\n    } else if (ioapi->filefunc64.zerror_file) {\n        zerror = ioapi->filefunc64.zerror_file;\n        opaque = ioapi->filefunc64.opaque;\n    } else\n        return MZ_PARAM_ERROR;\n\n    return zerror(opaque, ioapi->handle);\n}\n\nstatic int32_t mz_stream_ioapi_set_filefunc(void *stream, zlib_filefunc_def *filefunc) {\n    mz_stream_ioapi *ioapi = (mz_stream_ioapi *)stream;\n    memcpy(&ioapi->filefunc, filefunc, sizeof(zlib_filefunc_def));\n    return MZ_OK;\n}\n\nstatic int32_t mz_stream_ioapi_set_filefunc64(void *stream, zlib_filefunc64_def *filefunc) {\n    mz_stream_ioapi *ioapi = (mz_stream_ioapi *)stream;\n    memcpy(&ioapi->filefunc64, filefunc, sizeof(zlib_filefunc64_def));\n    return MZ_OK;\n}\n\nstatic void *mz_stream_ioapi_create(void **stream) {\n    mz_stream_ioapi *ioapi = NULL;\n\n    ioapi = (mz_stream_ioapi *)calloc(1, sizeof(mz_stream_ioapi));\n    if (ioapi)\n        ioapi->stream.vtbl = &mz_stream_ioapi_vtbl;\n    if (stream)\n        *stream = ioapi;\n\n    return ioapi;\n}\n\nstatic void mz_stream_ioapi_delete(void **stream) {\n    mz_stream_ioapi *ioapi = NULL;\n    if (!stream)\n        return;\n    ioapi = (mz_stream_ioapi *)*stream;\n    if (ioapi)\n        free(ioapi);\n    *stream = NULL;\n}\n\n/***************************************************************************/\n\nvoid fill_fopen_filefunc(zlib_filefunc_def *pzlib_filefunc_def) {\n    /* For 32-bit file support only, compile with MZ_FILE32_API */\n    if (pzlib_filefunc_def)\n        memset(pzlib_filefunc_def, 0, sizeof(zlib_filefunc_def));\n}\n\nvoid fill_fopen64_filefunc(zlib_filefunc64_def *pzlib_filefunc_def) {\n    /* All mz_stream_os_* support large files if compilation supports it */\n    if (pzlib_filefunc_def)\n        memset(pzlib_filefunc_def, 0, sizeof(zlib_filefunc64_def));\n}\n\nvoid fill_win32_filefunc(zlib_filefunc_def *pzlib_filefunc_def) {\n    /* Handled by mz_stream_os_win32 */\n    if (pzlib_filefunc_def)\n        memset(pzlib_filefunc_def, 0, sizeof(zlib_filefunc_def));\n}\n\nvoid fill_win32_filefunc64(zlib_filefunc64_def *pzlib_filefunc_def) {\n    /* Automatically supported in mz_stream_os_win32 */\n    if (pzlib_filefunc_def)\n        memset(pzlib_filefunc_def, 0, sizeof(zlib_filefunc64_def));\n}\n\nvoid fill_win32_filefunc64A(zlib_filefunc64_def *pzlib_filefunc_def) {\n    /* Automatically supported in mz_stream_os_win32 */\n    if (pzlib_filefunc_def)\n        memset(pzlib_filefunc_def, 0, sizeof(zlib_filefunc64_def));\n}\n\n/* NOTE: fill_win32_filefunc64W is no longer necessary since wide-character\n   support is automatically handled by the underlying os stream. Do not\n   pass wide-characters to zipOpen or unzOpen. */\n\nvoid fill_memory_filefunc(zlib_filefunc_def *pzlib_filefunc_def) {\n    /* Use opaque to indicate which stream interface to create */\n    if (pzlib_filefunc_def) {\n        memset(pzlib_filefunc_def, 0, sizeof(zlib_filefunc_def));\n        pzlib_filefunc_def->opaque = mz_stream_mem_get_interface();\n    }\n}\n\n/***************************************************************************/\n\nstatic int32_t zipConvertAppendToStreamMode(int append) {\n    int32_t mode = MZ_OPEN_MODE_WRITE;\n    switch (append) {\n    case APPEND_STATUS_CREATE:\n        mode |= MZ_OPEN_MODE_CREATE;\n        break;\n    case APPEND_STATUS_CREATEAFTER:\n        mode |= MZ_OPEN_MODE_CREATE | MZ_OPEN_MODE_APPEND;\n        break;\n    case APPEND_STATUS_ADDINZIP:\n        mode |= MZ_OPEN_MODE_READ | MZ_OPEN_MODE_APPEND;\n        break;\n    }\n    return mode;\n}\n\nzipFile zipOpen(const char *path, int append) {\n    return zipOpen2(path, append, NULL, NULL);\n}\n\nzipFile zipOpen64(const void *path, int append) {\n    return zipOpen2(path, append, NULL, NULL);\n}\n\nzipFile zipOpen2(const char *path, int append, const char **globalcomment,\n    zlib_filefunc_def *pzlib_filefunc_def) {\n    zipFile zip = NULL;\n    int32_t mode = zipConvertAppendToStreamMode(append);\n    void *stream = NULL;\n\n    if (pzlib_filefunc_def) {\n        if (pzlib_filefunc_def->zopen_file) {\n            if (!mz_stream_ioapi_create(&stream))\n                return NULL;\n            mz_stream_ioapi_set_filefunc(stream, pzlib_filefunc_def);\n        } else if (pzlib_filefunc_def->opaque) {\n            if (!mz_stream_create(&stream, (mz_stream_vtbl *)pzlib_filefunc_def->opaque))\n                return NULL;\n        }\n    }\n\n    if (!stream) {\n        if (!mz_stream_os_create(&stream))\n            return NULL;\n    }\n\n    if (mz_stream_open(stream, path, mode) != MZ_OK) {\n        mz_stream_delete(&stream);\n        return NULL;\n    }\n\n    zip = zipOpen_MZ(stream, append, globalcomment);\n\n    if (!zip) {\n        mz_stream_delete(&stream);\n        return NULL;\n    }\n\n    return zip;\n}\n\nzipFile zipOpen2_64(const void *path, int append, const char **globalcomment,\n    zlib_filefunc64_def *pzlib_filefunc_def) {\n    zipFile zip = NULL;\n    int32_t mode = zipConvertAppendToStreamMode(append);\n    void *stream = NULL;\n\n    if (pzlib_filefunc_def) {\n        if (pzlib_filefunc_def->zopen64_file) {\n            if (!mz_stream_ioapi_create(&stream))\n                return NULL;\n            mz_stream_ioapi_set_filefunc64(stream, pzlib_filefunc_def);\n        } else if (pzlib_filefunc_def->opaque) {\n            if (!mz_stream_create(&stream, (mz_stream_vtbl *)pzlib_filefunc_def->opaque))\n                return NULL;\n        }\n    }\n\n    if (!stream) {\n        if (!mz_stream_os_create(&stream))\n            return NULL;\n    }\n\n    if (mz_stream_open(stream, path, mode) != MZ_OK) {\n        mz_stream_delete(&stream);\n        return NULL;\n    }\n\n    zip = zipOpen_MZ(stream, append, globalcomment);\n\n    if (!zip) {\n        mz_stream_delete(&stream);\n        return NULL;\n    }\n\n    return zip;\n}\n\nzipFile zipOpen_MZ(void *stream, int append, const char **globalcomment) {\n    mz_compat *compat = NULL;\n    int32_t err = MZ_OK;\n    int32_t mode = zipConvertAppendToStreamMode(append);\n    void *handle = NULL;\n\n    mz_zip_create(&handle);\n    err = mz_zip_open(handle, stream, mode);\n\n    if (err != MZ_OK) {\n        mz_zip_delete(&handle);\n        return NULL;\n    }\n\n    if (globalcomment)\n        mz_zip_get_comment(handle, globalcomment);\n\n    compat = (mz_compat *)calloc(1, sizeof(mz_compat));\n    if (compat) {\n        compat->handle = handle;\n        compat->stream = stream;\n    } else {\n        mz_zip_delete(&handle);\n    }\n\n    return (zipFile)compat;\n}\n\nvoid* zipGetHandle_MZ(zipFile file) {\n    mz_compat *compat = (mz_compat *)file;\n    if (!compat)\n        return NULL;\n    return compat->handle;\n}\n\nvoid* zipGetStream_MZ(zipFile file) {\n    mz_compat *compat = (mz_compat *)file;\n    if (!compat)\n        return NULL;\n    return (void *)compat->stream;\n}\n\nint zipOpenNewFileInZip5(zipFile file, const char *filename, const zip_fileinfo *zipfi,\n    const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global,\n    uint16_t size_extrafield_global, const char *comment, int compression_method, int level,\n    int raw, int windowBits, int memLevel, int strategy, const char *password,\n    unsigned long crc_for_crypting, signed char aes, unsigned long version_madeby, unsigned long flag_base, int zip64) {\n    mz_compat *compat = (mz_compat *)file;\n    mz_zip_file file_info;\n\n    MZ_UNUSED(strategy);\n    MZ_UNUSED(memLevel);\n    MZ_UNUSED(windowBits);\n    MZ_UNUSED(size_extrafield_local);\n    MZ_UNUSED(extrafield_local);\n    MZ_UNUSED(crc_for_crypting);\n\n    if (!compat)\n        return ZIP_PARAMERROR;\n\n    memset(&file_info, 0, sizeof(file_info));\n\n    if (zipfi) {\n        uint64_t dos_date = 0;\n\n        if (zipfi->mz_dos_date != 0)\n            dos_date = zipfi->mz_dos_date;\n        else\n            dos_date = mz_zip_tm_to_dosdate(&zipfi->tmz_date);\n\n        file_info.modified_date = mz_zip_dosdate_to_time_t(dos_date);\n        file_info.external_fa = zipfi->external_fa;\n        file_info.internal_fa = zipfi->internal_fa;\n    }\n\n    if (!filename)\n        filename = \"-\";\n\n    file_info.compression_method = (uint16_t)compression_method;\n    file_info.filename = filename;\n    /* file_info.extrafield_local = extrafield_local; */\n    /* file_info.extrafield_local_size = size_extrafield_local; */\n    file_info.extrafield = extrafield_global;\n    file_info.extrafield_size = size_extrafield_global;\n    file_info.version_madeby = (uint16_t)version_madeby;\n    file_info.comment = comment;\n    if (file_info.comment)\n        file_info.comment_size = (uint16_t)strlen(file_info.comment);\n    file_info.flag = (uint16_t)flag_base;\n    if (zip64)\n        file_info.zip64 = MZ_ZIP64_FORCE;\n    else\n        file_info.zip64 = MZ_ZIP64_DISABLE;\n#ifdef HAVE_WZAES\n    if ((aes && password) || (raw && (file_info.flag & MZ_ZIP_FLAG_ENCRYPTED)))\n        file_info.aes_version = MZ_AES_VERSION;\n#endif\n\n    return mz_zip_entry_write_open(compat->handle, &file_info, (int16_t)level, (uint8_t)raw, password);\n}\n\nint zipOpenNewFileInZip4_64(zipFile file, const char *filename, const zip_fileinfo *zipfi,\n    const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global,\n    uint16_t size_extrafield_global, const char *comment, int compression_method, int level,\n    int raw, int windowBits, int memLevel,   int strategy, const char *password,\n    unsigned long crc_for_crypting, unsigned long version_madeby, unsigned long flag_base, int zip64) {\n    return zipOpenNewFileInZip5(file, filename, zipfi, extrafield_local, size_extrafield_local,\n        extrafield_global, size_extrafield_global, comment, compression_method, level, raw, windowBits,\n        memLevel, strategy, password, crc_for_crypting, 0, version_madeby, flag_base, zip64);\n}\n\nint zipOpenNewFileInZip4(zipFile file, const char *filename, const zip_fileinfo *zipfi,\n    const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global,\n    uint16_t size_extrafield_global, const char *comment, int compression_method, int level,\n    int raw, int windowBits, int memLevel, int strategy, const char *password,\n    unsigned long crc_for_crypting, unsigned long version_madeby, unsigned long flag_base) {\n    return zipOpenNewFileInZip4_64(file, filename, zipfi, extrafield_local, size_extrafield_local,\n        extrafield_global, size_extrafield_global, comment, compression_method, level, raw, windowBits,\n        memLevel, strategy, password, crc_for_crypting, version_madeby, flag_base, 0);\n}\n\nint zipOpenNewFileInZip3(zipFile file, const char *filename, const zip_fileinfo *zipfi,\n    const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global,\n    uint16_t size_extrafield_global, const char *comment, int compression_method, int level,\n    int raw, int windowBits, int memLevel, int strategy, const char *password,\n    unsigned long crc_for_crypting) {\n    return zipOpenNewFileInZip3_64(file, filename, zipfi, extrafield_local, size_extrafield_local,\n        extrafield_global, size_extrafield_global, comment, compression_method, level, raw, windowBits,\n        memLevel, strategy, password, crc_for_crypting, 0);\n}\n\nint zipOpenNewFileInZip3_64(zipFile file, const char *filename, const zip_fileinfo *zipfi,\n    const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global,\n    uint16_t size_extrafield_global, const char *comment, int compression_method, int level,\n    int raw, int windowBits, int memLevel, int strategy, const char *password,\n    unsigned long crc_for_crypting, int zip64) {\n    return zipOpenNewFileInZip4_64(file, filename, zipfi, extrafield_local, size_extrafield_local,\n        extrafield_global, size_extrafield_global, comment, compression_method, level, raw, windowBits,\n        memLevel, strategy, password, crc_for_crypting, MZ_VERSION_MADEBY, 0, zip64);\n}\n\nint zipOpenNewFileInZip2(zipFile file, const char *filename, const zip_fileinfo *zipfi,\n    const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global,\n    uint16_t size_extrafield_global, const char *comment, int compression_method, int level,\n    int raw) {\n    return zipOpenNewFileInZip3_64(file, filename, zipfi, extrafield_local, size_extrafield_local,\n        extrafield_global, size_extrafield_global, comment, compression_method, level, raw,\n            0, 0, 0, NULL, 0, 0);\n}\n\nint zipOpenNewFileInZip2_64(zipFile file, const char *filename, const zip_fileinfo *zipfi,\n    const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global,\n    uint16_t size_extrafield_global, const char *comment, int compression_method, int level,\n    int raw, int zip64) {\n    return zipOpenNewFileInZip3_64(file, filename, zipfi, extrafield_local, size_extrafield_local,\n        extrafield_global, size_extrafield_global, comment, compression_method, level, raw, 0,\n        0, 0, NULL, 0, zip64);\n}\n\nint zipOpenNewFileInZip(zipFile file, const char *filename, const zip_fileinfo *zipfi,\n    const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global,\n    uint16_t size_extrafield_global, const char *comment, int compression_method, int level) {\n    return zipOpenNewFileInZip_64(file, filename, zipfi, extrafield_local, size_extrafield_local,\n        extrafield_global, size_extrafield_global, comment, compression_method, level, 0);\n}\n\nint zipOpenNewFileInZip_64(zipFile file, const char *filename, const zip_fileinfo *zipfi,\n    const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global,\n    uint16_t size_extrafield_global, const char *comment, int compression_method, int level,\n    int zip64) {\n    return zipOpenNewFileInZip2_64(file, filename, zipfi, extrafield_local, size_extrafield_local,\n        extrafield_global, size_extrafield_global, comment, compression_method, level, 0, zip64);\n}\n\nint zipWriteInFileInZip(zipFile file, const void *buf, uint32_t len) {\n    mz_compat *compat = (mz_compat *)file;\n    int32_t written = 0;\n    if (!compat || len >= INT32_MAX)\n        return ZIP_PARAMERROR;\n    written = mz_zip_entry_write(compat->handle, buf, (int32_t)len);\n    if ((written < 0) || ((uint32_t)written != len))\n        return ZIP_ERRNO;\n    return ZIP_OK;\n}\n\nint zipCloseFileInZipRaw(zipFile file, unsigned long uncompressed_size, uint32_t crc32) {\n    return zipCloseFileInZipRaw64(file, uncompressed_size, crc32);\n}\n\nint zipCloseFileInZipRaw64(zipFile file, uint64_t uncompressed_size, uint32_t crc32) {\n    mz_compat *compat = (mz_compat *)file;\n    if (!compat)\n        return ZIP_PARAMERROR;\n    return mz_zip_entry_close_raw(compat->handle, (int64_t)uncompressed_size, crc32);\n}\n\nint zipCloseFileInZip(zipFile file) {\n    return zipCloseFileInZip64(file);\n}\n\nint zipCloseFileInZip64(zipFile file) {\n    mz_compat *compat = (mz_compat *)file;\n    if (!compat)\n        return ZIP_PARAMERROR;\n    return mz_zip_entry_close(compat->handle);\n}\n\nint zipClose(zipFile file, const char *global_comment) {\n    return zipClose_64(file, global_comment);\n}\n\nint zipClose_64(zipFile file, const char *global_comment) {\n    return zipClose2_64(file, global_comment, MZ_VERSION_MADEBY);\n}\n\nint zipClose2_64(zipFile file, const char *global_comment, uint16_t version_madeby) {\n    mz_compat *compat = (mz_compat *)file;\n    int32_t err = MZ_OK;\n\n    if (compat->handle)\n        err = zipClose2_MZ(file, global_comment, version_madeby);\n\n    if (compat->stream) {\n        mz_stream_close(compat->stream);\n        mz_stream_delete(&compat->stream);\n    }\n\n    free(compat);\n\n    return err;\n}\n\n/* Only closes the zip handle, does not close the stream */\nint zipClose_MZ(zipFile file, const char *global_comment) {\n    return zipClose2_MZ(file, global_comment, MZ_VERSION_MADEBY);\n}\n\n/* Only closes the zip handle, does not close the stream */\nint zipClose2_MZ(zipFile file, const char *global_comment, uint16_t version_madeby) {\n    mz_compat *compat = (mz_compat *)file;\n    int32_t err = MZ_OK;\n\n    if (!compat)\n        return ZIP_PARAMERROR;\n    if (!compat->handle)\n        return err;\n\n    if (global_comment)\n        mz_zip_set_comment(compat->handle, global_comment);\n\n    mz_zip_set_version_madeby(compat->handle, version_madeby);\n    err = mz_zip_close(compat->handle);\n    mz_zip_delete(&compat->handle);\n\n    return err;\n}\n\n/***************************************************************************/\n\nunzFile unzOpen(const char *path) {\n    return unzOpen64(path);\n}\n\nunzFile unzOpen64(const void *path) {\n    return unzOpen2(path, NULL);\n}\n\nunzFile unzOpen2(const char *path, zlib_filefunc_def *pzlib_filefunc_def) {\n   unzFile unz = NULL;\n    void *stream = NULL;\n\n    if (pzlib_filefunc_def) {\n        if (pzlib_filefunc_def->zopen_file) {\n            if (!mz_stream_ioapi_create(&stream))\n                return NULL;\n            mz_stream_ioapi_set_filefunc(stream, pzlib_filefunc_def);\n        } else if (pzlib_filefunc_def->opaque) {\n            if (!mz_stream_create(&stream, (mz_stream_vtbl *)pzlib_filefunc_def->opaque))\n                return NULL;\n        }\n    }\n\n    if (!stream) {\n        if (!mz_stream_os_create(&stream))\n            return NULL;\n    }\n\n    if (mz_stream_open(stream, path, MZ_OPEN_MODE_READ) != MZ_OK) {\n        mz_stream_delete(&stream);\n        return NULL;\n    }\n\n    unz = unzOpen_MZ(stream);\n    if (!unz) {\n        mz_stream_close(stream);\n        mz_stream_delete(&stream);\n        return NULL;\n    }\n    return unz;\n}\n\nunzFile unzOpen2_64(const void *path, zlib_filefunc64_def *pzlib_filefunc_def) {\n    unzFile unz = NULL;\n    void *stream = NULL;\n\n    if (pzlib_filefunc_def) {\n        if (pzlib_filefunc_def->zopen64_file) {\n            if (!mz_stream_ioapi_create(&stream))\n                return NULL;\n            mz_stream_ioapi_set_filefunc64(stream, pzlib_filefunc_def);\n        } else if (pzlib_filefunc_def->opaque) {\n            if (!mz_stream_create(&stream, (mz_stream_vtbl *)pzlib_filefunc_def->opaque))\n                return NULL;\n        }\n    }\n\n    if (!stream) {\n        if (!mz_stream_os_create(&stream))\n            return NULL;\n    }\n\n    if (mz_stream_open(stream, path, MZ_OPEN_MODE_READ) != MZ_OK) {\n        mz_stream_delete(&stream);\n        return NULL;\n    }\n\n    unz = unzOpen_MZ(stream);\n    if (!unz) {\n        mz_stream_close(stream);\n        mz_stream_delete(&stream);\n        return NULL;\n    }\n    return unz;\n}\n\nvoid* unzGetHandle_MZ(unzFile file) {\n    mz_compat *compat = (mz_compat *)file;\n    if (!compat)\n        return NULL;\n    return compat->handle;\n}\n\nvoid* unzGetStream_MZ(unzFile file) {\n    mz_compat *compat = (mz_compat *)file;\n    if (!compat)\n        return NULL;\n    return compat->stream;\n}\n\nunzFile unzOpen_MZ(void *stream) {\n    mz_compat *compat = NULL;\n    int32_t err = MZ_OK;\n    void *handle = NULL;\n\n    mz_zip_create(&handle);\n    err = mz_zip_open(handle, stream, MZ_OPEN_MODE_READ);\n\n    if (err != MZ_OK) {\n        mz_zip_delete(&handle);\n        return NULL;\n    }\n\n    compat = (mz_compat *)calloc(1, sizeof(mz_compat));\n    if (compat) {\n        compat->handle = handle;\n        compat->stream = stream;\n\n        mz_zip_goto_first_entry(compat->handle);\n    } else {\n        mz_zip_delete(&handle);\n    }\n\n    return (unzFile)compat;\n}\n\nint unzClose(unzFile file) {\n    mz_compat *compat = (mz_compat *)file;\n    int32_t err = MZ_OK;\n\n    if (!compat)\n        return UNZ_PARAMERROR;\n\n    if (compat->handle)\n        err = unzClose_MZ(file);\n\n    if (compat->stream) {\n        mz_stream_close(compat->stream);\n        mz_stream_delete(&compat->stream);\n    }\n\n    free(compat);\n\n    return err;\n}\n\n/* Only closes the zip handle, does not close the stream */\nint unzClose_MZ(unzFile file) {\n    mz_compat *compat = (mz_compat *)file;\n    int32_t err = MZ_OK;\n\n    if (!compat)\n        return UNZ_PARAMERROR;\n\n    err = mz_zip_close(compat->handle);\n    mz_zip_delete(&compat->handle);\n\n    return err;\n}\n\nint unzGetGlobalInfo(unzFile file, unz_global_info* pglobal_info32) {\n    mz_compat *compat = (mz_compat *)file;\n    unz_global_info64 global_info64;\n    int32_t err = MZ_OK;\n\n    memset(pglobal_info32, 0, sizeof(unz_global_info));\n    if (!compat)\n        return UNZ_PARAMERROR;\n\n    err = unzGetGlobalInfo64(file, &global_info64);\n    if (err == MZ_OK) {\n        pglobal_info32->number_entry = (uint32_t)global_info64.number_entry;\n        pglobal_info32->size_comment = global_info64.size_comment;\n        pglobal_info32->number_disk_with_CD = global_info64.number_disk_with_CD;\n    }\n    return err;\n}\n\nint unzGetGlobalInfo64(unzFile file, unz_global_info64 *pglobal_info) {\n    mz_compat *compat = (mz_compat *)file;\n    const char *comment_ptr = NULL;\n    int32_t err = MZ_OK;\n\n    memset(pglobal_info, 0, sizeof(unz_global_info64));\n    if (!compat)\n        return UNZ_PARAMERROR;\n    err = mz_zip_get_comment(compat->handle, &comment_ptr);\n    if (err == MZ_OK)\n        pglobal_info->size_comment = (uint16_t)strlen(comment_ptr);\n    if ((err == MZ_OK) || (err == MZ_EXIST_ERROR))\n        err = mz_zip_get_number_entry(compat->handle, &pglobal_info->number_entry);\n    if (err == MZ_OK)\n        err = mz_zip_get_disk_number_with_cd(compat->handle, &pglobal_info->number_disk_with_CD);\n    return err;\n}\n\nint unzGetGlobalComment(unzFile file, char *comment, unsigned long comment_size) {\n    mz_compat *compat = (mz_compat *)file;\n    const char *comment_ptr = NULL;\n    int32_t err = MZ_OK;\n\n    if (!comment || !comment_size)\n        return UNZ_PARAMERROR;\n    err = mz_zip_get_comment(compat->handle, &comment_ptr);\n    if (err == MZ_OK) {\n        strncpy(comment, comment_ptr, comment_size - 1);\n        comment[comment_size - 1] = 0;\n    }\n    return err;\n}\n\nint unzOpenCurrentFile3(unzFile file, int *method, int *level, int raw, const char *password) {\n    mz_compat *compat = (mz_compat *)file;\n    mz_zip_file *file_info = NULL;\n    int32_t err = MZ_OK;\n    void *stream = NULL;\n\n    if (!compat)\n        return UNZ_PARAMERROR;\n    if (method)\n        *method = 0;\n    if (level)\n        *level = 0;\n\n    if (mz_zip_entry_is_open(compat->handle) == MZ_OK) {\n        /* zlib minizip does not error out here if close returns errors */\n        unzCloseCurrentFile(file);\n    }\n\n    compat->total_out = 0;\n    err = mz_zip_entry_read_open(compat->handle, (uint8_t)raw, password);\n    if (err == MZ_OK)\n        err = mz_zip_entry_get_info(compat->handle, &file_info);\n    if (err == MZ_OK) {\n        if (method) {\n            *method = file_info->compression_method;\n        }\n\n        if (level) {\n            *level = 6;\n            switch (file_info->flag & 0x06) {\n            case MZ_ZIP_FLAG_DEFLATE_SUPER_FAST:\n                *level = 1;\n                break;\n            case MZ_ZIP_FLAG_DEFLATE_FAST:\n                *level = 2;\n                break;\n            case MZ_ZIP_FLAG_DEFLATE_MAX:\n                *level = 9;\n                break;\n            }\n        }\n    }\n    if (err == MZ_OK)\n        err = mz_zip_get_stream(compat->handle, &stream);\n    if (err == MZ_OK)\n        compat->entry_pos = mz_stream_tell(stream);\n    return err;\n}\n\nint unzOpenCurrentFile(unzFile file) {\n    return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL);\n}\n\nint unzOpenCurrentFilePassword(unzFile file, const char *password) {\n    return unzOpenCurrentFile3(file, NULL, NULL, 0, password);\n}\n\nint unzOpenCurrentFile2(unzFile file, int *method, int *level, int raw) {\n    return unzOpenCurrentFile3(file, method, level, raw, NULL);\n}\n\nint unzReadCurrentFile(unzFile file, void *buf, uint32_t len) {\n    mz_compat *compat = (mz_compat *)file;\n    int32_t err = MZ_OK;\n    if (!compat || len >= INT32_MAX)\n        return UNZ_PARAMERROR;\n    err = mz_zip_entry_read(compat->handle, buf, (int32_t)len);\n    if (err > 0)\n        compat->total_out += (uint32_t)err;\n    return err;\n}\n\nint unzCloseCurrentFile(unzFile file) {\n    mz_compat *compat = (mz_compat *)file;\n    int32_t err = MZ_OK;\n    if (!compat)\n        return UNZ_PARAMERROR;\n    err = mz_zip_entry_close(compat->handle);\n    return err;\n}\n\nint unzGetCurrentFileInfo(unzFile file, unz_file_info *pfile_info, char *filename,\n    unsigned long filename_size, void *extrafield, unsigned long extrafield_size, char *comment,\n    unsigned long comment_size) {\n    mz_compat *compat = (mz_compat *)file;\n    mz_zip_file *file_info = NULL;\n    uint16_t bytes_to_copy = 0;\n    int32_t err = MZ_OK;\n\n    if (!compat)\n        return UNZ_PARAMERROR;\n\n    err = mz_zip_entry_get_info(compat->handle, &file_info);\n    if (err != MZ_OK)\n        return err;\n\n    if (pfile_info) {\n        pfile_info->version = file_info->version_madeby;\n        pfile_info->version_needed = file_info->version_needed;\n        pfile_info->flag = file_info->flag;\n        pfile_info->compression_method = file_info->compression_method;\n        pfile_info->mz_dos_date = mz_zip_time_t_to_dos_date(file_info->modified_date);\n        //mz_zip_time_t_to_tm(file_info->modified_date, &pfile_info->tmu_date);\n        //pfile_info->tmu_date.tm_year += 1900;\n        pfile_info->crc = file_info->crc;\n\n        pfile_info->size_filename = file_info->filename_size;\n        pfile_info->size_file_extra = file_info->extrafield_size;\n        pfile_info->size_file_comment = file_info->comment_size;\n\n        pfile_info->disk_num_start = (uint16_t)file_info->disk_number;\n        pfile_info->internal_fa = file_info->internal_fa;\n        pfile_info->external_fa = file_info->external_fa;\n\n        pfile_info->compressed_size = (uint32_t)file_info->compressed_size;\n        pfile_info->uncompressed_size = (uint32_t)file_info->uncompressed_size;\n    }\n    if (filename_size > 0 && filename && file_info->filename) {\n        bytes_to_copy = (uint16_t)filename_size;\n        if (bytes_to_copy > file_info->filename_size)\n            bytes_to_copy = file_info->filename_size;\n        memcpy(filename, file_info->filename, bytes_to_copy);\n        if (bytes_to_copy < filename_size)\n            filename[bytes_to_copy] = 0;\n    }\n    if (extrafield_size > 0 && extrafield) {\n        bytes_to_copy = (uint16_t)extrafield_size;\n        if (bytes_to_copy > file_info->extrafield_size)\n            bytes_to_copy = file_info->extrafield_size;\n        memcpy(extrafield, file_info->extrafield, bytes_to_copy);\n    }\n    if (comment_size > 0 && comment && file_info->comment) {\n        bytes_to_copy = (uint16_t)comment_size;\n        if (bytes_to_copy > file_info->comment_size)\n            bytes_to_copy = file_info->comment_size;\n        memcpy(comment, file_info->comment, bytes_to_copy);\n        if (bytes_to_copy < comment_size)\n            comment[bytes_to_copy] = 0;\n    }\n    return err;\n}\n\nint unzGetCurrentFileInfo64(unzFile file, unz_file_info64 * pfile_info, char *filename,\n    unsigned long filename_size, void *extrafield, unsigned long extrafield_size, char *comment,\n    unsigned long comment_size) {\n    mz_compat *compat = (mz_compat *)file;\n    mz_zip_file *file_info = NULL;\n    uint16_t bytes_to_copy = 0;\n    int32_t err = MZ_OK;\n\n    if (!compat)\n        return UNZ_PARAMERROR;\n\n    err = mz_zip_entry_get_info(compat->handle, &file_info);\n    if (err != MZ_OK)\n        return err;\n\n    if (pfile_info) {\n        pfile_info->version = file_info->version_madeby;\n        pfile_info->version_needed = file_info->version_needed;\n        pfile_info->flag = file_info->flag;\n        pfile_info->compression_method = file_info->compression_method;\n        pfile_info->mz_dos_date = mz_zip_time_t_to_dos_date(file_info->modified_date);\n        //mz_zip_time_t_to_tm(file_info->modified_date, &pfile_info->tmu_date);\n        //pfile_info->tmu_date.tm_year += 1900;\n        pfile_info->crc = file_info->crc;\n\n        pfile_info->size_filename = file_info->filename_size;\n        pfile_info->size_file_extra = file_info->extrafield_size;\n        pfile_info->size_file_comment = file_info->comment_size;\n\n        pfile_info->disk_num_start = file_info->disk_number;\n        pfile_info->internal_fa = file_info->internal_fa;\n        pfile_info->external_fa = file_info->external_fa;\n\n        pfile_info->compressed_size = (uint64_t)file_info->compressed_size;\n        pfile_info->uncompressed_size = (uint64_t)file_info->uncompressed_size;\n    }\n    if (filename_size > 0 && filename && file_info->filename) {\n        bytes_to_copy = (uint16_t)filename_size;\n        if (bytes_to_copy > file_info->filename_size)\n            bytes_to_copy = file_info->filename_size;\n        memcpy(filename, file_info->filename, bytes_to_copy);\n        if (bytes_to_copy < filename_size)\n            filename[bytes_to_copy] = 0;\n    }\n    if (extrafield_size > 0 && extrafield) {\n        bytes_to_copy = (uint16_t)extrafield_size;\n        if (bytes_to_copy > file_info->extrafield_size)\n            bytes_to_copy = file_info->extrafield_size;\n        memcpy(extrafield, file_info->extrafield, bytes_to_copy);\n    }\n    if (comment_size > 0 && comment && file_info->comment) {\n        bytes_to_copy = (uint16_t)comment_size;\n        if (bytes_to_copy > file_info->comment_size)\n            bytes_to_copy = file_info->comment_size;\n        memcpy(comment, file_info->comment, bytes_to_copy);\n        if (bytes_to_copy < comment_size)\n            comment[bytes_to_copy] = 0;\n    }\n    return err;\n}\n\nint unzGoToFirstFile(unzFile file) {\n    mz_compat *compat = (mz_compat *)file;\n    if (!compat)\n        return UNZ_PARAMERROR;\n    compat->entry_index = 0;\n    return mz_zip_goto_first_entry(compat->handle);\n}\n\nint unzGoToNextFile(unzFile file) {\n    mz_compat *compat = (mz_compat *)file;\n    int32_t err = MZ_OK;\n    if (!compat)\n        return UNZ_PARAMERROR;\n    err = mz_zip_goto_next_entry(compat->handle);\n    if (err != MZ_END_OF_LIST)\n        compat->entry_index += 1;\n    return err;\n}\n\nint unzLocateFile(unzFile file, const char *filename, unzFileNameComparer filename_compare_func) {\n    mz_compat *compat = (mz_compat *)file;\n    mz_zip_file *file_info = NULL;\n    uint64_t preserve_index = 0;\n    int32_t err = MZ_OK;\n    int32_t result = 0;\n\n    if (!compat)\n        return UNZ_PARAMERROR;\n\n    preserve_index = compat->entry_index;\n\n    err = mz_zip_goto_first_entry(compat->handle);\n    while (err == MZ_OK) {\n        err = mz_zip_entry_get_info(compat->handle, &file_info);\n        if (err != MZ_OK)\n            break;\n\n        if ((intptr_t)filename_compare_func > 2) {\n            result = filename_compare_func(file, filename, file_info->filename);\n        } else {\n            int32_t case_sensitive = (int32_t)(intptr_t)filename_compare_func;\n            result = mz_path_compare_wc(filename, file_info->filename, !case_sensitive);\n        }\n\n        if (result == 0)\n            return MZ_OK;\n\n        err = mz_zip_goto_next_entry(compat->handle);\n    }\n\n    compat->entry_index = preserve_index;\n    return err;\n}\n\n/***************************************************************************/\n\nint unzGetFilePos(unzFile file, unz_file_pos *file_pos) {\n    unz64_file_pos file_pos64;\n    int32_t err = 0;\n\n    err = unzGetFilePos64(file, &file_pos64);\n    if (err < 0)\n        return err;\n\n    file_pos->pos_in_zip_directory = (uint32_t)file_pos64.pos_in_zip_directory;\n    file_pos->num_of_file = (uint32_t)file_pos64.num_of_file;\n    return err;\n}\n\nint unzGoToFilePos(unzFile file, unz_file_pos *file_pos) {\n    mz_compat *compat = (mz_compat *)file;\n    unz64_file_pos file_pos64;\n\n    if (!compat || !file_pos)\n        return UNZ_PARAMERROR;\n\n    file_pos64.pos_in_zip_directory = file_pos->pos_in_zip_directory;\n    file_pos64.num_of_file = file_pos->num_of_file;\n\n    return unzGoToFilePos64(file, &file_pos64);\n}\n\nint unzGetFilePos64(unzFile file, unz64_file_pos *file_pos) {\n    mz_compat *compat = (mz_compat *)file;\n    int64_t offset = 0;\n\n    if (!compat || !file_pos)\n        return UNZ_PARAMERROR;\n\n    offset = unzGetOffset64(file);\n    if (offset < 0)\n        return (int)offset;\n\n    file_pos->pos_in_zip_directory = offset;\n    file_pos->num_of_file = compat->entry_index;\n    return UNZ_OK;\n}\n\nint unzGoToFilePos64(unzFile file, const unz64_file_pos *file_pos) {\n    mz_compat *compat = (mz_compat *)file;\n    int32_t err = MZ_OK;\n\n    if (!compat || !file_pos)\n        return UNZ_PARAMERROR;\n\n    err = mz_zip_goto_entry(compat->handle, file_pos->pos_in_zip_directory);\n    if (err == MZ_OK)\n        compat->entry_index = file_pos->num_of_file;\n    return err;\n}\n\nunsigned long unzGetOffset(unzFile file) {\n    return (uint32_t)unzGetOffset64(file);\n}\n\nint64_t unzGetOffset64(unzFile file) {\n    mz_compat *compat = (mz_compat *)file;\n    if (!compat)\n        return UNZ_PARAMERROR;\n    return mz_zip_get_entry(compat->handle);\n}\n\nint unzSetOffset(unzFile file, unsigned long pos) {\n    return unzSetOffset64(file, pos);\n}\n\nint unzSetOffset64(unzFile file, int64_t pos) {\n    mz_compat *compat = (mz_compat *)file;\n    if (!compat)\n        return UNZ_PARAMERROR;\n    return (int)mz_zip_goto_entry(compat->handle, pos);\n}\n\nint unzGetLocalExtrafield(unzFile file, void *buf, unsigned int len) {\n    mz_compat *compat = (mz_compat *)file;\n    mz_zip_file *file_info = NULL;\n    int32_t err = MZ_OK;\n    int32_t bytes_to_copy = 0;\n\n    if (!compat || !buf || len >= INT32_MAX)\n        return UNZ_PARAMERROR;\n\n    err = mz_zip_entry_get_local_info(compat->handle, &file_info);\n    if (err != MZ_OK)\n        return err;\n\n    bytes_to_copy = (int32_t)len;\n    if (bytes_to_copy > file_info->extrafield_size)\n        bytes_to_copy = file_info->extrafield_size;\n\n    memcpy(buf, file_info->extrafield, bytes_to_copy);\n    return MZ_OK;\n}\n\nint32_t unzTell(unzFile file) {\n    return unztell(file);\n}\n\nint32_t unztell(unzFile file) {\n    return (int32_t)unztell64(file);\n}\n\nuint64_t unzTell64(unzFile file) {\n    return unztell64(file);\n}\n\nuint64_t unztell64(unzFile file) {\n    mz_compat *compat = (mz_compat *)file;\n    if (!compat)\n        return UNZ_PARAMERROR;\n    return compat->total_out;\n}\n\nint unzSeek(unzFile file, int32_t offset, int origin) {\n    return unzSeek64(file, offset, origin);\n}\n\nint unzSeek64(unzFile file, int64_t offset, int origin) {\n    mz_compat *compat = (mz_compat *)file;\n    mz_zip_file *file_info = NULL;\n    int64_t position = 0;\n    int32_t err = MZ_OK;\n    void *stream = NULL;\n\n    if (!compat)\n        return UNZ_PARAMERROR;\n    err = mz_zip_entry_get_info(compat->handle, &file_info);\n    if (err != MZ_OK)\n        return err;\n    if (file_info->compression_method != MZ_COMPRESS_METHOD_STORE)\n        return UNZ_ERRNO;\n\n    if (origin == SEEK_SET)\n        position = offset;\n    else if (origin == SEEK_CUR)\n        position = compat->total_out + offset;\n    else if (origin == SEEK_END)\n        position = (int64_t)file_info->compressed_size + offset;\n    else\n        return UNZ_PARAMERROR;\n\n    if (position > (int64_t)file_info->compressed_size)\n        return UNZ_PARAMERROR;\n\n    err = mz_zip_get_stream(compat->handle, &stream);\n    if (err == MZ_OK)\n        err = mz_stream_seek(stream, compat->entry_pos + position, MZ_SEEK_SET);\n    if (err == MZ_OK)\n        compat->total_out = position;\n    return err;\n}\n\nint unzEndOfFile(unzFile file) {\n    return unzeof(file);\n}\n\nint unzeof(unzFile file) {\n    mz_compat *compat = (mz_compat *)file;\n    mz_zip_file *file_info = NULL;\n    int32_t err = MZ_OK;\n\n    if (!compat)\n        return UNZ_PARAMERROR;\n    err = mz_zip_entry_get_info(compat->handle, &file_info);\n    if (err != MZ_OK)\n        return err;\n    if (compat->total_out == (int64_t)file_info->uncompressed_size)\n        return 1;\n    return 0;\n}\n\nvoid* unzGetStream(unzFile file) {\n    mz_compat *compat = (mz_compat *)file;\n    if (!compat)\n        return NULL;\n    return (void *)compat->stream;\n}\n\n/***************************************************************************/\n"
  },
  {
    "path": "ios/CodePush/SSZipArchive/minizip/mz_compat.h",
    "content": "/* mz_compat.h -- Backwards compatible interface for older versions\n   part of the minizip-ng project\n\n   Copyright (C) Nathan Moinvaziri\n     https://github.com/zlib-ng/minizip-ng\n   Copyright (C) 1998-2010 Gilles Vollant\n     https://www.winimage.com/zLibDll/minizip.html\n\n   This program is distributed under the terms of the same license as zlib.\n   See the accompanying LICENSE file for the full text of the license.\n \n WARNING: Be very careful updating/overwriting this file.\n It has specific changes for SSZipArchive support with some structs moved to SSZipCommon for public access\n*/\n\n#ifndef MZ_COMPAT_H\n#define MZ_COMPAT_H\n\n#include \"mz.h\"\n#include \"../SSZipCommon.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/***************************************************************************/\n\n#if defined(HAVE_ZLIB) && defined(MAX_MEM_LEVEL)\n#ifndef DEF_MEM_LEVEL\n#  if MAX_MEM_LEVEL >= 8\n#    define DEF_MEM_LEVEL 8\n#  else\n#    define DEF_MEM_LEVEL  MAX_MEM_LEVEL\n#  endif\n#endif\n#endif\n#ifndef MAX_WBITS\n#define MAX_WBITS     15 //removed () to suppress warning about ambiguous expansion of macro -SSZipArchive\n#endif\n#ifndef DEF_MEM_LEVEL\n#define DEF_MEM_LEVEL (8)\n#endif\n\n#ifndef ZEXPORT\n#  define ZEXPORT MZ_EXPORT\n#endif\n\n/***************************************************************************/\n\n#if defined(STRICTZIP) || defined(STRICTZIPUNZIP)\n/* like the STRICT of WIN32, we define a pointer that cannot be converted\n    from (void*) without cast */\ntypedef struct TagzipFile__ { int unused; } zip_file__;\ntypedef zip_file__ *zipFile;\n#else\ntypedef void *zipFile;\n#endif\n\n/***************************************************************************/\n\ntypedef uint64_t ZPOS64_T;\n\n#ifndef ZCALLBACK\n#define ZCALLBACK\n#endif\n\ntypedef void*         (ZCALLBACK *open_file_func)     (void *opaque, const char *filename, int mode);\ntypedef void*         (ZCALLBACK *open64_file_func)   (void *opaque, const void *filename, int mode);\ntypedef unsigned long (ZCALLBACK *read_file_func)     (void *opaque, void *stream, void* buf, unsigned long size);\ntypedef unsigned long (ZCALLBACK *write_file_func)    (void *opaque, void *stream, const void* buf,\n                                                       unsigned long size);\ntypedef int           (ZCALLBACK *close_file_func)    (void *opaque, void *stream);\ntypedef int           (ZCALLBACK *testerror_file_func)(void *opaque, void *stream);\ntypedef long          (ZCALLBACK *tell_file_func)     (void *opaque, void *stream);\ntypedef ZPOS64_T      (ZCALLBACK *tell64_file_func)   (void *opaque, void *stream);\ntypedef long          (ZCALLBACK *seek_file_func)     (void *opaque, void *stream, unsigned long offset, int origin);\ntypedef long          (ZCALLBACK *seek64_file_func)   (void *opaque, void *stream, ZPOS64_T offset, int origin);\n\ntypedef struct zlib_filefunc_def_s\n{\n    open_file_func      zopen_file;\n    read_file_func      zread_file;\n    write_file_func     zwrite_file;\n    tell_file_func      ztell_file;\n    seek_file_func      zseek_file;\n    close_file_func     zclose_file;\n    testerror_file_func zerror_file;\n    void*               opaque;\n} zlib_filefunc_def;\n\ntypedef struct zlib_filefunc64_def_s\n{\n    open64_file_func    zopen64_file;\n    read_file_func      zread_file;\n    write_file_func     zwrite_file;\n    tell64_file_func    ztell64_file;\n    seek64_file_func    zseek64_file;\n    close_file_func     zclose_file;\n    testerror_file_func zerror_file;\n    void*               opaque;\n} zlib_filefunc64_def;\n\n/***************************************************************************/\n\n#define ZLIB_FILEFUNC_SEEK_SET              (0)\n#define ZLIB_FILEFUNC_SEEK_CUR              (1)\n#define ZLIB_FILEFUNC_SEEK_END              (2)\n\n#define ZLIB_FILEFUNC_MODE_READ             (1)\n#define ZLIB_FILEFUNC_MODE_WRITE            (2)\n#define ZLIB_FILEFUNC_MODE_READWRITEFILTER  (3)\n\n#define ZLIB_FILEFUNC_MODE_EXISTING         (4)\n#define ZLIB_FILEFUNC_MODE_CREATE           (8)\n\n/***************************************************************************/\n\nZEXPORT void fill_fopen_filefunc(zlib_filefunc_def *pzlib_filefunc_def);\nZEXPORT void fill_fopen64_filefunc(zlib_filefunc64_def *pzlib_filefunc_def);\nZEXPORT void fill_win32_filefunc(zlib_filefunc_def *pzlib_filefunc_def);\nZEXPORT void fill_win32_filefunc64(zlib_filefunc64_def *pzlib_filefunc_def);\nZEXPORT void fill_win32_filefunc64A(zlib_filefunc64_def *pzlib_filefunc_def);\nZEXPORT void fill_memory_filefunc(zlib_filefunc_def *pzlib_filefunc_def);\n\n/***************************************************************************/\n\n\n// SSZipArchive 2.x+ uses dos_date\n#define MZ_COMPAT_VERSION 120\n\n#if MZ_COMPAT_VERSION <= 110\n#define mz_dos_date dosDate\n#else\n#define mz_dos_date dos_date\n#endif\n\ntypedef struct tm tm_unz;\ntypedef struct tm tm_zip;\n\ntypedef struct {\n    uint32_t    mz_dos_date;\n    struct tm   tmz_date;\n    uint16_t    internal_fa;        /* internal file attributes        2 bytes */\n    uint32_t    external_fa;        /* external file attributes        4 bytes */\n} zip_fileinfo;\n\ntypedef const char *zipcharpc;\n\n/***************************************************************************/\n\n#define ZIP_OK                          (0)\n#define ZIP_EOF                         (0)\n#define ZIP_ERRNO                       (-1)\n#define ZIP_PARAMERROR                  (-102)\n#define ZIP_BADZIPFILE                  (-103)\n#define ZIP_INTERNALERROR               (-104)\n\n#ifndef Z_DEFLATED\n#define Z_DEFLATED                      8 //removed () to suppress warning about ambiguous expansion of macro -SSZipArchive\n#endif\n#define Z_BZIP2ED                       (12)\n\n#define APPEND_STATUS_CREATE            (0)\n#define APPEND_STATUS_CREATEAFTER       (1)\n#define APPEND_STATUS_ADDINZIP          (2)\n\n/***************************************************************************/\n/* Writing a zip file  */\n\nZEXPORT zipFile zipOpen(const char *path, int append);\nZEXPORT zipFile zipOpen64(const void *path, int append);\nZEXPORT zipFile zipOpen2(const char *path, int append, const char **globalcomment,\n    zlib_filefunc_def *pzlib_filefunc_def);\n\nZEXPORT zipFile zipOpen2_64(const void *path, int append, const char **globalcomment,\n    zlib_filefunc64_def *pzlib_filefunc_def);\nZEXPORT zipFile zipOpen_MZ(void *stream, int append, const char **globalcomment);\n\nZEXPORT void*   zipGetHandle_MZ(zipFile);\nZEXPORT void*   zipGetStream_MZ(zipFile file);\n\nZEXPORT int     zipOpenNewFileInZip(zipFile file, const char *filename, const zip_fileinfo *zipfi,\n    const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global,\n    uint16_t size_extrafield_global, const char *comment, int compression_method, int level);\nZEXPORT int     zipOpenNewFileInZip_64(zipFile file, const char *filename, const zip_fileinfo *zipfi,\n    const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global,\n    uint16_t size_extrafield_global, const char *comment, int compression_method, int level,\n    int zip64);\nZEXPORT int     zipOpenNewFileInZip2(zipFile file, const char *filename, const zip_fileinfo *zipfi,\n    const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global,\n    uint16_t size_extrafield_global, const char *comment, int compression_method, int level,\n    int raw);\nZEXPORT int     zipOpenNewFileInZip2_64(zipFile file, const char *filename, const zip_fileinfo *zipfi,\n    const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global,\n    uint16_t size_extrafield_global, const char *comment, int compression_method, int level,\n    int raw, int zip64);\nZEXPORT int     zipOpenNewFileInZip3(zipFile file, const char *filename, const zip_fileinfo *zipfi,\n    const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global,\n    uint16_t size_extrafield_global, const char *comment, int compression_method, int level,\n    int raw, int windowBits, int memLevel, int strategy, const char *password,\n    unsigned long crc_for_crypting);\nZEXPORT int     zipOpenNewFileInZip3_64(zipFile file, const char *filename, const zip_fileinfo *zipfi,\n    const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global,\n    uint16_t size_extrafield_global, const char *comment, int compression_method, int level,\n    int raw, int windowBits, int memLevel, int strategy, const char *password,\n    unsigned long crc_for_crypting, int zip64);\nZEXPORT int     zipOpenNewFileInZip4(zipFile file, const char *filename, const zip_fileinfo *zipfi,\n    const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global,\n    uint16_t size_extrafield_global, const char *comment, int compression_method, int level,\n    int raw, int windowBits, int memLevel, int strategy, const char *password,\n    unsigned long crc_for_crypting, unsigned long version_madeby, unsigned long flag_base);\nZEXPORT int     zipOpenNewFileInZip4_64(zipFile file, const char *filename, const zip_fileinfo *zipfi,\n    const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global,\n    uint16_t size_extrafield_global, const char *comment, int compression_method, int level,\n    int raw, int windowBits, int memLevel, int strategy, const char *password,\n    unsigned long crc_for_crypting, unsigned long version_madeby, unsigned long flag_base, int zip64);\nZEXPORT int     zipOpenNewFileInZip5(zipFile file, const char *filename, const zip_fileinfo *zipfi,\n    const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global,\n    uint16_t size_extrafield_global, const char *comment, int compression_method, int level,\n    int raw, int windowBits, int memLevel, int strategy, const char *password,\n    unsigned long crc_for_crypting, signed char aes, unsigned long version_madeby, unsigned long flag_base, int zip64);\n\nZEXPORT int     zipWriteInFileInZip(zipFile file, const void *buf, uint32_t len);\n\nZEXPORT int     zipCloseFileInZipRaw(zipFile file, unsigned long uncompressed_size, uint32_t crc32);\nZEXPORT int     zipCloseFileInZipRaw64(zipFile file, uint64_t uncompressed_size, uint32_t crc32);\nZEXPORT int     zipCloseFileInZip(zipFile file);\nZEXPORT int     zipCloseFileInZip64(zipFile file);\n\nZEXPORT int     zipClose(zipFile file, const char *global_comment);\nZEXPORT int     zipClose_64(zipFile file, const char *global_comment);\nZEXPORT int     zipClose2_64(zipFile file, const char *global_comment, uint16_t version_madeby);\n        int     zipClose_MZ(zipFile file, const char *global_comment);\n        int     zipClose2_MZ(zipFile file, const char *global_comment, uint16_t version_madeby);\n\n/***************************************************************************/\n\n#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP)\n/* like the STRICT of WIN32, we define a pointer that cannot be converted\n    from (void*) without cast */\ntypedef struct TagunzFile__ { int unused; } unz_file__;\ntypedef unz_file__ *unzFile;\n#else\ntypedef void *unzFile;\n#endif\n\n/***************************************************************************/\n\n#define UNZ_OK                          (0)\n#define UNZ_END_OF_LIST_OF_FILE         (-100)\n#define UNZ_ERRNO                       (-1)\n#define UNZ_EOF                         (0)\n#define UNZ_PARAMERROR                  (-102)\n#define UNZ_BADZIPFILE                  (-103)\n#define UNZ_INTERNALERROR               (-104)\n#define UNZ_CRCERROR                    (-105)\n#define UNZ_BADPASSWORD                 (-106)\n\n/***************************************************************************/\n\ntypedef int (*unzFileNameComparer)(unzFile file, const char *filename1, const char *filename2);\ntypedef int (*unzIteratorFunction)(unzFile file);\ntypedef int (*unzIteratorFunction2)(unzFile file, unz_file_info64 *pfile_info, char *filename,\n    uint16_t filename_size, void *extrafield, uint16_t extrafield_size, char *comment,\n    uint16_t comment_size);\n\n/***************************************************************************/\n/* Reading a zip file */\n\nZEXPORT unzFile unzOpen(const char *path);\nZEXPORT unzFile unzOpen64(const void *path);\nZEXPORT unzFile unzOpen2(const char *path, zlib_filefunc_def *pzlib_filefunc_def);\nZEXPORT unzFile unzOpen2_64(const void *path, zlib_filefunc64_def *pzlib_filefunc_def);\n        unzFile unzOpen_MZ(void *stream);\n\nZEXPORT int     unzClose(unzFile file);\nZEXPORT int     unzClose_MZ(unzFile file);\n\nZEXPORT void*   unzGetHandle_MZ(unzFile file);\nZEXPORT void*   unzGetStream_MZ(zipFile file);\n\nZEXPORT int     unzGetGlobalInfo(unzFile file, unz_global_info* pglobal_info32);\nZEXPORT int     unzGetGlobalInfo64(unzFile file, unz_global_info64 *pglobal_info);\nZEXPORT int     unzGetGlobalComment(unzFile file, char *comment, unsigned long comment_size);\n\nZEXPORT int     unzOpenCurrentFile(unzFile file);\nZEXPORT int     unzOpenCurrentFilePassword(unzFile file, const char *password);\nZEXPORT int     unzOpenCurrentFile2(unzFile file, int *method, int *level, int raw);\nZEXPORT int     unzOpenCurrentFile3(unzFile file, int *method, int *level, int raw, const char *password);\nZEXPORT int     unzReadCurrentFile(unzFile file, void *buf, uint32_t len);\nZEXPORT int     unzCloseCurrentFile(unzFile file);\n\nZEXPORT int     unzGetCurrentFileInfo(unzFile file, unz_file_info *pfile_info, char *filename,\n    unsigned long filename_size, void *extrafield, unsigned long extrafield_size, char *comment,\n    unsigned long comment_size);\nZEXPORT int     unzGetCurrentFileInfo64(unzFile file, unz_file_info64 * pfile_info, char *filename,\n    unsigned long filename_size, void *extrafield, unsigned long extrafield_size, char *comment,\n    unsigned long comment_size);\n\nZEXPORT int     unzGoToFirstFile(unzFile file);\nZEXPORT int     unzGoToNextFile(unzFile file);\nZEXPORT int     unzLocateFile(unzFile file, const char *filename, unzFileNameComparer filename_compare_func);\n\nZEXPORT int     unzGetLocalExtrafield(unzFile file, void *buf, unsigned int len);\n\n/***************************************************************************/\n/* Raw access to zip file */\n\ntypedef struct unz_file_pos_s {\n    uint32_t pos_in_zip_directory;  /* offset in zip file directory */\n    uint32_t num_of_file;           /* # of file */\n} unz_file_pos;\n\nZEXPORT int     unzGetFilePos(unzFile file, unz_file_pos *file_pos);\nZEXPORT int     unzGoToFilePos(unzFile file, unz_file_pos *file_pos);\n\ntypedef struct unz64_file_pos_s {\n    int64_t  pos_in_zip_directory;   /* offset in zip file directory  */\n    uint64_t num_of_file;            /* # of file */\n} unz64_file_pos;\n\nZEXPORT int     unzGetFilePos64(unzFile file, unz64_file_pos *file_pos);\nZEXPORT int     unzGoToFilePos64(unzFile file, const unz64_file_pos *file_pos);\n\nZEXPORT int64_t unzGetOffset64(unzFile file);\nZEXPORT unsigned long\n                unzGetOffset(unzFile file);\nZEXPORT int     unzSetOffset64(unzFile file, int64_t pos);\nZEXPORT int     unzSetOffset(unzFile file, unsigned long pos);\nZEXPORT int32_t unztell(unzFile file);\nZEXPORT int32_t unzTell(unzFile file);\nZEXPORT uint64_t unztell64(unzFile file);\nZEXPORT uint64_t unzTell64(unzFile file);\nZEXPORT int     unzSeek(unzFile file, int32_t offset, int origin);\nZEXPORT int     unzSeek64(unzFile file, int64_t offset, int origin);\nZEXPORT int     unzEndOfFile(unzFile file);\nZEXPORT int     unzeof(unzFile file);\nZEXPORT void*   unzGetStream(unzFile file);\n\n/***************************************************************************/\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "ios/CodePush/SSZipArchive/minizip/mz_crypt.c",
    "content": "/* mz_crypt.c -- Crypto/hash functions\n   part of the minizip-ng project\n\n   Copyright (C) Nathan Moinvaziri\n     https://github.com/zlib-ng/minizip-ng\n\n   This program is distributed under the terms of the same license as zlib.\n   See the accompanying LICENSE file for the full text of the license.\n*/\n\n#include \"mz.h\"\n#include \"mz_os.h\"\n#include \"mz_crypt.h\"\n\n#if defined(HAVE_ZLIB)\n#  if !defined(ZLIB_COMPAT)\n#    include \"zlib-ng.h\"\n#    define ZLIB_PREFIX(x) zng_##x\n#  else\n#    include \"zlib.h\"\n#    define ZLIB_PREFIX(x) x\n#  endif\n#elif defined(HAVE_LZMA)\n#  include \"lzma.h\"\n#endif\n\n/***************************************************************************/\n\n#if defined(MZ_ZIP_NO_CRYPTO)\nint32_t mz_crypt_rand(uint8_t *buf, int32_t size) {\n    return mz_os_rand(buf, size);\n}\n#endif\n\nuint32_t mz_crypt_crc32_update(uint32_t value, const uint8_t *buf, int32_t size) {\n#if defined(HAVE_ZLIB)\n   /* Define z_crc_t in zlib 1.2.5 and less or if using zlib-ng */\n#  if (ZLIB_VERNUM < 0x1270)\n    typedef unsigned long z_crc_t;\n#  else\n    typedef uint32_t z_crc_t;\n#  endif\n    return (uint32_t)ZLIB_PREFIX(crc32)((z_crc_t)value, buf, (uInt)size);\n#elif defined(HAVE_LZMA)\n    return (uint32_t)lzma_crc32(buf, (size_t)size, (uint32_t)value);\n#else\n    static uint32_t crc32_table[256] = {\n        0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,\n        0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,\n        0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,\n        0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,\n        0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,\n        0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,\n        0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,\n        0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,\n        0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,\n        0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,\n        0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,\n        0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,\n        0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,\n        0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,\n        0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,\n        0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,\n        0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,\n        0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,\n        0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,\n        0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,\n        0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,\n        0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,\n        0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,\n        0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,\n        0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,\n        0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,\n        0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,\n        0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,\n        0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,\n        0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,\n        0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,\n        0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,\n        0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,\n        0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,\n        0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,\n        0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,\n        0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,\n        0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,\n        0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,\n        0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,\n        0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,\n        0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,\n        0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d\n    };\n    value = ~value;\n\n    while (size > 0) {\n        value = (value >> 8) ^ crc32_table[(value ^ *buf) & 0xFF];\n\n        buf += 1;\n        size -= 1;\n    }\n\n    return ~value;\n#endif\n}\n\n#if defined(HAVE_WZAES)\nint32_t  mz_crypt_pbkdf2(uint8_t *password, int32_t password_length, uint8_t *salt,\n    int32_t salt_length, uint16_t iteration_count, uint8_t *key, uint16_t key_length) {\n    void *hmac1 = NULL;\n    void *hmac2 = NULL;\n    void *hmac3 = NULL;\n    int32_t err = MZ_OK;\n    uint16_t i = 0;\n    uint16_t j = 0;\n    uint16_t k = 0;\n    uint16_t block_count = 0;\n    uint8_t uu[MZ_HASH_SHA1_SIZE];\n    uint8_t ux[MZ_HASH_SHA1_SIZE];\n\n    if (!password || !salt || !key)\n        return MZ_PARAM_ERROR;\n\n    memset(key, 0, key_length);\n\n    mz_crypt_hmac_create(&hmac1);\n    mz_crypt_hmac_create(&hmac2);\n    mz_crypt_hmac_create(&hmac3);\n\n    mz_crypt_hmac_set_algorithm(hmac1, MZ_HASH_SHA1);\n    mz_crypt_hmac_set_algorithm(hmac2, MZ_HASH_SHA1);\n    mz_crypt_hmac_set_algorithm(hmac3, MZ_HASH_SHA1);\n\n    err = mz_crypt_hmac_init(hmac1, password, password_length);\n    if (err == MZ_OK)\n        err = mz_crypt_hmac_init(hmac2, password, password_length);\n    if (err == MZ_OK)\n        err = mz_crypt_hmac_update(hmac2, salt, salt_length);\n\n    block_count = 1 + ((uint16_t)key_length - 1) / MZ_HASH_SHA1_SIZE;\n\n    for (i = 0; (err == MZ_OK) && (i < block_count); i += 1) {\n        memset(ux, 0, sizeof(ux));\n\n        err = mz_crypt_hmac_copy(hmac2, hmac3);\n        if (err != MZ_OK)\n            break;\n\n        uu[0] = (uint8_t)((i + 1) >> 24);\n        uu[1] = (uint8_t)((i + 1) >> 16);\n        uu[2] = (uint8_t)((i + 1) >> 8);\n        uu[3] = (uint8_t)(i + 1);\n\n        for (j = 0, k = 4; j < iteration_count; j += 1) {\n            err = mz_crypt_hmac_update(hmac3, uu, k);\n            if (err == MZ_OK)\n                err = mz_crypt_hmac_end(hmac3, uu, sizeof(uu));\n            if (err != MZ_OK)\n                break;\n\n            for (k = 0; k < MZ_HASH_SHA1_SIZE; k += 1)\n                ux[k] ^= uu[k];\n\n            err = mz_crypt_hmac_copy(hmac1, hmac3);\n            if (err != MZ_OK)\n                break;\n        }\n\n        if (err != MZ_OK)\n            break;\n\n        j = 0;\n        k = i * MZ_HASH_SHA1_SIZE;\n\n        while (j < MZ_HASH_SHA1_SIZE && k < key_length)\n            key[k++] = ux[j++];\n    }\n\n    /* hmac3 uses the same provider as hmac2, so it must be deleted\n       before the context is destroyed. */\n    mz_crypt_hmac_delete(&hmac3);\n    mz_crypt_hmac_delete(&hmac1);\n    mz_crypt_hmac_delete(&hmac2);\n\n    return err;\n}\n#endif\n\n/***************************************************************************/\n"
  },
  {
    "path": "ios/CodePush/SSZipArchive/minizip/mz_crypt.h",
    "content": "/* mz_crypt.h -- Crypto/hash functions\n   part of the minizip-ng project\n\n   Copyright (C) Nathan Moinvaziri\n     https://github.com/zlib-ng/minizip-ng\n\n   This program is distributed under the terms of the same license as zlib.\n   See the accompanying LICENSE file for the full text of the license.\n*/\n\n#ifndef MZ_CRYPT_H\n#define MZ_CRYPT_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/***************************************************************************/\n\nuint32_t mz_crypt_crc32_update(uint32_t value, const uint8_t *buf, int32_t size);\n\nint32_t  mz_crypt_pbkdf2(uint8_t *password, int32_t password_length, uint8_t *salt,\n            int32_t salt_length, uint16_t iteration_count, uint8_t *key, uint16_t key_length);\n\n/***************************************************************************/\n\nint32_t  mz_crypt_rand(uint8_t *buf, int32_t size);\n\nvoid     mz_crypt_sha_reset(void *handle);\nint32_t  mz_crypt_sha_begin(void *handle);\nint32_t  mz_crypt_sha_update(void *handle, const void *buf, int32_t size);\nint32_t  mz_crypt_sha_end(void *handle, uint8_t *digest, int32_t digest_size);\nvoid     mz_crypt_sha_set_algorithm(void *handle, uint16_t algorithm);\nvoid*    mz_crypt_sha_create(void **handle);\nvoid     mz_crypt_sha_delete(void **handle);\n\nvoid     mz_crypt_aes_reset(void *handle);\nint32_t  mz_crypt_aes_encrypt(void *handle, uint8_t *buf, int32_t size);\nint32_t  mz_crypt_aes_decrypt(void *handle, uint8_t *buf, int32_t size);\nint32_t  mz_crypt_aes_set_encrypt_key(void *handle, const void *key, int32_t key_length);\nint32_t  mz_crypt_aes_set_decrypt_key(void *handle, const void *key, int32_t key_length);\nvoid     mz_crypt_aes_set_mode(void *handle, int32_t mode);\nvoid*    mz_crypt_aes_create(void **handle);\nvoid     mz_crypt_aes_delete(void **handle);\n\nvoid     mz_crypt_hmac_reset(void *handle);\nint32_t  mz_crypt_hmac_init(void *handle, const void *key, int32_t key_length);\nint32_t  mz_crypt_hmac_update(void *handle, const void *buf, int32_t size);\nint32_t  mz_crypt_hmac_end(void *handle, uint8_t *digest, int32_t digest_size);\nint32_t  mz_crypt_hmac_copy(void *src_handle, void *target_handle);\nvoid     mz_crypt_hmac_set_algorithm(void *handle, uint16_t algorithm);\nvoid*    mz_crypt_hmac_create(void **handle);\nvoid     mz_crypt_hmac_delete(void **handle);\n\nint32_t  mz_crypt_sign(uint8_t *message, int32_t message_size, uint8_t *cert_data, int32_t cert_data_size,\n            const char *cert_pwd, uint8_t **signature, int32_t *signature_size);\nint32_t  mz_crypt_sign_verify(uint8_t *message, int32_t message_size, uint8_t *signature, int32_t signature_size);\n\n/***************************************************************************/\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "ios/CodePush/SSZipArchive/minizip/mz_crypt_apple.c",
    "content": "/* mz_crypt_apple.c -- Crypto/hash functions for Apple\n   part of the minizip-ng project\n\n   Copyright (C) Nathan Moinvaziri\n     https://github.com/zlib-ng/minizip-ng\n\n   This program is distributed under the terms of the same license as zlib.\n   See the accompanying LICENSE file for the full text of the license.\n*/\n\n#include \"mz.h\"\n\n#include <CoreFoundation/CoreFoundation.h>\n#include <CommonCrypto/CommonCryptor.h>\n#include <CommonCrypto/CommonDigest.h>\n#include <CommonCrypto/CommonHMAC.h>\n#include <Security/Security.h>\n#include <Security/SecPolicy.h>\n\n/***************************************************************************/\n\nint32_t mz_crypt_rand(uint8_t *buf, int32_t size) {\n    if (SecRandomCopyBytes(kSecRandomDefault, size, buf) != errSecSuccess)\n        return 0;\n    return size;\n}\n\n/***************************************************************************/\n\ntypedef struct mz_crypt_sha_s {\n    union {\n        CC_SHA1_CTX   ctx1;\n        CC_SHA256_CTX ctx256;\n        CC_SHA512_CTX ctx512;\n    };\n    int32_t           error;\n    int32_t           initialized;\n    uint16_t          algorithm;\n} mz_crypt_sha;\n\n/***************************************************************************/\n\nstatic const uint8_t mz_crypt_sha_digest_size[] = {\n    MZ_HASH_SHA1_SIZE,                     0, MZ_HASH_SHA224_SIZE,\n    MZ_HASH_SHA256_SIZE, MZ_HASH_SHA384_SIZE, MZ_HASH_SHA512_SIZE\n};\n\n/***************************************************************************/\n\nvoid mz_crypt_sha_reset(void *handle) {\n    mz_crypt_sha *sha = (mz_crypt_sha *)handle;\n\n    sha->error = 0;\n    sha->initialized = 0;\n}\n\nint32_t mz_crypt_sha_begin(void *handle) {\n    mz_crypt_sha *sha = (mz_crypt_sha *)handle;\n\n    if (!sha)\n        return MZ_PARAM_ERROR;\n\n    mz_crypt_sha_reset(handle);\n\n    switch (sha->algorithm) {\n    case MZ_HASH_SHA1:\n        sha->error = CC_SHA1_Init(&sha->ctx1);\n        break;\n    case MZ_HASH_SHA224:\n        sha->error = CC_SHA224_Init(&sha->ctx256);\n        break;\n    case MZ_HASH_SHA256:\n        sha->error = CC_SHA256_Init(&sha->ctx256);\n        break;\n    case MZ_HASH_SHA384:\n        sha->error = CC_SHA384_Init(&sha->ctx512);\n        break;\n    case MZ_HASH_SHA512:\n        sha->error = CC_SHA512_Init(&sha->ctx512);\n        break;\n    default:\n        return MZ_PARAM_ERROR;\n    }\n\n    if (!sha->error)\n        return MZ_HASH_ERROR;\n\n    sha->initialized = 1;\n    return MZ_OK;\n}\n\nint32_t mz_crypt_sha_update(void *handle, const void *buf, int32_t size) {\n    mz_crypt_sha *sha = (mz_crypt_sha *)handle;\n\n    if (!sha || !buf || !sha->initialized)\n        return MZ_PARAM_ERROR;\n\n    switch (sha->algorithm) {\n    case MZ_HASH_SHA1:\n        sha->error = CC_SHA1_Update(&sha->ctx1, buf, size);\n        break;\n    case MZ_HASH_SHA224:\n        sha->error = CC_SHA224_Update(&sha->ctx256, buf, size);\n        break;\n    case MZ_HASH_SHA256:\n        sha->error = CC_SHA256_Update(&sha->ctx256, buf, size);\n        break;\n    case MZ_HASH_SHA384:\n        sha->error = CC_SHA384_Update(&sha->ctx512, buf, size);\n        break;\n    case MZ_HASH_SHA512:\n        sha->error = CC_SHA512_Update(&sha->ctx512, buf, size);\n        break;\n    }\n\n    if (!sha->error)\n        return MZ_HASH_ERROR;\n\n    return size;\n}\n\nint32_t mz_crypt_sha_end(void *handle, uint8_t *digest, int32_t digest_size) {\n    mz_crypt_sha *sha = (mz_crypt_sha *)handle;\n\n    if (!sha || !digest || !sha->initialized)\n        return MZ_PARAM_ERROR;\n    if (digest_size < mz_crypt_sha_digest_size[sha->algorithm - MZ_HASH_SHA1])\n        return MZ_PARAM_ERROR;\n\n    switch (sha->algorithm) {\n    case MZ_HASH_SHA1:\n        sha->error = CC_SHA1_Final(digest, &sha->ctx1);\n        break;\n    case MZ_HASH_SHA224:\n        sha->error = CC_SHA224_Final(digest, &sha->ctx256);\n        break;\n    case MZ_HASH_SHA256:\n        sha->error = CC_SHA256_Final(digest, &sha->ctx256);\n        break;\n    case MZ_HASH_SHA384:\n        sha->error = CC_SHA384_Final(digest, &sha->ctx512);\n        break;\n    case MZ_HASH_SHA512:\n        sha->error = CC_SHA512_Final(digest, &sha->ctx512);\n        break;\n    }\n\n    if (!sha->error)\n        return MZ_HASH_ERROR;\n\n    return MZ_OK;\n}\n\nvoid mz_crypt_sha_set_algorithm(void *handle, uint16_t algorithm) {\n    mz_crypt_sha *sha = (mz_crypt_sha *)handle;\n    if (MZ_HASH_SHA1 <= algorithm && algorithm <= MZ_HASH_SHA512)\n        sha->algorithm = algorithm;\n}\n\nvoid *mz_crypt_sha_create(void **handle) {\n    mz_crypt_sha *sha = NULL;\n\n    sha = (mz_crypt_sha *)calloc(1, sizeof(mz_crypt_sha));\n    if (sha) {\n        memset(sha, 0, sizeof(mz_crypt_sha));\n        sha->algorithm = MZ_HASH_SHA256;\n    }\n    if (handle)\n        *handle = sha;\n\n    return sha;\n}\n\nvoid mz_crypt_sha_delete(void **handle) {\n    mz_crypt_sha *sha = NULL;\n    if (!handle)\n        return;\n    sha = (mz_crypt_sha *)*handle;\n    if (sha) {\n        mz_crypt_sha_reset(*handle);\n        free(sha);\n    }\n    *handle = NULL;\n}\n\n/***************************************************************************/\n\ntypedef struct mz_crypt_aes_s {\n    CCCryptorRef crypt;\n    int32_t      mode;\n    int32_t      error;\n} mz_crypt_aes;\n\n/***************************************************************************/\n\nvoid mz_crypt_aes_reset(void *handle) {\n    mz_crypt_aes *aes = (mz_crypt_aes *)handle;\n\n    if (aes->crypt)\n        CCCryptorRelease(aes->crypt);\n    aes->crypt = NULL;\n}\n\nint32_t mz_crypt_aes_encrypt(void *handle, uint8_t *buf, int32_t size) {\n    mz_crypt_aes *aes = (mz_crypt_aes *)handle;\n    size_t data_moved = 0;\n\n    if (!aes || !buf)\n        return MZ_PARAM_ERROR;\n    if (size != MZ_AES_BLOCK_SIZE)\n        return MZ_PARAM_ERROR;\n\n    aes->error = CCCryptorUpdate(aes->crypt, buf, size, buf, size, &data_moved);\n\n    if (aes->error != kCCSuccess)\n        return MZ_HASH_ERROR;\n\n    return size;\n}\n\nint32_t mz_crypt_aes_decrypt(void *handle, uint8_t *buf, int32_t size) {\n    mz_crypt_aes *aes = (mz_crypt_aes *)handle;\n    size_t data_moved = 0;\n\n    if (!aes || !buf)\n        return MZ_PARAM_ERROR;\n    if (size != MZ_AES_BLOCK_SIZE)\n        return MZ_PARAM_ERROR;\n\n    aes->error = CCCryptorUpdate(aes->crypt, buf, size, buf, size, &data_moved);\n\n    if (aes->error != kCCSuccess)\n        return MZ_HASH_ERROR;\n\n    return size;\n}\n\nint32_t mz_crypt_aes_set_encrypt_key(void *handle, const void *key, int32_t key_length) {\n    mz_crypt_aes *aes = (mz_crypt_aes *)handle;\n\n    if (!aes || !key || !key_length)\n        return MZ_PARAM_ERROR;\n\n    mz_crypt_aes_reset(handle);\n\n    aes->error = CCCryptorCreate(kCCEncrypt, kCCAlgorithmAES, kCCOptionECBMode,\n        key, key_length, NULL, &aes->crypt);\n\n    if (aes->error != kCCSuccess)\n        return MZ_HASH_ERROR;\n\n    return MZ_OK;\n}\n\nint32_t mz_crypt_aes_set_decrypt_key(void *handle, const void *key, int32_t key_length) {\n    mz_crypt_aes *aes = (mz_crypt_aes *)handle;\n\n    if (!aes || !key || !key_length)\n        return MZ_PARAM_ERROR;\n\n    mz_crypt_aes_reset(handle);\n\n    aes->error = CCCryptorCreate(kCCDecrypt, kCCAlgorithmAES, kCCOptionECBMode,\n        key, key_length, NULL, &aes->crypt);\n\n    if (aes->error != kCCSuccess)\n        return MZ_HASH_ERROR;\n\n    return MZ_OK;\n}\n\nvoid mz_crypt_aes_set_mode(void *handle, int32_t mode) {\n    mz_crypt_aes *aes = (mz_crypt_aes *)handle;\n    aes->mode = mode;\n}\n\nvoid *mz_crypt_aes_create(void **handle) {\n    mz_crypt_aes *aes = NULL;\n\n    aes = (mz_crypt_aes *)calloc(1, sizeof(mz_crypt_aes));\n    if (handle)\n        *handle = aes;\n\n    return aes;\n}\n\nvoid mz_crypt_aes_delete(void **handle) {\n    mz_crypt_aes *aes = NULL;\n    if (!handle)\n        return;\n    aes = (mz_crypt_aes *)*handle;\n    if (aes) {\n        mz_crypt_aes_reset(*handle);\n        free(aes);\n    }\n    *handle = NULL;\n}\n\n/***************************************************************************/\n\ntypedef struct mz_crypt_hmac_s {\n    CCHmacContext   ctx;\n    int32_t         initialized;\n    int32_t         error;\n    uint16_t        algorithm;\n} mz_crypt_hmac;\n\n/***************************************************************************/\n\nstatic void mz_crypt_hmac_free(void *handle) {\n    mz_crypt_hmac *hmac = (mz_crypt_hmac *)handle;\n    memset(&hmac->ctx, 0, sizeof(hmac->ctx));\n}\n\nvoid mz_crypt_hmac_reset(void *handle) {\n    mz_crypt_hmac *hmac = (mz_crypt_hmac *)handle;\n    mz_crypt_hmac_free(handle);\n    hmac->error = 0;\n}\n\nint32_t mz_crypt_hmac_init(void *handle, const void *key, int32_t key_length) {\n    mz_crypt_hmac *hmac = (mz_crypt_hmac *)handle;\n    CCHmacAlgorithm algorithm = 0;\n\n    if (!hmac || !key)\n        return MZ_PARAM_ERROR;\n\n    mz_crypt_hmac_reset(handle);\n\n    if (hmac->algorithm == MZ_HASH_SHA1)\n        algorithm = kCCHmacAlgSHA1;\n    else if (hmac->algorithm == MZ_HASH_SHA256)\n        algorithm = kCCHmacAlgSHA256;\n    else\n        return MZ_PARAM_ERROR;\n\n    CCHmacInit(&hmac->ctx, algorithm, key, key_length);\n    return MZ_OK;\n}\n\nint32_t mz_crypt_hmac_update(void *handle, const void *buf, int32_t size) {\n    mz_crypt_hmac *hmac = (mz_crypt_hmac *)handle;\n\n    if (!hmac || !buf)\n        return MZ_PARAM_ERROR;\n\n    CCHmacUpdate(&hmac->ctx, buf, size);\n    return MZ_OK;\n}\n\nint32_t mz_crypt_hmac_end(void *handle, uint8_t *digest, int32_t digest_size) {\n    mz_crypt_hmac *hmac = (mz_crypt_hmac *)handle;\n\n    if (!hmac || !digest)\n        return MZ_PARAM_ERROR;\n\n    if (hmac->algorithm == MZ_HASH_SHA1) {\n        if (digest_size < MZ_HASH_SHA1_SIZE)\n            return MZ_BUF_ERROR;\n        CCHmacFinal(&hmac->ctx, digest);\n    } else {\n        if (digest_size < MZ_HASH_SHA256_SIZE)\n            return MZ_BUF_ERROR;\n        CCHmacFinal(&hmac->ctx, digest);\n    }\n\n    return MZ_OK;\n}\n\nvoid mz_crypt_hmac_set_algorithm(void *handle, uint16_t algorithm) {\n    mz_crypt_hmac *hmac = (mz_crypt_hmac *)handle;\n    hmac->algorithm = algorithm;\n}\n\nint32_t mz_crypt_hmac_copy(void *src_handle, void *target_handle) {\n    mz_crypt_hmac *source = (mz_crypt_hmac *)src_handle;\n    mz_crypt_hmac *target = (mz_crypt_hmac *)target_handle;\n\n    if (!source || !target)\n        return MZ_PARAM_ERROR;\n\n    memcpy(&target->ctx, &source->ctx, sizeof(CCHmacContext));\n    return MZ_OK;\n}\n\nvoid *mz_crypt_hmac_create(void **handle) {\n    mz_crypt_hmac *hmac = NULL;\n\n    hmac = (mz_crypt_hmac *)calloc(1, sizeof(mz_crypt_hmac));\n    if (hmac)\n        hmac->algorithm = MZ_HASH_SHA256;\n    if (handle)\n        *handle = hmac;\n\n    return hmac;\n}\n\nvoid mz_crypt_hmac_delete(void **handle) {\n    mz_crypt_hmac *hmac = NULL;\n    if (!handle)\n        return;\n    hmac = (mz_crypt_hmac *)*handle;\n    if (hmac) {\n        mz_crypt_hmac_free(*handle);\n        free(hmac);\n    }\n    *handle = NULL;\n}\n\n/***************************************************************************/\n\n#if defined(MZ_ZIP_SIGNING)\nint32_t mz_crypt_sign(uint8_t *message, int32_t message_size, uint8_t *cert_data, int32_t cert_data_size,\n    const char *cert_pwd, uint8_t **signature, int32_t *signature_size) {\n    CFStringRef password_ref = NULL;\n    CFDictionaryRef options_dict = NULL;\n    CFDictionaryRef identity_trust = NULL;\n    CFDataRef signature_out = NULL;\n    CFDataRef pkcs12_data = NULL;\n    CFArrayRef items = 0;\n    SecIdentityRef identity = NULL;\n    SecTrustRef trust = NULL;\n    OSStatus status = noErr;\n    const void *options_key[2] = {kSecImportExportPassphrase, kSecReturnRef};\n    const void *options_values[2] = {0, kCFBooleanTrue};\n    int32_t err = MZ_SIGN_ERROR;\n\n    if (!message || !cert_data || !signature || !signature_size)\n        return MZ_PARAM_ERROR;\n\n    *signature = NULL;\n    *signature_size = 0;\n\n    password_ref = CFStringCreateWithCString(0, cert_pwd, kCFStringEncodingUTF8);\n    options_values[0] = password_ref;\n\n    options_dict = CFDictionaryCreate(0, options_key, options_values, 2, 0, 0);\n    if (options_dict)\n        pkcs12_data = CFDataCreate(0, cert_data, cert_data_size);\n    if (pkcs12_data)\n        status = SecPKCS12Import(pkcs12_data, options_dict, &items);\n    if (status == noErr)\n        identity_trust = CFArrayGetValueAtIndex(items, 0);\n    if (identity_trust)\n        identity = (SecIdentityRef)CFDictionaryGetValue(identity_trust, kSecImportItemIdentity);\n    if (identity)\n        trust = (SecTrustRef)CFDictionaryGetValue(identity_trust, kSecImportItemTrust);\n    if (trust) {\n        status = CMSEncodeContent(identity, NULL, NULL, FALSE, 0, message, message_size, &signature_out);\n\n        if (status == errSecSuccess) {\n            *signature_size = CFDataGetLength(signature_out);\n            *signature = (uint8_t *)malloc(*signature_size);\n\n            memcpy(*signature, CFDataGetBytePtr(signature_out), *signature_size);\n\n            err = MZ_OK;\n        }\n    }\n\n    if (signature_out)\n        CFRelease(signature_out);\n    if (items)\n        CFRelease(items);\n    if (pkcs12_data)\n        CFRelease(pkcs12_data);\n    if (options_dict)\n        CFRelease(options_dict);\n    if (password_ref)\n        CFRelease(password_ref);\n\n    return err;\n}\n\nint32_t mz_crypt_sign_verify(uint8_t *message, int32_t message_size, uint8_t *signature, int32_t signature_size) {\n    CMSDecoderRef decoder = NULL;\n    CMSSignerStatus signer_status = 0;\n    CFDataRef message_out = NULL;\n    SecPolicyRef trust_policy = NULL;\n    OSStatus status = noErr;\n    OSStatus verify_status = noErr;\n    size_t signer_count = 0;\n    size_t i = 0;\n    int32_t err = MZ_SIGN_ERROR;\n\n    if (!message || !signature)\n        return MZ_PARAM_ERROR;\n\n    status = CMSDecoderCreate(&decoder);\n    if (status == errSecSuccess)\n        status = CMSDecoderUpdateMessage(decoder, signature, signature_size);\n    if (status == errSecSuccess)\n        status = CMSDecoderFinalizeMessage(decoder);\n    if (status == errSecSuccess)\n        trust_policy = SecPolicyCreateBasicX509();\n\n    if (status == errSecSuccess && trust_policy) {\n        CMSDecoderGetNumSigners(decoder, &signer_count);\n        if (signer_count > 0)\n            err = MZ_OK;\n        for (i = 0; i < signer_count; i += 1) {\n            status = CMSDecoderCopySignerStatus(decoder, i, trust_policy, TRUE, &signer_status, NULL, &verify_status);\n            if (status != errSecSuccess || verify_status != 0 || signer_status != kCMSSignerValid) {\n                err = MZ_SIGN_ERROR;\n                break;\n            }\n        }\n    }\n\n    if (err == MZ_OK) {\n        status = CMSDecoderCopyContent(decoder, &message_out);\n        if ((status != errSecSuccess) ||\n            (CFDataGetLength(message_out) != message_size) ||\n            (memcmp(message, CFDataGetBytePtr(message_out), message_size) != 0))\n            err = MZ_SIGN_ERROR;\n    }\n\n    if (trust_policy)\n        CFRelease(trust_policy);\n    if (decoder)\n        CFRelease(decoder);\n\n    return err;\n}\n\n#endif\n"
  },
  {
    "path": "ios/CodePush/SSZipArchive/minizip/mz_os.c",
    "content": "/* mz_os.c -- System functions\n   part of the minizip-ng project\n\n   Copyright (C) Nathan Moinvaziri\n     https://github.com/zlib-ng/minizip-ng\n   Copyright (C) 1998-2010 Gilles Vollant\n     https://www.winimage.com/zLibDll/minizip.html\n\n   This program is distributed under the terms of the same license as zlib.\n   See the accompanying LICENSE file for the full text of the license.\n*/\n\n#include \"mz.h\"\n#include \"mz_crypt.h\"\n#include \"mz_os.h\"\n#include \"mz_strm.h\"\n#include \"mz_strm_os.h\"\n\n#include <ctype.h> /* tolower */\n\n/***************************************************************************/\n\nint32_t mz_path_combine(char *path, const char *join, int32_t max_path) {\n    int32_t path_len = 0;\n\n    if (!path || !join || !max_path)\n        return MZ_PARAM_ERROR;\n\n    path_len = (int32_t)strlen(path);\n\n    if (path_len == 0) {\n        strncpy(path, join, max_path - 1);\n        path[max_path - 1] = 0;\n    } else {\n        mz_path_append_slash(path, max_path, MZ_PATH_SLASH_PLATFORM);\n        path_len = (int32_t)strlen(path);\n        if (max_path > path_len)\n            strncat(path, join, max_path - path_len - 1);\n    }\n\n    return MZ_OK;\n}\n\nint32_t mz_path_append_slash(char *path, int32_t max_path, char slash) {\n    int32_t path_len = (int32_t)strlen(path);\n    if ((path_len + 2) >= max_path)\n        return MZ_BUF_ERROR;\n    if (path[path_len - 1] != '\\\\' && path[path_len - 1] != '/') {\n        path[path_len] = slash;\n        path[path_len + 1] = 0;\n    }\n    return MZ_OK;\n}\n\nint32_t mz_path_remove_slash(char *path) {\n    int32_t path_len = (int32_t)strlen(path);\n    while (path_len > 0) {\n        if (path[path_len - 1] == '\\\\' || path[path_len - 1] == '/')\n            path[path_len - 1] = 0;\n        else\n            break;\n\n        path_len -= 1;\n    }\n    return MZ_OK;\n}\n\nint32_t mz_path_has_slash(const char *path) {\n    int32_t path_len = (int32_t)strlen(path);\n    if (path[path_len - 1] != '\\\\' && path[path_len - 1] != '/')\n        return MZ_EXIST_ERROR;\n    return MZ_OK;\n}\n\nint32_t mz_path_convert_slashes(char *path, char slash) {\n    int32_t i = 0;\n\n    for (i = 0; i < (int32_t)strlen(path); i += 1) {\n        if (path[i] == '\\\\' || path[i] == '/')\n            path[i] = slash;\n    }\n    return MZ_OK;\n}\n\nint32_t mz_path_compare_wc(const char *path, const char *wildcard, uint8_t ignore_case) {\n    while (*path != 0) {\n        switch (*wildcard) {\n        case '*':\n\n            if (*(wildcard + 1) == 0)\n                return MZ_OK;\n\n            while (*path != 0) {\n                if (mz_path_compare_wc(path, (wildcard + 1), ignore_case) == MZ_OK)\n                    return MZ_OK;\n\n                path += 1;\n            }\n\n            return MZ_EXIST_ERROR;\n\n        default:\n            /* Ignore differences in path slashes on platforms */\n            if ((*path == '\\\\' && *wildcard == '/') || (*path == '/' && *wildcard == '\\\\'))\n                break;\n\n            if (ignore_case) {\n                if (tolower(*path) != tolower(*wildcard))\n                    return MZ_EXIST_ERROR;\n            } else {\n                if (*path != *wildcard)\n                    return MZ_EXIST_ERROR;\n            }\n\n            break;\n        }\n\n        path += 1;\n        wildcard += 1;\n    }\n\n    if ((*wildcard != 0) && (*wildcard != '*'))\n        return MZ_EXIST_ERROR;\n\n    return MZ_OK;\n}\n\nint32_t mz_path_resolve(const char *path, char *output, int32_t max_output) {\n    const char *source = path;\n    const char *check = output;\n    char *target = output;\n\n    if (max_output <= 0)\n        return MZ_PARAM_ERROR;\n\n    while (*source != 0 && max_output > 1) {\n        check = source;\n        if ((*check == '\\\\') || (*check == '/'))\n            check += 1;\n\n        if ((source == path) || (target == output) || (check != source)) {\n            /* Skip double paths */\n            if ((*check == '\\\\') || (*check == '/')) {\n                source += 1;\n                continue;\n            }\n            if (*check == '.') {\n                check += 1;\n\n                /* Remove . if at end of string and not at the beginning */\n                if ((*check == 0) && (source != path && target != output)) {\n                    /* Copy last slash */\n                    *target = *source;\n                    target += 1;\n                    max_output -= 1;\n                    source += (check - source);\n                    continue;\n                }\n                /* Remove . if not at end of string */\n                else if ((*check == '\\\\') || (*check == '/')) {\n                    source += (check - source);\n                    /* Skip slash if at beginning of string */\n                    if (target == output && *source != 0)\n                        source += 1;\n                    continue;\n                }\n                /* Go to parent directory .. */\n                else if (*check == '.') {\n                    check += 1;\n                    if ((*check == 0) || (*check == '\\\\' || *check == '/')) {\n                        source += (check - source);\n\n                        /* Search backwards for previous slash */\n                        if (target != output) {\n                            target -= 1;\n                            do {\n                                if ((*target == '\\\\') || (*target == '/'))\n                                    break;\n\n                                target -= 1;\n                                max_output += 1;\n                            } while (target > output);\n                        }\n\n                        if ((target == output) && (*source != 0))\n                            source += 1;\n                        if ((*target == '\\\\' || *target == '/') && (*source == 0))\n                            target += 1;\n\n                        *target = 0;\n                        continue;\n                    }\n                }\n            }\n        }\n\n        *target = *source;\n\n        source += 1;\n        target += 1;\n        max_output -= 1;\n    }\n\n    *target = 0;\n\n    if (*path == 0)\n        return MZ_INTERNAL_ERROR;\n\n    return MZ_OK;\n}\n\nint32_t mz_path_remove_filename(char *path) {\n    char *path_ptr = NULL;\n\n    if (!path)\n        return MZ_PARAM_ERROR;\n\n    path_ptr = path + strlen(path) - 1;\n\n    while (path_ptr > path) {\n        if ((*path_ptr == '/') || (*path_ptr == '\\\\')) {\n            *path_ptr = 0;\n            break;\n        }\n\n        path_ptr -= 1;\n    }\n\n    if (path_ptr == path)\n        *path_ptr = 0;\n\n    return MZ_OK;\n}\n\nint32_t mz_path_remove_extension(char *path) {\n    char *path_ptr = NULL;\n\n    if (!path)\n        return MZ_PARAM_ERROR;\n\n    path_ptr = path + strlen(path) - 1;\n\n    while (path_ptr > path) {\n        if ((*path_ptr == '/') || (*path_ptr == '\\\\'))\n            break;\n        if (*path_ptr == '.') {\n            *path_ptr = 0;\n            break;\n        }\n\n        path_ptr -= 1;\n    }\n\n    if (path_ptr == path)\n        *path_ptr = 0;\n\n    return MZ_OK;\n}\n\nint32_t mz_path_get_filename(const char *path, const char **filename) {\n    const char *match = NULL;\n\n    if (!path || !filename)\n        return MZ_PARAM_ERROR;\n\n    *filename = NULL;\n\n    for (match = path; *match != 0; match += 1) {\n        if ((*match == '\\\\') || (*match == '/'))\n            *filename = match + 1;\n    }\n\n    if (!*filename)\n        return MZ_EXIST_ERROR;\n\n    return MZ_OK;\n}\n\nint32_t mz_dir_make(const char *path) {\n    int32_t err = MZ_OK;\n    char *current_dir = NULL;\n    char *match = NULL;\n    char hold = 0;\n\n    current_dir = strdup(path);\n    if (!current_dir)\n        return MZ_MEM_ERROR;\n\n    mz_path_remove_slash(current_dir);\n\n    err = mz_os_make_dir(current_dir);\n    if (err != MZ_OK) {\n        match = current_dir + 1;\n        while (1) {\n            while (*match != 0 && *match != '\\\\' && *match != '/')\n                match += 1;\n            hold = *match;\n            *match = 0;\n\n            err = mz_os_make_dir(current_dir);\n            if (err != MZ_OK)\n                break;\n            if (hold == 0)\n                break;\n\n            *match = hold;\n            match += 1;\n        }\n    }\n\n    free(current_dir);\n    return err;\n}\n\nint32_t mz_file_get_crc(const char *path, uint32_t *result_crc) {\n    void *stream = NULL;\n    uint32_t crc32 = 0;\n    int32_t read = 0;\n    int32_t err = MZ_OK;\n    uint8_t buf[16384];\n\n    mz_stream_os_create(&stream);\n\n    err = mz_stream_os_open(stream, path, MZ_OPEN_MODE_READ);\n\n    if (err == MZ_OK) {\n        do {\n            read = mz_stream_os_read(stream, buf, sizeof(buf));\n\n            if (read < 0) {\n                err = read;\n                break;\n            }\n\n            crc32 = mz_crypt_crc32_update(crc32, buf, read);\n        } while ((err == MZ_OK) && (read > 0));\n\n        mz_stream_os_close(stream);\n    }\n\n    *result_crc = crc32;\n\n    mz_stream_os_delete(&stream);\n\n    return err;\n}\n\n/***************************************************************************/\n"
  },
  {
    "path": "ios/CodePush/SSZipArchive/minizip/mz_os.h",
    "content": "/* mz_os.h -- System functions\n   part of the minizip-ng project\n\n   Copyright (C) Nathan Moinvaziri\n     https://github.com/zlib-ng/minizip-ng\n\n   This program is distributed under the terms of the same license as zlib.\n   See the accompanying LICENSE file for the full text of the license.\n*/\n\n#ifndef MZ_OS_H\n#define MZ_OS_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/***************************************************************************/\n\n#if defined(__APPLE__)\n#  define MZ_VERSION_MADEBY_HOST_SYSTEM (MZ_HOST_SYSTEM_OSX_DARWIN)\n#elif defined(__riscos__)\n#  define MZ_VERSION_MADEBY_HOST_SYSTEM (MZ_HOST_SYSTEM_RISCOS)\n#elif defined(_WIN32)\n#  define MZ_VERSION_MADEBY_HOST_SYSTEM (MZ_HOST_SYSTEM_WINDOWS_NTFS)\n#else\n#  define MZ_VERSION_MADEBY_HOST_SYSTEM (MZ_HOST_SYSTEM_UNIX)\n#endif\n\n#if defined(HAVE_LZMA) || defined(HAVE_LIBCOMP)\n#  define MZ_VERSION_MADEBY_ZIP_VERSION (63)\n#elif defined(HAVE_WZAES)\n#  define MZ_VERSION_MADEBY_ZIP_VERSION (51)\n#elif defined(HAVE_BZIP2)\n#  define MZ_VERSION_MADEBY_ZIP_VERSION (46)\n#else\n#  define MZ_VERSION_MADEBY_ZIP_VERSION (45)\n#endif\n\n#define MZ_VERSION_MADEBY               ((MZ_VERSION_MADEBY_HOST_SYSTEM << 8) | \\\n                                         (MZ_VERSION_MADEBY_ZIP_VERSION))\n\n#define MZ_PATH_SLASH_UNIX              ('/')\n#define MZ_PATH_SLASH_WINDOWS           ('\\\\')\n#if defined(_WIN32)\n#  define MZ_PATH_SLASH_PLATFORM        (MZ_PATH_SLASH_WINDOWS)\n#else\n#  define MZ_PATH_SLASH_PLATFORM        (MZ_PATH_SLASH_UNIX)\n#endif\n\n/***************************************************************************/\n\n#if defined(_WIN32)\nstruct dirent {\n    char d_name[256];\n};\ntypedef void* DIR;\n#else\n#include <dirent.h>\n#endif\n\n/***************************************************************************/\n/* Shared functions */\n\nint32_t mz_path_combine(char *path, const char *join, int32_t max_path);\n/* Combines two paths */\n\nint32_t mz_path_append_slash(char *path, int32_t max_path, char slash);\n/* Appends a path slash on to the end of the path */\n\nint32_t mz_path_remove_slash(char *path);\n/* Removes a path slash from the end of the path */\n\nint32_t mz_path_has_slash(const char *path);\n/* Returns whether or not the path ends with slash */\n\nint32_t mz_path_convert_slashes(char *path, char slash);\n/* Converts the slashes in a path */\n\nint32_t mz_path_compare_wc(const char *path, const char *wildcard, uint8_t ignore_case);\n/* Compare two paths with wildcard */\n\nint32_t mz_path_resolve(const char *path, char *target, int32_t max_target);\n/* Resolves path */\n\nint32_t mz_path_remove_filename(char *path);\n/* Remove the filename from a path */\n\nint32_t mz_path_remove_extension(char *path);\n/* Remove the extension from a path */\n\nint32_t mz_path_get_filename(const char *path, const char **filename);\n/* Get the filename from a path */\n\nint32_t mz_dir_make(const char *path);\n/* Creates a directory recursively */\n\nint32_t mz_file_get_crc(const char *path, uint32_t *result_crc);\n/* Gets the crc32 hash of a file */\n\n/***************************************************************************/\n/* Platform specific functions */\n\nwchar_t *mz_os_unicode_string_create(const char *string, int32_t encoding);\n/* Create unicode string from a utf8 string */\n\nvoid     mz_os_unicode_string_delete(wchar_t **string);\n/* Delete a unicode string that was created */\n\nuint8_t *mz_os_utf8_string_create(const char *string, int32_t encoding);\n/* Create a utf8 string from a string with another encoding */\n\nvoid     mz_os_utf8_string_delete(uint8_t **string);\n/* Delete a utf8 string that was created */\n\nint32_t  mz_os_rand(uint8_t *buf, int32_t size);\n/* Random number generator (not cryptographically secure) */\n\nint32_t  mz_os_rename(const char *source_path, const char *target_path);\n/* Rename a file */\n\nint32_t  mz_os_unlink(const char *path);\n/* Delete an existing file  */\n\nint32_t  mz_os_file_exists(const char *path);\n/* Check to see if a file exists */\n\nint64_t  mz_os_get_file_size(const char *path);\n/* Gets the length of a file */\n\nint32_t  mz_os_get_file_date(const char *path, time_t *modified_date, time_t *accessed_date, time_t *creation_date);\n/* Gets a file's modified, access, and creation dates if supported */\n\nint32_t  mz_os_set_file_date(const char *path, time_t modified_date, time_t accessed_date, time_t creation_date);\n/* Sets a file's modified, access, and creation dates if supported */\n\nint32_t  mz_os_get_file_attribs(const char *path, uint32_t *attributes);\n/* Gets a file's attributes */\n\nint32_t  mz_os_set_file_attribs(const char *path, uint32_t attributes);\n/* Sets a file's attributes */\n\nint32_t  mz_os_make_dir(const char *path);\n/* Recursively creates a directory */\n\nDIR*     mz_os_open_dir(const char *path);\n/* Opens a directory for listing */\nstruct\ndirent*  mz_os_read_dir(DIR *dir);\n/* Reads a directory listing entry */\n\nint32_t  mz_os_close_dir(DIR *dir);\n/* Closes a directory that has been opened for listing */\n\nint32_t  mz_os_is_dir(const char *path);\n/* Checks to see if path is a directory */\n\nint32_t  mz_os_is_symlink(const char *path);\n/* Checks to see if path is a symbolic link */\n\nint32_t  mz_os_make_symlink(const char *path, const char *target_path);\n/* Creates a symbolic link pointing to a target */\n\nint32_t  mz_os_read_symlink(const char *path, char *target_path, int32_t max_target_path);\n/* Gets the target path for a symbolic link */\n\nuint64_t mz_os_ms_time(void);\n/* Gets the time in milliseconds */\n\n/***************************************************************************/\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "ios/CodePush/SSZipArchive/minizip/mz_os_posix.c",
    "content": "/* mz_os_posix.c -- System functions for posix\n   part of the minizip-ng project\n\n   Copyright (C) Nathan Moinvaziri\n     https://github.com/zlib-ng/minizip-ng\n\n   This program is distributed under the terms of the same license as zlib.\n   See the accompanying LICENSE file for the full text of the license.\n*/\n\n#include \"mz.h\"\n#include \"mz_strm.h\"\n#include \"mz_os.h\"\n\n#include <stdio.h> /* rename */\n#include <errno.h>\n#if defined(HAVE_ICONV)\n#include <iconv.h>\n#endif\n\n#include <sys/types.h>\n#include <sys/stat.h>\n\n#ifndef _WIN32\n#  include <utime.h>\n#  include <unistd.h>\n#endif\n#if defined(__APPLE__)\n#  include <mach/clock.h>\n#  include <mach/mach.h>\n#endif\n\n#if defined(HAVE_GETRANDOM)\n#  include <sys/random.h>\n#endif\n#if defined(HAVE_LIBBSD)\n#  include <stdlib.h> /* arc4random_buf */\n#endif\n\n/***************************************************************************/\n\n#if defined(HAVE_ICONV)\nuint8_t *mz_os_utf8_string_create(const char *string, int32_t encoding) {\n    iconv_t cd;\n    const char *from_encoding = NULL;\n    size_t result = 0;\n    size_t string_length = 0;\n    size_t string_utf8_size = 0;\n    uint8_t *string_utf8 = NULL;\n    uint8_t *string_utf8_ptr = NULL;\n\n    if (!string)\n        return NULL;\n\n    if (encoding == MZ_ENCODING_CODEPAGE_437)\n        from_encoding = \"CP437\";\n    else if (encoding == MZ_ENCODING_CODEPAGE_932)\n        from_encoding = \"CP932\";\n    else if (encoding == MZ_ENCODING_CODEPAGE_936)\n        from_encoding = \"CP936\";\n    else if (encoding == MZ_ENCODING_CODEPAGE_950)\n        from_encoding = \"CP950\";\n    else if (encoding == MZ_ENCODING_UTF8)\n        from_encoding = \"UTF-8\";\n    else\n        return NULL;\n\n    cd = iconv_open(\"UTF-8\", from_encoding);\n    if (cd == (iconv_t)-1)\n        return NULL;\n\n    string_length = strlen(string);\n    string_utf8_size = string_length * 2;\n    string_utf8 = (uint8_t *)calloc((int32_t)(string_utf8_size + 1), sizeof(char));\n    string_utf8_ptr = string_utf8;\n\n    if (string_utf8) {\n        result = iconv(cd, (char **)&string, &string_length,\n                (char **)&string_utf8_ptr, &string_utf8_size);\n    }\n\n    iconv_close(cd);\n\n    if (result == (size_t)-1) {\n        free(string_utf8);\n        string_utf8 = NULL;\n    }\n\n    return string_utf8;\n}\n#else\nuint8_t *mz_os_utf8_string_create(const char *string, int32_t encoding) {\n    return (uint8_t *)strdup(string);\n}\n#endif\n\nvoid mz_os_utf8_string_delete(uint8_t **string) {\n    if (string) {\n        free(*string);\n        *string = NULL;\n    }\n}\n\n/***************************************************************************/\n\n#if defined(HAVE_GETRANDOM)\nint32_t mz_os_rand(uint8_t *buf, int32_t size) {\n    int32_t left = size;\n    int32_t written = 0;\n\n    while (left > 0) {\n        written = getrandom(buf, left, 0);\n        if (written < 0)\n            return MZ_INTERNAL_ERROR;\n\n        buf += written;\n        left -= written;\n    }\n    return size - left;\n}\n#elif defined(HAVE_ARC4RANDOM_BUF)\nint32_t mz_os_rand(uint8_t *buf, int32_t size) {\n    if (size < 0)\n        return 0;\n    arc4random_buf(buf, (uint32_t)size);\n    return size;\n}\n#elif defined(HAVE_ARC4RANDOM)\nint32_t mz_os_rand(uint8_t *buf, int32_t size) {\n    int32_t left = size;\n    for (; left > 2; left -= 3, buf += 3) {\n        uint32_t val = arc4random();\n\n        buf[0] = (val) & 0xFF;\n        buf[1] = (val >> 8) & 0xFF;\n        buf[2] = (val >> 16) & 0xFF;\n    }\n    for (; left > 0; left--, buf++) {\n        *buf = arc4random() & 0xFF;\n    }\n    return size - left;\n}\n#else\nint32_t mz_os_rand(uint8_t *buf, int32_t size) {\n    static unsigned calls = 0;\n    int32_t i = 0;\n\n    /* Ensure different random header each time */\n    if (++calls == 1) {\n        #define PI_SEED 3141592654UL\n        srand((unsigned)(time(NULL) ^ PI_SEED));\n    }\n\n    while (i < size)\n        buf[i++] = (rand() >> 7) & 0xff;\n\n    return size;\n}\n#endif\n\nint32_t mz_os_rename(const char *source_path, const char *target_path) {\n    if (rename(source_path, target_path) == -1)\n        return MZ_EXIST_ERROR;\n\n    return MZ_OK;\n}\n\nint32_t mz_os_unlink(const char *path) {\n    if (unlink(path) == -1)\n        return MZ_EXIST_ERROR;\n\n    return MZ_OK;\n}\n\nint32_t mz_os_file_exists(const char *path) {\n    struct stat path_stat;\n\n    memset(&path_stat, 0, sizeof(path_stat));\n    if (stat(path, &path_stat) == 0)\n        return MZ_OK;\n    return MZ_EXIST_ERROR;\n}\n\nint64_t mz_os_get_file_size(const char *path) {\n    struct stat path_stat;\n\n    memset(&path_stat, 0, sizeof(path_stat));\n    if (stat(path, &path_stat) == 0) {\n        /* Stat returns size taken up by directory entry, so return 0 */\n        if (S_ISDIR(path_stat.st_mode))\n            return 0;\n\n        return path_stat.st_size;\n    }\n\n    return 0;\n}\n\nint32_t mz_os_get_file_date(const char *path, time_t *modified_date, time_t *accessed_date, time_t *creation_date) {\n    struct stat path_stat;\n    char *name = NULL;\n    int32_t err = MZ_INTERNAL_ERROR;\n\n    memset(&path_stat, 0, sizeof(path_stat));\n\n    if (strcmp(path, \"-\") != 0) {\n        /* Not all systems allow stat'ing a file with / appended */\n        name = strdup(path);\n        mz_path_remove_slash(name);\n\n        if (stat(name, &path_stat) == 0) {\n            if (modified_date)\n                *modified_date = path_stat.st_mtime;\n            if (accessed_date)\n                *accessed_date = path_stat.st_atime;\n            /* Creation date not supported */\n            if (creation_date)\n                *creation_date = 0;\n\n            err = MZ_OK;\n        }\n\n        free(name);\n    }\n\n    return err;\n}\n\nint32_t mz_os_set_file_date(const char *path, time_t modified_date, time_t accessed_date, time_t creation_date) {\n    struct utimbuf ut;\n\n    ut.actime = accessed_date;\n    ut.modtime = modified_date;\n\n    /* Creation date not supported */\n    MZ_UNUSED(creation_date);\n\n    if (utime(path, &ut) != 0)\n        return MZ_INTERNAL_ERROR;\n\n    return MZ_OK;\n}\n\nint32_t mz_os_get_file_attribs(const char *path, uint32_t *attributes) {\n    struct stat path_stat;\n    int32_t err = MZ_OK;\n\n    memset(&path_stat, 0, sizeof(path_stat));\n    if (lstat(path, &path_stat) == -1)\n        err = MZ_INTERNAL_ERROR;\n    *attributes = path_stat.st_mode;\n    return err;\n}\n\nint32_t mz_os_set_file_attribs(const char *path, uint32_t attributes) {\n    int32_t err = MZ_OK;\n\n    if (chmod(path, (mode_t)attributes) == -1)\n        err = MZ_INTERNAL_ERROR;\n\n    return err;\n}\n\nint32_t mz_os_make_dir(const char *path) {\n    int32_t err = 0;\n\n    err = mkdir(path, 0755);\n\n    if (err != 0 && errno != EEXIST)\n        return MZ_INTERNAL_ERROR;\n\n    return MZ_OK;\n}\n\nDIR* mz_os_open_dir(const char *path) {\n    return opendir(path);\n}\n\nstruct dirent* mz_os_read_dir(DIR *dir) {\n    if (!dir)\n        return NULL;\n    return readdir(dir);\n}\n\nint32_t mz_os_close_dir(DIR *dir) {\n    if (!dir)\n        return MZ_PARAM_ERROR;\n    if (closedir(dir) == -1)\n        return MZ_INTERNAL_ERROR;\n    return MZ_OK;\n}\n\nint32_t mz_os_is_dir(const char *path) {\n    struct stat path_stat;\n\n    memset(&path_stat, 0, sizeof(path_stat));\n    stat(path, &path_stat);\n    if (S_ISDIR(path_stat.st_mode))\n        return MZ_OK;\n\n    return MZ_EXIST_ERROR;\n}\n\nint32_t mz_os_is_symlink(const char *path) {\n    struct stat path_stat;\n\n    memset(&path_stat, 0, sizeof(path_stat));\n    lstat(path, &path_stat);\n    if (S_ISLNK(path_stat.st_mode))\n        return MZ_OK;\n\n    return MZ_EXIST_ERROR;\n}\n\nint32_t mz_os_make_symlink(const char *path, const char *target_path) {\n    if (symlink(target_path, path) != 0)\n        return MZ_INTERNAL_ERROR;\n    return MZ_OK;\n}\n\nint32_t mz_os_read_symlink(const char *path, char *target_path, int32_t max_target_path) {\n    size_t length = 0;\n\n    length = (size_t)readlink(path, target_path, max_target_path - 1);\n    if (length == (size_t)-1)\n        return MZ_EXIST_ERROR;\n\n    target_path[length] = 0;\n    return MZ_OK;\n}\n\nuint64_t mz_os_ms_time(void) {\n    struct timespec ts;\n\n#if defined(__APPLE__)\n    clock_serv_t cclock;\n    mach_timespec_t mts;\n\n    host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);\n    clock_get_time(cclock, &mts);\n    mach_port_deallocate(mach_task_self(), cclock);\n\n    ts.tv_sec = mts.tv_sec;\n    ts.tv_nsec = mts.tv_nsec;\n#else\n    clock_gettime(CLOCK_MONOTONIC, &ts);\n#endif\n\n    return ((uint64_t)ts.tv_sec * 1000) + ((uint64_t)ts.tv_nsec / 1000000);\n}\n"
  },
  {
    "path": "ios/CodePush/SSZipArchive/minizip/mz_strm.c",
    "content": "/* mz_strm.c -- Stream interface\n   part of the minizip-ng project\n\n   Copyright (C) Nathan Moinvaziri\n     https://github.com/zlib-ng/minizip-ng\n\n   This program is distributed under the terms of the same license as zlib.\n   See the accompanying LICENSE file for the full text of the license.\n*/\n\n#include \"mz.h\"\n#include \"mz_strm.h\"\n\n/***************************************************************************/\n\n#define MZ_STREAM_FIND_SIZE (1024)\n\n/***************************************************************************/\n\nint32_t mz_stream_open(void *stream, const char *path, int32_t mode) {\n    mz_stream *strm = (mz_stream *)stream;\n    if (!strm || !strm->vtbl || !strm->vtbl->open)\n        return MZ_STREAM_ERROR;\n    return strm->vtbl->open(strm, path, mode);\n}\n\nint32_t mz_stream_is_open(void *stream) {\n    mz_stream *strm = (mz_stream *)stream;\n    if (!strm || !strm->vtbl || !strm->vtbl->is_open)\n        return MZ_STREAM_ERROR;\n    return strm->vtbl->is_open(strm);\n}\n\nint32_t mz_stream_read(void *stream, void *buf, int32_t size) {\n    mz_stream *strm = (mz_stream *)stream;\n    if (!strm || !strm->vtbl || !strm->vtbl->read)\n        return MZ_PARAM_ERROR;\n    if (mz_stream_is_open(stream) != MZ_OK)\n        return MZ_STREAM_ERROR;\n    return strm->vtbl->read(strm, buf, size);\n}\n\nstatic int32_t mz_stream_read_value(void *stream, uint64_t *value, int32_t len) {\n    uint8_t buf[8];\n    int32_t n = 0;\n    int32_t i = 0;\n\n    *value = 0;\n    if (mz_stream_read(stream, buf, len) == len) {\n        for (n = 0; n < len; n += 1, i += 8)\n            *value += ((uint64_t)buf[n]) << i;\n    } else if (mz_stream_error(stream))\n        return MZ_STREAM_ERROR;\n    else\n        return MZ_END_OF_STREAM;\n\n    return MZ_OK;\n}\n\nint32_t mz_stream_read_uint8(void *stream, uint8_t *value) {\n    int32_t err = MZ_OK;\n    uint64_t value64 = 0;\n\n    *value = 0;\n    err = mz_stream_read_value(stream, &value64, sizeof(uint8_t));\n    if (err == MZ_OK)\n        *value = (uint8_t)value64;\n    return err;\n}\n\nint32_t mz_stream_read_uint16(void *stream, uint16_t *value) {\n    int32_t err = MZ_OK;\n    uint64_t value64 = 0;\n\n    *value = 0;\n    err = mz_stream_read_value(stream, &value64, sizeof(uint16_t));\n    if (err == MZ_OK)\n        *value = (uint16_t)value64;\n    return err;\n}\n\nint32_t mz_stream_read_uint32(void *stream, uint32_t *value) {\n    int32_t err = MZ_OK;\n    uint64_t value64 = 0;\n\n    *value = 0;\n    err = mz_stream_read_value(stream, &value64, sizeof(uint32_t));\n    if (err == MZ_OK)\n        *value = (uint32_t)value64;\n    return err;\n}\n\nint32_t mz_stream_read_int64(void *stream, int64_t *value) {\n    return mz_stream_read_value(stream, (uint64_t *)value, sizeof(uint64_t));\n}\n\nint32_t mz_stream_read_uint64(void *stream, uint64_t *value) {\n    return mz_stream_read_value(stream, value, sizeof(uint64_t));\n}\n\nint32_t mz_stream_write(void *stream, const void *buf, int32_t size) {\n    mz_stream *strm = (mz_stream *)stream;\n    if (size == 0)\n        return size;\n    if (!strm || !strm->vtbl || !strm->vtbl->write)\n        return MZ_PARAM_ERROR;\n    if (mz_stream_is_open(stream) != MZ_OK)\n        return MZ_STREAM_ERROR;\n    return strm->vtbl->write(strm, buf, size);\n}\n\nstatic int32_t mz_stream_write_value(void *stream, uint64_t value, int32_t len) {\n    uint8_t buf[8];\n    int32_t n = 0;\n\n    for (n = 0; n < len; n += 1) {\n        buf[n] = (uint8_t)(value & 0xff);\n        value >>= 8;\n    }\n\n    if (value != 0) {\n        /* Data overflow - hack for ZIP64 (X Roche) */\n        for (n = 0; n < len; n += 1)\n            buf[n] = 0xff;\n    }\n\n    if (mz_stream_write(stream, buf, len) != len)\n        return MZ_STREAM_ERROR;\n\n    return MZ_OK;\n}\n\nint32_t mz_stream_write_uint8(void *stream, uint8_t value) {\n    return mz_stream_write_value(stream, value, sizeof(uint8_t));\n}\n\nint32_t mz_stream_write_uint16(void *stream, uint16_t value) {\n    return mz_stream_write_value(stream, value, sizeof(uint16_t));\n}\n\nint32_t mz_stream_write_uint32(void *stream, uint32_t value) {\n    return mz_stream_write_value(stream, value, sizeof(uint32_t));\n}\n\nint32_t mz_stream_write_int64(void *stream, int64_t value) {\n    return mz_stream_write_value(stream, (uint64_t)value, sizeof(uint64_t));\n}\n\nint32_t mz_stream_write_uint64(void *stream, uint64_t value) {\n    return mz_stream_write_value(stream, value, sizeof(uint64_t));\n}\n\nint32_t mz_stream_copy(void *target, void *source, int32_t len) {\n    return mz_stream_copy_stream(target, NULL, source, NULL, len);\n}\n\nint32_t mz_stream_copy_to_end(void *target, void *source) {\n    return mz_stream_copy_stream_to_end(target, NULL, source, NULL);\n}\n\nint32_t mz_stream_copy_stream(void *target, mz_stream_write_cb write_cb, void *source,\n    mz_stream_read_cb read_cb, int32_t len) {\n    uint8_t buf[16384];\n    int32_t bytes_to_copy = 0;\n    int32_t read = 0;\n    int32_t written = 0;\n\n    if (!write_cb)\n        write_cb = mz_stream_write;\n    if (!read_cb)\n        read_cb = mz_stream_read;\n\n    while (len > 0) {\n        bytes_to_copy = len;\n        if (bytes_to_copy > (int32_t)sizeof(buf))\n            bytes_to_copy = sizeof(buf);\n        read = read_cb(source, buf, bytes_to_copy);\n        if (read <= 0)\n            return MZ_STREAM_ERROR;\n        written = write_cb(target, buf, read);\n        if (written != read)\n            return MZ_STREAM_ERROR;\n        len -= read;\n    }\n\n    return MZ_OK;\n}\n\nint32_t mz_stream_copy_stream_to_end(void *target, mz_stream_write_cb write_cb, void *source,\n    mz_stream_read_cb read_cb) {\n    uint8_t buf[16384];\n    int32_t read = 0;\n    int32_t written = 0;\n\n    if (!write_cb)\n        write_cb = mz_stream_write;\n    if (!read_cb)\n        read_cb = mz_stream_read;\n\n    read = read_cb(source, buf, sizeof(buf));\n    while (read > 0) {\n        written = write_cb(target, buf, read);\n        if (written != read)\n            return MZ_STREAM_ERROR;\n        read = read_cb(source, buf, sizeof(buf));\n    }\n\n    if (read < 0)\n        return MZ_STREAM_ERROR;\n\n    return MZ_OK;\n}\n\nint64_t mz_stream_tell(void *stream) {\n    mz_stream *strm = (mz_stream *)stream;\n    if (!strm || !strm->vtbl || !strm->vtbl->tell)\n        return MZ_PARAM_ERROR;\n    if (mz_stream_is_open(stream) != MZ_OK)\n        return MZ_STREAM_ERROR;\n    return strm->vtbl->tell(strm);\n}\n\nint32_t mz_stream_seek(void *stream, int64_t offset, int32_t origin) {\n    mz_stream *strm = (mz_stream *)stream;\n    if (!strm || !strm->vtbl || !strm->vtbl->seek)\n        return MZ_PARAM_ERROR;\n    if (mz_stream_is_open(stream) != MZ_OK)\n        return MZ_STREAM_ERROR;\n    if (origin == MZ_SEEK_SET && offset < 0)\n        return MZ_SEEK_ERROR;\n    return strm->vtbl->seek(strm, offset, origin);\n}\n\nint32_t mz_stream_find(void *stream, const void *find, int32_t find_size, int64_t max_seek, int64_t *position) {\n    uint8_t buf[MZ_STREAM_FIND_SIZE];\n    int32_t buf_pos = 0;\n    int32_t read_size = sizeof(buf);\n    int32_t read = 0;\n    int64_t read_pos = 0;\n    int64_t start_pos = 0;\n    int64_t disk_pos = 0;\n    int32_t i = 0;\n    uint8_t first = 1;\n    int32_t err = MZ_OK;\n\n    if (!stream || !find || !position)\n        return MZ_PARAM_ERROR;\n    if (find_size < 0 || find_size >= (int32_t)sizeof(buf))\n        return MZ_PARAM_ERROR;\n\n    *position = -1;\n\n    start_pos = mz_stream_tell(stream);\n\n    while (read_pos < max_seek) {\n        if (read_size > (int32_t)(max_seek - read_pos - buf_pos) && (max_seek - read_pos - buf_pos) < (int64_t)sizeof(buf))\n            read_size = (int32_t)(max_seek - read_pos - buf_pos);\n\n        read = mz_stream_read(stream, buf + buf_pos, read_size);\n        if ((read <= 0) || (read + buf_pos < find_size))\n            break;\n\n        for (i = 0; i <= read + buf_pos - find_size; i += 1) {\n            if (memcmp(&buf[i], find, find_size) != 0)\n                continue;\n\n            disk_pos = mz_stream_tell(stream);\n\n            /* Seek to position on disk where the data was found */\n            err = mz_stream_seek(stream, disk_pos - ((int64_t)read + buf_pos - i), MZ_SEEK_SET);\n            if (err != MZ_OK)\n                return MZ_EXIST_ERROR;\n\n            *position = start_pos + read_pos + i;\n            return MZ_OK;\n        }\n\n        if (first) {\n            read -= find_size;\n            read_size -= find_size;\n            buf_pos = find_size;\n            first = 0;\n        }\n\n        memmove(buf, buf + read, find_size);\n        read_pos += read;\n    }\n\n    return MZ_EXIST_ERROR;\n}\n\nint32_t mz_stream_find_reverse(void *stream, const void *find, int32_t find_size, int64_t max_seek, int64_t *position) {\n    uint8_t buf[MZ_STREAM_FIND_SIZE];\n    int32_t buf_pos = 0;\n    int32_t read_size = MZ_STREAM_FIND_SIZE;\n    int64_t read_pos = 0;\n    int32_t read = 0;\n    int64_t start_pos = 0;\n    int64_t disk_pos = 0;\n    uint8_t first = 1;\n    int32_t i = 0;\n    int32_t err = MZ_OK;\n\n    if (!stream || !find || !position)\n        return MZ_PARAM_ERROR;\n    if (find_size < 0 || find_size >= (int32_t)sizeof(buf))\n        return MZ_PARAM_ERROR;\n\n    *position = -1;\n\n    start_pos = mz_stream_tell(stream);\n\n    while (read_pos < max_seek) {\n        if (read_size > (int32_t)(max_seek - read_pos) && (max_seek - read_pos) < (int64_t)sizeof(buf))\n            read_size = (int32_t)(max_seek - read_pos);\n\n        if (mz_stream_seek(stream, start_pos - (read_pos + read_size), MZ_SEEK_SET) != MZ_OK)\n            break;\n        read = mz_stream_read(stream, buf, read_size);\n        if ((read <= 0) || (read + buf_pos < find_size))\n            break;\n        if (read + buf_pos < MZ_STREAM_FIND_SIZE)\n            memmove(buf + MZ_STREAM_FIND_SIZE - (read + buf_pos), buf, read);\n\n        for (i = find_size; i <= (read + buf_pos); i += 1) {\n            if (memcmp(&buf[MZ_STREAM_FIND_SIZE - i], find, find_size) != 0)\n                continue;\n\n            disk_pos = mz_stream_tell(stream);\n\n            /* Seek to position on disk where the data was found */\n            err = mz_stream_seek(stream, disk_pos + buf_pos - i, MZ_SEEK_SET);\n            if (err != MZ_OK)\n                return MZ_EXIST_ERROR;\n\n            *position = start_pos - (read_pos - buf_pos + i);\n            return MZ_OK;\n        }\n\n        if (first) {\n            read -= find_size;\n            read_size -= find_size;\n            buf_pos = find_size;\n            first = 0;\n        }\n\n        if (read == 0)\n            break;\n\n        memmove(buf + read_size, buf, find_size);\n        read_pos += read;\n    }\n\n    return MZ_EXIST_ERROR;\n}\n\nint32_t mz_stream_close(void *stream) {\n    mz_stream *strm = (mz_stream *)stream;\n    if (!strm || !strm->vtbl || !strm->vtbl->close)\n        return MZ_PARAM_ERROR;\n    if (mz_stream_is_open(stream) != MZ_OK)\n        return MZ_STREAM_ERROR;\n    return strm->vtbl->close(strm);\n}\n\nint32_t mz_stream_error(void *stream) {\n    mz_stream *strm = (mz_stream *)stream;\n    if (!strm || !strm->vtbl || !strm->vtbl->error)\n        return MZ_PARAM_ERROR;\n    return strm->vtbl->error(strm);\n}\n\nint32_t mz_stream_set_base(void *stream, void *base) {\n    mz_stream *strm = (mz_stream *)stream;\n    strm->base = (mz_stream *)base;\n    return MZ_OK;\n}\n\nvoid* mz_stream_get_interface(void *stream) {\n    mz_stream *strm = (mz_stream *)stream;\n    if (!strm || !strm->vtbl)\n        return NULL;\n    return (void *)strm->vtbl;\n}\n\nint32_t mz_stream_get_prop_int64(void *stream, int32_t prop, int64_t *value) {\n    mz_stream *strm = (mz_stream *)stream;\n    if (!strm || !strm->vtbl || !strm->vtbl->get_prop_int64)\n        return MZ_PARAM_ERROR;\n    return strm->vtbl->get_prop_int64(stream, prop, value);\n}\n\nint32_t mz_stream_set_prop_int64(void *stream, int32_t prop, int64_t value) {\n    mz_stream *strm = (mz_stream *)stream;\n    if (!strm || !strm->vtbl || !strm->vtbl->set_prop_int64)\n        return MZ_PARAM_ERROR;\n    return strm->vtbl->set_prop_int64(stream, prop, value);\n}\n\nvoid *mz_stream_create(void **stream, mz_stream_vtbl *vtbl) {\n    if (!stream || !vtbl || !vtbl->create)\n        return NULL;\n    return vtbl->create(stream);\n}\n\nvoid mz_stream_delete(void **stream) {\n    mz_stream *strm = NULL;\n    if (!stream)\n        return;\n    strm = (mz_stream *)*stream;\n    if (strm && strm->vtbl && strm->vtbl->destroy)\n        strm->vtbl->destroy(stream);\n    *stream = NULL;\n}\n\n/***************************************************************************/\n\ntypedef struct mz_stream_raw_s {\n    mz_stream   stream;\n    int64_t     total_in;\n    int64_t     total_out;\n    int64_t     max_total_in;\n} mz_stream_raw;\n\n/***************************************************************************/\n\nint32_t mz_stream_raw_open(void *stream, const char *path, int32_t mode) {\n    MZ_UNUSED(stream);\n    MZ_UNUSED(path);\n    MZ_UNUSED(mode);\n\n    return MZ_OK;\n}\n\nint32_t mz_stream_raw_is_open(void *stream) {\n    mz_stream_raw *raw = (mz_stream_raw *)stream;\n    return mz_stream_is_open(raw->stream.base);\n}\n\nint32_t mz_stream_raw_read(void *stream, void *buf, int32_t size) {\n    mz_stream_raw *raw = (mz_stream_raw *)stream;\n    int32_t bytes_to_read = size;\n    int32_t read = 0;\n\n    if (raw->max_total_in > 0) {\n        if ((int64_t)bytes_to_read > (raw->max_total_in - raw->total_in))\n            bytes_to_read = (int32_t)(raw->max_total_in - raw->total_in);\n    }\n\n    read = mz_stream_read(raw->stream.base, buf, bytes_to_read);\n\n    if (read > 0) {\n        raw->total_in += read;\n        raw->total_out += read;\n    }\n\n    return read;\n}\n\nint32_t mz_stream_raw_write(void *stream, const void *buf, int32_t size) {\n    mz_stream_raw *raw = (mz_stream_raw *)stream;\n    int32_t written = 0;\n\n    written = mz_stream_write(raw->stream.base, buf, size);\n\n    if (written > 0) {\n        raw->total_out += written;\n        raw->total_in += written;\n    }\n\n    return written;\n}\n\nint64_t mz_stream_raw_tell(void *stream) {\n    mz_stream_raw *raw = (mz_stream_raw *)stream;\n    return mz_stream_tell(raw->stream.base);\n}\n\nint32_t mz_stream_raw_seek(void *stream, int64_t offset, int32_t origin) {\n    mz_stream_raw *raw = (mz_stream_raw *)stream;\n    return mz_stream_seek(raw->stream.base, offset, origin);\n}\n\nint32_t mz_stream_raw_close(void *stream) {\n    MZ_UNUSED(stream);\n    return MZ_OK;\n}\n\nint32_t mz_stream_raw_error(void *stream) {\n    mz_stream_raw *raw = (mz_stream_raw *)stream;\n    return mz_stream_error(raw->stream.base);\n}\n\nint32_t mz_stream_raw_get_prop_int64(void *stream, int32_t prop, int64_t *value) {\n    mz_stream_raw *raw = (mz_stream_raw *)stream;\n    switch (prop) {\n    case MZ_STREAM_PROP_TOTAL_IN:\n        *value = raw->total_in;\n        return MZ_OK;\n    case MZ_STREAM_PROP_TOTAL_OUT:\n        *value = raw->total_out;\n        return MZ_OK;\n    }\n    return MZ_EXIST_ERROR;\n}\n\nint32_t mz_stream_raw_set_prop_int64(void *stream, int32_t prop, int64_t value) {\n    mz_stream_raw *raw = (mz_stream_raw *)stream;\n    switch (prop) {\n    case MZ_STREAM_PROP_TOTAL_IN_MAX:\n        raw->max_total_in = value;\n        return MZ_OK;\n    }\n    return MZ_EXIST_ERROR;\n}\n\n/***************************************************************************/\n\nstatic mz_stream_vtbl mz_stream_raw_vtbl = {\n    mz_stream_raw_open,\n    mz_stream_raw_is_open,\n    mz_stream_raw_read,\n    mz_stream_raw_write,\n    mz_stream_raw_tell,\n    mz_stream_raw_seek,\n    mz_stream_raw_close,\n    mz_stream_raw_error,\n    mz_stream_raw_create,\n    mz_stream_raw_delete,\n    mz_stream_raw_get_prop_int64,\n    mz_stream_raw_set_prop_int64\n};\n\n/***************************************************************************/\n\nvoid *mz_stream_raw_create(void **stream) {\n    mz_stream_raw *raw = NULL;\n\n    raw = (mz_stream_raw *)calloc(1, sizeof(mz_stream_raw));\n    if (raw)\n        raw->stream.vtbl = &mz_stream_raw_vtbl;\n    if (stream)\n        *stream = raw;\n\n    return raw;\n}\n\nvoid mz_stream_raw_delete(void **stream) {\n    mz_stream_raw *raw = NULL;\n    if (!stream)\n        return;\n    raw = (mz_stream_raw *)*stream;\n    if (raw)\n        free(raw);\n    *stream = NULL;\n}\n"
  },
  {
    "path": "ios/CodePush/SSZipArchive/minizip/mz_strm.h",
    "content": "/* mz_strm.h -- Stream interface\n   part of the minizip-ng project\n\n   Copyright (C) Nathan Moinvaziri\n     https://github.com/zlib-ng/minizip-ng\n\n   This program is distributed under the terms of the same license as zlib.\n   See the accompanying LICENSE file for the full text of the license.\n*/\n\n#ifndef MZ_STREAM_H\n#define MZ_STREAM_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/***************************************************************************/\n\n#define MZ_STREAM_PROP_TOTAL_IN             (1)\n#define MZ_STREAM_PROP_TOTAL_IN_MAX         (2)\n#define MZ_STREAM_PROP_TOTAL_OUT            (3)\n#define MZ_STREAM_PROP_TOTAL_OUT_MAX        (4)\n#define MZ_STREAM_PROP_HEADER_SIZE          (5)\n#define MZ_STREAM_PROP_FOOTER_SIZE          (6)\n#define MZ_STREAM_PROP_DISK_SIZE            (7)\n#define MZ_STREAM_PROP_DISK_NUMBER          (8)\n#define MZ_STREAM_PROP_COMPRESS_LEVEL       (9)\n#define MZ_STREAM_PROP_COMPRESS_METHOD      (10)\n#define MZ_STREAM_PROP_COMPRESS_WINDOW      (11)\n\n/***************************************************************************/\n\ntypedef int32_t (*mz_stream_open_cb)           (void *stream, const char *path, int32_t mode);\ntypedef int32_t (*mz_stream_is_open_cb)        (void *stream);\ntypedef int32_t (*mz_stream_read_cb)           (void *stream, void *buf, int32_t size);\ntypedef int32_t (*mz_stream_write_cb)          (void *stream, const void *buf, int32_t size);\ntypedef int64_t (*mz_stream_tell_cb)           (void *stream);\ntypedef int32_t (*mz_stream_seek_cb)           (void *stream, int64_t offset, int32_t origin);\ntypedef int32_t (*mz_stream_close_cb)          (void *stream);\ntypedef int32_t (*mz_stream_error_cb)          (void *stream);\ntypedef void*   (*mz_stream_create_cb)         (void **stream);\ntypedef void    (*mz_stream_destroy_cb)        (void **stream);\n\ntypedef int32_t (*mz_stream_get_prop_int64_cb) (void *stream, int32_t prop, int64_t *value);\ntypedef int32_t (*mz_stream_set_prop_int64_cb) (void *stream, int32_t prop, int64_t value);\n\ntypedef int32_t (*mz_stream_find_cb)           (void *stream, const void *find, int32_t find_size,\n                                                int64_t max_seek, int64_t *position);\n\n/***************************************************************************/\n\ntypedef struct mz_stream_vtbl_s {\n    mz_stream_open_cb           open;\n    mz_stream_is_open_cb        is_open;\n    mz_stream_read_cb           read;\n    mz_stream_write_cb          write;\n    mz_stream_tell_cb           tell;\n    mz_stream_seek_cb           seek;\n    mz_stream_close_cb          close;\n    mz_stream_error_cb          error;\n    mz_stream_create_cb         create;\n    mz_stream_destroy_cb        destroy;\n\n    mz_stream_get_prop_int64_cb get_prop_int64;\n    mz_stream_set_prop_int64_cb set_prop_int64;\n} mz_stream_vtbl;\n\ntypedef struct mz_stream_s {\n    mz_stream_vtbl              *vtbl;\n    struct mz_stream_s          *base;\n} mz_stream;\n\n/***************************************************************************/\n\nint32_t mz_stream_open(void *stream, const char *path, int32_t mode);\nint32_t mz_stream_is_open(void *stream);\nint32_t mz_stream_read(void *stream, void *buf, int32_t size);\nint32_t mz_stream_read_uint8(void *stream, uint8_t *value);\nint32_t mz_stream_read_uint16(void *stream, uint16_t *value);\nint32_t mz_stream_read_uint32(void *stream, uint32_t *value);\nint32_t mz_stream_read_int64(void *stream, int64_t *value);\nint32_t mz_stream_read_uint64(void *stream, uint64_t *value);\nint32_t mz_stream_write(void *stream, const void *buf, int32_t size);\nint32_t mz_stream_write_uint8(void *stream, uint8_t value);\nint32_t mz_stream_write_uint16(void *stream, uint16_t value);\nint32_t mz_stream_write_uint32(void *stream, uint32_t value);\nint32_t mz_stream_write_int64(void *stream, int64_t value);\nint32_t mz_stream_write_uint64(void *stream, uint64_t value);\nint32_t mz_stream_copy(void *target, void *source, int32_t len);\nint32_t mz_stream_copy_to_end(void *target, void *source);\nint32_t mz_stream_copy_stream(void *target, mz_stream_write_cb write_cb, void *source, mz_stream_read_cb read_cb, int32_t len);\nint32_t mz_stream_copy_stream_to_end(void *target, mz_stream_write_cb write_cb, void *source, mz_stream_read_cb read_cb);\nint64_t mz_stream_tell(void *stream);\nint32_t mz_stream_seek(void *stream, int64_t offset, int32_t origin);\nint32_t mz_stream_find(void *stream, const void *find, int32_t find_size, int64_t max_seek, int64_t *position);\nint32_t mz_stream_find_reverse(void *stream, const void *find, int32_t find_size, int64_t max_seek, int64_t *position);\nint32_t mz_stream_close(void *stream);\nint32_t mz_stream_error(void *stream);\n\nint32_t mz_stream_set_base(void *stream, void *base);\nvoid*   mz_stream_get_interface(void *stream);\nint32_t mz_stream_get_prop_int64(void *stream, int32_t prop, int64_t *value);\nint32_t mz_stream_set_prop_int64(void *stream, int32_t prop, int64_t value);\n\nvoid*   mz_stream_create(void **stream, mz_stream_vtbl *vtbl);\nvoid    mz_stream_delete(void **stream);\n\n/***************************************************************************/\n\nint32_t mz_stream_raw_open(void *stream, const char *filename, int32_t mode);\nint32_t mz_stream_raw_is_open(void *stream);\nint32_t mz_stream_raw_read(void *stream, void *buf, int32_t size);\nint32_t mz_stream_raw_write(void *stream, const void *buf, int32_t size);\nint64_t mz_stream_raw_tell(void *stream);\nint32_t mz_stream_raw_seek(void *stream, int64_t offset, int32_t origin);\nint32_t mz_stream_raw_close(void *stream);\nint32_t mz_stream_raw_error(void *stream);\n\nint32_t mz_stream_raw_get_prop_int64(void *stream, int32_t prop, int64_t *value);\nint32_t mz_stream_raw_set_prop_int64(void *stream, int32_t prop, int64_t value);\n\nvoid*   mz_stream_raw_create(void **stream);\nvoid    mz_stream_raw_delete(void **stream);\n\n/***************************************************************************/\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "ios/CodePush/SSZipArchive/minizip/mz_strm_buf.c",
    "content": "/* mz_strm_buf.c -- Stream for buffering reads/writes\n   part of the minizip-ng project\n\n   This version of ioapi is designed to buffer IO.\n\n   Copyright (C) Nathan Moinvaziri\n      https://github.com/zlib-ng/minizip-ng\n\n   This program is distributed under the terms of the same license as zlib.\n   See the accompanying LICENSE file for the full text of the license.\n*/\n\n#include \"mz.h\"\n#include \"mz_strm.h\"\n#include \"mz_strm_buf.h\"\n\n/***************************************************************************/\n\nstatic mz_stream_vtbl mz_stream_buffered_vtbl = {\n    mz_stream_buffered_open,\n    mz_stream_buffered_is_open,\n    mz_stream_buffered_read,\n    mz_stream_buffered_write,\n    mz_stream_buffered_tell,\n    mz_stream_buffered_seek,\n    mz_stream_buffered_close,\n    mz_stream_buffered_error,\n    mz_stream_buffered_create,\n    mz_stream_buffered_delete,\n    NULL,\n    NULL\n};\n\n/***************************************************************************/\n\ntypedef struct mz_stream_buffered_s {\n    mz_stream stream;\n    int32_t   error;\n    char      readbuf[INT16_MAX];\n    int32_t   readbuf_len;\n    int32_t   readbuf_pos;\n    int32_t   readbuf_hits;\n    int32_t   readbuf_misses;\n    char      writebuf[INT16_MAX];\n    int32_t   writebuf_len;\n    int32_t   writebuf_pos;\n    int32_t   writebuf_hits;\n    int32_t   writebuf_misses;\n    int64_t   position;\n} mz_stream_buffered;\n\n/***************************************************************************/\n\n#if 0\n#  define mz_stream_buffered_print printf\n#else\n#  define mz_stream_buffered_print(fmt,...)\n#endif\n\n/***************************************************************************/\n\nstatic int32_t mz_stream_buffered_reset(void *stream) {\n    mz_stream_buffered *buffered = (mz_stream_buffered *)stream;\n\n    buffered->readbuf_len = 0;\n    buffered->readbuf_pos = 0;\n    buffered->writebuf_len = 0;\n    buffered->writebuf_pos = 0;\n    buffered->position = 0;\n\n    return MZ_OK;\n}\n\nint32_t mz_stream_buffered_open(void *stream, const char *path, int32_t mode) {\n    mz_stream_buffered *buffered = (mz_stream_buffered *)stream;\n    mz_stream_buffered_print(\"Buffered - Open (mode %\" PRId32 \")\\n\", mode);\n    mz_stream_buffered_reset(buffered);\n    return mz_stream_open(buffered->stream.base, path, mode);\n}\n\nint32_t mz_stream_buffered_is_open(void *stream) {\n    mz_stream_buffered *buffered = (mz_stream_buffered *)stream;\n    return mz_stream_is_open(buffered->stream.base);\n}\n\nstatic int32_t mz_stream_buffered_flush(void *stream, int32_t *written) {\n    mz_stream_buffered *buffered = (mz_stream_buffered *)stream;\n    int32_t total_bytes_written = 0;\n    int32_t bytes_to_write = buffered->writebuf_len;\n    int32_t bytes_left_to_write = buffered->writebuf_len;\n    int32_t bytes_written = 0;\n\n    *written = 0;\n\n    while (bytes_left_to_write > 0) {\n        bytes_written = mz_stream_write(buffered->stream.base,\n            buffered->writebuf + (bytes_to_write - bytes_left_to_write), bytes_left_to_write);\n\n        if (bytes_written != bytes_left_to_write)\n            return MZ_WRITE_ERROR;\n\n        buffered->writebuf_misses += 1;\n\n        mz_stream_buffered_print(\"Buffered - Write flush (%\" PRId32 \":%\" PRId32 \" len %\" PRId32 \")\\n\",\n            bytes_to_write, bytes_left_to_write, buffered->writebuf_len);\n\n        total_bytes_written += bytes_written;\n        bytes_left_to_write -= bytes_written;\n        buffered->position += bytes_written;\n    }\n\n    buffered->writebuf_len = 0;\n    buffered->writebuf_pos = 0;\n\n    *written = total_bytes_written;\n    return MZ_OK;\n}\n\nint32_t mz_stream_buffered_read(void *stream, void *buf, int32_t size) {\n    mz_stream_buffered *buffered = (mz_stream_buffered *)stream;\n    int32_t buf_len = 0;\n    int32_t bytes_to_read = 0;\n    int32_t bytes_to_copy = 0;\n    int32_t bytes_left_to_read = size;\n    int32_t bytes_read = 0;\n    int32_t bytes_flushed = 0;\n\n    mz_stream_buffered_print(\"Buffered - Read (size %\" PRId32 \" pos %\" PRId64 \")\\n\", size, buffered->position);\n\n    if (buffered->writebuf_len > 0) {\n        int64_t position  = buffered->position + buffered->writebuf_pos\n\n        mz_stream_buffered_print(\"Buffered - Switch from write to read, flushing (pos %\" PRId64 \")\\n\", position);\n\n        mz_stream_buffered_flush(stream, &bytes_flushed);\n        mz_stream_buffered_seek(stream, position, MZ_SEEK_SET);\n    }\n\n    while (bytes_left_to_read > 0) {\n        if ((buffered->readbuf_len == 0) || (buffered->readbuf_pos == buffered->readbuf_len)) {\n            if (buffered->readbuf_len == sizeof(buffered->readbuf)) {\n                buffered->readbuf_pos = 0;\n                buffered->readbuf_len = 0;\n            }\n\n            bytes_to_read = (int32_t)sizeof(buffered->readbuf) - (buffered->readbuf_len - buffered->readbuf_pos);\n            bytes_read = mz_stream_read(buffered->stream.base, buffered->readbuf + buffered->readbuf_pos, bytes_to_read);\n            if (bytes_read < 0)\n                return bytes_read;\n\n            buffered->readbuf_misses += 1;\n            buffered->readbuf_len += bytes_read;\n            buffered->position += bytes_read;\n\n            mz_stream_buffered_print(\"Buffered - Filled (read %\" PRId32 \"/%\" PRId32 \" buf %\" PRId32 \":%\" PRId32 \" pos %\" PRId64 \")\\n\",\n                bytes_read, bytes_to_read, buffered->readbuf_pos, buffered->readbuf_len, buffered->position);\n\n            if (bytes_read == 0)\n                break;\n        }\n\n        if ((buffered->readbuf_len - buffered->readbuf_pos) > 0) {\n            bytes_to_copy = buffered->readbuf_len - buffered->readbuf_pos;\n            if (bytes_to_copy > bytes_left_to_read)\n                bytes_to_copy = bytes_left_to_read;\n\n            memcpy((char *)buf + buf_len, buffered->readbuf + buffered->readbuf_pos, bytes_to_copy);\n\n            buf_len += bytes_to_copy;\n            bytes_left_to_read -= bytes_to_copy;\n\n            buffered->readbuf_hits += 1;\n            buffered->readbuf_pos += bytes_to_copy;\n\n            mz_stream_buffered_print(\"Buffered - Emptied (copied %\" PRId32 \" remaining %\" PRId32 \" buf %\" PRId32 \":%\" PRId32 \" pos %\" PRId64 \")\\n\",\n                bytes_to_copy, bytes_left_to_read, buffered->readbuf_pos, buffered->readbuf_len, buffered->position);\n        }\n    }\n\n    return size - bytes_left_to_read;\n}\n\nint32_t mz_stream_buffered_write(void *stream, const void *buf, int32_t size) {\n    mz_stream_buffered *buffered = (mz_stream_buffered *)stream;\n    int32_t bytes_to_write = size;\n    int32_t bytes_left_to_write = size;\n    int32_t bytes_to_copy = 0;\n    int32_t bytes_used = 0;\n    int32_t bytes_flushed = 0;\n    int32_t err = MZ_OK;\n\n\n    mz_stream_buffered_print(\"Buffered - Write (size %\" PRId32 \" len %\" PRId32 \" pos %\" PRId64 \")\\n\",\n        size, buffered->writebuf_len, buffered->position);\n\n    if (buffered->readbuf_len > 0) {\n        buffered->position -= buffered->readbuf_len;\n        buffered->position += buffered->readbuf_pos;\n\n        buffered->readbuf_len = 0;\n        buffered->readbuf_pos = 0;\n\n        mz_stream_buffered_print(\"Buffered - Switch from read to write (pos %\" PRId64 \")\\n\", buffered->position);\n\n        err = mz_stream_seek(buffered->stream.base, buffered->position, MZ_SEEK_SET);\n        if (err != MZ_OK)\n            return err;\n    }\n\n    while (bytes_left_to_write > 0) {\n        bytes_used = buffered->writebuf_len;\n        if (bytes_used > buffered->writebuf_pos)\n            bytes_used = buffered->writebuf_pos;\n        bytes_to_copy = (int32_t)sizeof(buffered->writebuf) - bytes_used;\n        if (bytes_to_copy > bytes_left_to_write)\n            bytes_to_copy = bytes_left_to_write;\n\n        if (bytes_to_copy == 0) {\n            err = mz_stream_buffered_flush(stream, &bytes_flushed);\n            if (err != MZ_OK)\n                return err;\n            if (bytes_flushed == 0)\n                return 0;\n\n            continue;\n        }\n\n        memcpy(buffered->writebuf + buffered->writebuf_pos,\n            (const char *)buf + (bytes_to_write - bytes_left_to_write), bytes_to_copy);\n\n        mz_stream_buffered_print(\"Buffered - Write copy (remaining %\" PRId32 \" write %\" PRId32 \":%\" PRId32 \" len %\" PRId32 \")\\n\",\n            bytes_to_copy, bytes_to_write, bytes_left_to_write, buffered->writebuf_len);\n\n        bytes_left_to_write -= bytes_to_copy;\n\n        buffered->writebuf_pos += bytes_to_copy;\n        buffered->writebuf_hits += 1;\n        if (buffered->writebuf_pos > buffered->writebuf_len)\n            buffered->writebuf_len += buffered->writebuf_pos - buffered->writebuf_len;\n    }\n\n    return size - bytes_left_to_write;\n}\n\nint64_t mz_stream_buffered_tell(void *stream) {\n    mz_stream_buffered *buffered = (mz_stream_buffered *)stream;\n    int64_t position = mz_stream_tell(buffered->stream.base);\n\n    buffered->position = position;\n\n    mz_stream_buffered_print(\"Buffered - Tell (pos %\" PRId64 \" readpos %\" PRId32 \" writepos %\" PRId32 \")\\n\",\n        buffered->position, buffered->readbuf_pos, buffered->writebuf_pos);\n\n    if (buffered->readbuf_len > 0)\n        position -= ((int64_t)buffered->readbuf_len - buffered->readbuf_pos);\n    if (buffered->writebuf_len > 0)\n        position += buffered->writebuf_pos;\n    return position;\n}\n\nint32_t mz_stream_buffered_seek(void *stream, int64_t offset, int32_t origin) {\n    mz_stream_buffered *buffered = (mz_stream_buffered *)stream;\n    int32_t bytes_flushed = 0;\n    int32_t err = MZ_OK;\n\n    mz_stream_buffered_print(\"Buffered - Seek (origin %\" PRId32 \" offset %\" PRId64 \" pos %\" PRId64 \")\\n\",\n        origin, offset, buffered->position);\n\n    switch (origin) {\n    case MZ_SEEK_SET:\n\n        if ((buffered->readbuf_len > 0) && (offset < buffered->position) &&\n            (offset >= buffered->position - buffered->readbuf_len)) {\n            buffered->readbuf_pos = (int32_t)(offset - (buffered->position - buffered->readbuf_len));\n            return MZ_OK;\n        }\n        if (buffered->writebuf_len > 0) {\n            if ((offset >= buffered->position) && (offset <= buffered->position + buffered->writebuf_len)) {\n                buffered->writebuf_pos = (int32_t)(offset - buffered->position);\n                return MZ_OK;\n            }\n        }\n\n        err = mz_stream_buffered_flush(stream, &bytes_flushed);\n        if (err != MZ_OK)\n            return err;\n\n        buffered->position = offset;\n        break;\n\n    case MZ_SEEK_CUR:\n\n        if (buffered->readbuf_len > 0) {\n            if (offset <= ((int64_t)buffered->readbuf_len - buffered->readbuf_pos)) {\n                buffered->readbuf_pos += (uint32_t)offset;\n                return MZ_OK;\n            }\n            offset -= ((int64_t)buffered->readbuf_len - buffered->readbuf_pos);\n            buffered->position += offset;\n        }\n        if (buffered->writebuf_len > 0) {\n            if (offset <= ((int64_t)buffered->writebuf_len - buffered->writebuf_pos)) {\n                buffered->writebuf_pos += (uint32_t)offset;\n                return MZ_OK;\n            }\n            /* offset -= (buffered->writebuf_len - buffered->writebuf_pos); */\n        }\n\n        err = mz_stream_buffered_flush(stream, &bytes_flushed);\n        if (err != MZ_OK)\n            return err;\n\n        break;\n\n    case MZ_SEEK_END:\n\n        if (buffered->writebuf_len > 0) {\n            buffered->writebuf_pos = buffered->writebuf_len;\n            return MZ_OK;\n        }\n        break;\n    }\n\n    buffered->readbuf_len = 0;\n    buffered->readbuf_pos = 0;\n    buffered->writebuf_len = 0;\n    buffered->writebuf_pos = 0;\n\n    return mz_stream_seek(buffered->stream.base, offset, origin);\n}\n\nint32_t mz_stream_buffered_close(void *stream) {\n    mz_stream_buffered *buffered = (mz_stream_buffered *)stream;\n    int32_t bytes_flushed = 0;\n\n    mz_stream_buffered_flush(stream, &bytes_flushed);\n    mz_stream_buffered_print(\"Buffered - Close (flushed %\" PRId32 \")\\n\", bytes_flushed);\n\n    if (buffered->readbuf_hits + buffered->readbuf_misses > 0) {\n        mz_stream_buffered_print(\"Buffered - Read efficiency %.02f%%\\n\",\n            (buffered->readbuf_hits / ((float)buffered->readbuf_hits + buffered->readbuf_misses)) * 100);\n    }\n\n    if (buffered->writebuf_hits + buffered->writebuf_misses > 0) {\n        mz_stream_buffered_print(\"Buffered - Write efficiency %.02f%%\\n\",\n            (buffered->writebuf_hits / ((float)buffered->writebuf_hits + buffered->writebuf_misses)) * 100);\n    }\n\n    mz_stream_buffered_reset(buffered);\n\n    return mz_stream_close(buffered->stream.base);\n}\n\nint32_t mz_stream_buffered_error(void *stream) {\n    mz_stream_buffered *buffered = (mz_stream_buffered *)stream;\n    return mz_stream_error(buffered->stream.base);\n}\n\nvoid *mz_stream_buffered_create(void **stream) {\n    mz_stream_buffered *buffered = NULL;\n\n    buffered = (mz_stream_buffered *)calloc(1, sizeof(mz_stream_buffered));\n    if (buffered)\n        buffered->stream.vtbl = &mz_stream_buffered_vtbl;\n    if (stream)\n        *stream = buffered;\n\n    return buffered;\n}\n\nvoid mz_stream_buffered_delete(void **stream) {\n    mz_stream_buffered *buffered = NULL;\n    if (!stream)\n        return;\n    buffered = (mz_stream_buffered *)*stream;\n    if (buffered)\n        free(buffered);\n    *stream = NULL;\n}\n\nvoid *mz_stream_buffered_get_interface(void) {\n    return (void *)&mz_stream_buffered_vtbl;\n}\n"
  },
  {
    "path": "ios/CodePush/SSZipArchive/minizip/mz_strm_buf.h",
    "content": "/* mz_strm_buf.h -- Stream for buffering reads/writes\n   part of the minizip-ng project\n\n   This version of ioapi is designed to buffer IO.\n\n   Copyright (C) Nathan Moinvaziri\n      https://github.com/zlib-ng/minizip-ng\n\n   This program is distributed under the terms of the same license as zlib.\n   See the accompanying LICENSE file for the full text of the license.\n*/\n\n#ifndef MZ_STREAM_BUFFERED_H\n#define MZ_STREAM_BUFFERED_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/***************************************************************************/\n\nint32_t mz_stream_buffered_open(void *stream, const char *path, int32_t mode);\nint32_t mz_stream_buffered_is_open(void *stream);\nint32_t mz_stream_buffered_read(void *stream, void *buf, int32_t size);\nint32_t mz_stream_buffered_write(void *stream, const void *buf, int32_t size);\nint64_t mz_stream_buffered_tell(void *stream);\nint32_t mz_stream_buffered_seek(void *stream, int64_t offset, int32_t origin);\nint32_t mz_stream_buffered_close(void *stream);\nint32_t mz_stream_buffered_error(void *stream);\n\nvoid*   mz_stream_buffered_create(void **stream);\nvoid    mz_stream_buffered_delete(void **stream);\n\nvoid*   mz_stream_buffered_get_interface(void);\n\n/***************************************************************************/\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "ios/CodePush/SSZipArchive/minizip/mz_strm_mem.c",
    "content": "/* mz_strm_mem.c -- Stream for memory access\n   part of the minizip-ng project\n\n   This interface is designed to access memory rather than files.\n   We do use a region of memory to put data in to and take it out of.\n\n   Based on Unzip ioapi.c version 0.22, May 19th, 2003\n\n   Copyright (C) Nathan Moinvaziri\n     https://github.com/zlib-ng/minizip-ng\n   Copyright (C) 2003 Justin Fletcher\n   Copyright (C) 1998-2003 Gilles Vollant\n     https://www.winimage.com/zLibDll/minizip.html\n\n   This program is distributed under the terms of the same license as zlib.\n   See the accompanying LICENSE file for the full text of the license.\n*/\n\n#include \"mz.h\"\n#include \"mz_strm.h\"\n#include \"mz_strm_mem.h\"\n\n/***************************************************************************/\n\nstatic mz_stream_vtbl mz_stream_mem_vtbl = {\n    mz_stream_mem_open,\n    mz_stream_mem_is_open,\n    mz_stream_mem_read,\n    mz_stream_mem_write,\n    mz_stream_mem_tell,\n    mz_stream_mem_seek,\n    mz_stream_mem_close,\n    mz_stream_mem_error,\n    mz_stream_mem_create,\n    mz_stream_mem_delete,\n    NULL,\n    NULL\n};\n\n/***************************************************************************/\n\ntypedef struct mz_stream_mem_s {\n    mz_stream   stream;\n    int32_t     mode;\n    uint8_t     *buffer;    /* Memory buffer pointer */\n    int32_t     size;       /* Size of the memory buffer */\n    int32_t     limit;      /* Furthest we've written */\n    int32_t     position;   /* Current position in the memory */\n    int32_t     grow_size;  /* Size to grow when full */\n} mz_stream_mem;\n\n/***************************************************************************/\n\nstatic int32_t mz_stream_mem_set_size(void *stream, int32_t size) {\n    mz_stream_mem *mem = (mz_stream_mem *)stream;\n    int32_t new_size = size;\n    uint8_t *new_buf = NULL;\n\n    new_buf = (uint8_t *)malloc((uint32_t)new_size);\n    if (!new_buf)\n        return MZ_BUF_ERROR;\n\n    if (mem->buffer) {\n        memcpy(new_buf, mem->buffer, mem->size);\n        free(mem->buffer);\n    }\n\n    mem->buffer = new_buf;\n    mem->size = new_size;\n    return MZ_OK;\n}\n\nint32_t mz_stream_mem_open(void *stream, const char *path, int32_t mode) {\n    mz_stream_mem *mem = (mz_stream_mem *)stream;\n    int32_t err = MZ_OK;\n\n    MZ_UNUSED(path);\n\n    mem->mode = mode;\n    mem->limit = 0;\n    mem->position = 0;\n\n    if (mem->mode & MZ_OPEN_MODE_CREATE)\n        err = mz_stream_mem_set_size(stream, mem->grow_size);\n    else\n        mem->limit = mem->size;\n\n    return err;\n}\n\nint32_t mz_stream_mem_is_open(void *stream) {\n    mz_stream_mem *mem = (mz_stream_mem *)stream;\n    if (!mem->buffer)\n        return MZ_OPEN_ERROR;\n    return MZ_OK;\n}\n\nint32_t mz_stream_mem_read(void *stream, void *buf, int32_t size) {\n    mz_stream_mem *mem = (mz_stream_mem *)stream;\n\n    if (size > mem->size - mem->position)\n        size = mem->size - mem->position;\n    if (mem->position + size > mem->limit)\n        size = mem->limit - mem->position;\n\n    if (size <= 0)\n        return 0;\n\n    memcpy(buf, mem->buffer + mem->position, size);\n    mem->position += size;\n\n    return size;\n}\n\nint32_t mz_stream_mem_write(void *stream, const void *buf, int32_t size) {\n    mz_stream_mem *mem = (mz_stream_mem *)stream;\n    int32_t new_size = 0;\n    int32_t err = MZ_OK;\n\n    if (!size)\n        return size;\n\n    if (size > mem->size - mem->position) {\n        if (mem->mode & MZ_OPEN_MODE_CREATE) {\n            new_size = mem->size;\n            if (size < mem->grow_size)\n                new_size += mem->grow_size;\n            else\n                new_size += size;\n\n            err = mz_stream_mem_set_size(stream, new_size);\n            if (err != MZ_OK)\n                return err;\n        } else {\n            size = mem->size - mem->position;\n        }\n    }\n\n    memcpy(mem->buffer + mem->position, buf, size);\n\n    mem->position += size;\n    if (mem->position > mem->limit)\n        mem->limit = mem->position;\n\n    return size;\n}\n\nint64_t mz_stream_mem_tell(void *stream) {\n    mz_stream_mem *mem = (mz_stream_mem *)stream;\n    return mem->position;\n}\n\nint32_t mz_stream_mem_seek(void *stream, int64_t offset, int32_t origin) {\n    mz_stream_mem *mem = (mz_stream_mem *)stream;\n    int64_t new_pos = 0;\n    int32_t err = MZ_OK;\n\n    switch (origin) {\n    case MZ_SEEK_CUR:\n        new_pos = mem->position + offset;\n        break;\n    case MZ_SEEK_END:\n        new_pos = mem->limit + offset;\n        break;\n    case MZ_SEEK_SET:\n        new_pos = offset;\n        break;\n    default:\n        return MZ_SEEK_ERROR;\n    }\n\n    if (new_pos > mem->size) {\n        if ((mem->mode & MZ_OPEN_MODE_CREATE) == 0)\n            return MZ_SEEK_ERROR;\n\n        err = mz_stream_mem_set_size(stream, (int32_t)new_pos);\n        if (err != MZ_OK)\n            return err;\n    } else if (new_pos < 0) {\n        return MZ_SEEK_ERROR;\n    }\n\n    mem->position = (int32_t)new_pos;\n    return MZ_OK;\n}\n\nint32_t mz_stream_mem_close(void *stream) {\n    MZ_UNUSED(stream);\n\n    /* We never return errors */\n    return MZ_OK;\n}\n\nint32_t mz_stream_mem_error(void *stream) {\n    MZ_UNUSED(stream);\n\n    /* We never return errors */\n    return MZ_OK;\n}\n\nvoid mz_stream_mem_set_buffer(void *stream, void *buf, int32_t size) {\n    mz_stream_mem *mem = (mz_stream_mem *)stream;\n    mem->buffer = (uint8_t *)buf;\n    mem->size = size;\n    mem->limit = size;\n}\n\nint32_t mz_stream_mem_get_buffer(void *stream, const void **buf) {\n    return mz_stream_mem_get_buffer_at(stream, 0, buf);\n}\n\nint32_t mz_stream_mem_get_buffer_at(void *stream, int64_t position, const void **buf) {\n    mz_stream_mem *mem = (mz_stream_mem *)stream;\n    if (!buf || position < 0 || !mem->buffer|| mem->size < position)\n        return MZ_SEEK_ERROR;\n    *buf = mem->buffer + position;\n    return MZ_OK;\n}\n\nint32_t mz_stream_mem_get_buffer_at_current(void *stream, const void **buf) {\n    mz_stream_mem *mem = (mz_stream_mem *)stream;\n    return mz_stream_mem_get_buffer_at(stream, mem->position, buf);\n}\n\nvoid mz_stream_mem_get_buffer_length(void *stream, int32_t *length) {\n    mz_stream_mem *mem = (mz_stream_mem *)stream;\n    *length = mem->limit;\n}\n\nvoid mz_stream_mem_set_buffer_limit(void *stream, int32_t limit) {\n    mz_stream_mem *mem = (mz_stream_mem *)stream;\n    mem->limit = limit;\n}\n\nvoid mz_stream_mem_set_grow_size(void *stream, int32_t grow_size) {\n    mz_stream_mem *mem = (mz_stream_mem *)stream;\n    mem->grow_size = grow_size;\n}\n\nvoid *mz_stream_mem_create(void **stream) {\n    mz_stream_mem *mem = NULL;\n\n    mem = (mz_stream_mem *)calloc(1, sizeof(mz_stream_mem));\n    if (mem) {\n        mem->stream.vtbl = &mz_stream_mem_vtbl;\n        mem->grow_size = 4096;\n    }\n    if (stream)\n        *stream = mem;\n\n    return mem;\n}\n\nvoid mz_stream_mem_delete(void **stream) {\n    mz_stream_mem *mem = NULL;\n    if (!stream)\n        return;\n    mem = (mz_stream_mem *)*stream;\n    if (mem) {\n        if ((mem->mode & MZ_OPEN_MODE_CREATE) && (mem->buffer))\n            free(mem->buffer);\n        free(mem);\n    }\n    *stream = NULL;\n}\n\nvoid *mz_stream_mem_get_interface(void) {\n    return (void *)&mz_stream_mem_vtbl;\n}\n"
  },
  {
    "path": "ios/CodePush/SSZipArchive/minizip/mz_strm_mem.h",
    "content": "/* mz_strm_mem.h -- Stream for memory access\n   part of the minizip-ng project\n\n   Copyright (C) Nathan Moinvaziri\n      https://github.com/zlib-ng/minizip-ng\n\n   This program is distributed under the terms of the same license as zlib.\n   See the accompanying LICENSE file for the full text of the license.\n*/\n\n#ifndef MZ_STREAM_MEM_H\n#define MZ_STREAM_MEM_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/***************************************************************************/\n\nint32_t mz_stream_mem_open(void *stream, const char *filename, int32_t mode);\nint32_t mz_stream_mem_is_open(void *stream);\nint32_t mz_stream_mem_read(void *stream, void *buf, int32_t size);\nint32_t mz_stream_mem_write(void *stream, const void *buf, int32_t size);\nint64_t mz_stream_mem_tell(void *stream);\nint32_t mz_stream_mem_seek(void *stream, int64_t offset, int32_t origin);\nint32_t mz_stream_mem_close(void *stream);\nint32_t mz_stream_mem_error(void *stream);\n\nvoid    mz_stream_mem_set_buffer(void *stream, void *buf, int32_t size);\nint32_t mz_stream_mem_get_buffer(void *stream, const void **buf);\nint32_t mz_stream_mem_get_buffer_at(void *stream, int64_t position, const void **buf);\nint32_t mz_stream_mem_get_buffer_at_current(void *stream, const void **buf);\nvoid    mz_stream_mem_get_buffer_length(void *stream, int32_t *length);\nvoid    mz_stream_mem_set_buffer_limit(void *stream, int32_t limit);\nvoid    mz_stream_mem_set_grow_size(void *stream, int32_t grow_size);\n\nvoid*   mz_stream_mem_create(void **stream);\nvoid    mz_stream_mem_delete(void **stream);\n\nvoid*   mz_stream_mem_get_interface(void);\n\n/***************************************************************************/\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "ios/CodePush/SSZipArchive/minizip/mz_strm_os.h",
    "content": "/* mz_sstrm_os.h -- Stream for filesystem access\n   part of the minizip-ng project\n\n   Copyright (C) Nathan Moinvaziri\n     https://github.com/zlib-ng/minizip-ng\n\n   This program is distributed under the terms of the same license as zlib.\n   See the accompanying LICENSE file for the full text of the license.\n*/\n\n#ifndef MZ_STREAM_OS_H\n#define MZ_STREAM_OS_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/***************************************************************************/\n\nint32_t mz_stream_os_open(void *stream, const char *path, int32_t mode);\nint32_t mz_stream_os_is_open(void *stream);\nint32_t mz_stream_os_read(void *stream, void *buf, int32_t size);\nint32_t mz_stream_os_write(void *stream, const void *buf, int32_t size);\nint64_t mz_stream_os_tell(void *stream);\nint32_t mz_stream_os_seek(void *stream, int64_t offset, int32_t origin);\nint32_t mz_stream_os_close(void *stream);\nint32_t mz_stream_os_error(void *stream);\n\nvoid*   mz_stream_os_create(void **stream);\nvoid    mz_stream_os_delete(void **stream);\n\nvoid*   mz_stream_os_get_interface(void);\n\n/***************************************************************************/\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "ios/CodePush/SSZipArchive/minizip/mz_strm_os_posix.c",
    "content": "/* mz_strm_posix.c -- Stream for filesystem access for posix/linux\n   part of the minizip-ng project\n\n   Copyright (C) Nathan Moinvaziri\n     https://github.com/zlib-ng/minizip-ng\n   Modifications for Zip64 support\n     Copyright (C) 2009-2010 Mathias Svensson\n     http://result42.com\n   Copyright (C) 1998-2010 Gilles Vollant\n     https://www.winimage.com/zLibDll/minizip.html\n\n   This program is distributed under the terms of the same license as zlib.\n   See the accompanying LICENSE file for the full text of the license.\n*/\n\n#include \"mz.h\"\n#include \"mz_strm.h\"\n#include \"mz_strm_os.h\"\n\n#include <stdio.h> /* fopen, fread.. */\n#include <errno.h>\n\n/***************************************************************************/\n\n#define fopen64 fopen\n#ifndef MZ_FILE32_API\n#  ifndef NO_FSEEKO\n#    define ftello64 ftello\n#    define fseeko64 fseeko\n#  elif defined(_MSC_VER) && (_MSC_VER >= 1400)\n#    define ftello64 _ftelli64\n#    define fseeko64 _fseeki64\n#  endif\n#endif\n#ifndef ftello64\n#  define ftello64 ftell\n#endif\n#ifndef fseeko64\n#  define fseeko64 fseek\n#endif\n\n/***************************************************************************/\n\nstatic mz_stream_vtbl mz_stream_os_vtbl = {\n    mz_stream_os_open,\n    mz_stream_os_is_open,\n    mz_stream_os_read,\n    mz_stream_os_write,\n    mz_stream_os_tell,\n    mz_stream_os_seek,\n    mz_stream_os_close,\n    mz_stream_os_error,\n    mz_stream_os_create,\n    mz_stream_os_delete,\n    NULL,\n    NULL\n};\n\n/***************************************************************************/\n\ntypedef struct mz_stream_posix_s {\n    mz_stream   stream;\n    int32_t     error;\n    FILE        *handle;\n} mz_stream_posix;\n\n/***************************************************************************/\n\nint32_t mz_stream_os_open(void *stream, const char *path, int32_t mode) {\n    mz_stream_posix *posix = (mz_stream_posix *)stream;\n    const char *mode_fopen = NULL;\n\n    if (!path)\n        return MZ_PARAM_ERROR;\n\n    if ((mode & MZ_OPEN_MODE_READWRITE) == MZ_OPEN_MODE_READ)\n        mode_fopen = \"rb\";\n    else if (mode & MZ_OPEN_MODE_APPEND)\n        mode_fopen = \"r+b\";\n    else if (mode & MZ_OPEN_MODE_CREATE)\n        mode_fopen = \"wb\";\n    else\n        return MZ_OPEN_ERROR;\n\n    posix->handle = fopen64(path, mode_fopen);\n    if (!posix->handle) {\n        posix->error = errno;\n        return MZ_OPEN_ERROR;\n    }\n\n    if (mode & MZ_OPEN_MODE_APPEND)\n        return mz_stream_os_seek(stream, 0, MZ_SEEK_END);\n\n    return MZ_OK;\n}\n\nint32_t mz_stream_os_is_open(void *stream) {\n    mz_stream_posix *posix = (mz_stream_posix *)stream;\n    if (!posix->handle)\n        return MZ_OPEN_ERROR;\n    return MZ_OK;\n}\n\nint32_t mz_stream_os_read(void *stream, void *buf, int32_t size) {\n    mz_stream_posix *posix = (mz_stream_posix *)stream;\n    int32_t read = (int32_t)fread(buf, 1, (size_t)size, posix->handle);\n    if (read < size && ferror(posix->handle)) {\n        posix->error = errno;\n        return MZ_READ_ERROR;\n    }\n    return read;\n}\n\nint32_t mz_stream_os_write(void *stream, const void *buf, int32_t size) {\n    mz_stream_posix *posix = (mz_stream_posix *)stream;\n    int32_t written = (int32_t)fwrite(buf, 1, (size_t)size, posix->handle);\n    if (written < size && ferror(posix->handle)) {\n        posix->error = errno;\n        return MZ_WRITE_ERROR;\n    }\n    return written;\n}\n\nint64_t mz_stream_os_tell(void *stream) {\n    mz_stream_posix *posix = (mz_stream_posix *)stream;\n    int64_t position = ftello64(posix->handle);\n    if (position == -1) {\n        posix->error = errno;\n        return MZ_TELL_ERROR;\n    }\n    return position;\n}\n\nint32_t mz_stream_os_seek(void *stream, int64_t offset, int32_t origin) {\n    mz_stream_posix *posix = (mz_stream_posix *)stream;\n    int32_t fseek_origin = 0;\n\n    switch (origin) {\n    case MZ_SEEK_CUR:\n        fseek_origin = SEEK_CUR;\n        break;\n    case MZ_SEEK_END:\n        fseek_origin = SEEK_END;\n        break;\n    case MZ_SEEK_SET:\n        fseek_origin = SEEK_SET;\n        break;\n    default:\n        return MZ_SEEK_ERROR;\n    }\n\n    if (fseeko64(posix->handle, offset, fseek_origin) != 0) {\n        posix->error = errno;\n        return MZ_SEEK_ERROR;\n    }\n\n    return MZ_OK;\n}\n\nint32_t mz_stream_os_close(void *stream) {\n    mz_stream_posix *posix = (mz_stream_posix *)stream;\n    int32_t closed = 0;\n    if (posix->handle) {\n        closed = fclose(posix->handle);\n        posix->handle = NULL;\n    }\n    if (closed != 0) {\n        posix->error = errno;\n        return MZ_CLOSE_ERROR;\n    }\n    return MZ_OK;\n}\n\nint32_t mz_stream_os_error(void *stream) {\n    mz_stream_posix *posix = (mz_stream_posix *)stream;\n    return posix->error;\n}\n\nvoid *mz_stream_os_create(void **stream) {\n    mz_stream_posix *posix = NULL;\n\n    posix = (mz_stream_posix *)calloc(1, sizeof(mz_stream_posix));\n    if (posix)\n        posix->stream.vtbl = &mz_stream_os_vtbl;\n    if (stream)\n        *stream = posix;\n\n    return posix;\n}\n\nvoid mz_stream_os_delete(void **stream) {\n    mz_stream_posix *posix = NULL;\n    if (!stream)\n        return;\n    posix = (mz_stream_posix *)*stream;\n    if (posix)\n        free(posix);\n    *stream = NULL;\n}\n\nvoid *mz_stream_os_get_interface(void) {\n    return (void *)&mz_stream_os_vtbl;\n}\n"
  },
  {
    "path": "ios/CodePush/SSZipArchive/minizip/mz_strm_pkcrypt.c",
    "content": "/* mz_strm_pkcrypt.c -- Code for traditional PKWARE encryption\n   part of the minizip-ng project\n\n   Copyright (C) Nathan Moinvaziri\n      https://github.com/zlib-ng/minizip-ng\n   Copyright (C) 1998-2005 Gilles Vollant\n      Modifications for Info-ZIP crypting\n      https://www.winimage.com/zLibDll/minizip.html\n   Copyright (C) 2003 Terry Thorsen\n\n   This code is a modified version of crypting code in Info-ZIP distribution\n\n   Copyright (C) 1990-2000 Info-ZIP.  All rights reserved.\n\n   This program is distributed under the terms of the same license as zlib.\n   See the accompanying LICENSE file for the full text of the license.\n\n   This encryption code is a direct transcription of the algorithm from\n   Roger Schlafly, described by Phil Katz in the file appnote.txt. This\n   file (appnote.txt) is distributed with the PKZIP program (even in the\n   version without encryption capabilities).\n*/\n\n#include \"mz.h\"\n#include \"mz_crypt.h\"\n#include \"mz_strm.h\"\n#include \"mz_strm_pkcrypt.h\"\n\n/***************************************************************************/\n\nstatic mz_stream_vtbl mz_stream_pkcrypt_vtbl = {\n    mz_stream_pkcrypt_open,\n    mz_stream_pkcrypt_is_open,\n    mz_stream_pkcrypt_read,\n    mz_stream_pkcrypt_write,\n    mz_stream_pkcrypt_tell,\n    mz_stream_pkcrypt_seek,\n    mz_stream_pkcrypt_close,\n    mz_stream_pkcrypt_error,\n    mz_stream_pkcrypt_create,\n    mz_stream_pkcrypt_delete,\n    mz_stream_pkcrypt_get_prop_int64,\n    mz_stream_pkcrypt_set_prop_int64\n};\n\n/***************************************************************************/\n\ntypedef struct mz_stream_pkcrypt_s {\n    mz_stream       stream;\n    int32_t         error;\n    int16_t         initialized;\n    uint8_t         buffer[UINT16_MAX];\n    int64_t         total_in;\n    int64_t         max_total_in;\n    int64_t         total_out;\n    uint32_t        keys[3];          /* keys defining the pseudo-random sequence */\n    uint8_t         verify1;\n    uint8_t         verify2;\n    const char      *password;\n} mz_stream_pkcrypt;\n\n/***************************************************************************/\n\n#define mz_stream_pkcrypt_decode(strm, c)                                   \\\n    (mz_stream_pkcrypt_update_keys(strm,                                    \\\n        c ^= mz_stream_pkcrypt_decrypt_byte(strm)))\n\n#define mz_stream_pkcrypt_encode(strm, c, t)                                \\\n    (t = mz_stream_pkcrypt_decrypt_byte(strm),                              \\\n        mz_stream_pkcrypt_update_keys(strm, (uint8_t)c), (uint8_t)(t^(c)))\n\n/***************************************************************************/\n\nstatic uint8_t mz_stream_pkcrypt_decrypt_byte(void *stream) {\n    mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;\n\n    unsigned temp; /* POTENTIAL BUG:  temp*(temp^1) may overflow in an */\n                   /* unpredictable manner on 16-bit systems; not a problem */\n                   /* with any known compiler so far, though. */\n\n    temp = pkcrypt->keys[2] | 2;\n    return (uint8_t)(((temp * (temp ^ 1)) >> 8) & 0xff);\n}\n\nstatic uint8_t mz_stream_pkcrypt_update_keys(void *stream, uint8_t c) {\n    mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;\n    uint8_t buf = c;\n\n    pkcrypt->keys[0] = (uint32_t)~mz_crypt_crc32_update(~pkcrypt->keys[0], &buf, 1);\n\n    pkcrypt->keys[1] += pkcrypt->keys[0] & 0xff;\n    pkcrypt->keys[1] *= 134775813L;\n    pkcrypt->keys[1] += 1;\n\n    buf = (uint8_t)(pkcrypt->keys[1] >> 24);\n    pkcrypt->keys[2] = (uint32_t)~mz_crypt_crc32_update(~pkcrypt->keys[2], &buf, 1);\n\n    return (uint8_t)c;\n}\n\nstatic void mz_stream_pkcrypt_init_keys(void *stream, const char *password) {\n    mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;\n\n    pkcrypt->keys[0] = 305419896L;\n    pkcrypt->keys[1] = 591751049L;\n    pkcrypt->keys[2] = 878082192L;\n\n    while (*password != 0) {\n        mz_stream_pkcrypt_update_keys(stream, (uint8_t)*password);\n        password += 1;\n    }\n}\n\n/***************************************************************************/\n\nint32_t mz_stream_pkcrypt_open(void *stream, const char *path, int32_t mode) {\n    mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;\n    uint16_t t = 0;\n    int16_t i = 0;\n    uint8_t verify1 = 0;\n    uint8_t verify2 = 0;\n    uint8_t header[MZ_PKCRYPT_HEADER_SIZE];\n    const char *password = path;\n\n    pkcrypt->total_in = 0;\n    pkcrypt->total_out = 0;\n    pkcrypt->initialized = 0;\n\n    if (mz_stream_is_open(pkcrypt->stream.base) != MZ_OK)\n        return MZ_OPEN_ERROR;\n\n    if (!password)\n        password = pkcrypt->password;\n    if (!password)\n        return MZ_PARAM_ERROR;\n\n    mz_stream_pkcrypt_init_keys(stream, password);\n\n    if (mode & MZ_OPEN_MODE_WRITE) {\n        /* First generate RAND_HEAD_LEN - 2 random bytes. */\n        mz_crypt_rand(header, MZ_PKCRYPT_HEADER_SIZE - 2);\n\n        /* Encrypt random header (last two bytes is high word of crc) */\n        for (i = 0; i < MZ_PKCRYPT_HEADER_SIZE - 2; i++)\n            header[i] = mz_stream_pkcrypt_encode(stream, header[i], t);\n\n        header[i++] = mz_stream_pkcrypt_encode(stream, pkcrypt->verify1, t);\n        header[i++] = mz_stream_pkcrypt_encode(stream, pkcrypt->verify2, t);\n\n        if (mz_stream_write(pkcrypt->stream.base, header, sizeof(header)) != sizeof(header))\n            return MZ_WRITE_ERROR;\n\n        pkcrypt->total_out += MZ_PKCRYPT_HEADER_SIZE;\n    } else if (mode & MZ_OPEN_MODE_READ) {\n        if (mz_stream_read(pkcrypt->stream.base, header, sizeof(header)) != sizeof(header))\n            return MZ_READ_ERROR;\n\n        for (i = 0; i < MZ_PKCRYPT_HEADER_SIZE - 2; i++)\n            header[i] = mz_stream_pkcrypt_decode(stream, header[i]);\n\n        verify1 = mz_stream_pkcrypt_decode(stream, header[i++]);\n        verify2 = mz_stream_pkcrypt_decode(stream, header[i++]);\n\n        /* Older versions used 2 byte check, newer versions use 1 byte check. */\n        MZ_UNUSED(verify1);\n        if ((verify2 != 0) && (verify2 != pkcrypt->verify2))\n            return MZ_PASSWORD_ERROR;\n\n        pkcrypt->total_in += MZ_PKCRYPT_HEADER_SIZE;\n    }\n\n    pkcrypt->initialized = 1;\n    return MZ_OK;\n}\n\nint32_t mz_stream_pkcrypt_is_open(void *stream) {\n    mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;\n    if (!pkcrypt->initialized)\n        return MZ_OPEN_ERROR;\n    return MZ_OK;\n}\n\nint32_t mz_stream_pkcrypt_read(void *stream, void *buf, int32_t size) {\n    mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;\n    uint8_t *buf_ptr = (uint8_t *)buf;\n    int32_t bytes_to_read = size;\n    int32_t read = 0;\n    int32_t i = 0;\n\n    if ((int64_t)bytes_to_read > (pkcrypt->max_total_in - pkcrypt->total_in))\n        bytes_to_read = (int32_t)(pkcrypt->max_total_in - pkcrypt->total_in);\n\n    read = mz_stream_read(pkcrypt->stream.base, buf, bytes_to_read);\n\n    for (i = 0; i < read; i++)\n        buf_ptr[i] = mz_stream_pkcrypt_decode(stream, buf_ptr[i]);\n\n    if (read > 0)\n        pkcrypt->total_in += read;\n\n    return read;\n}\n\nint32_t mz_stream_pkcrypt_write(void *stream, const void *buf, int32_t size) {\n    mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;\n    const uint8_t *buf_ptr = (const uint8_t *)buf;\n    int32_t bytes_to_write = sizeof(pkcrypt->buffer);\n    int32_t total_written = 0;\n    int32_t written = 0;\n    int32_t i = 0;\n    uint16_t t = 0;\n\n    if (size < 0)\n        return MZ_PARAM_ERROR;\n\n    do {\n        if (bytes_to_write > (size - total_written))\n            bytes_to_write = (size - total_written);\n\n        for (i = 0; i < bytes_to_write; i += 1) {\n            pkcrypt->buffer[i] = mz_stream_pkcrypt_encode(stream, *buf_ptr, t);\n            buf_ptr += 1;\n        }\n\n        written = mz_stream_write(pkcrypt->stream.base, pkcrypt->buffer, bytes_to_write);\n        if (written < 0)\n            return written;\n\n        total_written += written;\n    } while (total_written < size && written > 0);\n\n    pkcrypt->total_out += total_written;\n    return total_written;\n}\n\nint64_t mz_stream_pkcrypt_tell(void *stream) {\n    mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;\n    return mz_stream_tell(pkcrypt->stream.base);\n}\n\nint32_t mz_stream_pkcrypt_seek(void *stream, int64_t offset, int32_t origin) {\n    mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;\n    return mz_stream_seek(pkcrypt->stream.base, offset, origin);\n}\n\nint32_t mz_stream_pkcrypt_close(void *stream) {\n    mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;\n    pkcrypt->initialized = 0;\n    return MZ_OK;\n}\n\nint32_t mz_stream_pkcrypt_error(void *stream) {\n    mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;\n    return pkcrypt->error;\n}\n\nvoid mz_stream_pkcrypt_set_password(void *stream, const char *password) {\n    mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;\n    pkcrypt->password = password;\n}\n\nvoid mz_stream_pkcrypt_set_verify(void *stream, uint8_t verify1, uint8_t verify2) {\n    mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;\n    pkcrypt->verify1 = verify1;\n    pkcrypt->verify2 = verify2;\n}\n\nvoid mz_stream_pkcrypt_get_verify(void *stream, uint8_t *verify1, uint8_t *verify2) {\n    mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;\n    *verify1 = pkcrypt->verify1;\n    *verify2 = pkcrypt->verify2;\n}\n\nint32_t mz_stream_pkcrypt_get_prop_int64(void *stream, int32_t prop, int64_t *value) {\n    mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;\n    switch (prop) {\n    case MZ_STREAM_PROP_TOTAL_IN:\n        *value = pkcrypt->total_in;\n        break;\n    case MZ_STREAM_PROP_TOTAL_OUT:\n        *value = pkcrypt->total_out;\n        break;\n    case MZ_STREAM_PROP_TOTAL_IN_MAX:\n        *value = pkcrypt->max_total_in;\n        break;\n    case MZ_STREAM_PROP_HEADER_SIZE:\n        *value = MZ_PKCRYPT_HEADER_SIZE;\n        break;\n    case MZ_STREAM_PROP_FOOTER_SIZE:\n        *value = 0;\n        break;\n    default:\n        return MZ_EXIST_ERROR;\n    }\n    return MZ_OK;\n}\n\nint32_t mz_stream_pkcrypt_set_prop_int64(void *stream, int32_t prop, int64_t value) {\n    mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;\n    switch (prop) {\n    case MZ_STREAM_PROP_TOTAL_IN_MAX:\n        pkcrypt->max_total_in = value;\n        break;\n    default:\n        return MZ_EXIST_ERROR;\n    }\n    return MZ_OK;\n}\n\nvoid *mz_stream_pkcrypt_create(void **stream) {\n    mz_stream_pkcrypt *pkcrypt = NULL;\n\n    pkcrypt = (mz_stream_pkcrypt *)calloc(1, sizeof(mz_stream_pkcrypt));\n    if (pkcrypt)\n        pkcrypt->stream.vtbl = &mz_stream_pkcrypt_vtbl;\n    if (stream)\n        *stream = pkcrypt;\n\n    return pkcrypt;\n}\n\nvoid mz_stream_pkcrypt_delete(void **stream) {\n    mz_stream_pkcrypt *pkcrypt = NULL;\n    if (!stream)\n        return;\n    pkcrypt = (mz_stream_pkcrypt *)*stream;\n    if (pkcrypt)\n        free(pkcrypt);\n    *stream = NULL;\n}\n\nvoid *mz_stream_pkcrypt_get_interface(void) {\n    return (void *)&mz_stream_pkcrypt_vtbl;\n}\n"
  },
  {
    "path": "ios/CodePush/SSZipArchive/minizip/mz_strm_pkcrypt.h",
    "content": "/* mz_strm_pkcrypt.h -- Code for traditional PKWARE encryption\n   part of the minizip-ng project\n\n   Copyright (C) Nathan Moinvaziri\n     https://github.com/zlib-ng/minizip-ng\n\n   This program is distributed under the terms of the same license as zlib.\n   See the accompanying LICENSE file for the full text of the license.\n*/\n\n#ifndef MZ_STREAM_PKCRYPT_H\n#define MZ_STREAM_PKCRYPT_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/***************************************************************************/\n\nint32_t mz_stream_pkcrypt_open(void *stream, const char *filename, int32_t mode);\nint32_t mz_stream_pkcrypt_is_open(void *stream);\nint32_t mz_stream_pkcrypt_read(void *stream, void *buf, int32_t size);\nint32_t mz_stream_pkcrypt_write(void *stream, const void *buf, int32_t size);\nint64_t mz_stream_pkcrypt_tell(void *stream);\nint32_t mz_stream_pkcrypt_seek(void *stream, int64_t offset, int32_t origin);\nint32_t mz_stream_pkcrypt_close(void *stream);\nint32_t mz_stream_pkcrypt_error(void *stream);\n\nvoid    mz_stream_pkcrypt_set_password(void *stream, const char *password);\nvoid    mz_stream_pkcrypt_set_verify(void *stream, uint8_t verify1, uint8_t verify2);\nvoid    mz_stream_pkcrypt_get_verify(void *stream, uint8_t *verify1, uint8_t *verify2);\nint32_t mz_stream_pkcrypt_get_prop_int64(void *stream, int32_t prop, int64_t *value);\nint32_t mz_stream_pkcrypt_set_prop_int64(void *stream, int32_t prop, int64_t value);\n\nvoid*   mz_stream_pkcrypt_create(void **stream);\nvoid    mz_stream_pkcrypt_delete(void **stream);\n\nvoid*   mz_stream_pkcrypt_get_interface(void);\n\n/***************************************************************************/\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "ios/CodePush/SSZipArchive/minizip/mz_strm_split.c",
    "content": "/* mz_strm_split.c -- Stream for split files\n   part of the minizip-ng project\n\n   Copyright (C) Nathan Moinvaziri\n     https://github.com/zlib-ng/minizip-ng\n\n   This program is distributed under the terms of the same license as zlib.\n   See the accompanying LICENSE file for the full text of the license.\n*/\n\n#include \"mz.h\"\n#include \"mz_os.h\"\n#include \"mz_strm.h\"\n#include \"mz_strm_split.h\"\n\n#include <stdio.h> /* snprintf */\n\n#if defined(_MSC_VER) && (_MSC_VER < 1900)\n#  define snprintf _snprintf\n#endif\n\n/***************************************************************************/\n\n#define MZ_ZIP_MAGIC_DISKHEADER (0x08074b50)\n\n/***************************************************************************/\n\nstatic mz_stream_vtbl mz_stream_split_vtbl = {\n    mz_stream_split_open,\n    mz_stream_split_is_open,\n    mz_stream_split_read,\n    mz_stream_split_write,\n    mz_stream_split_tell,\n    mz_stream_split_seek,\n    mz_stream_split_close,\n    mz_stream_split_error,\n    mz_stream_split_create,\n    mz_stream_split_delete,\n    mz_stream_split_get_prop_int64,\n    mz_stream_split_set_prop_int64\n};\n\n/***************************************************************************/\n\ntypedef struct mz_stream_split_s {\n    mz_stream   stream;\n    int32_t     is_open;\n    int64_t     disk_size;\n    int64_t     total_in;\n    int64_t     total_in_disk;\n    int64_t     total_out;\n    int64_t     total_out_disk;\n    int32_t     mode;\n    char        *path_cd;\n    char        *path_disk;\n    uint32_t    path_disk_size;\n    int32_t     number_disk;\n    int32_t     current_disk;\n    int64_t     current_disk_size;\n    int32_t     reached_end;\n} mz_stream_split;\n\n/***************************************************************************/\n\n#if 0\n#  define mz_stream_split_print printf\n#else\n#  define mz_stream_split_print(fmt, ...)\n#endif\n\n/***************************************************************************/\n\nstatic int32_t mz_stream_split_open_disk(void *stream, int32_t number_disk) {\n    mz_stream_split *split = (mz_stream_split *)stream;\n    uint32_t magic = 0;\n    int64_t position = 0;\n    int32_t i = 0;\n    int32_t err = MZ_OK;\n    int16_t disk_part = 0;\n\n    /* Check if we are reading or writing a disk part or the cd disk */\n    if (number_disk >= 0) {\n        if ((split->mode & MZ_OPEN_MODE_WRITE) == 0)\n            disk_part = MZ_OPEN_MODE_READ;\n        else if (split->disk_size > 0)\n            disk_part = MZ_OPEN_MODE_WRITE;\n    }\n\n    /* Construct disk path */\n    if (disk_part > 0) {\n        for (i = (int32_t)strlen(split->path_disk) - 1; i >= 0; i -= 1) {\n            if (split->path_disk[i] != '.')\n                continue;\n            snprintf(&split->path_disk[i], split->path_disk_size - (uint32_t)i,\n                \".z%02\" PRId32, number_disk + 1);\n            break;\n        }\n    } else {\n        strncpy(split->path_disk, split->path_cd, split->path_disk_size - 1);\n        split->path_disk[split->path_disk_size - 1] = 0;\n    }\n\n    mz_stream_split_print(\"Split - Goto disk - %s (disk %\" PRId32 \")\\n\", split->path_disk, number_disk);\n\n    /* If disk part doesn't exist during reading then return MZ_EXIST_ERROR */\n    if (disk_part == MZ_OPEN_MODE_READ)\n        err = mz_os_file_exists(split->path_disk);\n\n    if (err == MZ_OK)\n        err = mz_stream_open(split->stream.base, split->path_disk, split->mode);\n\n    if (err == MZ_OK) {\n        split->total_in_disk = 0;\n        split->total_out_disk = 0;\n        split->current_disk = number_disk;\n\n        if (split->mode & MZ_OPEN_MODE_WRITE) {\n            if ((split->current_disk == 0) && (split->disk_size > 0)) {\n                err = mz_stream_write_uint32(split->stream.base, MZ_ZIP_MAGIC_DISKHEADER);\n\n                split->total_out_disk += 4;\n                split->total_out += split->total_out_disk;\n            }\n        } else if (split->mode & MZ_OPEN_MODE_READ) {\n            if (split->current_disk == 0) {\n                err = mz_stream_read_uint32(split->stream.base, &magic);\n                if (magic != MZ_ZIP_MAGIC_DISKHEADER)\n                    err = MZ_FORMAT_ERROR;\n            }\n        }\n    }\n\n    if (err == MZ_OK) {\n        /* Get the size of the current disk we are on */\n        position = mz_stream_tell(split->stream.base);\n        mz_stream_seek(split->stream.base, 0, MZ_SEEK_END);\n        split->current_disk_size = mz_stream_tell(split->stream.base);\n        mz_stream_seek(split->stream.base, position, MZ_SEEK_SET);\n\n        split->is_open = 1;\n    }\n\n    return err;\n}\n\nstatic int32_t mz_stream_split_close_disk(void *stream) {\n    mz_stream_split *split = (mz_stream_split *)stream;\n\n    if (mz_stream_is_open(split->stream.base) != MZ_OK)\n        return MZ_OK;\n\n    mz_stream_split_print(\"Split - Close disk\\n\");\n    return mz_stream_close(split->stream.base);\n}\n\nstatic int32_t mz_stream_split_goto_disk(void *stream, int32_t number_disk) {\n    mz_stream_split *split = (mz_stream_split *)stream;\n    int32_t err = MZ_OK;\n    int32_t err_is_open = MZ_OK;\n\n    err_is_open = mz_stream_is_open(split->stream.base);\n\n    if ((split->disk_size == 0) && (split->mode & MZ_OPEN_MODE_WRITE)) {\n        if (err_is_open != MZ_OK)\n            err = mz_stream_split_open_disk(stream, number_disk);\n    } else if ((number_disk != split->current_disk) || (err_is_open != MZ_OK)) {\n        err = mz_stream_split_close_disk(stream);\n        if (err == MZ_OK) {\n            err = mz_stream_split_open_disk(stream, number_disk);\n            if (err == MZ_OK)\n                split->number_disk = number_disk;\n        }\n    }\n\n    return err;\n}\n\nint32_t mz_stream_split_open(void *stream, const char *path, int32_t mode) {\n    mz_stream_split *split = (mz_stream_split *)stream;\n    int32_t number_disk = 0;\n\n    split->mode = mode;\n    split->path_cd = strdup(path);\n\n    if (!split->path_cd)\n        return MZ_MEM_ERROR;\n\n    mz_stream_split_print(\"Split - Open - %s (disk %\" PRId32 \")\\n\", split->path_cd, number_disk);\n\n    split->path_disk_size = (uint32_t)strlen(path) + 10;\n    split->path_disk = (char *)malloc(split->path_disk_size);\n\n    if (!split->path_disk) {\n        free(split->path_cd);\n        return MZ_MEM_ERROR;\n    }\n\n    strncpy(split->path_disk, path, split->path_disk_size - 1);\n    split->path_disk[split->path_disk_size - 1] = 0;\n\n    if ((mode & MZ_OPEN_MODE_WRITE) && ((mode & MZ_OPEN_MODE_APPEND) == 0)) {\n        number_disk = 0;\n        split->current_disk = -1;\n    } else {\n        number_disk = -1;\n        split->current_disk = 0;\n    }\n\n    return mz_stream_split_goto_disk(stream, number_disk);\n}\n\nint32_t mz_stream_split_is_open(void *stream) {\n    mz_stream_split *split = (mz_stream_split *)stream;\n    if (split->is_open != 1)\n        return MZ_OPEN_ERROR;\n    return MZ_OK;\n}\n\nint32_t mz_stream_split_read(void *stream, void *buf, int32_t size) {\n    mz_stream_split *split = (mz_stream_split *)stream;\n    int32_t bytes_left = size;\n    int32_t read = 0;\n    int32_t err = MZ_OK;\n    uint8_t *buf_ptr = (uint8_t *)buf;\n\n    err = mz_stream_split_goto_disk(stream, split->number_disk);\n    if (err != MZ_OK)\n        return err;\n\n    while (bytes_left > 0) {\n        read = mz_stream_read(split->stream.base, buf_ptr, bytes_left);\n\n        mz_stream_split_print(\"Split - Read disk - %\" PRId32 \"\\n\", read);\n\n        if (read < 0)\n            return read;\n        if (read == 0) {\n            if (split->current_disk < 0) /* No more disks to goto */\n                break;\n            err = mz_stream_split_goto_disk(stream, split->current_disk + 1);\n            if (err == MZ_EXIST_ERROR) {\n                split->current_disk = -1;\n                break;\n            }\n            if (err != MZ_OK)\n                return err;\n        }\n\n        bytes_left -= read;\n        buf_ptr += read;\n        split->total_in += read;\n        split->total_in_disk += read;\n    }\n    return size - bytes_left;\n}\n\nint32_t mz_stream_split_write(void *stream, const void *buf, int32_t size) {\n    mz_stream_split *split = (mz_stream_split *)stream;\n    int64_t position = 0;\n    int32_t written = 0;\n    int32_t bytes_left = size;\n    int32_t bytes_to_write = 0;\n    int32_t bytes_avail = 0;\n    int32_t number_disk = -1;\n    int32_t err = MZ_OK;\n    const uint8_t *buf_ptr = (const uint8_t *)buf;\n\n    position = mz_stream_tell(split->stream.base);\n\n    while (bytes_left > 0) {\n        bytes_to_write = bytes_left;\n\n        if (split->disk_size > 0) {\n            if ((split->total_out_disk == split->disk_size && split->total_out > 0) ||\n                (split->number_disk == -1 && split->number_disk != split->current_disk)) {\n                if (split->number_disk != -1)\n                    number_disk = split->current_disk + 1;\n\n                err = mz_stream_split_goto_disk(stream, number_disk);\n                if (err != MZ_OK)\n                    return err;\n\n                position = 0;\n            }\n\n            if (split->number_disk != -1) {\n                bytes_avail = (int32_t)(split->disk_size - split->total_out_disk);\n                if (bytes_to_write > bytes_avail)\n                    bytes_to_write = bytes_avail;\n            }\n        }\n\n        written = mz_stream_write(split->stream.base, buf_ptr, bytes_to_write);\n        if (written != bytes_to_write)\n            return MZ_WRITE_ERROR;\n\n        mz_stream_split_print(\"Split - Write disk - %\" PRId32 \"\\n\", written);\n\n        bytes_left -= written;\n        buf_ptr += written;\n\n        split->total_out += written;\n        split->total_out_disk += written;\n\n        position += written;\n        if (position > split->current_disk_size)\n            split->current_disk_size = position;\n    }\n\n    return size - bytes_left;\n}\n\nint64_t mz_stream_split_tell(void *stream) {\n    mz_stream_split *split = (mz_stream_split *)stream;\n    int32_t err = MZ_OK;\n    err = mz_stream_split_goto_disk(stream, split->number_disk);\n    if (err != MZ_OK)\n        return err;\n    return mz_stream_tell(split->stream.base);\n}\n\nint32_t mz_stream_split_seek(void *stream, int64_t offset, int32_t origin) {\n    mz_stream_split *split = (mz_stream_split *)stream;\n    int64_t disk_left = 0;\n    int64_t position = 0;\n    int32_t err = MZ_OK;\n\n    err = mz_stream_split_goto_disk(stream, split->number_disk);\n\n    if (err != MZ_OK)\n        return err;\n\n    mz_stream_split_print(\"Split - Seek disk - %\" PRId64 \" (origin %\" PRId32 \")\\n\", offset, origin);\n\n    if ((origin == MZ_SEEK_CUR) && (split->number_disk != -1)) {\n        position = mz_stream_tell(split->stream.base);\n        disk_left = split->current_disk_size - position;\n\n        while (offset > disk_left) {\n            err = mz_stream_split_goto_disk(stream, split->current_disk + 1);\n            if (err != MZ_OK)\n                return err;\n\n            offset -= disk_left;\n            disk_left = split->current_disk_size;\n        }\n    }\n\n    return mz_stream_seek(split->stream.base, offset, origin);\n}\n\nint32_t mz_stream_split_close(void *stream) {\n    mz_stream_split *split = (mz_stream_split *)stream;\n    int32_t err = MZ_OK;\n\n    err = mz_stream_split_close_disk(stream);\n    split->is_open = 0;\n    return err;\n}\n\nint32_t mz_stream_split_error(void *stream) {\n    mz_stream_split *split = (mz_stream_split *)stream;\n    return mz_stream_error(split->stream.base);\n}\n\nint32_t mz_stream_split_get_prop_int64(void *stream, int32_t prop, int64_t *value) {\n    mz_stream_split *split = (mz_stream_split *)stream;\n    switch (prop) {\n    case MZ_STREAM_PROP_TOTAL_OUT:\n        *value = split->total_out;\n        break;\n    case MZ_STREAM_PROP_DISK_NUMBER:\n        *value = split->number_disk;\n        break;\n    case MZ_STREAM_PROP_DISK_SIZE:\n        *value = split->disk_size;\n        break;\n    default:\n        return MZ_EXIST_ERROR;\n    }\n    return MZ_OK;\n}\n\nint32_t mz_stream_split_set_prop_int64(void *stream, int32_t prop, int64_t value) {\n    mz_stream_split *split = (mz_stream_split *)stream;\n    switch (prop) {\n    case MZ_STREAM_PROP_DISK_NUMBER:\n        split->number_disk = (int32_t)value;\n        break;\n    case MZ_STREAM_PROP_DISK_SIZE:\n        split->disk_size = value;\n        break;\n    default:\n        return MZ_EXIST_ERROR;\n    }\n    return MZ_OK;\n}\n\nvoid *mz_stream_split_create(void **stream) {\n    mz_stream_split *split = NULL;\n\n    split = (mz_stream_split *)calloc(1, sizeof(mz_stream_split));\n    if (split)\n        split->stream.vtbl = &mz_stream_split_vtbl;\n    if (stream)\n        *stream = split;\n\n    return split;\n}\n\nvoid mz_stream_split_delete(void **stream) {\n    mz_stream_split *split = NULL;\n    if (!stream)\n        return;\n    split = (mz_stream_split *)*stream;\n    if (split) {\n        if (split->path_cd)\n            free(split->path_cd);\n        if (split->path_disk)\n            free(split->path_disk);\n\n        free(split);\n    }\n    *stream = NULL;\n}\n\nvoid *mz_stream_split_get_interface(void) {\n    return (void *)&mz_stream_split_vtbl;\n}\n"
  },
  {
    "path": "ios/CodePush/SSZipArchive/minizip/mz_strm_split.h",
    "content": "/* mz_strm_split.h -- Stream for split files\n   part of the minizip-ng project\n\n   Copyright (C) Nathan Moinvaziri\n      https://github.com/zlib-ng/minizip-ng\n\n   This program is distributed under the terms of the same license as zlib.\n   See the accompanying LICENSE file for the full text of the license.\n*/\n\n#ifndef MZ_STREAM_SPLIT_H\n#define MZ_STREAM_SPLIT_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/***************************************************************************/\n\nint32_t mz_stream_split_open(void *stream, const char *filename, int32_t mode);\nint32_t mz_stream_split_is_open(void *stream);\nint32_t mz_stream_split_read(void *stream, void *buf, int32_t size);\nint32_t mz_stream_split_write(void *stream, const void *buf, int32_t size);\nint64_t mz_stream_split_tell(void *stream);\nint32_t mz_stream_split_seek(void *stream, int64_t offset, int32_t origin);\nint32_t mz_stream_split_close(void *stream);\nint32_t mz_stream_split_error(void *stream);\n\nint32_t mz_stream_split_get_prop_int64(void *stream, int32_t prop, int64_t *value);\nint32_t mz_stream_split_set_prop_int64(void *stream, int32_t prop, int64_t value);\n\nvoid*   mz_stream_split_create(void **stream);\nvoid    mz_stream_split_delete(void **stream);\n\nvoid*   mz_stream_split_get_interface(void);\n\n/***************************************************************************/\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "ios/CodePush/SSZipArchive/minizip/mz_strm_wzaes.c",
    "content": "/* mz_strm_wzaes.c -- Stream for WinZip AES encryption\n   part of the minizip-ng project\n\n   Copyright (C) Nathan Moinvaziri\n      https://github.com/zlib-ng/minizip-ng\n   Copyright (C) 1998-2010 Brian Gladman, Worcester, UK\n\n   This program is distributed under the terms of the same license as zlib.\n   See the accompanying LICENSE file for the full text of the license.\n*/\n\n#include \"mz.h\"\n#include \"mz_crypt.h\"\n#include \"mz_strm.h\"\n#include \"mz_strm_wzaes.h\"\n\n/***************************************************************************/\n\n#define MZ_AES_KEYING_ITERATIONS    (1000)\n#define MZ_AES_SALT_LENGTH(MODE)    (4 * (MODE & 3) + 4)\n#define MZ_AES_SALT_LENGTH_MAX      (16)\n#define MZ_AES_PW_LENGTH_MAX        (128)\n#define MZ_AES_PW_VERIFY_SIZE       (2)\n#define MZ_AES_AUTHCODE_SIZE        (10)\n\n/***************************************************************************/\n\nstatic mz_stream_vtbl mz_stream_wzaes_vtbl = {\n    mz_stream_wzaes_open,\n    mz_stream_wzaes_is_open,\n    mz_stream_wzaes_read,\n    mz_stream_wzaes_write,\n    mz_stream_wzaes_tell,\n    mz_stream_wzaes_seek,\n    mz_stream_wzaes_close,\n    mz_stream_wzaes_error,\n    mz_stream_wzaes_create,\n    mz_stream_wzaes_delete,\n    mz_stream_wzaes_get_prop_int64,\n    mz_stream_wzaes_set_prop_int64\n};\n\n/***************************************************************************/\n\ntypedef struct mz_stream_wzaes_s {\n    mz_stream       stream;\n    int32_t         mode;\n    int32_t         error;\n    int16_t         initialized;\n    uint8_t         buffer[UINT16_MAX];\n    int64_t         total_in;\n    int64_t         max_total_in;\n    int64_t         total_out;\n    int16_t         encryption_mode;\n    const char      *password;\n    void            *aes;\n    uint32_t        crypt_pos;\n    uint8_t         crypt_block[MZ_AES_BLOCK_SIZE];\n    void            *hmac;\n    uint8_t         nonce[MZ_AES_BLOCK_SIZE];\n} mz_stream_wzaes;\n\n/***************************************************************************/\n\nint32_t mz_stream_wzaes_open(void *stream, const char *path, int32_t mode) {\n    mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream;\n    uint16_t salt_length = 0;\n    uint16_t password_length = 0;\n    uint16_t key_length = 0;\n    uint8_t kbuf[2 * MZ_AES_KEY_LENGTH_MAX + MZ_AES_PW_VERIFY_SIZE];\n    uint8_t verify[MZ_AES_PW_VERIFY_SIZE];\n    uint8_t verify_expected[MZ_AES_PW_VERIFY_SIZE];\n    uint8_t salt_value[MZ_AES_SALT_LENGTH_MAX];\n    const char *password = path;\n\n    wzaes->total_in = 0;\n    wzaes->total_out = 0;\n    wzaes->initialized = 0;\n\n    if (mz_stream_is_open(wzaes->stream.base) != MZ_OK)\n        return MZ_OPEN_ERROR;\n\n    if (!password)\n        password = wzaes->password;\n    if (!password)\n        return MZ_PARAM_ERROR;\n    password_length = (uint16_t)strlen(password);\n    if (password_length > MZ_AES_PW_LENGTH_MAX)\n        return MZ_PARAM_ERROR;\n\n    if (wzaes->encryption_mode < 1 || wzaes->encryption_mode > 3)\n        return MZ_PARAM_ERROR;\n\n    salt_length = MZ_AES_SALT_LENGTH(wzaes->encryption_mode);\n\n    if (mode & MZ_OPEN_MODE_WRITE) {\n        mz_crypt_rand(salt_value, salt_length);\n    } else if (mode & MZ_OPEN_MODE_READ) {\n        if (mz_stream_read(wzaes->stream.base, salt_value, salt_length) != salt_length)\n            return MZ_READ_ERROR;\n    }\n\n    key_length = MZ_AES_KEY_LENGTH(wzaes->encryption_mode);\n\n    /* Derive the encryption and authentication keys and the password verifier */\n    mz_crypt_pbkdf2((uint8_t *)password, password_length, salt_value, salt_length,\n        MZ_AES_KEYING_ITERATIONS, kbuf, 2 * key_length + MZ_AES_PW_VERIFY_SIZE);\n\n    /* Initialize the encryption nonce and buffer pos */\n    wzaes->crypt_pos = MZ_AES_BLOCK_SIZE;\n    memset(wzaes->nonce, 0, sizeof(wzaes->nonce));\n\n    /* Initialize for encryption using key 1 */\n    mz_crypt_aes_reset(wzaes->aes);\n    mz_crypt_aes_set_mode(wzaes->aes, wzaes->encryption_mode);\n    mz_crypt_aes_set_encrypt_key(wzaes->aes, kbuf, key_length);\n\n    /* Initialize for authentication using key 2 */\n    mz_crypt_hmac_reset(wzaes->hmac);\n    mz_crypt_hmac_set_algorithm(wzaes->hmac, MZ_HASH_SHA1);\n    mz_crypt_hmac_init(wzaes->hmac, kbuf + key_length, key_length);\n\n    memcpy(verify, kbuf + (2 * key_length), MZ_AES_PW_VERIFY_SIZE);\n\n    if (mode & MZ_OPEN_MODE_WRITE) {\n        if (mz_stream_write(wzaes->stream.base, salt_value, salt_length) != salt_length)\n            return MZ_WRITE_ERROR;\n\n        wzaes->total_out += salt_length;\n\n        if (mz_stream_write(wzaes->stream.base, verify, MZ_AES_PW_VERIFY_SIZE) != MZ_AES_PW_VERIFY_SIZE)\n            return MZ_WRITE_ERROR;\n\n        wzaes->total_out += MZ_AES_PW_VERIFY_SIZE;\n    } else if (mode & MZ_OPEN_MODE_READ) {\n        wzaes->total_in += salt_length;\n\n        if (mz_stream_read(wzaes->stream.base, verify_expected, MZ_AES_PW_VERIFY_SIZE) != MZ_AES_PW_VERIFY_SIZE)\n            return MZ_READ_ERROR;\n\n        wzaes->total_in += MZ_AES_PW_VERIFY_SIZE;\n\n        if (memcmp(verify_expected, verify, MZ_AES_PW_VERIFY_SIZE) != 0)\n            return MZ_PASSWORD_ERROR;\n    }\n\n    wzaes->mode = mode;\n    wzaes->initialized = 1;\n\n    return MZ_OK;\n}\n\nint32_t mz_stream_wzaes_is_open(void *stream) {\n    mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream;\n    if (!wzaes->initialized)\n        return MZ_OPEN_ERROR;\n    return MZ_OK;\n}\n\nstatic int32_t mz_stream_wzaes_ctr_encrypt(void *stream, uint8_t *buf, int32_t size) {\n    mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream;\n    uint32_t pos = wzaes->crypt_pos;\n    uint32_t i = 0;\n    int32_t err = MZ_OK;\n\n    while (i < (uint32_t)size) {\n        if (pos == MZ_AES_BLOCK_SIZE) {\n            uint32_t j = 0;\n\n            /* Increment encryption nonce */\n            while (j < 8 && !++wzaes->nonce[j])\n                j += 1;\n\n            /* Encrypt the nonce to form next xor buffer */\n            memcpy(wzaes->crypt_block, wzaes->nonce, MZ_AES_BLOCK_SIZE);\n            mz_crypt_aes_encrypt(wzaes->aes, wzaes->crypt_block, sizeof(wzaes->crypt_block));\n            pos = 0;\n        }\n\n        buf[i++] ^= wzaes->crypt_block[pos++];\n    }\n\n    wzaes->crypt_pos = pos;\n    return err;\n}\n\nint32_t mz_stream_wzaes_read(void *stream, void *buf, int32_t size) {\n    mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream;\n    int64_t max_total_in = 0;\n    int32_t bytes_to_read = size;\n    int32_t read = 0;\n\n    max_total_in = wzaes->max_total_in - MZ_AES_FOOTER_SIZE;\n    if ((int64_t)bytes_to_read > (max_total_in - wzaes->total_in))\n        bytes_to_read = (int32_t)(max_total_in - wzaes->total_in);\n\n    read = mz_stream_read(wzaes->stream.base, buf, bytes_to_read);\n\n    if (read > 0) {\n        mz_crypt_hmac_update(wzaes->hmac, (uint8_t *)buf, read);\n        mz_stream_wzaes_ctr_encrypt(stream, (uint8_t *)buf, read);\n\n        wzaes->total_in += read;\n    }\n\n    return read;\n}\n\nint32_t mz_stream_wzaes_write(void *stream, const void *buf, int32_t size) {\n    mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream;\n    const uint8_t *buf_ptr = (const uint8_t *)buf;\n    int32_t bytes_to_write = sizeof(wzaes->buffer);\n    int32_t total_written = 0;\n    int32_t written = 0;\n\n    if (size < 0)\n        return MZ_PARAM_ERROR;\n\n    do {\n        if (bytes_to_write > (size - total_written))\n            bytes_to_write = (size - total_written);\n\n        memcpy(wzaes->buffer, buf_ptr, bytes_to_write);\n        buf_ptr += bytes_to_write;\n\n        mz_stream_wzaes_ctr_encrypt(stream, (uint8_t *)wzaes->buffer, bytes_to_write);\n        mz_crypt_hmac_update(wzaes->hmac, wzaes->buffer, bytes_to_write);\n\n        written = mz_stream_write(wzaes->stream.base, wzaes->buffer, bytes_to_write);\n        if (written < 0)\n            return written;\n\n        total_written += written;\n    } while (total_written < size && written > 0);\n\n    wzaes->total_out += total_written;\n    return total_written;\n}\n\nint64_t mz_stream_wzaes_tell(void *stream) {\n    mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream;\n    return mz_stream_tell(wzaes->stream.base);\n}\n\nint32_t mz_stream_wzaes_seek(void *stream, int64_t offset, int32_t origin) {\n    mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream;\n    return mz_stream_seek(wzaes->stream.base, offset, origin);\n}\n\nint32_t mz_stream_wzaes_close(void *stream) {\n    mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream;\n    uint8_t expected_hash[MZ_AES_AUTHCODE_SIZE];\n    uint8_t computed_hash[MZ_HASH_SHA1_SIZE];\n\n    mz_crypt_hmac_end(wzaes->hmac, computed_hash, sizeof(computed_hash));\n\n    if (wzaes->mode & MZ_OPEN_MODE_WRITE) {\n        if (mz_stream_write(wzaes->stream.base, computed_hash, MZ_AES_AUTHCODE_SIZE) != MZ_AES_AUTHCODE_SIZE)\n            return MZ_WRITE_ERROR;\n\n        wzaes->total_out += MZ_AES_AUTHCODE_SIZE;\n    } else if (wzaes->mode & MZ_OPEN_MODE_READ) {\n        if (mz_stream_read(wzaes->stream.base, expected_hash, MZ_AES_AUTHCODE_SIZE) != MZ_AES_AUTHCODE_SIZE)\n            return MZ_READ_ERROR;\n\n        wzaes->total_in += MZ_AES_AUTHCODE_SIZE;\n\n        /* If entire entry was not read this will fail */\n        if (memcmp(computed_hash, expected_hash, MZ_AES_AUTHCODE_SIZE) != 0)\n            return MZ_CRC_ERROR;\n    }\n\n    wzaes->initialized = 0;\n    return MZ_OK;\n}\n\nint32_t mz_stream_wzaes_error(void *stream) {\n    mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream;\n    return wzaes->error;\n}\n\nvoid mz_stream_wzaes_set_password(void *stream, const char *password) {\n    mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream;\n    wzaes->password = password;\n}\n\nvoid mz_stream_wzaes_set_encryption_mode(void *stream, int16_t encryption_mode) {\n    mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream;\n    wzaes->encryption_mode = encryption_mode;\n}\n\nint32_t mz_stream_wzaes_get_prop_int64(void *stream, int32_t prop, int64_t *value) {\n    mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream;\n    switch (prop) {\n    case MZ_STREAM_PROP_TOTAL_IN:\n        *value = wzaes->total_in;\n        break;\n    case MZ_STREAM_PROP_TOTAL_OUT:\n        *value = wzaes->total_out;\n        break;\n    case MZ_STREAM_PROP_TOTAL_IN_MAX:\n        *value = wzaes->max_total_in;\n        break;\n    case MZ_STREAM_PROP_HEADER_SIZE:\n        *value = MZ_AES_SALT_LENGTH((int64_t)wzaes->encryption_mode) + MZ_AES_PW_VERIFY_SIZE;\n        break;\n    case MZ_STREAM_PROP_FOOTER_SIZE:\n        *value = MZ_AES_AUTHCODE_SIZE;\n        break;\n    default:\n        return MZ_EXIST_ERROR;\n    }\n    return MZ_OK;\n}\n\nint32_t mz_stream_wzaes_set_prop_int64(void *stream, int32_t prop, int64_t value) {\n    mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream;\n    switch (prop) {\n    case MZ_STREAM_PROP_TOTAL_IN_MAX:\n        wzaes->max_total_in = value;\n        break;\n    default:\n        return MZ_EXIST_ERROR;\n    }\n    return MZ_OK;\n}\n\nvoid *mz_stream_wzaes_create(void **stream) {\n    mz_stream_wzaes *wzaes = NULL;\n\n    wzaes = (mz_stream_wzaes *)calloc(1, sizeof(mz_stream_wzaes));\n    if (wzaes) {\n        wzaes->stream.vtbl = &mz_stream_wzaes_vtbl;\n        wzaes->encryption_mode = MZ_AES_ENCRYPTION_MODE_256;\n\n        mz_crypt_hmac_create(&wzaes->hmac);\n        mz_crypt_aes_create(&wzaes->aes);\n    }\n    if (stream)\n        *stream = wzaes;\n\n    return wzaes;\n}\n\nvoid mz_stream_wzaes_delete(void **stream) {\n    mz_stream_wzaes *wzaes = NULL;\n    if (!stream)\n        return;\n    wzaes = (mz_stream_wzaes *)*stream;\n    if (wzaes) {\n        mz_crypt_aes_delete(&wzaes->aes);\n        mz_crypt_hmac_delete(&wzaes->hmac);\n        free(wzaes);\n    }\n    *stream = NULL;\n}\n\nvoid *mz_stream_wzaes_get_interface(void) {\n    return (void *)&mz_stream_wzaes_vtbl;\n}\n"
  },
  {
    "path": "ios/CodePush/SSZipArchive/minizip/mz_strm_wzaes.h",
    "content": "/* mz_strm_wzaes.h -- Stream for WinZIP AES encryption\n   part of the minizip-ng project\n\n   Copyright (C) Nathan Moinvaziri\n      https://github.com/zlib-ng/minizip-ng\n\n   This program is distributed under the terms of the same license as zlib.\n   See the accompanying LICENSE file for the full text of the license.\n*/\n\n#ifndef MZ_STREAM_WZAES_SHA1_H\n#define MZ_STREAM_WZAES_SHA1_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/***************************************************************************/\n\nint32_t mz_stream_wzaes_open(void *stream, const char *filename, int32_t mode);\nint32_t mz_stream_wzaes_is_open(void *stream);\nint32_t mz_stream_wzaes_read(void *stream, void *buf, int32_t size);\nint32_t mz_stream_wzaes_write(void *stream, const void *buf, int32_t size);\nint64_t mz_stream_wzaes_tell(void *stream);\nint32_t mz_stream_wzaes_seek(void *stream, int64_t offset, int32_t origin);\nint32_t mz_stream_wzaes_close(void *stream);\nint32_t mz_stream_wzaes_error(void *stream);\n\nvoid    mz_stream_wzaes_set_password(void *stream, const char *password);\nvoid    mz_stream_wzaes_set_encryption_mode(void *stream, int16_t encryption_mode);\n\nint32_t mz_stream_wzaes_get_prop_int64(void *stream, int32_t prop, int64_t *value);\nint32_t mz_stream_wzaes_set_prop_int64(void *stream, int32_t prop, int64_t value);\n\nvoid*   mz_stream_wzaes_create(void **stream);\nvoid    mz_stream_wzaes_delete(void **stream);\n\nvoid*   mz_stream_wzaes_get_interface(void);\n\n/***************************************************************************/\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "ios/CodePush/SSZipArchive/minizip/mz_strm_zlib.c",
    "content": "/* mz_strm_zlib.c -- Stream for zlib inflate/deflate\n   part of the minizip-ng project\n\n   Copyright (C) Nathan Moinvaziri\n      https://github.com/zlib-ng/minizip-ng\n\n   This program is distributed under the terms of the same license as zlib.\n   See the accompanying LICENSE file for the full text of the license.\n*/\n\n#include \"mz.h\"\n#include \"mz_strm.h\"\n#include \"mz_strm_zlib.h\"\n\n#if !defined(ZLIB_COMPAT)\n#  include \"zlib-ng.h\"\n#else\n#  include \"zlib.h\"\n#endif\n\n/***************************************************************************/\n\n#if !defined(ZLIB_COMPAT)\n#  define ZLIB_PREFIX(x) zng_ ## x\n   typedef zng_stream zlib_stream;\n#else\n#  define ZLIB_PREFIX(x) x\n   typedef z_stream zlib_stream;\n#endif\n\n#if !defined(DEF_MEM_LEVEL)\n#  if MAX_MEM_LEVEL >= 8\n#    define DEF_MEM_LEVEL 8\n#  else\n#    define DEF_MEM_LEVEL  MAX_MEM_LEVEL\n#  endif\n#endif\n\n/***************************************************************************/\n\nstatic mz_stream_vtbl mz_stream_zlib_vtbl = {\n    mz_stream_zlib_open,\n    mz_stream_zlib_is_open,\n    mz_stream_zlib_read,\n    mz_stream_zlib_write,\n    mz_stream_zlib_tell,\n    mz_stream_zlib_seek,\n    mz_stream_zlib_close,\n    mz_stream_zlib_error,\n    mz_stream_zlib_create,\n    mz_stream_zlib_delete,\n    mz_stream_zlib_get_prop_int64,\n    mz_stream_zlib_set_prop_int64\n};\n\n/***************************************************************************/\n\ntypedef struct mz_stream_zlib_s {\n    mz_stream   stream;\n    zlib_stream zstream;\n    uint8_t     buffer[INT16_MAX];\n    int32_t     buffer_len;\n    int64_t     total_in;\n    int64_t     total_out;\n    int64_t     max_total_in;\n    int8_t      initialized;\n    int16_t     level;\n    int32_t     window_bits;\n    int32_t     mode;\n    int32_t     error;\n} mz_stream_zlib;\n\n/***************************************************************************/\n\nint32_t mz_stream_zlib_open(void *stream, const char *path, int32_t mode) {\n    mz_stream_zlib *zlib = (mz_stream_zlib *)stream;\n\n    MZ_UNUSED(path);\n\n    zlib->zstream.data_type = Z_BINARY;\n    zlib->zstream.zalloc = Z_NULL;\n    zlib->zstream.zfree = Z_NULL;\n    zlib->zstream.opaque = Z_NULL;\n    zlib->zstream.total_in = 0;\n    zlib->zstream.total_out = 0;\n\n    zlib->total_in = 0;\n    zlib->total_out = 0;\n\n    if (mode & MZ_OPEN_MODE_WRITE) {\n#ifdef MZ_ZIP_NO_COMPRESSION\n        return MZ_SUPPORT_ERROR;\n#else\n        zlib->zstream.next_out = zlib->buffer;\n        zlib->zstream.avail_out = sizeof(zlib->buffer);\n\n        zlib->error = ZLIB_PREFIX(deflateInit2)(&zlib->zstream, (int8_t)zlib->level, Z_DEFLATED,\n            zlib->window_bits, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);\n#endif\n    } else if (mode & MZ_OPEN_MODE_READ) {\n#ifdef MZ_ZIP_NO_DECOMPRESSION\n        return MZ_SUPPORT_ERROR;\n#else\n        zlib->zstream.next_in = zlib->buffer;\n        zlib->zstream.avail_in = 0;\n\n        zlib->error = ZLIB_PREFIX(inflateInit2)(&zlib->zstream, zlib->window_bits);\n#endif\n    }\n\n    if (zlib->error != Z_OK)\n        return MZ_OPEN_ERROR;\n\n    zlib->initialized = 1;\n    zlib->mode = mode;\n    return MZ_OK;\n}\n\nint32_t mz_stream_zlib_is_open(void *stream) {\n    mz_stream_zlib *zlib = (mz_stream_zlib *)stream;\n    if (zlib->initialized != 1)\n        return MZ_OPEN_ERROR;\n    return MZ_OK;\n}\n\nint32_t mz_stream_zlib_read(void *stream, void *buf, int32_t size) {\n#ifdef MZ_ZIP_NO_DECOMPRESSION\n    MZ_UNUSED(stream);\n    MZ_UNUSED(buf);\n    MZ_UNUSED(size);\n    return MZ_SUPPORT_ERROR;\n#else\n    mz_stream_zlib *zlib = (mz_stream_zlib *)stream;\n    uint64_t total_in_before = 0;\n    uint64_t total_in_after = 0;\n    uint64_t total_out_before = 0;\n    uint64_t total_out_after = 0;\n    uint32_t total_in = 0;\n    uint32_t total_out = 0;\n    uint32_t in_bytes = 0;\n    uint32_t out_bytes = 0;\n    int32_t bytes_to_read = sizeof(zlib->buffer);\n    int32_t read = 0;\n    int32_t err = Z_OK;\n\n    zlib->zstream.next_out = (Bytef *)buf;\n    zlib->zstream.avail_out = (uInt)size;\n\n    do {\n        if (zlib->zstream.avail_in == 0) {\n            if (zlib->max_total_in > 0) {\n                if ((int64_t)bytes_to_read > (zlib->max_total_in - zlib->total_in))\n                    bytes_to_read = (int32_t)(zlib->max_total_in - zlib->total_in);\n            }\n\n            read = mz_stream_read(zlib->stream.base, zlib->buffer, bytes_to_read);\n\n            if (read < 0)\n                return read;\n\n            zlib->zstream.next_in = zlib->buffer;\n            zlib->zstream.avail_in = read;\n        }\n\n        total_in_before = zlib->zstream.avail_in;\n        total_out_before = zlib->zstream.total_out;\n\n        err = ZLIB_PREFIX(inflate)(&zlib->zstream, Z_SYNC_FLUSH);\n        if ((err >= Z_OK) && (zlib->zstream.msg)) {\n            zlib->error = Z_DATA_ERROR;\n            break;\n        }\n\n        total_in_after = zlib->zstream.avail_in;\n        total_out_after = zlib->zstream.total_out;\n\n        in_bytes = (uint32_t)(total_in_before - total_in_after);\n        out_bytes = (uint32_t)(total_out_after - total_out_before);\n\n        total_in += in_bytes;\n        total_out += out_bytes;\n\n        zlib->total_in += in_bytes;\n        zlib->total_out += out_bytes;\n\n        if (err == Z_STREAM_END)\n            break;\n        if (err != Z_OK) {\n            zlib->error = err;\n            break;\n        }\n    } while (zlib->zstream.avail_out > 0);\n\n    if (zlib->error != 0) {\n        /* Zlib errors are compatible with MZ */\n        return zlib->error;\n    }\n\n    return total_out;\n#endif\n}\n\n#ifndef MZ_ZIP_NO_COMPRESSION\nstatic int32_t mz_stream_zlib_flush(void *stream) {\n    mz_stream_zlib *zlib = (mz_stream_zlib *)stream;\n    if (mz_stream_write(zlib->stream.base, zlib->buffer, zlib->buffer_len) != zlib->buffer_len)\n        return MZ_WRITE_ERROR;\n    return MZ_OK;\n}\n\nstatic int32_t mz_stream_zlib_deflate(void *stream, int flush) {\n    mz_stream_zlib *zlib = (mz_stream_zlib *)stream;\n    uint64_t total_out_before = 0;\n    uint64_t total_out_after = 0;\n    int32_t out_bytes = 0;\n    int32_t err = Z_OK;\n\n    do {\n        if (zlib->zstream.avail_out == 0) {\n            err = mz_stream_zlib_flush(zlib);\n            if (err != MZ_OK)\n                return err;\n\n            zlib->zstream.avail_out = sizeof(zlib->buffer);\n            zlib->zstream.next_out = zlib->buffer;\n\n            zlib->buffer_len = 0;\n        }\n\n        total_out_before = zlib->zstream.total_out;\n        err = ZLIB_PREFIX(deflate)(&zlib->zstream, flush);\n        total_out_after = zlib->zstream.total_out;\n\n        out_bytes = (uint32_t)(total_out_after - total_out_before);\n\n        zlib->buffer_len += out_bytes;\n        zlib->total_out += out_bytes;\n\n        if (err == Z_STREAM_END)\n            break;\n        if (err != Z_OK) {\n            zlib->error = err;\n            return MZ_DATA_ERROR;\n        }\n    } while ((zlib->zstream.avail_in > 0) || (flush == Z_FINISH && err == Z_OK));\n\n    return MZ_OK;\n}\n#endif\n\nint32_t mz_stream_zlib_write(void *stream, const void *buf, int32_t size) {\n#ifdef MZ_ZIP_NO_COMPRESSION\n    MZ_UNUSED(stream);\n    MZ_UNUSED(buf);\n    MZ_UNUSED(size);\n    return MZ_SUPPORT_ERROR;\n#else\n    mz_stream_zlib *zlib = (mz_stream_zlib *)stream;\n    int32_t err = MZ_OK;\n\n    zlib->zstream.next_in = (Bytef *)(intptr_t)buf;\n    zlib->zstream.avail_in = (uInt)size;\n\n    err = mz_stream_zlib_deflate(stream, Z_NO_FLUSH);\n    if (err != MZ_OK) {\n        return err;\n    }\n\n    zlib->total_in += size;\n    return size;\n#endif\n}\n\nint64_t mz_stream_zlib_tell(void *stream) {\n    MZ_UNUSED(stream);\n\n    return MZ_TELL_ERROR;\n}\n\nint32_t mz_stream_zlib_seek(void *stream, int64_t offset, int32_t origin) {\n    MZ_UNUSED(stream);\n    MZ_UNUSED(offset);\n    MZ_UNUSED(origin);\n\n    return MZ_SEEK_ERROR;\n}\n\nint32_t mz_stream_zlib_close(void *stream) {\n    mz_stream_zlib *zlib = (mz_stream_zlib *)stream;\n\n    if (zlib->mode & MZ_OPEN_MODE_WRITE) {\n#ifdef MZ_ZIP_NO_COMPRESSION\n        return MZ_SUPPORT_ERROR;\n#else\n        mz_stream_zlib_deflate(stream, Z_FINISH);\n        mz_stream_zlib_flush(stream);\n\n        ZLIB_PREFIX(deflateEnd)(&zlib->zstream);\n#endif\n    } else if (zlib->mode & MZ_OPEN_MODE_READ) {\n#ifdef MZ_ZIP_NO_DECOMPRESSION\n        return MZ_SUPPORT_ERROR;\n#else\n        ZLIB_PREFIX(inflateEnd)(&zlib->zstream);\n#endif\n    }\n\n    zlib->initialized = 0;\n\n    if (zlib->error != Z_OK)\n        return MZ_CLOSE_ERROR;\n    return MZ_OK;\n}\n\nint32_t mz_stream_zlib_error(void *stream) {\n    mz_stream_zlib *zlib = (mz_stream_zlib *)stream;\n    return zlib->error;\n}\n\nint32_t mz_stream_zlib_get_prop_int64(void *stream, int32_t prop, int64_t *value) {\n    mz_stream_zlib *zlib = (mz_stream_zlib *)stream;\n    switch (prop) {\n    case MZ_STREAM_PROP_TOTAL_IN:\n        *value = zlib->total_in;\n        break;\n    case MZ_STREAM_PROP_TOTAL_IN_MAX:\n        *value = zlib->max_total_in;\n        break;\n    case MZ_STREAM_PROP_TOTAL_OUT:\n        *value = zlib->total_out;\n        break;\n    case MZ_STREAM_PROP_HEADER_SIZE:\n        *value = 0;\n        break;\n    case MZ_STREAM_PROP_COMPRESS_WINDOW:\n        *value = zlib->window_bits;\n        break;\n    default:\n        return MZ_EXIST_ERROR;\n    }\n    return MZ_OK;\n}\n\nint32_t mz_stream_zlib_set_prop_int64(void *stream, int32_t prop, int64_t value) {\n    mz_stream_zlib *zlib = (mz_stream_zlib *)stream;\n    switch (prop) {\n    case MZ_STREAM_PROP_COMPRESS_LEVEL:\n        zlib->level = (int16_t)value;\n        break;\n    case MZ_STREAM_PROP_TOTAL_IN_MAX:\n        zlib->max_total_in = value;\n        break;\n    case MZ_STREAM_PROP_COMPRESS_WINDOW:\n        zlib->window_bits = (int32_t)value;\n        break;\n    default:\n        return MZ_EXIST_ERROR;\n    }\n    return MZ_OK;\n}\n\nvoid *mz_stream_zlib_create(void **stream) {\n    mz_stream_zlib *zlib = NULL;\n\n    zlib = (mz_stream_zlib *)calloc(1, sizeof(mz_stream_zlib));\n    if (zlib) {\n        zlib->stream.vtbl = &mz_stream_zlib_vtbl;\n        zlib->level = Z_DEFAULT_COMPRESSION;\n        zlib->window_bits = -MAX_WBITS;\n    }\n    if (stream)\n        *stream = zlib;\n\n    return zlib;\n}\n\nvoid mz_stream_zlib_delete(void **stream) {\n    mz_stream_zlib *zlib = NULL;\n    if (!stream)\n        return;\n    zlib = (mz_stream_zlib *)*stream;\n    if (zlib)\n        free(zlib);\n    *stream = NULL;\n}\n\nvoid *mz_stream_zlib_get_interface(void) {\n    return (void *)&mz_stream_zlib_vtbl;\n}\n"
  },
  {
    "path": "ios/CodePush/SSZipArchive/minizip/mz_strm_zlib.h",
    "content": "/* mz_strm_zlib.h -- Stream for zlib inflate/deflate\n   part of the minizip-ng project\n\n   Copyright (C) Nathan Moinvaziri\n      https://github.com/zlib-ng/minizip-ng\n\n   This program is distributed under the terms of the same license as zlib.\n   See the accompanying LICENSE file for the full text of the license.\n*/\n\n#ifndef MZ_STREAM_ZLIB_H\n#define MZ_STREAM_ZLIB_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/***************************************************************************/\n\nint32_t mz_stream_zlib_open(void *stream, const char *filename, int32_t mode);\nint32_t mz_stream_zlib_is_open(void *stream);\nint32_t mz_stream_zlib_read(void *stream, void *buf, int32_t size);\nint32_t mz_stream_zlib_write(void *stream, const void *buf, int32_t size);\nint64_t mz_stream_zlib_tell(void *stream);\nint32_t mz_stream_zlib_seek(void *stream, int64_t offset, int32_t origin);\nint32_t mz_stream_zlib_close(void *stream);\nint32_t mz_stream_zlib_error(void *stream);\n\nint32_t mz_stream_zlib_get_prop_int64(void *stream, int32_t prop, int64_t *value);\nint32_t mz_stream_zlib_set_prop_int64(void *stream, int32_t prop, int64_t value);\n\nvoid*   mz_stream_zlib_create(void **stream);\nvoid    mz_stream_zlib_delete(void **stream);\n\nvoid*   mz_stream_zlib_get_interface(void);\n\n/***************************************************************************/\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "ios/CodePush/SSZipArchive/minizip/mz_zip.c",
    "content": "/* zip.c -- Zip manipulation\n   part of the minizip-ng project\n\n   Copyright (C) Nathan Moinvaziri\n     https://github.com/zlib-ng/minizip-ng\n   Copyright (C) 2009-2010 Mathias Svensson\n     Modifications for Zip64 support\n     http://result42.com\n   Copyright (C) 2007-2008 Even Rouault\n     Modifications of Unzip for Zip64\n   Copyright (C) 1998-2010 Gilles Vollant\n     https://www.winimage.com/zLibDll/minizip.html\n\n   This program is distributed under the terms of the same license as zlib.\n   See the accompanying LICENSE file for the full text of the license.\n*/\n\n#include \"mz.h\"\n#include \"mz_crypt.h\"\n#include \"mz_strm.h\"\n#ifdef HAVE_BZIP2\n#  include \"mz_strm_bzip.h\"\n#endif\n#ifdef HAVE_LIBCOMP\n#  include \"mz_strm_libcomp.h\"\n#endif\n#ifdef HAVE_LZMA\n#  include \"mz_strm_lzma.h\"\n#endif\n#include \"mz_strm_mem.h\"\n#ifdef HAVE_PKCRYPT\n#  include \"mz_strm_pkcrypt.h\"\n#endif\n#ifdef HAVE_WZAES\n#  include \"mz_strm_wzaes.h\"\n#endif\n#ifdef HAVE_ZLIB\n#  include \"mz_strm_zlib.h\"\n#endif\n#ifdef HAVE_ZSTD\n#  include \"mz_strm_zstd.h\"\n#endif\n\n#include \"mz_zip.h\"\n\n#include <ctype.h> /* tolower */\n#include <stdio.h> /* snprintf */\n\n#if defined(_MSC_VER) || defined(__MINGW32__)\n#  define localtime_r(t1, t2) (localtime_s(t2, t1) == 0 ? t1 : NULL)\n#endif\n#if defined(_MSC_VER) && (_MSC_VER < 1900)\n#  define snprintf _snprintf\n#endif\n\n/***************************************************************************/\n\n#define MZ_ZIP_MAGIC_LOCALHEADER        (0x04034b50)\n#define MZ_ZIP_MAGIC_LOCALHEADERU8      { 0x50, 0x4b, 0x03, 0x04 }\n#define MZ_ZIP_MAGIC_CENTRALHEADER      (0x02014b50)\n#define MZ_ZIP_MAGIC_CENTRALHEADERU8    { 0x50, 0x4b, 0x01, 0x02 }\n#define MZ_ZIP_MAGIC_ENDHEADER          (0x06054b50)\n#define MZ_ZIP_MAGIC_ENDHEADERU8        { 0x50, 0x4b, 0x05, 0x06 }\n#define MZ_ZIP_MAGIC_ENDHEADER64        (0x06064b50)\n#define MZ_ZIP_MAGIC_ENDLOCHEADER64     (0x07064b50)\n#define MZ_ZIP_MAGIC_DATADESCRIPTOR     (0x08074b50)\n#define MZ_ZIP_MAGIC_DATADESCRIPTORU8   { 0x50, 0x4b, 0x07, 0x08 }\n\n#define MZ_ZIP_SIZE_LD_ITEM             (30)\n#define MZ_ZIP_SIZE_CD_ITEM             (46)\n#define MZ_ZIP_SIZE_CD_LOCATOR64        (20)\n#define MZ_ZIP_SIZE_MAX_DATA_DESCRIPTOR (24)\n\n#define MZ_ZIP_OFFSET_CRC_SIZES         (14)\n#define MZ_ZIP_UNCOMPR_SIZE64_CUSHION   (2 * 1024 * 1024)\n\n#ifndef MZ_ZIP_EOCD_MAX_BACK\n#define MZ_ZIP_EOCD_MAX_BACK            (1 << 20)\n#endif\n\n/***************************************************************************/\n\ntypedef struct mz_zip_s {\n    mz_zip_file file_info;\n    mz_zip_file local_file_info;\n\n    void *stream;                   /* main stream */\n    void *cd_stream;                /* pointer to the stream with the cd */\n    void *cd_mem_stream;            /* memory stream for central directory */\n    void *compress_stream;          /* compression stream */\n    void *crypt_stream;             /* encryption stream */\n    void *file_info_stream;         /* memory stream for storing file info */\n    void *local_file_info_stream;   /* memory stream for storing local file info */\n\n    int32_t  open_mode;\n    uint8_t  recover;\n    uint8_t  data_descriptor;\n\n    uint32_t disk_number_with_cd;   /* number of the disk with the central dir */\n    int64_t  disk_offset_shift;     /* correction for zips that have wrong offset start of cd */\n\n    int64_t  cd_start_pos;          /* pos of the first file in the central dir stream */\n    int64_t  cd_current_pos;        /* pos of the current file in the central dir */\n    int64_t  cd_offset;             /* offset of start of central directory */\n    int64_t  cd_size;               /* size of the central directory */\n    uint32_t cd_signature;          /* signature of central directory */\n\n    uint8_t  entry_scanned;         /* entry header information read ok */\n    uint8_t  entry_opened;          /* entry is open for read/write */\n    uint8_t  entry_raw;             /* entry opened with raw mode */\n    uint32_t entry_crc32;           /* entry crc32  */\n\n    uint64_t number_entry;\n\n    uint16_t version_madeby;\n    char     *comment;\n} mz_zip;\n\n/***************************************************************************/\n\n#if 0\n#  define mz_zip_print printf\n#else\n#  define mz_zip_print(fmt, ...)\n#endif\n\n/***************************************************************************/\n\n/* Locate the end of central directory */\nstatic int32_t mz_zip_search_eocd(void *stream, int64_t *central_pos) {\n    int64_t file_size = 0;\n    int64_t max_back = MZ_ZIP_EOCD_MAX_BACK;\n    uint8_t find[4] = MZ_ZIP_MAGIC_ENDHEADERU8;\n    int32_t err = MZ_OK;\n\n    err = mz_stream_seek(stream, 0, MZ_SEEK_END);\n    if (err != MZ_OK)\n        return err;\n\n    file_size = mz_stream_tell(stream);\n\n    if (max_back <= 0 || max_back > file_size)\n        max_back = file_size;\n\n    return mz_stream_find_reverse(stream, (const void *)find, sizeof(find), max_back, central_pos);\n}\n\n/* Locate the end of central directory 64 of a zip file */\nstatic int32_t mz_zip_search_zip64_eocd(void *stream, const int64_t end_central_offset, int64_t *central_pos) {\n    int64_t offset = 0;\n    uint32_t value32 = 0;\n    int32_t err = MZ_OK;\n\n    *central_pos = 0;\n\n    /* Zip64 end of central directory locator */\n    err = mz_stream_seek(stream, end_central_offset - MZ_ZIP_SIZE_CD_LOCATOR64, MZ_SEEK_SET);\n    /* Read locator signature */\n    if (err == MZ_OK) {\n        err = mz_stream_read_uint32(stream, &value32);\n        if (value32 != MZ_ZIP_MAGIC_ENDLOCHEADER64)\n            err = MZ_FORMAT_ERROR;\n    }\n    /* Number of the disk with the start of the zip64 end of  central directory */\n    if (err == MZ_OK)\n        err = mz_stream_read_uint32(stream, &value32);\n    /* Relative offset of the zip64 end of central directory record8 */\n    if (err == MZ_OK)\n        err = mz_stream_read_uint64(stream, (uint64_t *)&offset);\n    /* Total number of disks */\n    if (err == MZ_OK)\n        err = mz_stream_read_uint32(stream, &value32);\n    /* Goto end of central directory record */\n    if (err == MZ_OK)\n        err = mz_stream_seek(stream, (int64_t)offset, MZ_SEEK_SET);\n    /* The signature */\n    if (err == MZ_OK) {\n        err = mz_stream_read_uint32(stream, &value32);\n        if (value32 != MZ_ZIP_MAGIC_ENDHEADER64)\n            err = MZ_FORMAT_ERROR;\n    }\n\n    if (err == MZ_OK)\n        *central_pos = offset;\n\n    return err;\n}\n\n#ifdef HAVE_PKCRYPT\n/* Get PKWARE traditional encryption verifier */\nstatic uint16_t mz_zip_get_pk_verify(uint32_t dos_date, uint64_t crc, uint16_t flag)\n{\n    /* Info-ZIP modification to ZipCrypto format: if bit 3 of the general\n     * purpose bit flag is set, it uses high byte of 16-bit File Time. */\n    if (flag & MZ_ZIP_FLAG_DATA_DESCRIPTOR)\n        return ((dos_date >> 16) & 0xff) << 8 | ((dos_date >> 8) & 0xff);\n    return ((crc >> 16) & 0xff) << 8 | ((crc >> 24) & 0xff);\n}\n#endif\n\n/* Get info about the current file in the zip file */\nstatic int32_t mz_zip_entry_read_header(void *stream, uint8_t local, mz_zip_file *file_info, void *file_extra_stream) {\n    uint64_t ntfs_time = 0;\n    uint32_t reserved = 0;\n    uint32_t magic = 0;\n    uint32_t dos_date = 0;\n    uint32_t field_pos = 0;\n    uint16_t field_type = 0;\n    uint16_t field_length = 0;\n    uint32_t field_length_read = 0;\n    uint16_t ntfs_attrib_id = 0;\n    uint16_t ntfs_attrib_size = 0;\n    uint16_t linkname_size;\n    uint16_t value16 = 0;\n    uint32_t value32 = 0;\n    int64_t extrafield_pos = 0;\n    int64_t comment_pos = 0;\n    int64_t linkname_pos = 0;\n    int64_t saved_pos = 0;\n    int32_t err = MZ_OK;\n    char *linkname = NULL;\n\n    memset(file_info, 0, sizeof(mz_zip_file));\n\n    /* Check the magic */\n    err = mz_stream_read_uint32(stream, &magic);\n    if (err == MZ_END_OF_STREAM)\n        err = MZ_END_OF_LIST;\n    else if (magic == MZ_ZIP_MAGIC_ENDHEADER || magic == MZ_ZIP_MAGIC_ENDHEADER64)\n        err = MZ_END_OF_LIST;\n    else if ((local) && (magic != MZ_ZIP_MAGIC_LOCALHEADER))\n        err = MZ_FORMAT_ERROR;\n    else if ((!local) && (magic != MZ_ZIP_MAGIC_CENTRALHEADER))\n        err = MZ_FORMAT_ERROR;\n\n    /* Read header fields */\n    if (err == MZ_OK) {\n        if (!local)\n            err = mz_stream_read_uint16(stream, &file_info->version_madeby);\n        if (err == MZ_OK)\n            err = mz_stream_read_uint16(stream, &file_info->version_needed);\n        if (err == MZ_OK)\n            err = mz_stream_read_uint16(stream, &file_info->flag);\n        if (err == MZ_OK)\n            err = mz_stream_read_uint16(stream, &file_info->compression_method);\n        if (err == MZ_OK) {\n            err = mz_stream_read_uint32(stream, &dos_date);\n            file_info->modified_date = mz_zip_dosdate_to_time_t(dos_date);\n        }\n        if (err == MZ_OK)\n            err = mz_stream_read_uint32(stream, &file_info->crc);\n#ifdef HAVE_PKCRYPT\n        if (err == MZ_OK && file_info->flag & MZ_ZIP_FLAG_ENCRYPTED) {\n            /* Use dos_date from header instead of derived from time in zip extensions */\n            file_info->pk_verify = mz_zip_get_pk_verify(dos_date, file_info->crc, file_info->flag);\n        }\n#endif\n        if (err == MZ_OK) {\n            err = mz_stream_read_uint32(stream, &value32);\n            file_info->compressed_size = value32;\n        }\n        if (err == MZ_OK) {\n            err = mz_stream_read_uint32(stream, &value32);\n            file_info->uncompressed_size = value32;\n        }\n        if (err == MZ_OK)\n            err = mz_stream_read_uint16(stream, &file_info->filename_size);\n        if (err == MZ_OK)\n            err = mz_stream_read_uint16(stream, &file_info->extrafield_size);\n        if (!local) {\n            if (err == MZ_OK)\n                err = mz_stream_read_uint16(stream, &file_info->comment_size);\n            if (err == MZ_OK) {\n                err = mz_stream_read_uint16(stream, &value16);\n                file_info->disk_number = value16;\n            }\n            if (err == MZ_OK)\n                err = mz_stream_read_uint16(stream, &file_info->internal_fa);\n            if (err == MZ_OK)\n                err = mz_stream_read_uint32(stream, &file_info->external_fa);\n            if (err == MZ_OK) {\n                err = mz_stream_read_uint32(stream, &value32);\n                file_info->disk_offset = value32;\n            }\n        }\n    }\n\n    if (err == MZ_OK)\n        err = mz_stream_seek(file_extra_stream, 0, MZ_SEEK_SET);\n\n    /* Copy variable length data to memory stream for later retrieval */\n    if ((err == MZ_OK) && (file_info->filename_size > 0))\n        err = mz_stream_copy(file_extra_stream, stream, file_info->filename_size);\n    mz_stream_write_uint8(file_extra_stream, 0);\n    extrafield_pos = mz_stream_tell(file_extra_stream);\n\n    if ((err == MZ_OK) && (file_info->extrafield_size > 0))\n        err = mz_stream_copy(file_extra_stream, stream, file_info->extrafield_size);\n    mz_stream_write_uint8(file_extra_stream, 0);\n\n    comment_pos = mz_stream_tell(file_extra_stream);\n    if ((err == MZ_OK) && (file_info->comment_size > 0))\n        err = mz_stream_copy(file_extra_stream, stream, file_info->comment_size);\n    mz_stream_write_uint8(file_extra_stream, 0);\n\n    linkname_pos = mz_stream_tell(file_extra_stream);\n    /* Overwrite if we encounter UNIX1 extra block */\n    mz_stream_write_uint8(file_extra_stream, 0);\n\n    if ((err == MZ_OK) && (file_info->extrafield_size > 0)) {\n        /* Seek to and parse the extra field */\n        err = mz_stream_seek(file_extra_stream, extrafield_pos, MZ_SEEK_SET);\n\n        while ((err == MZ_OK) && (field_pos + 4 <= file_info->extrafield_size)) {\n            err = mz_zip_extrafield_read(file_extra_stream, &field_type, &field_length);\n            if (err != MZ_OK)\n                break;\n            field_pos += 4;\n\n            /* Don't allow field length to exceed size of remaining extrafield */\n            if (field_length > (file_info->extrafield_size - field_pos))\n                field_length = (uint16_t)(file_info->extrafield_size - field_pos);\n\n            /* Read ZIP64 extra field */\n            if ((field_type == MZ_ZIP_EXTENSION_ZIP64) && (field_length >= 8)) {\n                if ((err == MZ_OK) && (file_info->uncompressed_size == UINT32_MAX)) {\n                    err = mz_stream_read_int64(file_extra_stream, &file_info->uncompressed_size);\n                    if (file_info->uncompressed_size < 0)\n                        err = MZ_FORMAT_ERROR;\n                }\n                if ((err == MZ_OK) && (file_info->compressed_size == UINT32_MAX)) {\n                    err = mz_stream_read_int64(file_extra_stream, &file_info->compressed_size);\n                    if (file_info->compressed_size < 0)\n                        err = MZ_FORMAT_ERROR;\n                }\n                if ((err == MZ_OK) && (file_info->disk_offset == UINT32_MAX)) {\n                    err = mz_stream_read_int64(file_extra_stream, &file_info->disk_offset);\n                    if (file_info->disk_offset < 0)\n                        err = MZ_FORMAT_ERROR;\n                }\n                if ((err == MZ_OK) && (file_info->disk_number == UINT16_MAX))\n                    err = mz_stream_read_uint32(file_extra_stream, &file_info->disk_number);\n            }\n            /* Read NTFS extra field */\n            else if ((field_type == MZ_ZIP_EXTENSION_NTFS) && (field_length > 4)) {\n                if (err == MZ_OK)\n                    err = mz_stream_read_uint32(file_extra_stream, &reserved);\n                field_length_read = 4;\n\n                while ((err == MZ_OK) && (field_length_read + 4 <= field_length)) {\n                    err = mz_stream_read_uint16(file_extra_stream, &ntfs_attrib_id);\n                    if (err == MZ_OK)\n                        err = mz_stream_read_uint16(file_extra_stream, &ntfs_attrib_size);\n                    field_length_read += 4;\n\n                    if ((err == MZ_OK) && (ntfs_attrib_id == 0x01) && (ntfs_attrib_size == 24)) {\n                        err = mz_stream_read_uint64(file_extra_stream, &ntfs_time);\n                        mz_zip_ntfs_to_unix_time(ntfs_time, &file_info->modified_date);\n\n                        if (err == MZ_OK) {\n                            err = mz_stream_read_uint64(file_extra_stream, &ntfs_time);\n                            mz_zip_ntfs_to_unix_time(ntfs_time, &file_info->accessed_date);\n                        }\n                        if (err == MZ_OK) {\n                            err = mz_stream_read_uint64(file_extra_stream, &ntfs_time);\n                            mz_zip_ntfs_to_unix_time(ntfs_time, &file_info->creation_date);\n                        }\n                    } else if ((err == MZ_OK) && (field_length_read + ntfs_attrib_size <= field_length)) {\n                        err = mz_stream_seek(file_extra_stream, ntfs_attrib_size, MZ_SEEK_CUR);\n                    }\n\n                    field_length_read += ntfs_attrib_size;\n                }\n            }\n            /* Read UNIX1 extra field */\n            else if ((field_type == MZ_ZIP_EXTENSION_UNIX1) && (field_length >= 12)) {\n                if (err == MZ_OK) {\n                    err = mz_stream_read_uint32(file_extra_stream, &value32);\n                    if (err == MZ_OK && file_info->accessed_date == 0)\n                        file_info->accessed_date = value32;\n                }\n                if (err == MZ_OK) {\n                    err = mz_stream_read_uint32(file_extra_stream, &value32);\n                    if (err == MZ_OK && file_info->modified_date == 0)\n                        file_info->modified_date = value32;\n                }\n                if (err == MZ_OK)\n                    err = mz_stream_read_uint16(file_extra_stream, &value16); /* User id */\n                if (err == MZ_OK)\n                    err = mz_stream_read_uint16(file_extra_stream, &value16); /* Group id */\n\n                /* Copy linkname to end of file extra stream so we can return null\n                   terminated string */\n                linkname_size = field_length - 12;\n                if ((err == MZ_OK) && (linkname_size > 0)) {\n                    linkname = (char *)malloc(linkname_size);\n                    if (linkname) {\n                        if (mz_stream_read(file_extra_stream, linkname, linkname_size) != linkname_size)\n                            err = MZ_READ_ERROR;\n                        if (err == MZ_OK) {\n                            saved_pos = mz_stream_tell(file_extra_stream);\n\n                            mz_stream_seek(file_extra_stream, linkname_pos, MZ_SEEK_SET);\n                            mz_stream_write(file_extra_stream, linkname, linkname_size);\n                            mz_stream_write_uint8(file_extra_stream, 0);\n\n                            mz_stream_seek(file_extra_stream, saved_pos, MZ_SEEK_SET);\n                        }\n                        free(linkname);\n                    }\n                }\n            }\n#ifdef HAVE_WZAES\n            /* Read AES extra field */\n            else if ((field_type == MZ_ZIP_EXTENSION_AES) && (field_length == 7)) {\n                uint8_t value8 = 0;\n                /* Verify version info */\n                err = mz_stream_read_uint16(file_extra_stream, &value16);\n                /* Support AE-1 and AE-2 */\n                if (value16 != 1 && value16 != 2)\n                    err = MZ_FORMAT_ERROR;\n                file_info->aes_version = value16;\n                if (err == MZ_OK)\n                    err = mz_stream_read_uint8(file_extra_stream, &value8);\n                if ((char)value8 != 'A')\n                    err = MZ_FORMAT_ERROR;\n                if (err == MZ_OK)\n                    err = mz_stream_read_uint8(file_extra_stream, &value8);\n                if ((char)value8 != 'E')\n                    err = MZ_FORMAT_ERROR;\n                /* Get AES encryption strength and actual compression method */\n                if (err == MZ_OK) {\n                    err = mz_stream_read_uint8(file_extra_stream, &value8);\n                    file_info->aes_encryption_mode = value8;\n                }\n                if (err == MZ_OK) {\n                    err = mz_stream_read_uint16(file_extra_stream, &value16);\n                    file_info->compression_method = value16;\n                }\n            }\n#endif\n            else if (field_length > 0) {\n                err = mz_stream_seek(file_extra_stream, field_length, MZ_SEEK_CUR);\n            }\n\n            field_pos += field_length;\n        }\n    }\n\n    /* Get pointers to variable length data */\n    mz_stream_mem_get_buffer(file_extra_stream, (const void **)&file_info->filename);\n    mz_stream_mem_get_buffer_at(file_extra_stream, extrafield_pos, (const void **)&file_info->extrafield);\n    mz_stream_mem_get_buffer_at(file_extra_stream, comment_pos, (const void **)&file_info->comment);\n    mz_stream_mem_get_buffer_at(file_extra_stream, linkname_pos, (const void **)&file_info->linkname);\n\n    /* Set to empty string just in-case */\n    if (!file_info->filename)\n        file_info->filename = \"\";\n    if (!file_info->extrafield)\n        file_info->extrafield_size = 0;\n    if (!file_info->comment)\n        file_info->comment = \"\";\n    if (!file_info->linkname)\n        file_info->linkname = \"\";\n\n    if (err == MZ_OK) {\n        mz_zip_print(\"Zip - Entry - Read header - %s (local %\" PRId8 \")\\n\",\n            file_info->filename, local);\n        mz_zip_print(\"Zip - Entry - Read header compress (ucs %\" PRId64 \" cs %\" PRId64 \" crc 0x%08\" PRIx32 \")\\n\",\n            file_info->uncompressed_size, file_info->compressed_size, file_info->crc);\n        if (!local) {\n            mz_zip_print(\"Zip - Entry - Read header disk (disk %\" PRIu32 \" offset %\" PRId64 \")\\n\",\n                file_info->disk_number, file_info->disk_offset);\n        }\n        mz_zip_print(\"Zip - Entry - Read header variable (fnl %\" PRId32 \" efs %\" PRId32 \" cms %\" PRId32 \")\\n\",\n            file_info->filename_size, file_info->extrafield_size, file_info->comment_size);\n    }\n\n    return err;\n}\n\nstatic int32_t mz_zip_entry_read_descriptor(void *stream, uint8_t zip64, uint32_t *crc32, int64_t *compressed_size, int64_t *uncompressed_size) {\n    uint32_t value32 = 0;\n    int64_t value64 = 0;\n    int32_t err = MZ_OK;\n\n    err = mz_stream_read_uint32(stream, &value32);\n    if (value32 != MZ_ZIP_MAGIC_DATADESCRIPTOR)\n        err = MZ_FORMAT_ERROR;\n    if (err == MZ_OK)\n        err = mz_stream_read_uint32(stream, &value32);\n    if (err == MZ_OK && crc32)\n        *crc32 = value32;\n    if (err == MZ_OK) {\n        /* If zip 64 extension is enabled then read as 8 byte */\n        if (!zip64) {\n            err = mz_stream_read_uint32(stream, &value32);\n            value64 = value32;\n        } else {\n            err = mz_stream_read_int64(stream, &value64);\n            if (value64 < 0)\n                err = MZ_FORMAT_ERROR;\n        }\n        if (err == MZ_OK && compressed_size)\n            *compressed_size = value64;\n    }\n    if (err == MZ_OK) {\n        if (!zip64) {\n            err = mz_stream_read_uint32(stream, &value32);\n            value64 = value32;\n        } else {\n            err = mz_stream_read_int64(stream, &value64);\n            if (value64 < 0)\n                err = MZ_FORMAT_ERROR;\n        }\n        if (err == MZ_OK && uncompressed_size)\n            *uncompressed_size = value64;\n    }\n\n    return err;\n}\n\nstatic int32_t mz_zip_entry_write_crc_sizes(void *stream, uint8_t zip64, uint8_t mask, mz_zip_file *file_info) {\n    int32_t err = MZ_OK;\n\n    if (mask)\n        err = mz_stream_write_uint32(stream, 0);\n    else\n        err = mz_stream_write_uint32(stream, file_info->crc); /* crc */\n\n    /* For backwards-compatibility with older zip applications we set all sizes to UINT32_MAX\n     * when zip64 is needed, instead of only setting sizes larger than UINT32_MAX. */\n\n    if (err == MZ_OK) {\n        if (zip64) /* compr size */\n            err = mz_stream_write_uint32(stream, UINT32_MAX);\n        else\n            err = mz_stream_write_uint32(stream, (uint32_t)file_info->compressed_size);\n    }\n    if (err == MZ_OK) {\n        if (mask) /* uncompr size */\n            err = mz_stream_write_uint32(stream, 0);\n        else if (zip64)\n            err = mz_stream_write_uint32(stream, UINT32_MAX);\n        else\n            err = mz_stream_write_uint32(stream, (uint32_t)file_info->uncompressed_size);\n    }\n    return err;\n}\n\nstatic int32_t mz_zip_entry_needs_zip64(mz_zip_file *file_info, uint8_t local, uint8_t *zip64) {\n    uint32_t max_uncompressed_size = UINT32_MAX;\n    uint8_t needs_zip64 = 0;\n\n    if (!zip64)\n        return MZ_PARAM_ERROR;\n\n    *zip64 = 0;\n\n    if (local) {\n        /* At local header we might not know yet whether compressed size will overflow unsigned\n           32-bit integer which might happen for high entropy data so we give it some cushion */\n\n        max_uncompressed_size -= MZ_ZIP_UNCOMPR_SIZE64_CUSHION;\n    }\n\n    needs_zip64 = (file_info->uncompressed_size >= max_uncompressed_size) ||\n                  (file_info->compressed_size >= UINT32_MAX);\n\n    if (!local) {\n        /* Disk offset and number only used in central directory header */\n        needs_zip64 |= (file_info->disk_offset >= UINT32_MAX) ||\n                       (file_info->disk_number >= UINT16_MAX);\n    }\n\n    if (file_info->zip64 == MZ_ZIP64_AUTO) {\n        /* If uncompressed size is unknown, assume zip64 for 64-bit data descriptors */\n        if (local && file_info->uncompressed_size == 0) {\n            /* Don't use zip64 for local header directory entries */\n            if (mz_zip_attrib_is_dir(file_info->external_fa, file_info->version_madeby) != MZ_OK) {\n                *zip64 = 1;\n            }\n        }\n        *zip64 |= needs_zip64;\n    } else if (file_info->zip64 == MZ_ZIP64_FORCE) {\n        *zip64 = 1;\n    } else if (file_info->zip64 == MZ_ZIP64_DISABLE) {\n        /* Zip64 extension is required to zip file */\n        if (needs_zip64)\n            return MZ_PARAM_ERROR;\n    }\n\n    return MZ_OK;\n}\n\nstatic int32_t mz_zip_entry_write_header(void *stream, uint8_t local, mz_zip_file *file_info) {\n    uint64_t ntfs_time = 0;\n    uint32_t reserved = 0;\n    uint32_t dos_date = 0;\n    uint16_t extrafield_size = 0;\n    uint16_t field_type = 0;\n    uint16_t field_length = 0;\n    uint16_t field_length_zip64 = 0;\n    uint16_t field_length_ntfs = 0;\n    uint16_t field_length_aes = 0;\n    uint16_t field_length_unix1 = 0;\n    uint16_t filename_size = 0;\n    uint16_t filename_length = 0;\n    uint16_t linkname_size = 0;\n    uint16_t version_needed = 0;\n    int32_t comment_size = 0;\n    int32_t err = MZ_OK;\n    int32_t err_mem = MZ_OK;\n    uint8_t zip64 = 0;\n    uint8_t skip_aes = 0;\n    uint8_t mask = 0;\n    uint8_t write_end_slash = 0;\n    const char *filename = NULL;\n    char masked_name[64];\n    void *file_extra_stream = NULL;\n\n    if (!file_info)\n        return MZ_PARAM_ERROR;\n\n    if ((local) && (file_info->flag & MZ_ZIP_FLAG_MASK_LOCAL_INFO))\n        mask = 1;\n\n    /* Determine if zip64 extra field is necessary */\n    err = mz_zip_entry_needs_zip64(file_info, local, &zip64);\n    if (err != MZ_OK)\n        return err;\n\n    /* Start calculating extra field sizes */\n    if (zip64) {\n        /* Both compressed and uncompressed sizes must be included (at least in local header) */\n        field_length_zip64 = 8 + 8;\n        if ((!local) && (file_info->disk_offset >= UINT32_MAX))\n            field_length_zip64 += 8;\n\n        extrafield_size += 4;\n        extrafield_size += field_length_zip64;\n    }\n\n    /* Calculate extra field size and check for duplicates */\n    if (file_info->extrafield_size > 0) {\n        mz_stream_mem_create(&file_extra_stream);\n        mz_stream_mem_set_buffer(file_extra_stream, (void *)file_info->extrafield,\n            file_info->extrafield_size);\n\n        do {\n            err_mem = mz_stream_read_uint16(file_extra_stream, &field_type);\n            if (err_mem == MZ_OK)\n                err_mem = mz_stream_read_uint16(file_extra_stream, &field_length);\n            if (err_mem != MZ_OK)\n                break;\n\n            /* Prefer incoming aes extensions over ours */\n            if (field_type == MZ_ZIP_EXTENSION_AES)\n                skip_aes = 1;\n\n            /* Prefer our zip64, ntfs, unix1 extension over incoming */\n            if (field_type != MZ_ZIP_EXTENSION_ZIP64 && field_type != MZ_ZIP_EXTENSION_NTFS &&\n                field_type != MZ_ZIP_EXTENSION_UNIX1)\n                extrafield_size += 4 + field_length;\n\n            if (err_mem == MZ_OK)\n                err_mem = mz_stream_seek(file_extra_stream, field_length, MZ_SEEK_CUR);\n        } while (err_mem == MZ_OK);\n    }\n\n#ifdef HAVE_WZAES\n    if (!skip_aes) {\n        if ((file_info->flag & MZ_ZIP_FLAG_ENCRYPTED) && (file_info->aes_version)) {\n            field_length_aes = 1 + 1 + 1 + 2 + 2;\n            extrafield_size += 4 + field_length_aes;\n        }\n    }\n#else\n    MZ_UNUSED(field_length_aes);\n    MZ_UNUSED(skip_aes);\n#endif\n    /* NTFS timestamps */\n    if ((file_info->modified_date != 0) &&\n        (file_info->accessed_date != 0) &&\n        (file_info->creation_date != 0) && (!mask)) {\n        field_length_ntfs = 8 + 8 + 8 + 4 + 2 + 2;\n        extrafield_size += 4 + field_length_ntfs;\n    }\n\n    /* Unix1 symbolic links */\n    if (file_info->linkname && *file_info->linkname != 0) {\n        linkname_size = (uint16_t)strlen(file_info->linkname);\n        field_length_unix1 = 12 + linkname_size;\n        extrafield_size += 4 + field_length_unix1;\n    }\n\n    if (local)\n        err = mz_stream_write_uint32(stream, MZ_ZIP_MAGIC_LOCALHEADER);\n    else {\n        err = mz_stream_write_uint32(stream, MZ_ZIP_MAGIC_CENTRALHEADER);\n        if (err == MZ_OK)\n            err = mz_stream_write_uint16(stream, file_info->version_madeby);\n    }\n\n    /* Calculate version needed to extract */\n    if (err == MZ_OK) {\n        version_needed = file_info->version_needed;\n        if (version_needed == 0) {\n            version_needed = 20;\n            if (zip64)\n                version_needed = 45;\n#ifdef HAVE_WZAES\n            if ((file_info->flag & MZ_ZIP_FLAG_ENCRYPTED) && (file_info->aes_version))\n                version_needed = 51;\n#endif\n#if defined(HAVE_LZMA) || defined(HAVE_LIBCOMP)\n            if ((file_info->compression_method == MZ_COMPRESS_METHOD_LZMA) ||\n                (file_info->compression_method == MZ_COMPRESS_METHOD_XZ))\n                version_needed = 63;\n#endif\n        }\n        err = mz_stream_write_uint16(stream, version_needed);\n    }\n    if (err == MZ_OK)\n        err = mz_stream_write_uint16(stream, file_info->flag);\n    if (err == MZ_OK) {\n#ifdef HAVE_WZAES\n        if ((file_info->flag & MZ_ZIP_FLAG_ENCRYPTED) && (file_info->aes_version))\n            err = mz_stream_write_uint16(stream, MZ_COMPRESS_METHOD_AES);\n        else\n#endif\n            err = mz_stream_write_uint16(stream, file_info->compression_method);\n    }\n    if (err == MZ_OK) {\n        if (file_info->modified_date != 0 && !mask)\n            dos_date = mz_zip_time_t_to_dos_date(file_info->modified_date);\n        err = mz_stream_write_uint32(stream, dos_date);\n    }\n\n    if (err == MZ_OK)\n        err = mz_zip_entry_write_crc_sizes(stream, zip64, mask, file_info);\n\n    if (mask) {\n        snprintf(masked_name, sizeof(masked_name), \"%\" PRIx32 \"_%\" PRIx64,\n            file_info->disk_number, file_info->disk_offset);\n        filename = masked_name;\n    } else {\n        filename = file_info->filename;\n    }\n\n    filename_length = (uint16_t)strlen(filename);\n    filename_size += filename_length;\n\n    if ((mz_zip_attrib_is_dir(file_info->external_fa, file_info->version_madeby) == MZ_OK) &&\n        ((filename[filename_length - 1] != '/') && (filename[filename_length - 1] != '\\\\'))) {\n        filename_size += 1;\n        write_end_slash = 1;\n    }\n\n    if (err == MZ_OK)\n        err = mz_stream_write_uint16(stream, filename_size);\n    if (err == MZ_OK)\n        err = mz_stream_write_uint16(stream, extrafield_size);\n\n    if (!local) {\n        if (file_info->comment) {\n            comment_size = (int32_t)strlen(file_info->comment);\n            if (comment_size > UINT16_MAX)\n                comment_size = UINT16_MAX;\n        }\n        if (err == MZ_OK)\n            err = mz_stream_write_uint16(stream, (uint16_t)comment_size);\n        if (err == MZ_OK)\n            err = mz_stream_write_uint16(stream, (uint16_t)file_info->disk_number);\n        if (err == MZ_OK)\n            err = mz_stream_write_uint16(stream, file_info->internal_fa);\n        if (err == MZ_OK)\n            err = mz_stream_write_uint32(stream, file_info->external_fa);\n        if (err == MZ_OK) {\n            if (file_info->disk_offset >= UINT32_MAX)\n                err = mz_stream_write_uint32(stream, UINT32_MAX);\n            else\n                err = mz_stream_write_uint32(stream, (uint32_t)file_info->disk_offset);\n        }\n    }\n\n    if (err == MZ_OK) {\n        const char *backslash = NULL;\n        const char *next = filename;\n        int32_t left = filename_length;\n\n        /* Ensure all slashes are written as forward slashes according to 4.4.17.1 */\n        while ((err == MZ_OK) && (backslash = strrchr(next, '\\\\'))) {\n            int32_t part_length = (int32_t)(backslash - next);\n\n            if (mz_stream_write(stream, next, part_length) != part_length ||\n                mz_stream_write(stream, \"/\", 1) != 1)\n                err = MZ_WRITE_ERROR;\n\n            left -= part_length + 1;\n            next = backslash + 1;\n        }\n\n        if (err == MZ_OK && left > 0) {\n            if (mz_stream_write(stream, next, left) != left)\n                err = MZ_WRITE_ERROR;\n        }\n\n        /* Ensure that directories have a slash appended to them for compatibility */\n        if (err == MZ_OK && write_end_slash)\n            err = mz_stream_write_uint8(stream, '/');\n    }\n\n    /* Write ZIP64 extra field first so we can update sizes later if data descriptor not used */\n    if ((err == MZ_OK) && (zip64)) {\n        err = mz_zip_extrafield_write(stream, MZ_ZIP_EXTENSION_ZIP64, field_length_zip64);\n        if (err == MZ_OK) {\n            if (mask)\n                err = mz_stream_write_int64(stream, 0);\n            else\n                err = mz_stream_write_int64(stream, file_info->uncompressed_size);\n        }\n        if (err == MZ_OK)\n            err = mz_stream_write_int64(stream, file_info->compressed_size);\n        if ((err == MZ_OK) && (!local) && (file_info->disk_offset >= UINT32_MAX))\n            err = mz_stream_write_int64(stream, file_info->disk_offset);\n        if ((err == MZ_OK) && (!local) && (file_info->disk_number >= UINT16_MAX))\n            err = mz_stream_write_uint32(stream, file_info->disk_number);\n    }\n    /* Write NTFS extra field */\n    if ((err == MZ_OK) && (field_length_ntfs > 0)) {\n        err = mz_zip_extrafield_write(stream, MZ_ZIP_EXTENSION_NTFS, field_length_ntfs);\n        if (err == MZ_OK)\n            err = mz_stream_write_uint32(stream, reserved);\n        if (err == MZ_OK)\n            err = mz_stream_write_uint16(stream, 0x01);\n        if (err == MZ_OK)\n            err = mz_stream_write_uint16(stream, field_length_ntfs - 8);\n        if (err == MZ_OK) {\n            mz_zip_unix_to_ntfs_time(file_info->modified_date, &ntfs_time);\n            err = mz_stream_write_uint64(stream, ntfs_time);\n        }\n        if (err == MZ_OK) {\n            mz_zip_unix_to_ntfs_time(file_info->accessed_date, &ntfs_time);\n            err = mz_stream_write_uint64(stream, ntfs_time);\n        }\n        if (err == MZ_OK) {\n            mz_zip_unix_to_ntfs_time(file_info->creation_date, &ntfs_time);\n            err = mz_stream_write_uint64(stream, ntfs_time);\n        }\n    }\n    /* Write UNIX extra block extra field */\n    if ((err == MZ_OK) && (field_length_unix1 > 0)) {\n        err = mz_zip_extrafield_write(stream, MZ_ZIP_EXTENSION_UNIX1, field_length_unix1);\n        if (err == MZ_OK)\n            err = mz_stream_write_uint32(stream, (uint32_t)file_info->accessed_date);\n        if (err == MZ_OK)\n            err = mz_stream_write_uint32(stream, (uint32_t)file_info->modified_date);\n        if (err == MZ_OK) /* User id */\n            err = mz_stream_write_uint16(stream, 0);\n        if (err == MZ_OK) /* Group id */\n            err = mz_stream_write_uint16(stream, 0);\n        if (err == MZ_OK && linkname_size > 0) {\n            if (mz_stream_write(stream, file_info->linkname, linkname_size) != linkname_size)\n                err = MZ_WRITE_ERROR;\n        }\n    }\n#ifdef HAVE_WZAES\n    /* Write AES extra field */\n    if ((err == MZ_OK) && (!skip_aes) && (file_info->flag & MZ_ZIP_FLAG_ENCRYPTED) && (file_info->aes_version)) {\n        err = mz_zip_extrafield_write(stream, MZ_ZIP_EXTENSION_AES, field_length_aes);\n        if (err == MZ_OK)\n            err = mz_stream_write_uint16(stream, file_info->aes_version);\n        if (err == MZ_OK)\n            err = mz_stream_write_uint8(stream, 'A');\n        if (err == MZ_OK)\n            err = mz_stream_write_uint8(stream, 'E');\n        if (err == MZ_OK)\n            err = mz_stream_write_uint8(stream, file_info->aes_encryption_mode);\n        if (err == MZ_OK)\n            err = mz_stream_write_uint16(stream, file_info->compression_method);\n    }\n#endif\n\n    if (file_info->extrafield_size > 0) {\n        err_mem = mz_stream_mem_seek(file_extra_stream, 0, MZ_SEEK_SET);\n        while (err == MZ_OK && err_mem == MZ_OK) {\n            err_mem = mz_stream_read_uint16(file_extra_stream, &field_type);\n            if (err_mem == MZ_OK)\n                err_mem = mz_stream_read_uint16(file_extra_stream, &field_length);\n            if (err_mem != MZ_OK)\n                break;\n\n            /* Prefer our zip 64, ntfs, unix1 extensions over incoming */\n            if (field_type == MZ_ZIP_EXTENSION_ZIP64 || field_type == MZ_ZIP_EXTENSION_NTFS ||\n                field_type == MZ_ZIP_EXTENSION_UNIX1) {\n                err_mem = mz_stream_seek(file_extra_stream, field_length, MZ_SEEK_CUR);\n                continue;\n            }\n\n            err = mz_stream_write_uint16(stream, field_type);\n            if (err == MZ_OK)\n                err = mz_stream_write_uint16(stream, field_length);\n            if (err == MZ_OK)\n                err = mz_stream_copy(stream, file_extra_stream, field_length);\n        }\n\n        mz_stream_mem_delete(&file_extra_stream);\n    }\n\n    if (err == MZ_OK && !local && file_info->comment) {\n        if (mz_stream_write(stream, file_info->comment, file_info->comment_size) != file_info->comment_size)\n            err = MZ_WRITE_ERROR;\n    }\n\n    return err;\n}\n\nstatic int32_t mz_zip_entry_write_descriptor(void *stream, uint8_t zip64, uint32_t crc32, int64_t compressed_size, int64_t uncompressed_size) {\n    int32_t err = MZ_OK;\n\n    err = mz_stream_write_uint32(stream, MZ_ZIP_MAGIC_DATADESCRIPTOR);\n    if (err == MZ_OK)\n        err = mz_stream_write_uint32(stream, crc32);\n\n    /* Store data descriptor as 8 bytes if zip 64 extension enabled */\n    if (err == MZ_OK) {\n        /* Zip 64 extension is enabled when uncompressed size is > UINT32_MAX */\n        if (!zip64)\n            err = mz_stream_write_uint32(stream, (uint32_t)compressed_size);\n        else\n            err = mz_stream_write_int64(stream, compressed_size);\n    }\n    if (err == MZ_OK) {\n        if (!zip64)\n            err = mz_stream_write_uint32(stream, (uint32_t)uncompressed_size);\n        else\n            err = mz_stream_write_int64(stream, uncompressed_size);\n    }\n\n    return err;\n}\n\nstatic int32_t mz_zip_read_cd(void *handle) {\n    mz_zip *zip = (mz_zip *)handle;\n    uint64_t number_entry_cd64 = 0;\n    uint64_t number_entry_cd = 0;\n    int64_t eocd_pos = 0;\n    int64_t eocd_pos64 = 0;\n    int64_t value64i = 0;\n    uint16_t value16 = 0;\n    uint32_t value32 = 0;\n    uint64_t value64 = 0;\n    uint16_t comment_size = 0;\n    int32_t comment_read = 0;\n    int32_t err = MZ_OK;\n\n    if (!zip)\n        return MZ_PARAM_ERROR;\n\n    /* Read and cache central directory records */\n    err = mz_zip_search_eocd(zip->stream, &eocd_pos);\n    if (err == MZ_OK) {\n        /* The signature, already checked */\n        err = mz_stream_read_uint32(zip->stream, &value32);\n        /* Number of this disk */\n        if (err == MZ_OK)\n            err = mz_stream_read_uint16(zip->stream, &value16);\n        /* Number of the disk with the start of the central directory */\n        if (err == MZ_OK)\n            err = mz_stream_read_uint16(zip->stream, &value16);\n        zip->disk_number_with_cd = value16;\n        /* Total number of entries in the central dir on this disk */\n        if (err == MZ_OK)\n            err = mz_stream_read_uint16(zip->stream, &value16);\n        zip->number_entry = value16;\n        /* Total number of entries in the central dir */\n        if (err == MZ_OK)\n            err = mz_stream_read_uint16(zip->stream, &value16);\n        number_entry_cd = value16;\n        if (number_entry_cd != zip->number_entry)\n            err = MZ_FORMAT_ERROR;\n        /* Size of the central directory */\n        if (err == MZ_OK)\n            err = mz_stream_read_uint32(zip->stream, &value32);\n        if (err == MZ_OK)\n            zip->cd_size = value32;\n        /* Offset of start of central directory with respect to the starting disk number */\n        if (err == MZ_OK)\n            err = mz_stream_read_uint32(zip->stream, &value32);\n        if (err == MZ_OK)\n            zip->cd_offset = value32;\n        /* Zip file global comment length */\n        if (err == MZ_OK)\n            err = mz_stream_read_uint16(zip->stream, &comment_size);\n        if ((err == MZ_OK) && (comment_size > 0)) {\n            zip->comment = (char *)malloc(comment_size + 1);\n            if (zip->comment) {\n                comment_read = mz_stream_read(zip->stream, zip->comment, comment_size);\n                /* Don't fail if incorrect comment length read, not critical */\n                if (comment_read < 0)\n                    comment_read = 0;\n                zip->comment[comment_read] = 0;\n            }\n        }\n\n        if ((err == MZ_OK) && ((number_entry_cd == UINT16_MAX) || (zip->cd_offset == UINT32_MAX))) {\n            /* Format should be Zip64, as the central directory or file size is too large */\n            if (mz_zip_search_zip64_eocd(zip->stream, eocd_pos, &eocd_pos64) == MZ_OK) {\n                eocd_pos = eocd_pos64;\n\n                err = mz_stream_seek(zip->stream, eocd_pos, MZ_SEEK_SET);\n                /* The signature, already checked */\n                if (err == MZ_OK)\n                    err = mz_stream_read_uint32(zip->stream, &value32);\n                /* Size of zip64 end of central directory record */\n                if (err == MZ_OK)\n                    err = mz_stream_read_uint64(zip->stream, &value64);\n                /* Version made by */\n                if (err == MZ_OK)\n                    err = mz_stream_read_uint16(zip->stream, &zip->version_madeby);\n                /* Version needed to extract */\n                if (err == MZ_OK)\n                    err = mz_stream_read_uint16(zip->stream, &value16);\n                /* Number of this disk */\n                if (err == MZ_OK)\n                    err = mz_stream_read_uint32(zip->stream, &value32);\n                /* Number of the disk with the start of the central directory */\n                if (err == MZ_OK)\n                    err = mz_stream_read_uint32(zip->stream, &zip->disk_number_with_cd);\n                /* Total number of entries in the central directory on this disk */\n                if (err == MZ_OK)\n                    err = mz_stream_read_uint64(zip->stream, &zip->number_entry);\n                /* Total number of entries in the central directory */\n                if (err == MZ_OK)\n                    err = mz_stream_read_uint64(zip->stream, &number_entry_cd64);\n                if (zip->number_entry != number_entry_cd64)\n                    err = MZ_FORMAT_ERROR;\n                /* Size of the central directory */\n                if (err == MZ_OK) {\n                    err = mz_stream_read_int64(zip->stream, &zip->cd_size);\n                    if (zip->cd_size < 0)\n                        err = MZ_FORMAT_ERROR;\n                }\n                /* Offset of start of central directory with respect to the starting disk number */\n                if (err == MZ_OK) {\n                    err = mz_stream_read_int64(zip->stream, &zip->cd_offset);\n                    if (zip->cd_offset < 0)\n                        err = MZ_FORMAT_ERROR;\n                }\n            } else if ((zip->number_entry == UINT16_MAX) || (number_entry_cd != zip->number_entry) ||\n                       (zip->cd_size == UINT16_MAX) || (zip->cd_offset == UINT32_MAX)) {\n                err = MZ_FORMAT_ERROR;\n            }\n        }\n    }\n\n    if (err == MZ_OK) {\n        mz_zip_print(\"Zip - Read cd (disk %\" PRId32 \" entries %\" PRId64 \" offset %\" PRId64 \" size %\" PRId64 \")\\n\",\n            zip->disk_number_with_cd, zip->number_entry, zip->cd_offset, zip->cd_size);\n\n        /* Verify central directory signature exists at offset */\n        err = mz_stream_seek(zip->stream, zip->cd_offset, MZ_SEEK_SET);\n        if (err == MZ_OK)\n            err = mz_stream_read_uint32(zip->stream, &zip->cd_signature);\n        if ((err == MZ_OK) && (zip->cd_signature != MZ_ZIP_MAGIC_CENTRALHEADER)) {\n            /* If cd exists in large file and no zip-64 support, error for recover */\n            if (eocd_pos > UINT32_MAX && eocd_pos64 == 0)\n                err = MZ_FORMAT_ERROR;\n            /* If cd not found attempt to seek backward to find it */\n            if (err == MZ_OK)\n                err = mz_stream_seek(zip->stream, eocd_pos - zip->cd_size, MZ_SEEK_SET);\n            if (err == MZ_OK)\n                err = mz_stream_read_uint32(zip->stream, &zip->cd_signature);\n            if ((err == MZ_OK) && (zip->cd_signature == MZ_ZIP_MAGIC_CENTRALHEADER)) {\n                /* If found compensate for incorrect locations */\n                value64i = zip->cd_offset;\n                zip->cd_offset = eocd_pos - zip->cd_size;\n                /* Assume disk has prepended data */\n                zip->disk_offset_shift = zip->cd_offset - value64i;\n            }\n        }\n    }\n\n    if (err == MZ_OK) {\n        if (eocd_pos < zip->cd_offset) {\n            /* End of central dir should always come after central dir */\n            err = MZ_FORMAT_ERROR;\n        } else if ((uint64_t)eocd_pos < (uint64_t)zip->cd_offset + zip->cd_size) {\n            /* Truncate size of cd if incorrect size or offset provided */\n            zip->cd_size = eocd_pos - zip->cd_offset;\n        }\n    }\n\n    return err;\n}\n\nstatic int32_t mz_zip_write_cd(void *handle) {\n    mz_zip *zip = (mz_zip *)handle;\n    int64_t zip64_eocd_pos_inzip = 0;\n    int64_t disk_number = 0;\n    int64_t disk_size = 0;\n    int32_t comment_size = 0;\n    int32_t err = MZ_OK;\n\n    if (!zip)\n        return MZ_PARAM_ERROR;\n\n    if (mz_stream_get_prop_int64(zip->stream, MZ_STREAM_PROP_DISK_NUMBER, &disk_number) == MZ_OK)\n        zip->disk_number_with_cd = (uint32_t)disk_number;\n    if (mz_stream_get_prop_int64(zip->stream, MZ_STREAM_PROP_DISK_SIZE, &disk_size) == MZ_OK && disk_size > 0)\n        zip->disk_number_with_cd += 1;\n    mz_stream_set_prop_int64(zip->stream, MZ_STREAM_PROP_DISK_NUMBER, -1);\n    if ((zip->disk_number_with_cd > 0) && (zip->open_mode & MZ_OPEN_MODE_APPEND)) {\n        // Overwrite existing central directory if using split disks\n        mz_stream_seek(zip->stream, 0, MZ_SEEK_SET);\n    }\n\n    zip->cd_offset = mz_stream_tell(zip->stream);\n    mz_stream_seek(zip->cd_mem_stream, 0, MZ_SEEK_END);\n    zip->cd_size = (uint32_t)mz_stream_tell(zip->cd_mem_stream);\n    mz_stream_seek(zip->cd_mem_stream, 0, MZ_SEEK_SET);\n\n    err = mz_stream_copy(zip->stream, zip->cd_mem_stream, (int32_t)zip->cd_size);\n\n    mz_zip_print(\"Zip - Write cd (disk %\" PRId32 \" entries %\" PRId64 \" offset %\" PRId64 \" size %\" PRId64 \")\\n\",\n        zip->disk_number_with_cd, zip->number_entry, zip->cd_offset, zip->cd_size);\n\n    if (zip->cd_size == 0 && zip->number_entry > 0) {\n        // Zip does not contain central directory, open with recovery option\n        return MZ_FORMAT_ERROR;\n    }\n\n    /* Write the ZIP64 central directory header */\n    if (zip->cd_offset >= UINT32_MAX || zip->number_entry >= UINT16_MAX) {\n        zip64_eocd_pos_inzip = mz_stream_tell(zip->stream);\n\n        err = mz_stream_write_uint32(zip->stream, MZ_ZIP_MAGIC_ENDHEADER64);\n\n        /* Size of this 'zip64 end of central directory' */\n        if (err == MZ_OK)\n            err = mz_stream_write_uint64(zip->stream, (uint64_t)44);\n        /* Version made by */\n        if (err == MZ_OK)\n            err = mz_stream_write_uint16(zip->stream, zip->version_madeby);\n        /* Version needed */\n        if (err == MZ_OK)\n            err = mz_stream_write_uint16(zip->stream, (uint16_t)45);\n        /* Number of this disk */\n        if (err == MZ_OK)\n            err = mz_stream_write_uint32(zip->stream, zip->disk_number_with_cd);\n        /* Number of the disk with the start of the central directory */\n        if (err == MZ_OK)\n            err = mz_stream_write_uint32(zip->stream, zip->disk_number_with_cd);\n        /* Total number of entries in the central dir on this disk */\n        if (err == MZ_OK)\n            err = mz_stream_write_uint64(zip->stream, zip->number_entry);\n        /* Total number of entries in the central dir */\n        if (err == MZ_OK)\n            err = mz_stream_write_uint64(zip->stream, zip->number_entry);\n        /* Size of the central directory */\n        if (err == MZ_OK)\n            err = mz_stream_write_int64(zip->stream, zip->cd_size);\n        /* Offset of start of central directory with respect to the starting disk number */\n        if (err == MZ_OK)\n            err = mz_stream_write_int64(zip->stream, zip->cd_offset);\n        if (err == MZ_OK)\n            err = mz_stream_write_uint32(zip->stream, MZ_ZIP_MAGIC_ENDLOCHEADER64);\n\n        /* Number of the disk with the start of the central directory */\n        if (err == MZ_OK)\n            err = mz_stream_write_uint32(zip->stream, zip->disk_number_with_cd);\n        /* Relative offset to the end of zip64 central directory */\n        if (err == MZ_OK)\n            err = mz_stream_write_int64(zip->stream, zip64_eocd_pos_inzip);\n        /* Number of the disk with the start of the central directory */\n        if (err == MZ_OK)\n            err = mz_stream_write_uint32(zip->stream, zip->disk_number_with_cd + 1);\n    }\n\n    /* Write the central directory header */\n\n    /* Signature */\n    if (err == MZ_OK)\n        err = mz_stream_write_uint32(zip->stream, MZ_ZIP_MAGIC_ENDHEADER);\n    /* Number of this disk */\n    if (err == MZ_OK)\n        err = mz_stream_write_uint16(zip->stream, (uint16_t)zip->disk_number_with_cd);\n    /* Number of the disk with the start of the central directory */\n    if (err == MZ_OK)\n        err = mz_stream_write_uint16(zip->stream, (uint16_t)zip->disk_number_with_cd);\n    /* Total number of entries in the central dir on this disk */\n    if (err == MZ_OK) {\n        if (zip->number_entry >= UINT16_MAX)\n            err = mz_stream_write_uint16(zip->stream, UINT16_MAX);\n        else\n            err = mz_stream_write_uint16(zip->stream, (uint16_t)zip->number_entry);\n    }\n    /* Total number of entries in the central dir */\n    if (err == MZ_OK) {\n        if (zip->number_entry >= UINT16_MAX)\n            err = mz_stream_write_uint16(zip->stream, UINT16_MAX);\n        else\n            err = mz_stream_write_uint16(zip->stream, (uint16_t)zip->number_entry);\n    }\n    /* Size of the central directory */\n    if (err == MZ_OK)\n        err = mz_stream_write_uint32(zip->stream, (uint32_t)zip->cd_size);\n    /* Offset of start of central directory with respect to the starting disk number */\n    if (err == MZ_OK) {\n        if (zip->cd_offset >= UINT32_MAX)\n            err = mz_stream_write_uint32(zip->stream, UINT32_MAX);\n        else\n            err = mz_stream_write_uint32(zip->stream, (uint32_t)zip->cd_offset);\n    }\n\n    /* Write global comment */\n    if (zip->comment) {\n        comment_size = (int32_t)strlen(zip->comment);\n        if (comment_size > UINT16_MAX)\n            comment_size = UINT16_MAX;\n    }\n    if (err == MZ_OK)\n        err = mz_stream_write_uint16(zip->stream, (uint16_t)comment_size);\n    if (err == MZ_OK) {\n        if (mz_stream_write(zip->stream, zip->comment, comment_size) != comment_size)\n            err = MZ_READ_ERROR;\n    }\n    return err;\n}\n\nstatic int32_t mz_zip_recover_cd(void *handle) {\n    mz_zip *zip = (mz_zip *)handle;\n    mz_zip_file local_file_info;\n    void *local_file_info_stream = NULL;\n    void *cd_mem_stream = NULL;\n    uint64_t number_entry = 0;\n    int64_t descriptor_pos = 0;\n    int64_t next_header_pos = 0;\n    int64_t disk_offset = 0;\n    int64_t disk_number = 0;\n    int64_t compressed_pos = 0;\n    int64_t compressed_end_pos = 0;\n    int64_t compressed_size = 0;\n    int64_t uncompressed_size = 0;\n    uint8_t descriptor_magic[4] = MZ_ZIP_MAGIC_DATADESCRIPTORU8;\n    uint8_t local_header_magic[4] = MZ_ZIP_MAGIC_LOCALHEADERU8;\n    uint8_t central_header_magic[4] = MZ_ZIP_MAGIC_CENTRALHEADERU8;\n    uint32_t crc32 = 0;\n    int32_t disk_number_with_cd = 0;\n    int32_t err = MZ_OK;\n    uint8_t zip64 = 0;\n    uint8_t eof = 0;\n\n    mz_zip_print(\"Zip - Recover - Start\\n\");\n\n    mz_zip_get_cd_mem_stream(handle, &cd_mem_stream);\n\n    /* Determine if we are on a split disk or not */\n    mz_stream_set_prop_int64(zip->stream, MZ_STREAM_PROP_DISK_NUMBER, 0);\n    if (mz_stream_tell(zip->stream) < 0) {\n        mz_stream_set_prop_int64(zip->stream, MZ_STREAM_PROP_DISK_NUMBER, -1);\n        mz_stream_seek(zip->stream, 0, MZ_SEEK_SET);\n    } else\n        disk_number_with_cd = 1;\n\n    if (mz_stream_is_open(cd_mem_stream) != MZ_OK)\n        err = mz_stream_mem_open(cd_mem_stream, NULL, MZ_OPEN_MODE_CREATE);\n\n    mz_stream_mem_create(&local_file_info_stream);\n    mz_stream_mem_open(local_file_info_stream, NULL, MZ_OPEN_MODE_CREATE);\n\n    if (err == MZ_OK) {\n        err = mz_stream_find(zip->stream, (const void *)local_header_magic, sizeof(local_header_magic),\n                INT64_MAX, &next_header_pos);\n    }\n\n    while (err == MZ_OK && !eof) {\n        /* Get current offset and disk number for central dir record */\n        disk_offset = mz_stream_tell(zip->stream);\n        mz_stream_get_prop_int64(zip->stream, MZ_STREAM_PROP_DISK_NUMBER, &disk_number);\n\n        /* Read local headers */\n        memset(&local_file_info, 0, sizeof(local_file_info));\n        err = mz_zip_entry_read_header(zip->stream, 1, &local_file_info, local_file_info_stream);\n        if (err != MZ_OK)\n            break;\n\n        local_file_info.disk_offset = disk_offset;\n        if (disk_number < 0)\n            disk_number = 0;\n        local_file_info.disk_number = (uint32_t)disk_number;\n\n        compressed_pos = mz_stream_tell(zip->stream);\n\n        if ((err == MZ_OK) && (local_file_info.compressed_size > 0)) {\n            mz_stream_seek(zip->stream, local_file_info.compressed_size, MZ_SEEK_CUR);\n        }\n\n        for (;;) {\n            /* Search for the next local header */\n            err = mz_stream_find(zip->stream, (const void *)local_header_magic, sizeof(local_header_magic),\n                    INT64_MAX, &next_header_pos);\n\n            if (err == MZ_EXIST_ERROR) {\n                mz_stream_seek(zip->stream, compressed_pos, MZ_SEEK_SET);\n\n                /* Search for central dir if no local header found */\n                err = mz_stream_find(zip->stream, (const void *)central_header_magic, sizeof(central_header_magic),\n                    INT64_MAX, &next_header_pos);\n\n                if (err == MZ_EXIST_ERROR) {\n                    /* Get end of stream if no central header found */\n                    mz_stream_seek(zip->stream, 0, MZ_SEEK_END);\n                    next_header_pos = mz_stream_tell(zip->stream);\n                }\n\n                eof = 1;\n            }\n\n            if (local_file_info.flag & MZ_ZIP_FLAG_DATA_DESCRIPTOR || local_file_info.compressed_size == 0) {\n                /* Search backwards for the descriptor, seeking too far back will be incorrect if compressed size is small */\n                err = mz_stream_find_reverse(zip->stream, (const void *)descriptor_magic, sizeof(descriptor_magic),\n                            MZ_ZIP_SIZE_MAX_DATA_DESCRIPTOR, &descriptor_pos);\n                if (err == MZ_OK) {\n                    if (mz_zip_extrafield_contains(local_file_info.extrafield,\n                        local_file_info.extrafield_size, MZ_ZIP_EXTENSION_ZIP64, NULL) == MZ_OK)\n                        zip64 = 1;\n\n                    err = mz_zip_entry_read_descriptor(zip->stream, zip64, &crc32,\n                        &compressed_size, &uncompressed_size);\n\n                    if (err == MZ_OK) {\n                        if (local_file_info.crc == 0)\n                            local_file_info.crc = crc32;\n                        if (local_file_info.compressed_size == 0)\n                            local_file_info.compressed_size = compressed_size;\n                        if (local_file_info.uncompressed_size == 0)\n                            local_file_info.uncompressed_size = uncompressed_size;\n                    }\n\n                    compressed_end_pos = descriptor_pos;\n                } else if (eof) {\n                    compressed_end_pos = next_header_pos;\n                } else if (local_file_info.flag & MZ_ZIP_FLAG_DATA_DESCRIPTOR) {\n                    /* Wrong local file entry found, keep searching */\n                    next_header_pos += 1;\n                    mz_stream_seek(zip->stream, next_header_pos, MZ_SEEK_SET);\n                    continue;\n                }\n            } else {\n                compressed_end_pos = next_header_pos;\n            }\n\n            break;\n        }\n\n        compressed_size = compressed_end_pos - compressed_pos;\n\n        if (compressed_size > UINT32_MAX) {\n            /* Update sizes if 4GB file is written with no ZIP64 support */\n            if (local_file_info.uncompressed_size < UINT32_MAX) {\n                local_file_info.compressed_size = compressed_size;\n                local_file_info.uncompressed_size = 0;\n            }\n        }\n\n        mz_zip_print(\"Zip - Recover - Entry %s (csize %\" PRId64 \" usize %\" PRId64 \" flags 0x%\" PRIx16 \")\\n\",\n            local_file_info.filename, local_file_info.compressed_size, local_file_info.uncompressed_size,\n            local_file_info.flag);\n\n        /* Rewrite central dir with local headers and offsets */\n        err = mz_zip_entry_write_header(cd_mem_stream, 0, &local_file_info);\n        if (err == MZ_OK)\n            number_entry += 1;\n\n        err = mz_stream_seek(zip->stream, next_header_pos, MZ_SEEK_SET);\n    }\n\n    mz_stream_mem_delete(&local_file_info_stream);\n\n    mz_zip_print(\"Zip - Recover - Complete (cddisk %\" PRId32 \" entries %\" PRId64 \")\\n\",\n        disk_number_with_cd, number_entry);\n\n    if (number_entry == 0)\n        return err;\n\n    /* Set new upper seek boundary for central dir mem stream */\n    disk_offset = mz_stream_tell(cd_mem_stream);\n    mz_stream_mem_set_buffer_limit(cd_mem_stream, (int32_t)disk_offset);\n\n    /* Set new central directory info */\n    mz_zip_set_cd_stream(handle, 0, cd_mem_stream);\n    mz_zip_set_number_entry(handle, number_entry);\n    mz_zip_set_disk_number_with_cd(handle, disk_number_with_cd);\n\n    return MZ_OK;\n}\n\nvoid *mz_zip_create(void **handle) {\n    mz_zip *zip = NULL;\n\n    zip = (mz_zip *)calloc(1, sizeof(mz_zip));\n    if (zip)\n        zip->data_descriptor = 1;\n    if (handle)\n        *handle = zip;\n\n    return zip;\n}\n\nvoid mz_zip_delete(void **handle) {\n    mz_zip *zip = NULL;\n    if (!handle)\n        return;\n    zip = (mz_zip *)*handle;\n    if (zip) {\n        free(zip);\n    }\n    *handle = NULL;\n}\n\nint32_t mz_zip_open(void *handle, void *stream, int32_t mode) {\n    mz_zip *zip = (mz_zip *)handle;\n    int32_t err = MZ_OK;\n\n    if (!zip)\n        return MZ_PARAM_ERROR;\n\n    mz_zip_print(\"Zip - Open\\n\");\n\n    zip->stream = stream;\n\n    mz_stream_mem_create(&zip->cd_mem_stream);\n\n    if (mode & MZ_OPEN_MODE_WRITE) {\n        mz_stream_mem_open(zip->cd_mem_stream, NULL, MZ_OPEN_MODE_CREATE);\n        zip->cd_stream = zip->cd_mem_stream;\n    } else {\n        zip->cd_stream = stream;\n    }\n\n    if ((mode & MZ_OPEN_MODE_READ) || (mode & MZ_OPEN_MODE_APPEND)) {\n        if ((mode & MZ_OPEN_MODE_CREATE) == 0) {\n            err = mz_zip_read_cd(zip);\n            if (err != MZ_OK) {\n                mz_zip_print(\"Zip - Error detected reading cd (%\" PRId32 \")\\n\", err);\n                if (zip->recover && mz_zip_recover_cd(zip) == MZ_OK)\n                    err = MZ_OK;\n            }\n        }\n\n        if ((err == MZ_OK) && (mode & MZ_OPEN_MODE_APPEND)) {\n            if (zip->cd_size > 0) {\n                /* Store central directory in memory */\n                err = mz_stream_seek(zip->stream, zip->cd_offset, MZ_SEEK_SET);\n                if (err == MZ_OK)\n                    err = mz_stream_copy(zip->cd_mem_stream, zip->stream, (int32_t)zip->cd_size);\n                if (err == MZ_OK)\n                    err = mz_stream_seek(zip->stream, zip->cd_offset, MZ_SEEK_SET);\n            } else {\n                if (zip->cd_signature == MZ_ZIP_MAGIC_ENDHEADER) {\n                    /* If tiny zip then overwrite end header */\n                    err = mz_stream_seek(zip->stream, zip->cd_offset, MZ_SEEK_SET);\n                } else {\n                    /* If no central directory, append new zip to end of file */\n                    err = mz_stream_seek(zip->stream, 0, MZ_SEEK_END);\n                }\n            }\n\n            if (zip->disk_number_with_cd > 0) {\n                /* Move to last disk to begin appending */\n                mz_stream_set_prop_int64(zip->stream, MZ_STREAM_PROP_DISK_NUMBER, zip->disk_number_with_cd - 1);\n            }\n        } else {\n            zip->cd_start_pos = zip->cd_offset;\n        }\n    }\n\n    if (err != MZ_OK) {\n        mz_zip_close(zip);\n        return err;\n    }\n\n    /* Memory streams used to store variable length file info data */\n    mz_stream_mem_create(&zip->file_info_stream);\n    mz_stream_mem_open(zip->file_info_stream, NULL, MZ_OPEN_MODE_CREATE);\n\n    mz_stream_mem_create(&zip->local_file_info_stream);\n    mz_stream_mem_open(zip->local_file_info_stream, NULL, MZ_OPEN_MODE_CREATE);\n\n    zip->open_mode = mode;\n\n    return err;\n}\n\nint32_t mz_zip_close(void *handle) {\n    mz_zip *zip = (mz_zip *)handle;\n    int32_t err = MZ_OK;\n\n    if (!zip)\n        return MZ_PARAM_ERROR;\n\n    mz_zip_print(\"Zip - Close\\n\");\n\n    if (mz_zip_entry_is_open(handle) == MZ_OK)\n        err = mz_zip_entry_close(handle);\n\n    if ((err == MZ_OK) && (zip->open_mode & MZ_OPEN_MODE_WRITE))\n        err = mz_zip_write_cd(handle);\n\n    if (zip->cd_mem_stream) {\n        mz_stream_close(zip->cd_mem_stream);\n        mz_stream_delete(&zip->cd_mem_stream);\n    }\n\n    if (zip->file_info_stream) {\n        mz_stream_mem_close(zip->file_info_stream);\n        mz_stream_mem_delete(&zip->file_info_stream);\n    }\n    if (zip->local_file_info_stream) {\n        mz_stream_mem_close(zip->local_file_info_stream);\n        mz_stream_mem_delete(&zip->local_file_info_stream);\n    }\n\n    if (zip->comment) {\n        free(zip->comment);\n        zip->comment = NULL;\n    }\n\n    zip->stream = NULL;\n    zip->cd_stream = NULL;\n\n    return err;\n}\n\nint32_t mz_zip_get_comment(void *handle, const char **comment) {\n    mz_zip *zip = (mz_zip *)handle;\n    if (!zip || !comment)\n        return MZ_PARAM_ERROR;\n    if (!zip->comment)\n        return MZ_EXIST_ERROR;\n    *comment = zip->comment;\n    return MZ_OK;\n}\n\nint32_t mz_zip_set_comment(void *handle, const char *comment) {\n    mz_zip *zip = (mz_zip *)handle;\n    int32_t comment_size = 0;\n    if (!zip || !comment)\n        return MZ_PARAM_ERROR;\n    if (zip->comment)\n        free(zip->comment);\n    comment_size = (int32_t)strlen(comment);\n    if (comment_size > UINT16_MAX)\n        return MZ_PARAM_ERROR;\n    zip->comment = (char *)calloc(comment_size + 1, sizeof(char));\n    if (!zip->comment)\n        return MZ_MEM_ERROR;\n    strncpy(zip->comment, comment, comment_size);\n    return MZ_OK;\n}\n\nint32_t mz_zip_get_version_madeby(void *handle, uint16_t *version_madeby) {\n    mz_zip *zip = (mz_zip *)handle;\n    if (!zip || !version_madeby)\n        return MZ_PARAM_ERROR;\n    *version_madeby = zip->version_madeby;\n    return MZ_OK;\n}\n\nint32_t mz_zip_set_version_madeby(void *handle, uint16_t version_madeby) {\n    mz_zip *zip = (mz_zip *)handle;\n    if (!zip)\n        return MZ_PARAM_ERROR;\n    zip->version_madeby = version_madeby;\n    return MZ_OK;\n}\n\nint32_t mz_zip_set_recover(void *handle, uint8_t recover) {\n    mz_zip *zip = (mz_zip *)handle;\n    if (!zip)\n        return MZ_PARAM_ERROR;\n    zip->recover = recover;\n    return MZ_OK;\n}\n\nint32_t mz_zip_set_data_descriptor(void *handle, uint8_t data_descriptor) {\n    mz_zip *zip = (mz_zip *)handle;\n    if (!zip)\n        return MZ_PARAM_ERROR;\n    zip->data_descriptor = data_descriptor;\n    return MZ_OK;\n}\n\nint32_t mz_zip_get_stream(void *handle, void **stream) {\n    mz_zip *zip = (mz_zip *)handle;\n    if (!zip || !stream)\n        return MZ_PARAM_ERROR;\n    *stream = zip->stream;\n    if (!*stream)\n        return MZ_EXIST_ERROR;\n    return MZ_OK;\n}\n\nint32_t mz_zip_set_cd_stream(void *handle, int64_t cd_start_pos, void *cd_stream) {\n    mz_zip *zip = (mz_zip *)handle;\n    if (!zip || !cd_stream)\n        return MZ_PARAM_ERROR;\n    zip->cd_offset = 0;\n    zip->cd_stream = cd_stream;\n    zip->cd_start_pos = cd_start_pos;\n    return MZ_OK;\n}\n\nint32_t mz_zip_get_cd_mem_stream(void *handle, void **cd_mem_stream) {\n    mz_zip *zip = (mz_zip *)handle;\n    if (!zip || !cd_mem_stream)\n        return MZ_PARAM_ERROR;\n    *cd_mem_stream = zip->cd_mem_stream;\n    if (!*cd_mem_stream)\n        return MZ_EXIST_ERROR;\n    return MZ_OK;\n}\n\nint32_t mz_zip_set_number_entry(void *handle, uint64_t number_entry) {\n    mz_zip *zip = (mz_zip *)handle;\n    if (!zip)\n        return MZ_PARAM_ERROR;\n    zip->number_entry = number_entry;\n    return MZ_OK;\n}\n\nint32_t mz_zip_get_number_entry(void *handle, uint64_t *number_entry) {\n    mz_zip *zip = (mz_zip *)handle;\n    if (!zip || !number_entry)\n        return MZ_PARAM_ERROR;\n    *number_entry = zip->number_entry;\n    return MZ_OK;\n}\n\nint32_t mz_zip_set_disk_number_with_cd(void *handle, uint32_t disk_number_with_cd) {\n    mz_zip *zip = (mz_zip *)handle;\n    if (!zip)\n        return MZ_PARAM_ERROR;\n    zip->disk_number_with_cd = disk_number_with_cd;\n    return MZ_OK;\n}\n\nint32_t mz_zip_get_disk_number_with_cd(void *handle, uint32_t *disk_number_with_cd) {\n    mz_zip *zip = (mz_zip *)handle;\n    if (!zip || !disk_number_with_cd)\n        return MZ_PARAM_ERROR;\n    *disk_number_with_cd = zip->disk_number_with_cd;\n    return MZ_OK;\n}\n\nstatic int32_t mz_zip_entry_close_int(void *handle) {\n    mz_zip *zip = (mz_zip *)handle;\n\n    if (zip->crypt_stream)\n        mz_stream_delete(&zip->crypt_stream);\n    zip->crypt_stream = NULL;\n    if (zip->compress_stream)\n        mz_stream_delete(&zip->compress_stream);\n    zip->compress_stream = NULL;\n\n    zip->entry_opened = 0;\n\n    return MZ_OK;\n}\n\nstatic int32_t mz_zip_entry_open_int(void *handle, uint8_t raw, int16_t compress_level, const char *password) {\n    mz_zip *zip = (mz_zip *)handle;\n    int64_t max_total_in = 0;\n    int64_t header_size = 0;\n    int64_t footer_size = 0;\n    int32_t err = MZ_OK;\n    uint8_t use_crypt = 0;\n\n    if (!zip)\n        return MZ_PARAM_ERROR;\n\n    switch (zip->file_info.compression_method) {\n    case MZ_COMPRESS_METHOD_STORE:\n    case MZ_COMPRESS_METHOD_DEFLATE:\n#ifdef HAVE_BZIP2\n    case MZ_COMPRESS_METHOD_BZIP2:\n#endif\n#ifdef HAVE_LZMA\n    case MZ_COMPRESS_METHOD_LZMA:\n#endif\n#if defined(HAVE_LZMA) || defined(HAVE_LIBCOMP)\n    case MZ_COMPRESS_METHOD_XZ:\n#endif\n#ifdef HAVE_ZSTD\n    case MZ_COMPRESS_METHOD_ZSTD:\n#endif\n        err = MZ_OK;\n        break;\n    default:\n        return MZ_SUPPORT_ERROR;\n    }\n\n#ifndef HAVE_WZAES\n    if (zip->file_info.aes_version)\n        return MZ_SUPPORT_ERROR;\n#endif\n\n    zip->entry_raw = raw;\n\n    if ((zip->file_info.flag & MZ_ZIP_FLAG_ENCRYPTED) && (password)) {\n        if (zip->open_mode & MZ_OPEN_MODE_WRITE) {\n            /* Encrypt only when we are not trying to write raw and password is supplied. */\n            if (!zip->entry_raw)\n                use_crypt = 1;\n        } else if (zip->open_mode & MZ_OPEN_MODE_READ) {\n            /* Decrypt only when password is supplied. Don't error when password */\n            /* is not supplied as we may want to read the raw encrypted data. */\n            use_crypt = 1;\n        }\n    }\n\n    if ((err == MZ_OK) && (use_crypt)) {\n#ifdef HAVE_WZAES\n        if (zip->file_info.aes_version) {\n            mz_stream_wzaes_create(&zip->crypt_stream);\n            mz_stream_wzaes_set_password(zip->crypt_stream, password);\n            mz_stream_wzaes_set_encryption_mode(zip->crypt_stream, zip->file_info.aes_encryption_mode);\n        } else\n#endif\n        {\n#ifdef HAVE_PKCRYPT\n            uint8_t verify1 = (uint8_t)((zip->file_info.pk_verify >> 8) & 0xff);\n            uint8_t verify2 = (uint8_t)((zip->file_info.pk_verify) & 0xff);\n\n            mz_stream_pkcrypt_create(&zip->crypt_stream);\n            mz_stream_pkcrypt_set_password(zip->crypt_stream, password);\n            mz_stream_pkcrypt_set_verify(zip->crypt_stream, verify1, verify2);\n#endif\n        }\n    }\n\n    if (err == MZ_OK) {\n        if (!zip->crypt_stream)\n            mz_stream_raw_create(&zip->crypt_stream);\n\n        mz_stream_set_base(zip->crypt_stream, zip->stream);\n\n        err = mz_stream_open(zip->crypt_stream, NULL, zip->open_mode);\n    }\n\n    if (err == MZ_OK) {\n        if (zip->entry_raw || zip->file_info.compression_method == MZ_COMPRESS_METHOD_STORE)\n            mz_stream_raw_create(&zip->compress_stream);\n#ifdef HAVE_ZLIB\n        else if (zip->file_info.compression_method == MZ_COMPRESS_METHOD_DEFLATE)\n            mz_stream_zlib_create(&zip->compress_stream);\n#endif\n#ifdef HAVE_BZIP2\n        else if (zip->file_info.compression_method == MZ_COMPRESS_METHOD_BZIP2)\n            mz_stream_bzip_create(&zip->compress_stream);\n#endif\n#ifdef HAVE_LIBCOMP\n        else if (zip->file_info.compression_method == MZ_COMPRESS_METHOD_DEFLATE ||\n                 zip->file_info.compression_method == MZ_COMPRESS_METHOD_XZ) {\n            mz_stream_libcomp_create(&zip->compress_stream);\n            mz_stream_set_prop_int64(zip->compress_stream, MZ_STREAM_PROP_COMPRESS_METHOD,\n                zip->file_info.compression_method);\n        }\n#endif\n#ifdef HAVE_LZMA\n        else if (zip->file_info.compression_method == MZ_COMPRESS_METHOD_LZMA ||\n                 zip->file_info.compression_method == MZ_COMPRESS_METHOD_XZ) {\n            mz_stream_lzma_create(&zip->compress_stream);\n            mz_stream_set_prop_int64(zip->compress_stream, MZ_STREAM_PROP_COMPRESS_METHOD,\n                zip->file_info.compression_method);\n        }\n#endif\n#ifdef HAVE_ZSTD\n        else if (zip->file_info.compression_method == MZ_COMPRESS_METHOD_ZSTD)\n            mz_stream_zstd_create(&zip->compress_stream);\n#endif\n        else\n            err = MZ_PARAM_ERROR;\n    }\n\n    if (err == MZ_OK) {\n        if (zip->open_mode & MZ_OPEN_MODE_WRITE) {\n            mz_stream_set_prop_int64(zip->compress_stream, MZ_STREAM_PROP_COMPRESS_LEVEL, compress_level);\n        } else {\n            int32_t set_end_of_stream = 0;\n\n#ifndef HAVE_LIBCOMP\n            if (zip->entry_raw ||\n                zip->file_info.compression_method == MZ_COMPRESS_METHOD_STORE ||\n                zip->file_info.flag & MZ_ZIP_FLAG_ENCRYPTED)\n#endif\n            {\n                max_total_in = zip->file_info.compressed_size;\n                mz_stream_set_prop_int64(zip->crypt_stream, MZ_STREAM_PROP_TOTAL_IN_MAX, max_total_in);\n\n                if (mz_stream_get_prop_int64(zip->crypt_stream, MZ_STREAM_PROP_HEADER_SIZE, &header_size) == MZ_OK)\n                    max_total_in -= header_size;\n                if (mz_stream_get_prop_int64(zip->crypt_stream, MZ_STREAM_PROP_FOOTER_SIZE, &footer_size) == MZ_OK)\n                    max_total_in -= footer_size;\n\n                mz_stream_set_prop_int64(zip->compress_stream, MZ_STREAM_PROP_TOTAL_IN_MAX, max_total_in);\n            }\n\n            switch (zip->file_info.compression_method) {\n            case MZ_COMPRESS_METHOD_LZMA:\n            case MZ_COMPRESS_METHOD_XZ:\n                set_end_of_stream = (zip->file_info.flag & MZ_ZIP_FLAG_LZMA_EOS_MARKER);\n                break;\n            case MZ_COMPRESS_METHOD_ZSTD:\n                set_end_of_stream = 1;\n                break;\n            }\n\n            if (set_end_of_stream) {\n                mz_stream_set_prop_int64(zip->compress_stream, MZ_STREAM_PROP_TOTAL_IN_MAX, zip->file_info.compressed_size);\n                mz_stream_set_prop_int64(zip->compress_stream, MZ_STREAM_PROP_TOTAL_OUT_MAX, zip->file_info.uncompressed_size);\n            }\n        }\n\n        mz_stream_set_base(zip->compress_stream, zip->crypt_stream);\n\n        err = mz_stream_open(zip->compress_stream, NULL, zip->open_mode);\n    }\n\n    if (err == MZ_OK) {\n        zip->entry_opened = 1;\n        zip->entry_crc32 = 0;\n    } else {\n        mz_zip_entry_close_int(handle);\n    }\n\n    return err;\n}\n\nint32_t mz_zip_entry_is_open(void *handle) {\n    mz_zip *zip = (mz_zip *)handle;\n    if (!zip)\n        return MZ_PARAM_ERROR;\n    if (zip->entry_opened == 0)\n        return MZ_EXIST_ERROR;\n    return MZ_OK;\n}\n\nint32_t mz_zip_entry_read_open(void *handle, uint8_t raw, const char *password) {\n    mz_zip *zip = (mz_zip *)handle;\n    int32_t err = MZ_OK;\n    int32_t err_shift = MZ_OK;\n\n#if defined(MZ_ZIP_NO_ENCRYPTION)\n    if (password)\n        return MZ_SUPPORT_ERROR;\n#endif\n    if (!zip || !zip->entry_scanned)\n        return MZ_PARAM_ERROR;\n    if ((zip->open_mode & MZ_OPEN_MODE_READ) == 0)\n        return MZ_PARAM_ERROR;\n\n    mz_zip_print(\"Zip - Entry - Read open (raw %\" PRId32 \")\\n\", raw);\n\n    err = mz_zip_entry_seek_local_header(handle);\n    if (err == MZ_OK)\n        err = mz_zip_entry_read_header(zip->stream, 1, &zip->local_file_info, zip->local_file_info_stream);\n\n    if (err == MZ_FORMAT_ERROR && zip->disk_offset_shift > 0) {\n        /* Perhaps we didn't compensated correctly for incorrect cd offset */\n        err_shift = mz_stream_seek(zip->stream, zip->file_info.disk_offset, MZ_SEEK_SET);\n        if (err_shift == MZ_OK)\n            err_shift = mz_zip_entry_read_header(zip->stream, 1, &zip->local_file_info, zip->local_file_info_stream);\n        if (err_shift == MZ_OK) {\n            zip->disk_offset_shift = 0;\n            err = err_shift;\n        }\n    }\n\n#ifdef MZ_ZIP_NO_DECOMPRESSION\n    if (!raw && zip->file_info.compression_method != MZ_COMPRESS_METHOD_STORE)\n        err = MZ_SUPPORT_ERROR;\n#endif\n    if (err == MZ_OK)\n        err = mz_zip_entry_open_int(handle, raw, 0, password);\n\n    return err;\n}\n\nint32_t mz_zip_entry_write_open(void *handle, const mz_zip_file *file_info, int16_t compress_level, uint8_t raw, const char *password) {\n    mz_zip *zip = (mz_zip *)handle;\n    int64_t filename_pos = -1;\n    int64_t extrafield_pos = 0;\n    int64_t comment_pos = 0;\n    int64_t linkname_pos = 0;\n    int64_t disk_number = 0;\n    uint8_t is_dir = 0;\n    int32_t err = MZ_OK;\n\n#if defined(MZ_ZIP_NO_ENCRYPTION)\n    if (password)\n        return MZ_SUPPORT_ERROR;\n#endif\n    if (!zip || !file_info || !file_info->filename)\n        return MZ_PARAM_ERROR;\n\n    if (mz_zip_entry_is_open(handle) == MZ_OK) {\n        err = mz_zip_entry_close(handle);\n        if (err != MZ_OK)\n            return err;\n    }\n\n    memcpy(&zip->file_info, file_info, sizeof(mz_zip_file));\n\n    mz_zip_print(\"Zip - Entry - Write open - %s (level %\" PRId16 \" raw %\" PRId8 \")\\n\",\n        zip->file_info.filename, compress_level, raw);\n\n    mz_stream_seek(zip->file_info_stream, 0, MZ_SEEK_SET);\n    mz_stream_write(zip->file_info_stream, file_info, sizeof(mz_zip_file));\n\n    /* Copy filename, extrafield, and comment internally */\n    filename_pos = mz_stream_tell(zip->file_info_stream);\n    if (file_info->filename)\n        mz_stream_write(zip->file_info_stream, file_info->filename, (int32_t)strlen(file_info->filename));\n    mz_stream_write_uint8(zip->file_info_stream, 0);\n\n    extrafield_pos = mz_stream_tell(zip->file_info_stream);\n    if (file_info->extrafield)\n        mz_stream_write(zip->file_info_stream, file_info->extrafield, file_info->extrafield_size);\n    mz_stream_write_uint8(zip->file_info_stream, 0);\n\n    comment_pos = mz_stream_tell(zip->file_info_stream);\n    if (file_info->comment)\n        mz_stream_write(zip->file_info_stream, file_info->comment, file_info->comment_size);\n    mz_stream_write_uint8(zip->file_info_stream, 0);\n\n    linkname_pos = mz_stream_tell(zip->file_info_stream);\n    if (file_info->linkname)\n        mz_stream_write(zip->file_info_stream, file_info->linkname, (int32_t)strlen(file_info->linkname));\n    mz_stream_write_uint8(zip->file_info_stream, 0);\n\n    mz_stream_mem_get_buffer_at(zip->file_info_stream, filename_pos, (const void **)&zip->file_info.filename);\n    mz_stream_mem_get_buffer_at(zip->file_info_stream, extrafield_pos, (const void **)&zip->file_info.extrafield);\n    mz_stream_mem_get_buffer_at(zip->file_info_stream, comment_pos, (const void **)&zip->file_info.comment);\n    mz_stream_mem_get_buffer_at(zip->file_info_stream, linkname_pos, (const void **)&zip->file_info.linkname);\n\n    if (zip->file_info.compression_method == MZ_COMPRESS_METHOD_DEFLATE) {\n        if ((compress_level == 8) || (compress_level == 9))\n            zip->file_info.flag |= MZ_ZIP_FLAG_DEFLATE_MAX;\n        if (compress_level == 2)\n            zip->file_info.flag |= MZ_ZIP_FLAG_DEFLATE_FAST;\n        if (compress_level == 1)\n            zip->file_info.flag |= MZ_ZIP_FLAG_DEFLATE_SUPER_FAST;\n    }\n#if defined(HAVE_LZMA) || defined(HAVE_LIBCOMP)\n    else if (zip->file_info.compression_method == MZ_COMPRESS_METHOD_LZMA ||\n             zip->file_info.compression_method == MZ_COMPRESS_METHOD_XZ)\n        zip->file_info.flag |= MZ_ZIP_FLAG_LZMA_EOS_MARKER;\n#endif\n\n    if (mz_zip_attrib_is_dir(zip->file_info.external_fa, zip->file_info.version_madeby) == MZ_OK)\n        is_dir = 1;\n\n    if (!is_dir) {\n        if (zip->data_descriptor)\n            zip->file_info.flag |= MZ_ZIP_FLAG_DATA_DESCRIPTOR;\n        if (password)\n            zip->file_info.flag |= MZ_ZIP_FLAG_ENCRYPTED;\n    }\n\n    mz_stream_get_prop_int64(zip->stream, MZ_STREAM_PROP_DISK_NUMBER, &disk_number);\n    zip->file_info.disk_number = (uint32_t)disk_number;\n    zip->file_info.disk_offset = mz_stream_tell(zip->stream);\n\n    if (zip->file_info.flag & MZ_ZIP_FLAG_ENCRYPTED) {\n#ifdef HAVE_PKCRYPT\n        /* Pre-calculated CRC value is required for PKWARE traditional encryption */\n        uint32_t dos_date = mz_zip_time_t_to_dos_date(zip->file_info.modified_date);\n        zip->file_info.pk_verify = mz_zip_get_pk_verify(dos_date, zip->file_info.crc, zip->file_info.flag);\n#endif\n#ifdef HAVE_WZAES\n        if (zip->file_info.aes_version && zip->file_info.aes_encryption_mode == 0)\n            zip->file_info.aes_encryption_mode = MZ_AES_ENCRYPTION_MODE_256;\n#endif\n    }\n\n    zip->file_info.crc = 0;\n    zip->file_info.compressed_size = 0;\n\n    if ((compress_level == 0) || (is_dir))\n        zip->file_info.compression_method = MZ_COMPRESS_METHOD_STORE;\n\n#ifdef MZ_ZIP_NO_COMPRESSION\n    if (zip->file_info.compression_method != MZ_COMPRESS_METHOD_STORE)\n        err = MZ_SUPPORT_ERROR;\n#endif\n    if (err == MZ_OK)\n        err = mz_zip_entry_write_header(zip->stream, 1, &zip->file_info);\n    if (err == MZ_OK)\n        err = mz_zip_entry_open_int(handle, raw, compress_level, password);\n\n    return err;\n}\n\nint32_t mz_zip_entry_read(void *handle, void *buf, int32_t len) {\n    mz_zip *zip = (mz_zip *)handle;\n    int32_t read = 0;\n\n    if (!zip || mz_zip_entry_is_open(handle) != MZ_OK)\n        return MZ_PARAM_ERROR;\n    if (UINT_MAX == UINT16_MAX && len > UINT16_MAX) /* zlib limitation */\n        return MZ_PARAM_ERROR;\n    if (len == 0)\n        return MZ_PARAM_ERROR;\n\n    if (zip->file_info.compressed_size == 0)\n        return 0;\n\n    /* Read entire entry even if uncompressed_size = 0, otherwise */\n    /* aes encryption validation will fail if compressed_size > 0 */\n    read = mz_stream_read(zip->compress_stream, buf, len);\n    if (read > 0)\n        zip->entry_crc32 = mz_crypt_crc32_update(zip->entry_crc32, buf, read);\n\n    mz_zip_print(\"Zip - Entry - Read - %\" PRId32 \" (max %\" PRId32 \")\\n\", read, len);\n\n    return read;\n}\n\nint32_t mz_zip_entry_write(void *handle, const void *buf, int32_t len) {\n    mz_zip *zip = (mz_zip *)handle;\n    int32_t written = 0;\n\n    if (!zip || mz_zip_entry_is_open(handle) != MZ_OK)\n        return MZ_PARAM_ERROR;\n    written = mz_stream_write(zip->compress_stream, buf, len);\n    if (written > 0)\n        zip->entry_crc32 = mz_crypt_crc32_update(zip->entry_crc32, buf, written);\n\n    mz_zip_print(\"Zip - Entry - Write - %\" PRId32 \" (max %\" PRId32 \")\\n\", written, len);\n\n    return written;\n}\n\nint32_t mz_zip_entry_read_close(void *handle, uint32_t *crc32, int64_t *compressed_size,\n    int64_t *uncompressed_size) {\n    mz_zip *zip = (mz_zip *)handle;\n    int64_t total_in = 0;\n    int32_t err = MZ_OK;\n    uint8_t zip64 = 0;\n\n    if (!zip || mz_zip_entry_is_open(handle) != MZ_OK)\n        return MZ_PARAM_ERROR;\n\n    mz_stream_close(zip->compress_stream);\n\n    mz_zip_print(\"Zip - Entry - Read Close\\n\");\n\n    if (crc32)\n        *crc32 = zip->file_info.crc;\n    if (compressed_size)\n        *compressed_size = zip->file_info.compressed_size;\n    if (uncompressed_size)\n        *uncompressed_size = zip->file_info.uncompressed_size;\n\n    mz_stream_get_prop_int64(zip->compress_stream, MZ_STREAM_PROP_TOTAL_IN, &total_in);\n\n    if ((zip->file_info.flag & MZ_ZIP_FLAG_DATA_DESCRIPTOR) &&\n        ((zip->file_info.flag & MZ_ZIP_FLAG_MASK_LOCAL_INFO) == 0) &&\n        (crc32 || compressed_size || uncompressed_size)) {\n        /* Check to see if data descriptor is zip64 bit format or not */\n        if (mz_zip_extrafield_contains(zip->local_file_info.extrafield,\n            zip->local_file_info.extrafield_size, MZ_ZIP_EXTENSION_ZIP64, NULL) == MZ_OK)\n            zip64 = 1;\n\n        err = mz_zip_entry_seek_local_header(handle);\n\n        /* Seek to end of compressed stream since we might have over-read during compression */\n        if (err == MZ_OK)\n            err = mz_stream_seek(zip->stream, MZ_ZIP_SIZE_LD_ITEM +\n                (int64_t)zip->local_file_info.filename_size +\n                (int64_t)zip->local_file_info.extrafield_size +\n                total_in, MZ_SEEK_CUR);\n\n        /* Read data descriptor */\n        if (err == MZ_OK)\n            err = mz_zip_entry_read_descriptor(zip->stream, zip64,\n                crc32, compressed_size, uncompressed_size);\n    }\n\n    /* If entire entry was not read verification will fail */\n    if ((err == MZ_OK) && (total_in == zip->file_info.compressed_size) && (!zip->entry_raw)) {\n#ifdef HAVE_WZAES\n        /* AES zip version AE-1 will expect a valid crc as well */\n        if (zip->file_info.aes_version <= 0x0001)\n#endif\n        {\n            if (zip->entry_crc32 != zip->file_info.crc) {\n                mz_zip_print(\"Zip - Entry - Crc failed (actual 0x%08\" PRIx32 \" expected 0x%08\" PRIx32 \")\\n\",\n                    zip->entry_crc32, zip->file_info.crc);\n\n                err = MZ_CRC_ERROR;\n            }\n        }\n    }\n\n    mz_zip_entry_close_int(handle);\n\n    return err;\n}\n\nint32_t mz_zip_entry_write_close(void *handle, uint32_t crc32, int64_t compressed_size,\n    int64_t uncompressed_size) {\n    mz_zip *zip = (mz_zip *)handle;\n    int64_t end_disk_number = 0;\n    int32_t err = MZ_OK;\n    uint8_t zip64 = 0;\n\n    if (!zip || mz_zip_entry_is_open(handle) != MZ_OK)\n        return MZ_PARAM_ERROR;\n\n    mz_stream_close(zip->compress_stream);\n\n    if (!zip->entry_raw)\n        crc32 = zip->entry_crc32;\n\n    mz_zip_print(\"Zip - Entry - Write Close (crc 0x%08\" PRIx32 \" cs %\" PRId64 \" ucs %\" PRId64 \")\\n\",\n        crc32, compressed_size, uncompressed_size);\n\n    /* If sizes are not set, then read them from the compression stream */\n    if (compressed_size < 0)\n        mz_stream_get_prop_int64(zip->compress_stream, MZ_STREAM_PROP_TOTAL_OUT, &compressed_size);\n    if (uncompressed_size < 0)\n        mz_stream_get_prop_int64(zip->compress_stream, MZ_STREAM_PROP_TOTAL_IN, &uncompressed_size);\n\n    if (zip->file_info.flag & MZ_ZIP_FLAG_ENCRYPTED) {\n        mz_stream_set_base(zip->crypt_stream, zip->stream);\n        err = mz_stream_close(zip->crypt_stream);\n\n        mz_stream_get_prop_int64(zip->crypt_stream, MZ_STREAM_PROP_TOTAL_OUT, &compressed_size);\n    }\n\n    mz_zip_entry_needs_zip64(&zip->file_info, 1, &zip64);\n\n    if ((err == MZ_OK) && (zip->file_info.flag & MZ_ZIP_FLAG_DATA_DESCRIPTOR)) {\n        /* Determine if we need to write data descriptor in zip64 format,\n           if local extrafield was saved with zip64 extrafield */\n\n        if (zip->file_info.flag & MZ_ZIP_FLAG_MASK_LOCAL_INFO)\n            err = mz_zip_entry_write_descriptor(zip->stream,\n                zip64, 0, compressed_size, 0);\n        else\n            err = mz_zip_entry_write_descriptor(zip->stream,\n                zip64, crc32, compressed_size, uncompressed_size);\n    }\n\n    /* Write file info to central directory */\n\n    mz_zip_print(\"Zip - Entry - Write cd (ucs %\" PRId64 \" cs %\" PRId64 \" crc 0x%08\" PRIx32 \")\\n\",\n        uncompressed_size, compressed_size, crc32);\n\n    zip->file_info.crc = crc32;\n    zip->file_info.compressed_size = compressed_size;\n    zip->file_info.uncompressed_size = uncompressed_size;\n\n    if (err == MZ_OK)\n        err = mz_zip_entry_write_header(zip->cd_mem_stream, 0, &zip->file_info);\n\n    /* Update local header with crc32 and sizes */\n    if ((err == MZ_OK) && ((zip->file_info.flag & MZ_ZIP_FLAG_DATA_DESCRIPTOR) == 0) &&\n        ((zip->file_info.flag & MZ_ZIP_FLAG_MASK_LOCAL_INFO) == 0)) {\n        /* Save the disk number and position we are to seek back after updating local header */\n        int64_t end_pos = mz_stream_tell(zip->stream);\n        mz_stream_get_prop_int64(zip->stream, MZ_STREAM_PROP_DISK_NUMBER, &end_disk_number);\n\n        err = mz_zip_entry_seek_local_header(handle);\n\n        if (err == MZ_OK) {\n            /* Seek to crc32 and sizes offset in local header */\n            err = mz_stream_set_prop_int64(zip->stream, MZ_STREAM_PROP_DISK_NUMBER, zip->file_info.disk_number);\n            if (err == MZ_OK)\n                err = mz_stream_seek(zip->stream, zip->file_info.disk_offset + MZ_ZIP_OFFSET_CRC_SIZES, MZ_SEEK_SET);\n        }\n\n        if (err == MZ_OK)\n            err = mz_zip_entry_write_crc_sizes(zip->stream, zip64, 0, &zip->file_info);\n\n        /* Seek to and update zip64 extension sizes */\n        if ((err == MZ_OK) && (zip64)) {\n            int64_t filename_size = zip->file_info.filename_size;\n\n            if (filename_size == 0)\n                filename_size = strlen(zip->file_info.filename);\n\n            /* Since we write zip64 extension first we know its offset */\n            err = mz_stream_seek(zip->stream, 2 + 2 + filename_size + 4, MZ_SEEK_CUR);\n\n            if (err == MZ_OK)\n                err = mz_stream_write_uint64(zip->stream, zip->file_info.uncompressed_size);\n            if (err == MZ_OK)\n                err = mz_stream_write_uint64(zip->stream, zip->file_info.compressed_size);\n        }\n\n        mz_stream_set_prop_int64(zip->stream, MZ_STREAM_PROP_DISK_NUMBER, end_disk_number);\n        mz_stream_seek(zip->stream, end_pos, MZ_SEEK_SET);\n    }\n\n    zip->number_entry += 1;\n\n    mz_zip_entry_close_int(handle);\n\n    return err;\n}\n\nint32_t mz_zip_entry_seek_local_header(void *handle) {\n    mz_zip *zip = (mz_zip *)handle;\n    int64_t disk_size = 0;\n    uint32_t disk_number = zip->file_info.disk_number;\n\n    if (disk_number == zip->disk_number_with_cd) {\n        mz_stream_get_prop_int64(zip->stream, MZ_STREAM_PROP_DISK_SIZE, &disk_size);\n        if ((disk_size == 0) || ((zip->open_mode & MZ_OPEN_MODE_WRITE) == 0))\n            disk_number = (uint32_t)-1;\n    }\n\n    mz_stream_set_prop_int64(zip->stream, MZ_STREAM_PROP_DISK_NUMBER, disk_number);\n\n    mz_zip_print(\"Zip - Entry - Seek local (disk %\" PRId32 \" offset %\" PRId64 \")\\n\",\n        disk_number, zip->file_info.disk_offset);\n\n    /* Guard against seek overflows */\n    if ((zip->disk_offset_shift > 0) &&\n        (zip->file_info.disk_offset > (INT64_MAX - zip->disk_offset_shift)))\n        return MZ_FORMAT_ERROR;\n\n    return mz_stream_seek(zip->stream, zip->file_info.disk_offset + zip->disk_offset_shift, MZ_SEEK_SET);\n}\n\nint32_t mz_zip_entry_get_compress_stream(void *handle, void **compress_stream) {\n    mz_zip *zip = (mz_zip *)handle;\n    if (!zip || !compress_stream)\n        return MZ_PARAM_ERROR;\n    *compress_stream = zip->compress_stream;\n    if (!*compress_stream)\n        return MZ_EXIST_ERROR;\n    return MZ_OK;\n}\n\nint32_t mz_zip_entry_close(void *handle) {\n    return mz_zip_entry_close_raw(handle, UINT64_MAX, 0);\n}\n\nint32_t mz_zip_entry_close_raw(void *handle, int64_t uncompressed_size, uint32_t crc32) {\n    mz_zip *zip = (mz_zip *)handle;\n    int32_t err = MZ_OK;\n\n    if (!zip || mz_zip_entry_is_open(handle) != MZ_OK)\n        return MZ_PARAM_ERROR;\n\n    if (zip->open_mode & MZ_OPEN_MODE_WRITE)\n        err = mz_zip_entry_write_close(handle, crc32, UINT64_MAX, uncompressed_size);\n    else\n        err = mz_zip_entry_read_close(handle, NULL, NULL, NULL);\n\n    return err;\n}\n\nint32_t mz_zip_entry_is_dir(void *handle) {\n    mz_zip *zip = (mz_zip *)handle;\n    int32_t filename_length = 0;\n\n    if (!zip || !zip->entry_scanned)\n        return MZ_PARAM_ERROR;\n    if (mz_zip_attrib_is_dir(zip->file_info.external_fa, zip->file_info.version_madeby) == MZ_OK)\n        return MZ_OK;\n\n    filename_length = (int32_t)strlen(zip->file_info.filename);\n    if (filename_length > 0) {\n        if ((zip->file_info.filename[filename_length - 1] == '/') ||\n            (zip->file_info.filename[filename_length - 1] == '\\\\'))\n            return MZ_OK;\n    }\n    return MZ_EXIST_ERROR;\n}\n\nint32_t mz_zip_entry_is_symlink(void *handle) {\n    mz_zip *zip = (mz_zip *)handle;\n\n    if (!zip || !zip->entry_scanned)\n        return MZ_PARAM_ERROR;\n    if (mz_zip_attrib_is_symlink(zip->file_info.external_fa, zip->file_info.version_madeby) != MZ_OK)\n        return MZ_EXIST_ERROR;\n\n    return MZ_OK;\n}\n\nint32_t mz_zip_entry_get_info(void *handle, mz_zip_file **file_info) {\n    mz_zip *zip = (mz_zip *)handle;\n\n    if (!zip)\n        return MZ_PARAM_ERROR;\n\n    if ((zip->open_mode & MZ_OPEN_MODE_WRITE) == 0) {\n        if (!zip->entry_scanned)\n            return MZ_PARAM_ERROR;\n    }\n\n    *file_info = &zip->file_info;\n    return MZ_OK;\n}\n\nint32_t mz_zip_entry_get_local_info(void *handle, mz_zip_file **local_file_info) {\n    mz_zip *zip = (mz_zip *)handle;\n    if (!zip || mz_zip_entry_is_open(handle) != MZ_OK)\n        return MZ_PARAM_ERROR;\n    *local_file_info = &zip->local_file_info;\n    return MZ_OK;\n}\n\nint32_t mz_zip_entry_set_extrafield(void *handle, const uint8_t *extrafield, uint16_t extrafield_size) {\n    mz_zip *zip = (mz_zip *)handle;\n\n    if (!zip || mz_zip_entry_is_open(handle) != MZ_OK)\n        return MZ_PARAM_ERROR;\n\n    zip->file_info.extrafield = extrafield;\n    zip->file_info.extrafield_size = extrafield_size;\n    return MZ_OK;\n}\n\nstatic int32_t mz_zip_goto_next_entry_int(void *handle) {\n    mz_zip *zip = (mz_zip *)handle;\n    int32_t err = MZ_OK;\n\n    if (!zip)\n        return MZ_PARAM_ERROR;\n\n    zip->entry_scanned = 0;\n\n    mz_stream_set_prop_int64(zip->cd_stream, MZ_STREAM_PROP_DISK_NUMBER, -1);\n\n    err = mz_stream_seek(zip->cd_stream, zip->cd_current_pos, MZ_SEEK_SET);\n    if (err == MZ_OK)\n        err = mz_zip_entry_read_header(zip->cd_stream, 0, &zip->file_info, zip->file_info_stream);\n    if (err == MZ_OK)\n        zip->entry_scanned = 1;\n    return err;\n}\n\nint64_t mz_zip_get_entry(void *handle) {\n    mz_zip *zip = (mz_zip *)handle;\n\n    if (!zip)\n        return MZ_PARAM_ERROR;\n\n    return zip->cd_current_pos;\n}\n\nint32_t mz_zip_goto_entry(void *handle, int64_t cd_pos) {\n    mz_zip *zip = (mz_zip *)handle;\n\n    if (!zip)\n        return MZ_PARAM_ERROR;\n\n    if (cd_pos < zip->cd_start_pos || cd_pos > zip->cd_start_pos + zip->cd_size)\n        return MZ_PARAM_ERROR;\n\n    zip->cd_current_pos = cd_pos;\n\n    return mz_zip_goto_next_entry_int(handle);\n}\n\nint32_t mz_zip_goto_first_entry(void *handle) {\n    mz_zip *zip = (mz_zip *)handle;\n\n    if (!zip)\n        return MZ_PARAM_ERROR;\n\n    zip->cd_current_pos = zip->cd_start_pos;\n\n    return mz_zip_goto_next_entry_int(handle);\n}\n\nint32_t mz_zip_goto_next_entry(void *handle) {\n    mz_zip *zip = (mz_zip *)handle;\n\n    if (!zip)\n        return MZ_PARAM_ERROR;\n\n    zip->cd_current_pos += (int64_t)MZ_ZIP_SIZE_CD_ITEM + zip->file_info.filename_size +\n        zip->file_info.extrafield_size + zip->file_info.comment_size;\n\n    return mz_zip_goto_next_entry_int(handle);\n}\n\nint32_t mz_zip_locate_entry(void *handle, const char *filename, uint8_t ignore_case) {\n    mz_zip *zip = (mz_zip *)handle;\n    int32_t err = MZ_OK;\n    int32_t result = 0;\n\n    if (!zip || !filename)\n        return MZ_PARAM_ERROR;\n\n    /* If we are already on the current entry, no need to search */\n    if (zip->entry_scanned && zip->file_info.filename) {\n        result = mz_zip_path_compare(zip->file_info.filename, filename, ignore_case);\n        if (result == 0)\n            return MZ_OK;\n    }\n\n    /* Search all entries starting at the first */\n    err = mz_zip_goto_first_entry(handle);\n    while (err == MZ_OK) {\n        result = mz_zip_path_compare(zip->file_info.filename, filename, ignore_case);\n        if (result == 0)\n            return MZ_OK;\n\n        err = mz_zip_goto_next_entry(handle);\n    }\n\n    return err;\n}\n\nint32_t mz_zip_locate_first_entry(void *handle, void *userdata, mz_zip_locate_entry_cb cb) {\n    mz_zip *zip = (mz_zip *)handle;\n    int32_t err = MZ_OK;\n    int32_t result = 0;\n\n    /* Search first entry looking for match */\n    err = mz_zip_goto_first_entry(handle);\n    if (err != MZ_OK)\n        return err;\n\n    result = cb(handle, userdata, &zip->file_info);\n    if (result == 0)\n        return MZ_OK;\n\n    return mz_zip_locate_next_entry(handle, userdata, cb);\n}\n\nint32_t mz_zip_locate_next_entry(void *handle, void *userdata, mz_zip_locate_entry_cb cb) {\n    mz_zip *zip = (mz_zip *)handle;\n    int32_t err = MZ_OK;\n    int32_t result = 0;\n\n    /* Search next entries looking for match */\n    err = mz_zip_goto_next_entry(handle);\n    while (err == MZ_OK) {\n        result = cb(handle, userdata, &zip->file_info);\n        if (result == 0)\n            return MZ_OK;\n\n        err = mz_zip_goto_next_entry(handle);\n    }\n\n    return err;\n}\n\n/***************************************************************************/\n\nint32_t mz_zip_attrib_is_dir(uint32_t attrib, int32_t version_madeby) {\n    uint32_t posix_attrib = 0;\n    uint8_t system = MZ_HOST_SYSTEM(version_madeby);\n    int32_t err = MZ_OK;\n\n    err = mz_zip_attrib_convert(system, attrib, MZ_HOST_SYSTEM_UNIX, &posix_attrib);\n    if (err == MZ_OK) {\n        if ((posix_attrib & 0170000) == 0040000) /* S_ISDIR */\n            return MZ_OK;\n    }\n\n    return MZ_EXIST_ERROR;\n}\n\nint32_t mz_zip_attrib_is_symlink(uint32_t attrib, int32_t version_madeby) {\n    uint32_t posix_attrib = 0;\n    uint8_t system = MZ_HOST_SYSTEM(version_madeby);\n    int32_t err = MZ_OK;\n\n    err = mz_zip_attrib_convert(system, attrib, MZ_HOST_SYSTEM_UNIX, &posix_attrib);\n    if (err == MZ_OK) {\n        if ((posix_attrib & 0170000) == 0120000) /* S_ISLNK */\n            return MZ_OK;\n    }\n\n    return MZ_EXIST_ERROR;\n}\n\nint32_t mz_zip_attrib_convert(uint8_t src_sys, uint32_t src_attrib, uint8_t target_sys, uint32_t *target_attrib) {\n    if (!target_attrib)\n        return MZ_PARAM_ERROR;\n\n    *target_attrib = 0;\n\n    if ((src_sys == MZ_HOST_SYSTEM_MSDOS) || (src_sys == MZ_HOST_SYSTEM_WINDOWS_NTFS)) {\n        if ((target_sys == MZ_HOST_SYSTEM_MSDOS) || (target_sys == MZ_HOST_SYSTEM_WINDOWS_NTFS)) {\n            *target_attrib = src_attrib;\n            return MZ_OK;\n        }\n        if ((target_sys == MZ_HOST_SYSTEM_UNIX) || (target_sys == MZ_HOST_SYSTEM_OSX_DARWIN) || (target_sys == MZ_HOST_SYSTEM_RISCOS))\n            return mz_zip_attrib_win32_to_posix(src_attrib, target_attrib);\n    } else if ((src_sys == MZ_HOST_SYSTEM_UNIX) || (src_sys == MZ_HOST_SYSTEM_OSX_DARWIN) || (src_sys == MZ_HOST_SYSTEM_RISCOS)) {\n        /* If high bytes are set, it contains unix specific attributes */\n        if ((src_attrib >> 16) != 0)\n            src_attrib >>= 16;\n\n        if ((target_sys == MZ_HOST_SYSTEM_UNIX) || (target_sys == MZ_HOST_SYSTEM_OSX_DARWIN) || (target_sys == MZ_HOST_SYSTEM_RISCOS)) {\n            *target_attrib = src_attrib;\n            return MZ_OK;\n        }\n        if ((target_sys == MZ_HOST_SYSTEM_MSDOS) || (target_sys == MZ_HOST_SYSTEM_WINDOWS_NTFS))\n            return mz_zip_attrib_posix_to_win32(src_attrib, target_attrib);\n    }\n\n    return MZ_SUPPORT_ERROR;\n}\n\nint32_t mz_zip_attrib_posix_to_win32(uint32_t posix_attrib, uint32_t *win32_attrib) {\n    if (!win32_attrib)\n        return MZ_PARAM_ERROR;\n\n    *win32_attrib = 0;\n\n    /* S_IWUSR | S_IWGRP | S_IWOTH | S_IXUSR | S_IXGRP | S_IXOTH */\n    if ((posix_attrib & 0000333) == 0 && (posix_attrib & 0000444) != 0)\n        *win32_attrib |= 0x01;      /* FILE_ATTRIBUTE_READONLY */\n    /* S_IFLNK */\n    if ((posix_attrib & 0170000) == 0120000)\n        *win32_attrib |= 0x400;     /* FILE_ATTRIBUTE_REPARSE_POINT */\n    /* S_IFDIR */\n    else if ((posix_attrib & 0170000) == 0040000)\n        *win32_attrib |= 0x10;      /* FILE_ATTRIBUTE_DIRECTORY */\n    /* S_IFREG */\n    else\n        *win32_attrib |= 0x80;      /* FILE_ATTRIBUTE_NORMAL */\n\n    return MZ_OK;\n}\n\nint32_t mz_zip_attrib_win32_to_posix(uint32_t win32_attrib, uint32_t *posix_attrib) {\n    if (!posix_attrib)\n        return MZ_PARAM_ERROR;\n\n    *posix_attrib = 0000444;        /* S_IRUSR | S_IRGRP | S_IROTH */\n    /* FILE_ATTRIBUTE_READONLY */\n    if ((win32_attrib & 0x01) == 0)\n        *posix_attrib |= 0000222;   /* S_IWUSR | S_IWGRP | S_IWOTH */\n    /* FILE_ATTRIBUTE_REPARSE_POINT */\n    if ((win32_attrib & 0x400) == 0x400)\n        *posix_attrib |= 0120000;   /* S_IFLNK */\n    /* FILE_ATTRIBUTE_DIRECTORY */\n    else if ((win32_attrib & 0x10) == 0x10)\n        *posix_attrib |= 0040111;   /* S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH */\n    else\n        *posix_attrib |= 0100000;   /* S_IFREG */\n\n    return MZ_OK;\n}\n\n/***************************************************************************/\n\nint32_t mz_zip_extrafield_find(void *stream, uint16_t type, int32_t max_seek, uint16_t *length) {\n    int32_t err = MZ_OK;\n    uint16_t field_type = 0;\n    uint16_t field_length = 0;\n\n    if (max_seek < 4)\n        return MZ_EXIST_ERROR;\n\n    do {\n        err = mz_stream_read_uint16(stream, &field_type);\n        if (err == MZ_OK)\n            err = mz_stream_read_uint16(stream, &field_length);\n        if (err != MZ_OK)\n            break;\n\n        if (type == field_type) {\n            if (length)\n                *length = field_length;\n            return MZ_OK;\n        }\n\n        max_seek -= field_length - 4;\n        if (max_seek < 0)\n            return MZ_EXIST_ERROR;\n\n        err = mz_stream_seek(stream, field_length, MZ_SEEK_CUR);\n    } while (err == MZ_OK);\n\n    return MZ_EXIST_ERROR;\n}\n\nint32_t mz_zip_extrafield_contains(const uint8_t *extrafield, int32_t extrafield_size,\n    uint16_t type, uint16_t *length) {\n    void *file_extra_stream = NULL;\n    int32_t err = MZ_OK;\n\n    if (!extrafield || !extrafield_size)\n        return MZ_PARAM_ERROR;\n\n    mz_stream_mem_create(&file_extra_stream);\n    mz_stream_mem_set_buffer(file_extra_stream, (void *)extrafield, extrafield_size);\n\n    err = mz_zip_extrafield_find(file_extra_stream, type, extrafield_size, length);\n\n    mz_stream_mem_delete(&file_extra_stream);\n\n    return err;\n}\n\nint32_t mz_zip_extrafield_read(void *stream, uint16_t *type, uint16_t *length) {\n    int32_t err = MZ_OK;\n    if (!type || !length)\n        return MZ_PARAM_ERROR;\n    err = mz_stream_read_uint16(stream, type);\n    if (err == MZ_OK)\n        err = mz_stream_read_uint16(stream, length);\n    return err;\n}\n\nint32_t mz_zip_extrafield_write(void *stream, uint16_t type, uint16_t length) {\n    int32_t err = MZ_OK;\n    err = mz_stream_write_uint16(stream, type);\n    if (err == MZ_OK)\n        err = mz_stream_write_uint16(stream, length);\n    return err;\n}\n\n/***************************************************************************/\n\nstatic int32_t mz_zip_invalid_date(const struct tm *ptm) {\n#define datevalue_in_range(min, max, value) ((min) <= (value) && (value) <= (max))\n    return (!datevalue_in_range(0, 127 + 80, ptm->tm_year) ||  /* 1980-based year, allow 80 extra */\n            !datevalue_in_range(0, 11, ptm->tm_mon) ||\n            !datevalue_in_range(1, 31, ptm->tm_mday) ||\n            !datevalue_in_range(0, 23, ptm->tm_hour) ||\n            !datevalue_in_range(0, 59, ptm->tm_min) ||\n            !datevalue_in_range(0, 59, ptm->tm_sec));\n#undef datevalue_in_range\n}\n\nstatic void mz_zip_dosdate_to_raw_tm(uint64_t dos_date, struct tm *ptm) {\n    uint64_t date = (uint64_t)(dos_date >> 16);\n\n    ptm->tm_mday  = (uint16_t)(date & 0x1f);\n    ptm->tm_mon   = (uint16_t)(((date & 0x1E0) / 0x20) - 1);\n    ptm->tm_year  = (uint16_t)(((date & 0x0FE00) / 0x0200) + 80);\n    ptm->tm_hour  = (uint16_t)((dos_date & 0xF800) / 0x800);\n    ptm->tm_min   = (uint16_t)((dos_date & 0x7E0) / 0x20);\n    ptm->tm_sec   = (uint16_t)(2 * (dos_date & 0x1f));\n    ptm->tm_isdst = -1;\n}\n\nint32_t mz_zip_dosdate_to_tm(uint64_t dos_date, struct tm *ptm) {\n    if (!ptm)\n        return MZ_PARAM_ERROR;\n\n    mz_zip_dosdate_to_raw_tm(dos_date, ptm);\n\n    if (mz_zip_invalid_date(ptm)) {\n        /* Invalid date stored, so don't return it */\n        memset(ptm, 0, sizeof(struct tm));\n        return MZ_FORMAT_ERROR;\n    }\n    return MZ_OK;\n}\n\ntime_t mz_zip_dosdate_to_time_t(uint64_t dos_date) {\n    struct tm ptm;\n    mz_zip_dosdate_to_raw_tm(dos_date, &ptm);\n    return mktime(&ptm);\n}\n\nint32_t mz_zip_time_t_to_tm(time_t unix_time, struct tm *ptm) {\n    struct tm ltm;\n    if (!ptm)\n        return MZ_PARAM_ERROR;\n    if (!localtime_r(&unix_time, &ltm)) { /* Returns a 1900-based year */\n        /* Invalid date stored, so don't return it */\n        memset(ptm, 0, sizeof(struct tm));\n        return MZ_INTERNAL_ERROR;\n    }\n    memcpy(ptm, &ltm, sizeof(struct tm));\n    return MZ_OK;\n}\n\nuint32_t mz_zip_time_t_to_dos_date(time_t unix_time) {\n    struct tm ptm;\n    mz_zip_time_t_to_tm(unix_time, &ptm);\n    return mz_zip_tm_to_dosdate((const struct tm *)&ptm);\n}\n\nuint32_t mz_zip_tm_to_dosdate(const struct tm *ptm) {\n    struct tm fixed_tm;\n\n    /* Years supported: */\n\n    /* [00, 79]      (assumed to be between 2000 and 2079) */\n    /* [80, 207]     (assumed to be between 1980 and 2107, typical output of old */\n    /*                software that does 'year-1900' to get a double digit year) */\n    /* [1980, 2107]  (due to format limitations, only years 1980-2107 can be stored.) */\n\n    memcpy(&fixed_tm, ptm, sizeof(struct tm));\n    if (fixed_tm.tm_year >= 1980) /* range [1980, 2107] */\n        fixed_tm.tm_year -= 1980;\n    else if (fixed_tm.tm_year >= 80) /* range [80, 207] */\n        fixed_tm.tm_year -= 80;\n    else /* range [00, 79] */\n        fixed_tm.tm_year += 20;\n\n    if (mz_zip_invalid_date(&fixed_tm))\n        return 0;\n\n    return (((uint32_t)fixed_tm.tm_mday + (32 * ((uint32_t)fixed_tm.tm_mon + 1)) + (512 * (uint32_t)fixed_tm.tm_year)) << 16) |\n        (((uint32_t)fixed_tm.tm_sec / 2) + (32 * (uint32_t)fixed_tm.tm_min) + (2048 * (uint32_t)fixed_tm.tm_hour));\n}\n\nint32_t mz_zip_ntfs_to_unix_time(uint64_t ntfs_time, time_t *unix_time) {\n    *unix_time = (time_t)((ntfs_time - 116444736000000000LL) / 10000000);\n    return MZ_OK;\n}\n\nint32_t mz_zip_unix_to_ntfs_time(time_t unix_time, uint64_t *ntfs_time) {\n    *ntfs_time = ((uint64_t)unix_time * 10000000) + 116444736000000000LL;\n    return MZ_OK;\n}\n\n/***************************************************************************/\n\nint32_t mz_zip_path_compare(const char *path1, const char *path2, uint8_t ignore_case) {\n    do {\n        if ((*path1 == '\\\\' && *path2 == '/') ||\n            (*path2 == '\\\\' && *path1 == '/')) {\n            /* Ignore comparison of path slashes */\n        } else if (ignore_case) {\n            if (tolower(*path1) != tolower(*path2))\n                break;\n        } else if (*path1 != *path2) {\n            break;\n        }\n\n        path1 += 1;\n        path2 += 1;\n    } while (*path1 != 0 && *path2 != 0);\n\n    if (ignore_case)\n        return (int32_t)(tolower(*path1) - tolower(*path2));\n\n    return (int32_t)(*path1 - *path2);\n}\n\n/***************************************************************************/\n\nconst char* mz_zip_get_compression_method_string(int32_t compression_method)\n{\n    const char *method = \"?\";\n    switch (compression_method) {\n    case MZ_COMPRESS_METHOD_STORE:\n        method = \"stored\";\n        break;\n    case MZ_COMPRESS_METHOD_DEFLATE:\n        method = \"deflate\";\n        break;\n    case MZ_COMPRESS_METHOD_BZIP2:\n        method = \"bzip2\";\n        break;\n    case MZ_COMPRESS_METHOD_LZMA:\n        method = \"lzma\";\n        break;\n    case MZ_COMPRESS_METHOD_XZ:\n        method = \"xz\";\n        break;\n    case MZ_COMPRESS_METHOD_ZSTD:\n        method = \"zstd\";\n        break;\n    }\n    return method;\n}\n\n/***************************************************************************/\n"
  },
  {
    "path": "ios/CodePush/SSZipArchive/minizip/mz_zip.h",
    "content": "/* mz_zip.h -- Zip manipulation\n   part of the minizip-ng project\n\n   Copyright (C) Nathan Moinvaziri\n     https://github.com/zlib-ng/minizip-ng\n   Copyright (C) 2009-2010 Mathias Svensson\n     Modifications for Zip64 support\n     http://result42.com\n   Copyright (C) 1998-2010 Gilles Vollant\n     https://www.winimage.com/zLibDll/minizip.html\n\n   This program is distributed under the terms of the same license as zlib.\n   See the accompanying LICENSE file for the full text of the license.\n*/\n\n#ifndef MZ_ZIP_H\n#define MZ_ZIP_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/***************************************************************************/\n\ntypedef struct mz_zip_file_s {\n    uint16_t version_madeby;            /* version made by */\n    uint16_t version_needed;            /* version needed to extract */\n    uint16_t flag;                      /* general purpose bit flag */\n    uint16_t compression_method;        /* compression method */\n    time_t   modified_date;             /* last modified date in unix time */\n    time_t   accessed_date;             /* last accessed date in unix time */\n    time_t   creation_date;             /* creation date in unix time */\n    uint32_t crc;                       /* crc-32 */\n    int64_t  compressed_size;           /* compressed size */\n    int64_t  uncompressed_size;         /* uncompressed size */\n    uint16_t filename_size;             /* filename length */\n    uint16_t extrafield_size;           /* extra field length */\n    uint16_t comment_size;              /* file comment length */\n    uint32_t disk_number;               /* disk number start */\n    int64_t  disk_offset;               /* relative offset of local header */\n    uint16_t internal_fa;               /* internal file attributes */\n    uint32_t external_fa;               /* external file attributes */\n\n    const char     *filename;           /* filename utf8 null-terminated string */\n    const uint8_t  *extrafield;         /* extrafield data */\n    const char     *comment;            /* comment utf8 null-terminated string */\n    const char     *linkname;           /* sym-link filename utf8 null-terminated string */\n\n    uint16_t zip64;                     /* zip64 extension mode */\n    uint16_t aes_version;               /* winzip aes extension if not 0 */\n    uint8_t  aes_encryption_mode;       /* winzip aes encryption mode */\n    uint16_t pk_verify;                 /* pkware encryption verifier */\n\n} mz_zip_file, mz_zip_entry;\n\n/***************************************************************************/\n\ntypedef int32_t (*mz_zip_locate_entry_cb)(void *handle, void *userdata, mz_zip_file *file_info);\n\n/***************************************************************************/\n\nvoid *  mz_zip_create(void **handle);\n/* Create zip instance for opening */\n\nvoid    mz_zip_delete(void **handle);\n/* Delete zip object */\n\nint32_t mz_zip_open(void *handle, void *stream, int32_t mode);\n/* Create a zip file, no delete file in zip functionality */\n\nint32_t mz_zip_close(void *handle);\n/* Close the zip file */\n\nint32_t mz_zip_get_comment(void *handle, const char **comment);\n/* Get a pointer to the global comment */\n\nint32_t mz_zip_set_comment(void *handle, const char *comment);\n/* Sets the global comment used for writing zip file */\n\nint32_t mz_zip_get_version_madeby(void *handle, uint16_t *version_madeby);\n/* Get the version made by */\n\nint32_t mz_zip_set_version_madeby(void *handle, uint16_t version_madeby);\n/* Sets the version made by used for writing zip file */\n\nint32_t mz_zip_set_recover(void *handle, uint8_t recover);\n/* Sets the ability to recover the central dir by reading local file headers */\n\nint32_t mz_zip_set_data_descriptor(void *handle, uint8_t data_descriptor);\n/* Sets the use of data descriptor flag when writing zip entries */\n\nint32_t mz_zip_get_stream(void *handle, void **stream);\n/* Get a pointer to the stream used to open */\n\nint32_t mz_zip_set_cd_stream(void *handle, int64_t cd_start_pos, void *cd_stream);\n/* Sets the stream to use for reading the central dir */\n\nint32_t mz_zip_get_cd_mem_stream(void *handle, void **cd_mem_stream);\n/* Get a pointer to the stream used to store the central dir in memory */\n\nint32_t mz_zip_set_number_entry(void *handle, uint64_t number_entry);\n/* Sets the total number of entries */\n\nint32_t mz_zip_get_number_entry(void *handle, uint64_t *number_entry);\n/* Get the total number of entries */\n\nint32_t mz_zip_set_disk_number_with_cd(void *handle, uint32_t disk_number_with_cd);\n/* Sets the disk number containing the central directory record */\n\nint32_t mz_zip_get_disk_number_with_cd(void *handle, uint32_t *disk_number_with_cd);\n/* Get the disk number containing the central directory record */\n\n/***************************************************************************/\n\nint32_t mz_zip_entry_is_open(void *handle);\n/* Check to see if entry is open for read/write */\n\nint32_t mz_zip_entry_read_open(void *handle, uint8_t raw, const char *password);\n/* Open for reading the current file in the zip file */\n\nint32_t mz_zip_entry_read(void *handle, void *buf, int32_t len);\n/* Read bytes from the current file in the zip file */\n\nint32_t mz_zip_entry_read_close(void *handle, uint32_t *crc32, int64_t *compressed_size,\n    int64_t *uncompressed_size);\n/* Close the current file for reading and get data descriptor values */\n\nint32_t mz_zip_entry_write_open(void *handle, const mz_zip_file *file_info,\n    int16_t compress_level, uint8_t raw, const char *password);\n/* Open for writing the current file in the zip file */\n\nint32_t mz_zip_entry_write(void *handle, const void *buf, int32_t len);\n/* Write bytes from the current file in the zip file */\n\nint32_t mz_zip_entry_write_close(void *handle, uint32_t crc32, int64_t compressed_size,\n    int64_t uncompressed_size);\n/* Close the current file for writing and set data descriptor values */\n\nint32_t mz_zip_entry_seek_local_header(void *handle);\n/* Seeks to the local header for the entry */\n\nint32_t mz_zip_entry_get_compress_stream(void *handle, void **compress_stream);\n/* Get a pointer to the compression stream used for the current entry */\n\nint32_t mz_zip_entry_close_raw(void *handle, int64_t uncompressed_size, uint32_t crc32);\n/* Close the current file in the zip file where raw is compressed data */\n\nint32_t mz_zip_entry_close(void *handle);\n/* Close the current file in the zip file */\n\n/***************************************************************************/\n\nint32_t mz_zip_entry_is_dir(void *handle);\n/* Checks to see if the entry is a directory */\n\nint32_t mz_zip_entry_is_symlink(void *handle);\n/* Checks to see if the entry is a symbolic link */\n\nint32_t mz_zip_entry_get_info(void *handle, mz_zip_file **file_info);\n/* Get info about the current file, only valid while current entry is open */\n\nint32_t mz_zip_entry_get_local_info(void *handle, mz_zip_file **local_file_info);\n/* Get local info about the current file, only valid while current entry is being read */\n\nint32_t mz_zip_entry_set_extrafield(void *handle, const uint8_t *extrafield, uint16_t extrafield_size);\n/* Sets or updates the extra field for the entry to be used before writing cd */\n\nint64_t mz_zip_get_entry(void *handle);\n/* Return offset of the current entry in the zip file */\n\nint32_t mz_zip_goto_entry(void *handle, int64_t cd_pos);\n/* Go to specified entry in the zip file */\n\nint32_t mz_zip_goto_first_entry(void *handle);\n/* Go to the first entry in the zip file */\n\nint32_t mz_zip_goto_next_entry(void *handle);\n/* Go to the next entry in the zip file or MZ_END_OF_LIST if reaching the end */\n\nint32_t mz_zip_locate_entry(void *handle, const char *filename, uint8_t ignore_case);\n/* Locate the file with the specified name in the zip file or MZ_END_LIST if not found */\n\nint32_t mz_zip_locate_first_entry(void *handle, void *userdata, mz_zip_locate_entry_cb cb);\n/* Locate the first matching entry based on a match callback */\n\nint32_t mz_zip_locate_next_entry(void *handle, void *userdata, mz_zip_locate_entry_cb cb);\n/* Locate the next matching entry based on a match callback */\n\n/***************************************************************************/\n\nint32_t mz_zip_attrib_is_dir(uint32_t attrib, int32_t version_madeby);\n/* Checks to see if the attribute is a directory based on platform */\n\nint32_t mz_zip_attrib_is_symlink(uint32_t attrib, int32_t version_madeby);\n/* Checks to see if the attribute is a symbolic link based on platform */\n\nint32_t mz_zip_attrib_convert(uint8_t src_sys, uint32_t src_attrib, uint8_t target_sys,\n    uint32_t *target_attrib);\n/* Converts file attributes from one host system to another */\n\nint32_t mz_zip_attrib_posix_to_win32(uint32_t posix_attrib, uint32_t *win32_attrib);\n/* Converts posix file attributes to win32 file attributes */\n\nint32_t mz_zip_attrib_win32_to_posix(uint32_t win32_attrib, uint32_t *posix_attrib);\n/* Converts win32 file attributes to posix file attributes */\n\n/***************************************************************************/\n\nint32_t mz_zip_extrafield_find(void *stream, uint16_t type, int32_t max_seek, uint16_t *length);\n/* Seeks to extra field by its type and returns its length */\n\nint32_t mz_zip_extrafield_contains(const uint8_t *extrafield, int32_t extrafield_size,\n    uint16_t type, uint16_t *length);\n/* Gets whether an extrafield exists and its size */\n\nint32_t mz_zip_extrafield_read(void *stream, uint16_t *type, uint16_t *length);\n/* Reads an extrafield header from a stream */\n\nint32_t mz_zip_extrafield_write(void *stream, uint16_t type, uint16_t length);\n/* Writes an extrafield header to a stream */\n\n/***************************************************************************/\n\nint32_t  mz_zip_dosdate_to_tm(uint64_t dos_date, struct tm *ptm);\n/* Convert dos date/time format to struct tm */\n\ntime_t   mz_zip_dosdate_to_time_t(uint64_t dos_date);\n/* Convert dos date/time format to time_t */\n\nint32_t  mz_zip_time_t_to_tm(time_t unix_time, struct tm *ptm);\n/* Convert time_t to time struct */\n\nuint32_t mz_zip_time_t_to_dos_date(time_t unix_time);\n/* Convert time_t to dos date/time format */\n\nuint32_t mz_zip_tm_to_dosdate(const struct tm *ptm);\n/* Convert struct tm to dos date/time format */\n\nint32_t  mz_zip_ntfs_to_unix_time(uint64_t ntfs_time, time_t *unix_time);\n/* Convert ntfs time to unix time */\n\nint32_t  mz_zip_unix_to_ntfs_time(time_t unix_time, uint64_t *ntfs_time);\n/* Convert unix time to ntfs time */\n\n/***************************************************************************/\n\nint32_t  mz_zip_path_compare(const char *path1, const char *path2, uint8_t ignore_case);\n/* Compare two paths without regard to slashes */\n\n/***************************************************************************/\n\nconst\nchar*    mz_zip_get_compression_method_string(int32_t compression_method);\n/* Gets a string representing the compression method */\n\n/***************************************************************************/\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* _ZIP_H */\n"
  },
  {
    "path": "ios/CodePush/SSZipArchive/minizip/mz_zip_rw.c",
    "content": "/* mz_zip_rw.c -- Zip reader/writer\n   part of the minizip-ng project\n\n   Copyright (C) Nathan Moinvaziri\n     https://github.com/zlib-ng/minizip-ng\n\n   This program is distributed under the terms of the same license as zlib.\n   See the accompanying LICENSE file for the full text of the license.\n*/\n\n#include \"mz.h\"\n#include \"mz_crypt.h\"\n#include \"mz_os.h\"\n#include \"mz_strm.h\"\n#include \"mz_strm_buf.h\"\n#include \"mz_strm_mem.h\"\n#include \"mz_strm_os.h\"\n#include \"mz_strm_split.h\"\n#include \"mz_strm_wzaes.h\"\n#include \"mz_zip.h\"\n\n#include \"mz_zip_rw.h\"\n\n/***************************************************************************/\n\n#define MZ_DEFAULT_PROGRESS_INTERVAL    (1000u)\n\n#define MZ_ZIP_CD_FILENAME              (\"__cdcd__\")\n\n/***************************************************************************/\n\ntypedef struct mz_zip_reader_s {\n    void        *zip_handle;\n    void        *file_stream;\n    void        *buffered_stream;\n    void        *split_stream;\n    void        *mem_stream;\n    void        *hash;\n    uint16_t    hash_algorithm;\n    uint16_t    hash_digest_size;\n    mz_zip_file *file_info;\n    const char  *pattern;\n    uint8_t     pattern_ignore_case;\n    const char  *password;\n    void        *overwrite_userdata;\n    mz_zip_reader_overwrite_cb\n                overwrite_cb;\n    void        *password_userdata;\n    mz_zip_reader_password_cb\n                password_cb;\n    void        *progress_userdata;\n    mz_zip_reader_progress_cb\n                progress_cb;\n    uint32_t    progress_cb_interval_ms;\n    void        *entry_userdata;\n    mz_zip_reader_entry_cb\n                entry_cb;\n    uint8_t     raw;\n    uint8_t     buffer[UINT16_MAX];\n    int32_t     encoding;\n    uint8_t     sign_required;\n    uint8_t     cd_verified;\n    uint8_t     cd_zipped;\n    uint8_t     entry_verified;\n    uint8_t     recover;\n} mz_zip_reader;\n\n/***************************************************************************/\n\nint32_t mz_zip_reader_is_open(void *handle) {\n    mz_zip_reader *reader = (mz_zip_reader *)handle;\n    if (!reader)\n        return MZ_PARAM_ERROR;\n    if (!reader->zip_handle)\n        return MZ_PARAM_ERROR;\n    return MZ_OK;\n}\n\nint32_t mz_zip_reader_open(void *handle, void *stream) {\n    mz_zip_reader *reader = (mz_zip_reader *)handle;\n    int32_t err = MZ_OK;\n\n    reader->cd_verified = 0;\n    reader->cd_zipped = 0;\n\n    mz_zip_create(&reader->zip_handle);\n    mz_zip_set_recover(reader->zip_handle, reader->recover);\n\n    err = mz_zip_open(reader->zip_handle, stream, MZ_OPEN_MODE_READ);\n\n    if (err != MZ_OK) {\n        mz_zip_reader_close(handle);\n        return err;\n    }\n\n    mz_zip_reader_unzip_cd(reader);\n    return MZ_OK;\n}\n\nint32_t mz_zip_reader_open_file(void *handle, const char *path) {\n    mz_zip_reader *reader = (mz_zip_reader *)handle;\n    int32_t err = MZ_OK;\n\n    mz_zip_reader_close(handle);\n\n    mz_stream_os_create(&reader->file_stream);\n    mz_stream_buffered_create(&reader->buffered_stream);\n    mz_stream_split_create(&reader->split_stream);\n\n    mz_stream_set_base(reader->buffered_stream, reader->file_stream);\n    mz_stream_set_base(reader->split_stream, reader->buffered_stream);\n\n    err = mz_stream_open(reader->split_stream, path, MZ_OPEN_MODE_READ);\n    if (err == MZ_OK)\n        err = mz_zip_reader_open(handle, reader->split_stream);\n    return err;\n}\n\nint32_t mz_zip_reader_open_file_in_memory(void *handle, const char *path) {\n    mz_zip_reader *reader = (mz_zip_reader *)handle;\n    void *file_stream = NULL;\n    int64_t file_size = 0;\n    int32_t err = 0;\n\n    mz_zip_reader_close(handle);\n\n    mz_stream_os_create(&file_stream);\n\n    err = mz_stream_os_open(file_stream, path, MZ_OPEN_MODE_READ);\n\n    if (err != MZ_OK) {\n        mz_stream_os_delete(&file_stream);\n        mz_zip_reader_close(handle);\n        return err;\n    }\n\n    mz_stream_os_seek(file_stream, 0, MZ_SEEK_END);\n    file_size = mz_stream_os_tell(file_stream);\n    mz_stream_os_seek(file_stream, 0, MZ_SEEK_SET);\n\n    if ((file_size <= 0) || (file_size > UINT32_MAX)) {\n        /* Memory size is too large or too small */\n\n        mz_stream_os_close(file_stream);\n        mz_stream_os_delete(&file_stream);\n        mz_zip_reader_close(handle);\n        return MZ_MEM_ERROR;\n    }\n\n    mz_stream_mem_create(&reader->mem_stream);\n    mz_stream_mem_set_grow_size(reader->mem_stream, (int32_t)file_size);\n    mz_stream_mem_open(reader->mem_stream, NULL, MZ_OPEN_MODE_CREATE);\n\n    err = mz_stream_copy(reader->mem_stream, file_stream, (int32_t)file_size);\n\n    mz_stream_os_close(file_stream);\n    mz_stream_os_delete(&file_stream);\n\n    if (err == MZ_OK)\n        err = mz_zip_reader_open(handle, reader->mem_stream);\n    if (err != MZ_OK)\n        mz_zip_reader_close(handle);\n\n    return err;\n}\n\nint32_t mz_zip_reader_open_buffer(void *handle, uint8_t *buf, int32_t len, uint8_t copy) {\n    mz_zip_reader *reader = (mz_zip_reader *)handle;\n    int32_t err = MZ_OK;\n\n    mz_zip_reader_close(handle);\n\n    mz_stream_mem_create(&reader->mem_stream);\n\n    if (copy) {\n        mz_stream_mem_set_grow_size(reader->mem_stream, len);\n        mz_stream_mem_open(reader->mem_stream, NULL, MZ_OPEN_MODE_CREATE);\n        mz_stream_mem_write(reader->mem_stream, buf, len);\n        mz_stream_mem_seek(reader->mem_stream, 0, MZ_SEEK_SET);\n    } else {\n        mz_stream_mem_open(reader->mem_stream, NULL, MZ_OPEN_MODE_READ);\n        mz_stream_mem_set_buffer(reader->mem_stream, buf, len);\n    }\n\n    if (err == MZ_OK)\n        err = mz_zip_reader_open(handle, reader->mem_stream);\n\n    return err;\n}\n\nint32_t mz_zip_reader_close(void *handle) {\n    mz_zip_reader *reader = (mz_zip_reader *)handle;\n    int32_t err = MZ_OK;\n\n    if (reader->zip_handle) {\n        err = mz_zip_close(reader->zip_handle);\n        mz_zip_delete(&reader->zip_handle);\n    }\n\n    if (reader->split_stream) {\n        mz_stream_split_close(reader->split_stream);\n        mz_stream_split_delete(&reader->split_stream);\n    }\n\n    if (reader->buffered_stream)\n        mz_stream_buffered_delete(&reader->buffered_stream);\n\n    if (reader->file_stream)\n        mz_stream_os_delete(&reader->file_stream);\n\n    if (reader->mem_stream) {\n        mz_stream_close(reader->mem_stream);\n        mz_stream_delete(&reader->mem_stream);\n    }\n\n    return err;\n}\n\n/***************************************************************************/\n\nint32_t mz_zip_reader_unzip_cd(void *handle) {\n    mz_zip_reader *reader = (mz_zip_reader *)handle;\n    mz_zip_file *cd_info = NULL;\n    void *cd_mem_stream = NULL;\n    void *new_cd_stream = NULL;\n    void *file_extra_stream = NULL;\n    uint64_t number_entry = 0;\n    int32_t err = MZ_OK;\n\n    err = mz_zip_reader_goto_first_entry(handle);\n    if (err != MZ_OK)\n        return err;\n    err = mz_zip_reader_entry_get_info(handle, &cd_info);\n    if (err != MZ_OK)\n        return err;\n\n    if (strcmp(cd_info->filename, MZ_ZIP_CD_FILENAME) != 0)\n        return mz_zip_reader_goto_first_entry(handle);\n\n    err = mz_zip_reader_entry_open(handle);\n    if (err != MZ_OK)\n        return err;\n\n    mz_stream_mem_create(&file_extra_stream);\n    mz_stream_mem_set_buffer(file_extra_stream, (void *)cd_info->extrafield, cd_info->extrafield_size);\n\n    err = mz_zip_extrafield_find(file_extra_stream, MZ_ZIP_EXTENSION_CDCD, INT32_MAX, NULL);\n    if (err == MZ_OK)\n        err = mz_stream_read_uint64(file_extra_stream, &number_entry);\n\n    mz_stream_mem_delete(&file_extra_stream);\n\n    if (err != MZ_OK)\n        return err;\n\n    mz_zip_get_cd_mem_stream(reader->zip_handle, &cd_mem_stream);\n    if (mz_stream_mem_is_open(cd_mem_stream) != MZ_OK)\n        mz_stream_mem_open(cd_mem_stream, NULL, MZ_OPEN_MODE_CREATE);\n\n    err = mz_stream_seek(cd_mem_stream, 0, MZ_SEEK_SET);\n    if (err == MZ_OK)\n        err = mz_stream_copy_stream(cd_mem_stream, NULL, handle, mz_zip_reader_entry_read,\n            (int32_t)cd_info->uncompressed_size);\n\n    if (err == MZ_OK) {\n        reader->cd_zipped = 1;\n\n        mz_zip_set_cd_stream(reader->zip_handle, 0, cd_mem_stream);\n        mz_zip_set_number_entry(reader->zip_handle, number_entry);\n\n        err = mz_zip_reader_goto_first_entry(handle);\n    }\n\n    reader->cd_verified = reader->entry_verified;\n\n    mz_stream_mem_delete(&new_cd_stream);\n    return err;\n}\n\n/***************************************************************************/\n\nstatic int32_t mz_zip_reader_locate_entry_cb(void *handle, void *userdata, mz_zip_file *file_info) {\n    mz_zip_reader *reader = (mz_zip_reader *)userdata;\n    int32_t result = 0;\n    MZ_UNUSED(handle);\n    result = mz_path_compare_wc(file_info->filename, reader->pattern, reader->pattern_ignore_case);\n    return result;\n}\n\nint32_t mz_zip_reader_goto_first_entry(void *handle) {\n    mz_zip_reader *reader = (mz_zip_reader *)handle;\n    int32_t err = MZ_OK;\n\n    if (mz_zip_reader_is_open(handle) != MZ_OK)\n        return MZ_PARAM_ERROR;\n\n    if (mz_zip_entry_is_open(reader->zip_handle) == MZ_OK)\n        mz_zip_reader_entry_close(handle);\n\n    if (!reader->pattern)\n        err = mz_zip_goto_first_entry(reader->zip_handle);\n    else\n        err = mz_zip_locate_first_entry(reader->zip_handle, reader, mz_zip_reader_locate_entry_cb);\n\n    reader->file_info = NULL;\n    if (err == MZ_OK)\n        err = mz_zip_entry_get_info(reader->zip_handle, &reader->file_info);\n\n    return err;\n}\n\nint32_t mz_zip_reader_goto_next_entry(void *handle) {\n    mz_zip_reader *reader = (mz_zip_reader *)handle;\n    int32_t err = MZ_OK;\n\n    if (mz_zip_reader_is_open(handle) != MZ_OK)\n        return MZ_PARAM_ERROR;\n\n    if (mz_zip_entry_is_open(reader->zip_handle) == MZ_OK)\n        mz_zip_reader_entry_close(handle);\n\n    if (!reader->pattern)\n        err = mz_zip_goto_next_entry(reader->zip_handle);\n    else\n        err = mz_zip_locate_next_entry(reader->zip_handle, reader, mz_zip_reader_locate_entry_cb);\n\n    reader->file_info = NULL;\n    if (err == MZ_OK)\n        err = mz_zip_entry_get_info(reader->zip_handle, &reader->file_info);\n\n    return err;\n}\n\nint32_t mz_zip_reader_locate_entry(void *handle, const char *filename, uint8_t ignore_case) {\n    mz_zip_reader *reader = (mz_zip_reader *)handle;\n    int32_t err = MZ_OK;\n\n    if (mz_zip_entry_is_open(reader->zip_handle) == MZ_OK)\n        mz_zip_reader_entry_close(handle);\n\n    err = mz_zip_locate_entry(reader->zip_handle, filename, ignore_case);\n\n    reader->file_info = NULL;\n    if (err == MZ_OK)\n        err = mz_zip_entry_get_info(reader->zip_handle, &reader->file_info);\n\n    return err;\n}\n\n/***************************************************************************/\n\nint32_t mz_zip_reader_entry_open(void *handle) {\n    mz_zip_reader *reader = (mz_zip_reader *)handle;\n    int32_t err = MZ_OK;\n    const char *password = NULL;\n    char password_buf[120];\n\n    reader->entry_verified = 0;\n\n    if (mz_zip_reader_is_open(reader) != MZ_OK)\n        return MZ_PARAM_ERROR;\n    if (!reader->file_info)\n        return MZ_PARAM_ERROR;\n\n    /* If the entry isn't open for reading, open it */\n    if (mz_zip_entry_is_open(reader->zip_handle) == MZ_OK)\n        return MZ_OK;\n\n    password = reader->password;\n\n    /* Check if we need a password and ask for it if we need to */\n    if (!password && reader->password_cb && (reader->file_info->flag & MZ_ZIP_FLAG_ENCRYPTED)) {\n        reader->password_cb(handle, reader->password_userdata, reader->file_info,\n            password_buf, sizeof(password_buf));\n\n        password = password_buf;\n    }\n\n    err = mz_zip_entry_read_open(reader->zip_handle, reader->raw, password);\n#ifndef MZ_ZIP_NO_CRYPTO\n    if (err != MZ_OK)\n        return err;\n\n    if (mz_zip_reader_entry_get_first_hash(handle, &reader->hash_algorithm, &reader->hash_digest_size) == MZ_OK) {\n        mz_crypt_sha_create(&reader->hash);\n        if (reader->hash_algorithm == MZ_HASH_SHA1)\n            mz_crypt_sha_set_algorithm(reader->hash, MZ_HASH_SHA1);\n        else if (reader->hash_algorithm == MZ_HASH_SHA256)\n            mz_crypt_sha_set_algorithm(reader->hash, MZ_HASH_SHA256);\n        else\n            err = MZ_SUPPORT_ERROR;\n\n        if (err == MZ_OK)\n            mz_crypt_sha_begin(reader->hash);\n#ifdef MZ_ZIP_SIGNING\n        if (err == MZ_OK) {\n            if (mz_zip_reader_entry_has_sign(handle) == MZ_OK) {\n                err = mz_zip_reader_entry_sign_verify(handle);\n                if (err == MZ_OK)\n                    reader->entry_verified = 1;\n            } else if (reader->sign_required && !reader->cd_verified)\n                err = MZ_SIGN_ERROR;\n        }\n#endif\n    } else if (reader->sign_required && !reader->cd_verified)\n        err = MZ_SIGN_ERROR;\n#endif\n\n    return err;\n}\n\nint32_t mz_zip_reader_entry_close(void *handle) {\n    mz_zip_reader *reader = (mz_zip_reader *)handle;\n    int32_t err = MZ_OK;\n    int32_t err_close = MZ_OK;\n#ifndef MZ_ZIP_NO_CRYPTO\n    int32_t err_hash = MZ_OK;\n    uint8_t computed_hash[MZ_HASH_MAX_SIZE];\n    uint8_t expected_hash[MZ_HASH_MAX_SIZE];\n\n    if (reader->hash) {\n        mz_crypt_sha_end(reader->hash, computed_hash, sizeof(computed_hash));\n        mz_crypt_sha_delete(&reader->hash);\n\n        err_hash = mz_zip_reader_entry_get_hash(handle, reader->hash_algorithm, expected_hash,\n            reader->hash_digest_size);\n\n        if (err_hash == MZ_OK) {\n            /* Verify expected hash against computed hash */\n            if (memcmp(computed_hash, expected_hash, reader->hash_digest_size) != 0)\n                err = MZ_CRC_ERROR;\n        }\n    }\n#endif\n\n    err_close = mz_zip_entry_close(reader->zip_handle);\n    if (err == MZ_OK)\n        err = err_close;\n    return err;\n}\n\nint32_t mz_zip_reader_entry_read(void *handle, void *buf, int32_t len) {\n    mz_zip_reader *reader = (mz_zip_reader *)handle;\n    int32_t read = 0;\n    read = mz_zip_entry_read(reader->zip_handle, buf, len);\n#ifndef MZ_ZIP_NO_CRYPTO\n    if (read > 0 && reader->hash)\n        mz_crypt_sha_update(reader->hash, buf, read);\n#endif\n    return read;\n}\n\nint32_t mz_zip_reader_entry_has_sign(void *handle) {\n    mz_zip_reader *reader = (mz_zip_reader *)handle;\n\n    if (!reader || mz_zip_entry_is_open(reader->zip_handle) != MZ_OK)\n        return MZ_PARAM_ERROR;\n\n    return mz_zip_extrafield_contains(reader->file_info->extrafield,\n        reader->file_info->extrafield_size, MZ_ZIP_EXTENSION_SIGN, NULL);\n}\n\n#if !defined(MZ_ZIP_NO_CRYPTO) && defined(MZ_ZIP_SIGNING)\nint32_t mz_zip_reader_entry_sign_verify(void *handle) {\n    mz_zip_reader *reader = (mz_zip_reader *)handle;\n    void *file_extra_stream = NULL;\n    int32_t err = MZ_OK;\n    uint8_t *signature = NULL;\n    uint16_t signature_size = 0;\n    uint8_t hash[MZ_HASH_MAX_SIZE];\n\n    if (!reader || mz_zip_entry_is_open(reader->zip_handle) != MZ_OK)\n        return MZ_PARAM_ERROR;\n\n    mz_stream_mem_create(&file_extra_stream);\n    mz_stream_mem_set_buffer(file_extra_stream, (void *)reader->file_info->extrafield,\n        reader->file_info->extrafield_size);\n\n    err = mz_zip_extrafield_find(file_extra_stream, MZ_ZIP_EXTENSION_SIGN, INT32_MAX, &signature_size);\n    if ((err == MZ_OK) && (signature_size > 0)) {\n        signature = (uint8_t *)malloc(signature_size);\n        if (mz_stream_read(file_extra_stream, signature, signature_size) != signature_size)\n            err = MZ_READ_ERROR;\n    }\n\n    mz_stream_mem_delete(&file_extra_stream);\n\n    if (err == MZ_OK) {\n        /* Get most secure hash to verify signature against */\n        err = mz_zip_reader_entry_get_hash(handle, reader->hash_algorithm, hash, reader->hash_digest_size);\n    }\n\n    if (err == MZ_OK) {\n        /* Verify the pkcs signature */\n        err = mz_crypt_sign_verify(hash, reader->hash_digest_size, signature, signature_size);\n    }\n\n    if (signature)\n        free(signature);\n\n    return err;\n}\n#endif\n\nint32_t mz_zip_reader_entry_get_hash(void *handle, uint16_t algorithm, uint8_t *digest, int32_t digest_size) {\n    mz_zip_reader *reader = (mz_zip_reader *)handle;\n    void *file_extra_stream = NULL;\n    int32_t err = MZ_OK;\n    int32_t return_err = MZ_EXIST_ERROR;\n    uint16_t cur_algorithm = 0;\n    uint16_t cur_digest_size = 0;\n\n    mz_stream_mem_create(&file_extra_stream);\n    mz_stream_mem_set_buffer(file_extra_stream, (void *)reader->file_info->extrafield,\n        reader->file_info->extrafield_size);\n\n    do {\n        err = mz_zip_extrafield_find(file_extra_stream, MZ_ZIP_EXTENSION_HASH, INT32_MAX, NULL);\n        if (err != MZ_OK)\n            break;\n\n        err = mz_stream_read_uint16(file_extra_stream, &cur_algorithm);\n        if (err == MZ_OK)\n            err = mz_stream_read_uint16(file_extra_stream, &cur_digest_size);\n        if ((err == MZ_OK) && (cur_algorithm == algorithm) && (cur_digest_size <= digest_size) &&\n            (cur_digest_size <= MZ_HASH_MAX_SIZE)) {\n            /* Read hash digest */\n            if (mz_stream_read(file_extra_stream, digest, digest_size) == cur_digest_size)\n                return_err = MZ_OK;\n            break;\n        } else {\n            err = mz_stream_seek(file_extra_stream, cur_digest_size, MZ_SEEK_CUR);\n        }\n    } while (err == MZ_OK);\n\n    mz_stream_mem_delete(&file_extra_stream);\n\n    return return_err;\n}\n\nint32_t mz_zip_reader_entry_get_first_hash(void *handle, uint16_t *algorithm, uint16_t *digest_size) {\n    mz_zip_reader *reader = (mz_zip_reader *)handle;\n    void *file_extra_stream = NULL;\n    int32_t err = MZ_OK;\n    uint16_t cur_algorithm = 0;\n    uint16_t cur_digest_size = 0;\n\n    if (!reader || !algorithm)\n        return MZ_PARAM_ERROR;\n\n    mz_stream_mem_create(&file_extra_stream);\n    mz_stream_mem_set_buffer(file_extra_stream, (void *)reader->file_info->extrafield,\n        reader->file_info->extrafield_size);\n\n    err = mz_zip_extrafield_find(file_extra_stream, MZ_ZIP_EXTENSION_HASH, INT32_MAX, NULL);\n    if (err == MZ_OK)\n        err = mz_stream_read_uint16(file_extra_stream, &cur_algorithm);\n    if (err == MZ_OK)\n        err = mz_stream_read_uint16(file_extra_stream, &cur_digest_size);\n\n    if (algorithm)\n        *algorithm = cur_algorithm;\n    if (digest_size)\n        *digest_size = cur_digest_size;\n\n    mz_stream_mem_delete(&file_extra_stream);\n\n    return err;\n}\n\nint32_t mz_zip_reader_entry_get_info(void *handle, mz_zip_file **file_info) {\n    mz_zip_reader *reader = (mz_zip_reader *)handle;\n    int32_t err = MZ_OK;\n    if (!file_info || mz_zip_reader_is_open(handle) != MZ_OK)\n        return MZ_PARAM_ERROR;\n    *file_info = reader->file_info;\n    if (!*file_info)\n        return MZ_EXIST_ERROR;\n    return err;\n}\n\nint32_t mz_zip_reader_entry_is_dir(void *handle) {\n    mz_zip_reader *reader = (mz_zip_reader *)handle;\n    if (mz_zip_reader_is_open(handle) != MZ_OK)\n        return MZ_PARAM_ERROR;\n    return mz_zip_entry_is_dir(reader->zip_handle);\n}\n\nint32_t mz_zip_reader_entry_save_process(void *handle, void *stream, mz_stream_write_cb write_cb) {\n    mz_zip_reader *reader = (mz_zip_reader *)handle;\n    int32_t err = MZ_OK;\n    int32_t read = 0;\n    int32_t written = 0;\n\n    if (mz_zip_reader_is_open(reader) != MZ_OK)\n        return MZ_PARAM_ERROR;\n    if (!reader->file_info || !write_cb)\n        return MZ_PARAM_ERROR;\n\n    /* If the entry isn't open for reading, open it */\n    if (mz_zip_entry_is_open(reader->zip_handle) != MZ_OK)\n        err = mz_zip_reader_entry_open(handle);\n\n    if (err != MZ_OK)\n        return err;\n\n    /* Unzip entry in zip file */\n    read = mz_zip_reader_entry_read(handle, reader->buffer, sizeof(reader->buffer));\n\n    if (read == 0) {\n        /* If we are done close the entry */\n        err = mz_zip_reader_entry_close(handle);\n        if (err != MZ_OK)\n            return err;\n\n        return MZ_END_OF_STREAM;\n    }\n\n    if (read > 0) {\n        /* Write the data to the specified stream */\n        written = write_cb(stream, reader->buffer, read);\n        if (written != read)\n            return MZ_WRITE_ERROR;\n    }\n\n    return read;\n}\n\nint32_t mz_zip_reader_entry_save(void *handle, void *stream, mz_stream_write_cb write_cb) {\n    mz_zip_reader *reader = (mz_zip_reader *)handle;\n    uint64_t current_time = 0;\n    uint64_t update_time = 0;\n    int64_t current_pos = 0;\n    int64_t update_pos = 0;\n    int32_t err = MZ_OK;\n    int32_t written = 0;\n\n    if (mz_zip_reader_is_open(reader) != MZ_OK)\n        return MZ_PARAM_ERROR;\n    if (!reader->file_info)\n        return MZ_PARAM_ERROR;\n\n    /* Update the progress at the beginning */\n    if (reader->progress_cb)\n        reader->progress_cb(handle, reader->progress_userdata, reader->file_info, current_pos);\n\n    /* Write data to stream until done */\n    while (err == MZ_OK) {\n        written = mz_zip_reader_entry_save_process(handle, stream, write_cb);\n        if (written == MZ_END_OF_STREAM)\n            break;\n        if (written > 0)\n            current_pos += written;\n        if (written < 0)\n            err = written;\n\n        /* Update progress if enough time have passed */\n        current_time = mz_os_ms_time();\n        if ((current_time - update_time) > reader->progress_cb_interval_ms) {\n            if (reader->progress_cb)\n                reader->progress_cb(handle, reader->progress_userdata, reader->file_info, current_pos);\n\n            update_pos = current_pos;\n            update_time = current_time;\n        }\n    }\n\n    /* Update the progress at the end */\n    if (reader->progress_cb && update_pos != current_pos)\n        reader->progress_cb(handle, reader->progress_userdata, reader->file_info, current_pos);\n\n    return err;\n}\n\nint32_t mz_zip_reader_entry_save_file(void *handle, const char *path) {\n    mz_zip_reader *reader = (mz_zip_reader *)handle;\n    void *stream = NULL;\n    uint32_t target_attrib = 0;\n    int32_t err_attrib = 0;\n    int32_t err = MZ_OK;\n    int32_t err_cb = MZ_OK;\n    char pathwfs[512];\n    char directory[512];\n\n    if (mz_zip_reader_is_open(reader) != MZ_OK)\n        return MZ_PARAM_ERROR;\n    if (!reader->file_info || !path)\n        return MZ_PARAM_ERROR;\n\n    /* Convert to forward slashes for unix which doesn't like backslashes */\n    strncpy(pathwfs, path, sizeof(pathwfs) - 1);\n    pathwfs[sizeof(pathwfs) - 1] = 0;\n    mz_path_convert_slashes(pathwfs, MZ_PATH_SLASH_UNIX);\n\n    if (reader->entry_cb)\n        reader->entry_cb(handle, reader->entry_userdata, reader->file_info, pathwfs);\n\n    strncpy(directory, pathwfs, sizeof(directory) - 1);\n    directory[sizeof(directory) - 1] = 0;\n    mz_path_remove_filename(directory);\n\n    /* If it is a directory entry then create a directory instead of writing file */\n    if ((mz_zip_entry_is_dir(reader->zip_handle) == MZ_OK) &&\n        (mz_zip_entry_is_symlink(reader->zip_handle) != MZ_OK)) {\n        err = mz_dir_make(directory);\n        return err;\n    }\n\n    /* Check if file exists and ask if we want to overwrite */\n    if (reader->overwrite_cb && mz_os_file_exists(pathwfs) == MZ_OK) {\n        err_cb = reader->overwrite_cb(handle, reader->overwrite_userdata, reader->file_info, pathwfs);\n        if (err_cb != MZ_OK)\n            return err;\n        /* We want to overwrite the file so we delete the existing one */\n        mz_os_unlink(pathwfs);\n    }\n\n    /* If symbolic link then properly construct destination path and link path */\n    if ((mz_zip_entry_is_symlink(reader->zip_handle) == MZ_OK) &&\n        (mz_path_has_slash(pathwfs) == MZ_OK)) {\n        mz_path_remove_slash(pathwfs);\n        mz_path_remove_filename(directory);\n    }\n\n    /* Create the output directory if it doesn't already exist */\n    if (mz_os_is_dir(directory) != MZ_OK) {\n        err = mz_dir_make(directory);\n        if (err != MZ_OK)\n            return err;\n    }\n\n    /* If it is a symbolic link then create symbolic link instead of writing file */\n    if (mz_zip_entry_is_symlink(reader->zip_handle) == MZ_OK) {\n        if (reader->file_info->linkname && *reader->file_info->linkname != 0) {\n            /* Create symbolic link from UNIX1 extrafield */\n            err = mz_os_make_symlink(pathwfs, reader->file_info->linkname);\n        } else if (reader->file_info->uncompressed_size < UINT16_MAX) {\n            /* Create symbolic link from zip entry contents */\n            mz_stream_mem_create(&stream);\n            err = mz_stream_mem_open(stream, NULL, MZ_OPEN_MODE_CREATE);\n\n            if (err == MZ_OK)\n                err = mz_zip_reader_entry_save(handle, stream, mz_stream_write);\n\n            if (err == MZ_OK)\n                err = mz_stream_write_uint8(stream, 0);\n\n            if (err == MZ_OK) {\n                const char *linkname = NULL;\n                if (mz_stream_mem_get_buffer(stream, (const void **)&linkname) == MZ_OK)\n                    err = mz_os_make_symlink(pathwfs, linkname);\n            }\n\n            mz_stream_mem_close(stream);\n            mz_stream_mem_delete(&stream);\n        }\n\n        /* Don't check return value because we aren't validating symbolic link target */\n        return err;\n    }\n\n    /* Create the file on disk so we can save to it */\n    mz_stream_os_create(&stream);\n    err = mz_stream_os_open(stream, pathwfs, MZ_OPEN_MODE_CREATE);\n\n    if (err == MZ_OK)\n        err = mz_zip_reader_entry_save(handle, stream, mz_stream_write);\n\n    mz_stream_close(stream);\n    mz_stream_delete(&stream);\n\n    if (err == MZ_OK) {\n        /* Set the time of the file that has been created */\n        mz_os_set_file_date(pathwfs, reader->file_info->modified_date,\n            reader->file_info->accessed_date, reader->file_info->creation_date);\n    }\n\n    if (err == MZ_OK) {\n        /* Set file attributes for the correct system */\n        err_attrib = mz_zip_attrib_convert(MZ_HOST_SYSTEM(reader->file_info->version_madeby),\n            reader->file_info->external_fa, MZ_VERSION_MADEBY_HOST_SYSTEM, &target_attrib);\n\n        if (err_attrib == MZ_OK)\n            mz_os_set_file_attribs(pathwfs, target_attrib);\n    }\n\n    return err;\n}\n\nint32_t mz_zip_reader_entry_save_buffer(void *handle, void *buf, int32_t len) {\n    mz_zip_reader *reader = (mz_zip_reader *)handle;\n    void *mem_stream = NULL;\n    int32_t err = MZ_OK;\n\n    if (mz_zip_reader_is_open(reader) != MZ_OK)\n        return MZ_PARAM_ERROR;\n    if (!reader->file_info || reader->file_info->uncompressed_size > INT32_MAX)\n        return MZ_PARAM_ERROR;\n    if (len != (int32_t)reader->file_info->uncompressed_size)\n        return MZ_BUF_ERROR;\n\n    /* Create a memory stream backed by our buffer and save to it */\n    mz_stream_mem_create(&mem_stream);\n    mz_stream_mem_set_buffer(mem_stream, buf, len);\n\n    err = mz_stream_mem_open(mem_stream, NULL, MZ_OPEN_MODE_READ);\n    if (err == MZ_OK)\n        err = mz_zip_reader_entry_save(handle, mem_stream, mz_stream_mem_write);\n\n    mz_stream_mem_delete(&mem_stream);\n    return err;\n}\n\nint32_t mz_zip_reader_entry_save_buffer_length(void *handle) {\n    mz_zip_reader *reader = (mz_zip_reader *)handle;\n\n    if (mz_zip_reader_is_open(reader) != MZ_OK)\n        return MZ_PARAM_ERROR;\n    if (!reader->file_info || reader->file_info->uncompressed_size > INT32_MAX)\n        return MZ_PARAM_ERROR;\n\n    /* Get the maximum size required for the save buffer */\n    return (int32_t)reader->file_info->uncompressed_size;\n}\n\n/***************************************************************************/\n\nint32_t mz_zip_reader_save_all(void *handle, const char *destination_dir) {\n    mz_zip_reader *reader = (mz_zip_reader *)handle;\n    int32_t err = MZ_OK;\n    uint8_t *utf8_string = NULL;\n    char path[512];\n    char utf8_name[256];\n    char resolved_name[256];\n\n    err = mz_zip_reader_goto_first_entry(handle);\n\n    if (err == MZ_END_OF_LIST)\n        return err;\n\n    while (err == MZ_OK) {\n        /* Construct output path */\n        path[0] = 0;\n\n        strncpy(utf8_name, reader->file_info->filename, sizeof(utf8_name) - 1);\n        utf8_name[sizeof(utf8_name) - 1] = 0;\n\n        if ((reader->encoding > 0) && (reader->file_info->flag & MZ_ZIP_FLAG_UTF8) == 0) {\n            utf8_string = mz_os_utf8_string_create(reader->file_info->filename, reader->encoding);\n            if (utf8_string) {\n                strncpy(utf8_name, (char *)utf8_string, sizeof(utf8_name) - 1);\n                utf8_name[sizeof(utf8_name) - 1] = 0;\n                mz_os_utf8_string_delete(&utf8_string);\n            }\n        }\n\n        err = mz_path_resolve(utf8_name, resolved_name, sizeof(resolved_name));\n        if (err != MZ_OK)\n            break;\n\n        if (destination_dir)\n            mz_path_combine(path, destination_dir, sizeof(path));\n\n        mz_path_combine(path, resolved_name, sizeof(path));\n\n        /* Save file to disk */\n        err = mz_zip_reader_entry_save_file(handle, path);\n\n        if (err == MZ_OK)\n            err = mz_zip_reader_goto_next_entry(handle);\n    }\n\n    if (err == MZ_END_OF_LIST)\n        return MZ_OK;\n\n    return err;\n}\n\n/***************************************************************************/\n\nvoid mz_zip_reader_set_pattern(void *handle, const char *pattern, uint8_t ignore_case) {\n    mz_zip_reader *reader = (mz_zip_reader *)handle;\n    reader->pattern = pattern;\n    reader->pattern_ignore_case = ignore_case;\n}\n\nvoid mz_zip_reader_set_password(void *handle, const char *password) {\n    mz_zip_reader *reader = (mz_zip_reader *)handle;\n    reader->password = password;\n}\n\nvoid mz_zip_reader_set_raw(void *handle, uint8_t raw) {\n    mz_zip_reader *reader = (mz_zip_reader *)handle;\n    reader->raw = raw;\n}\n\nint32_t mz_zip_reader_get_raw(void *handle, uint8_t *raw) {\n    mz_zip_reader *reader = (mz_zip_reader *)handle;\n    if (!raw)\n        return MZ_PARAM_ERROR;\n    *raw = reader->raw;\n    return MZ_OK;\n}\n\nint32_t mz_zip_reader_get_zip_cd(void *handle, uint8_t *zip_cd) {\n    mz_zip_reader *reader = (mz_zip_reader *)handle;\n    if (!zip_cd)\n        return MZ_PARAM_ERROR;\n    *zip_cd = reader->cd_zipped;\n    return MZ_OK;\n}\n\nint32_t mz_zip_reader_get_comment(void *handle, const char **comment) {\n    mz_zip_reader *reader = (mz_zip_reader *)handle;\n    if (mz_zip_reader_is_open(reader) != MZ_OK)\n        return MZ_PARAM_ERROR;\n    if (!comment)\n        return MZ_PARAM_ERROR;\n    return mz_zip_get_comment(reader->zip_handle, comment);\n}\n\nint32_t mz_zip_reader_set_recover(void *handle, uint8_t recover) {\n    mz_zip_reader *reader = (mz_zip_reader *)handle;\n    if (!reader)\n        return MZ_PARAM_ERROR;\n    reader->recover = recover;\n    return MZ_OK;\n}\n\nvoid mz_zip_reader_set_encoding(void *handle, int32_t encoding) {\n    mz_zip_reader *reader = (mz_zip_reader *)handle;\n    reader->encoding = encoding;\n}\n\nvoid mz_zip_reader_set_sign_required(void *handle, uint8_t sign_required) {\n    mz_zip_reader *reader = (mz_zip_reader *)handle;\n    reader->sign_required = sign_required;\n}\n\nvoid mz_zip_reader_set_overwrite_cb(void *handle, void *userdata, mz_zip_reader_overwrite_cb cb) {\n    mz_zip_reader *reader = (mz_zip_reader *)handle;\n    reader->overwrite_cb = cb;\n    reader->overwrite_userdata = userdata;\n}\n\nvoid mz_zip_reader_set_password_cb(void *handle, void *userdata, mz_zip_reader_password_cb cb) {\n    mz_zip_reader *reader = (mz_zip_reader *)handle;\n    reader->password_cb = cb;\n    reader->password_userdata = userdata;\n}\n\nvoid mz_zip_reader_set_progress_cb(void *handle, void *userdata, mz_zip_reader_progress_cb cb) {\n    mz_zip_reader *reader = (mz_zip_reader *)handle;\n    reader->progress_cb = cb;\n    reader->progress_userdata = userdata;\n}\n\nvoid mz_zip_reader_set_progress_interval(void *handle, uint32_t milliseconds) {\n    mz_zip_reader *reader = (mz_zip_reader *)handle;\n    reader->progress_cb_interval_ms = milliseconds;\n}\n\nvoid mz_zip_reader_set_entry_cb(void *handle, void *userdata, mz_zip_reader_entry_cb cb) {\n    mz_zip_reader *reader = (mz_zip_reader *)handle;\n    reader->entry_cb = cb;\n    reader->entry_userdata = userdata;\n}\n\nint32_t mz_zip_reader_get_zip_handle(void *handle, void **zip_handle) {\n    mz_zip_reader *reader = (mz_zip_reader *)handle;\n    if (!zip_handle)\n        return MZ_PARAM_ERROR;\n    *zip_handle = reader->zip_handle;\n    if (!*zip_handle)\n        return MZ_EXIST_ERROR;\n    return MZ_OK;\n}\n\n/***************************************************************************/\n\nvoid *mz_zip_reader_create(void **handle) {\n    mz_zip_reader *reader = NULL;\n\n    reader = (mz_zip_reader *)calloc(1, sizeof(mz_zip_reader));\n    if (reader) {\n        reader->recover = 1;\n        reader->progress_cb_interval_ms = MZ_DEFAULT_PROGRESS_INTERVAL;\n    }\n    if (handle)\n        *handle = reader;\n\n    return reader;\n}\n\nvoid mz_zip_reader_delete(void **handle) {\n    mz_zip_reader *reader = NULL;\n    if (!handle)\n        return;\n    reader = (mz_zip_reader *)*handle;\n    if (reader) {\n        mz_zip_reader_close(reader);\n        free(reader);\n    }\n    *handle = NULL;\n}\n\n/***************************************************************************/\n\ntypedef struct mz_zip_writer_s {\n    void        *zip_handle;\n    void        *file_stream;\n    void        *buffered_stream;\n    void        *split_stream;\n    void        *sha256;\n    void        *mem_stream;\n    void        *file_extra_stream;\n    mz_zip_file file_info;\n    void        *overwrite_userdata;\n    mz_zip_writer_overwrite_cb\n                overwrite_cb;\n    void        *password_userdata;\n    mz_zip_writer_password_cb\n                password_cb;\n    void        *progress_userdata;\n    mz_zip_writer_progress_cb\n                progress_cb;\n    uint32_t    progress_cb_interval_ms;\n    void        *entry_userdata;\n    mz_zip_writer_entry_cb\n                entry_cb;\n    const char  *password;\n    const char  *comment;\n    uint8_t     *cert_data;\n    int32_t     cert_data_size;\n    const char  *cert_pwd;\n    uint16_t    compress_method;\n    int16_t     compress_level;\n    uint8_t     follow_links;\n    uint8_t     store_links;\n    uint8_t     zip_cd;\n    uint8_t     aes;\n    uint8_t     raw;\n    uint8_t     buffer[UINT16_MAX];\n} mz_zip_writer;\n\n/***************************************************************************/\n\nint32_t mz_zip_writer_zip_cd(void *handle) {\n    mz_zip_writer *writer = (mz_zip_writer *)handle;\n    mz_zip_file cd_file;\n    uint64_t number_entry = 0;\n    int64_t cd_mem_length = 0;\n    int32_t err = MZ_OK;\n    int32_t extrafield_size = 0;\n    void *file_extra_stream = NULL;\n    void *cd_mem_stream = NULL;\n\n    memset(&cd_file, 0, sizeof(cd_file));\n\n    mz_zip_get_number_entry(writer->zip_handle, &number_entry);\n    mz_zip_get_cd_mem_stream(writer->zip_handle, &cd_mem_stream);\n    mz_stream_seek(cd_mem_stream, 0, MZ_SEEK_END);\n    cd_mem_length = (uint32_t)mz_stream_tell(cd_mem_stream);\n    mz_stream_seek(cd_mem_stream, 0, MZ_SEEK_SET);\n\n    cd_file.filename = MZ_ZIP_CD_FILENAME;\n    cd_file.modified_date = time(NULL);\n    cd_file.version_madeby = MZ_VERSION_MADEBY;\n    cd_file.compression_method = writer->compress_method;\n    cd_file.uncompressed_size = (int32_t)cd_mem_length;\n    cd_file.flag = MZ_ZIP_FLAG_UTF8;\n\n    if (writer->password)\n        cd_file.flag |= MZ_ZIP_FLAG_ENCRYPTED;\n\n    mz_stream_mem_create(&file_extra_stream);\n    mz_stream_mem_open(file_extra_stream, NULL, MZ_OPEN_MODE_CREATE);\n\n    mz_zip_extrafield_write(file_extra_stream, MZ_ZIP_EXTENSION_CDCD, 8);\n\n    mz_stream_write_uint64(file_extra_stream, number_entry);\n\n    mz_stream_mem_get_buffer(file_extra_stream, (const void **)&cd_file.extrafield);\n    mz_stream_mem_get_buffer_length(file_extra_stream, &extrafield_size);\n    cd_file.extrafield_size = (uint16_t)extrafield_size;\n\n    err = mz_zip_writer_entry_open(handle, &cd_file);\n    if (err == MZ_OK) {\n        mz_stream_copy_stream(handle, mz_zip_writer_entry_write, cd_mem_stream,\n            NULL, (int32_t)cd_mem_length);\n\n        mz_stream_seek(cd_mem_stream, 0, MZ_SEEK_SET);\n        mz_stream_mem_set_buffer_limit(cd_mem_stream, 0);\n\n        err = mz_zip_writer_entry_close(writer);\n    }\n\n    mz_stream_mem_delete(&file_extra_stream);\n\n    return err;\n}\n\n/***************************************************************************/\n\nint32_t mz_zip_writer_is_open(void *handle) {\n    mz_zip_writer *writer = (mz_zip_writer *)handle;\n    if (!writer || !writer->zip_handle)\n        return MZ_PARAM_ERROR;\n    return MZ_OK;\n}\n\nstatic int32_t mz_zip_writer_open_int(void *handle, void *stream, int32_t mode) {\n    mz_zip_writer *writer = (mz_zip_writer *)handle;\n    int32_t err = MZ_OK;\n\n    mz_zip_create(&writer->zip_handle);\n    err = mz_zip_open(writer->zip_handle, stream, mode);\n\n    if (err != MZ_OK) {\n        mz_zip_writer_close(handle);\n        return err;\n    }\n\n    return MZ_OK;\n}\n\nint32_t mz_zip_writer_open(void *handle, void *stream, uint8_t append) {\n    int32_t mode = MZ_OPEN_MODE_WRITE;\n\n    if (append) {\n        mode |= MZ_OPEN_MODE_APPEND;\n    } else {\n        mode |= MZ_OPEN_MODE_CREATE;\n    }\n\n    return mz_zip_writer_open_int(handle, stream, mode);\n}\n\nint32_t mz_zip_writer_open_file(void *handle, const char *path, int64_t disk_size, uint8_t append) {\n    mz_zip_writer *writer = (mz_zip_writer *)handle;\n    int32_t mode = MZ_OPEN_MODE_READWRITE;\n    int32_t err = MZ_OK;\n    int32_t err_cb = 0;\n    char directory[320];\n\n    mz_zip_writer_close(handle);\n\n    if (mz_os_file_exists(path) != MZ_OK) {\n        /* If the file doesn't exist, we don't append file */\n        mode |= MZ_OPEN_MODE_CREATE;\n\n        /* Create destination directory if it doesn't already exist */\n        if (strchr(path, '/') || strrchr(path, '\\\\')) {\n            strncpy(directory, path, sizeof(directory) - 1);\n            directory[sizeof(directory) - 1] = 0;\n            mz_path_remove_filename(directory);\n            if (mz_os_file_exists(directory) != MZ_OK)\n                mz_dir_make(directory);\n        }\n    } else if (append) {\n        mode |= MZ_OPEN_MODE_APPEND;\n    } else {\n        if (writer->overwrite_cb)\n            err_cb = writer->overwrite_cb(handle, writer->overwrite_userdata, path);\n\n        if (err_cb == MZ_INTERNAL_ERROR)\n            return err;\n\n        if (err_cb == MZ_OK)\n            mode |= MZ_OPEN_MODE_CREATE;\n        else\n            mode |= MZ_OPEN_MODE_APPEND;\n    }\n\n    mz_stream_os_create(&writer->file_stream);\n    mz_stream_buffered_create(&writer->buffered_stream);\n    mz_stream_split_create(&writer->split_stream);\n\n    mz_stream_set_base(writer->buffered_stream, writer->file_stream);\n    mz_stream_set_base(writer->split_stream, writer->buffered_stream);\n\n    mz_stream_split_set_prop_int64(writer->split_stream, MZ_STREAM_PROP_DISK_SIZE, disk_size);\n\n    err = mz_stream_open(writer->split_stream, path, mode);\n    if (err == MZ_OK)\n        err = mz_zip_writer_open_int(handle, writer->split_stream, mode);\n\n    return err;\n}\n\nint32_t mz_zip_writer_open_file_in_memory(void *handle, const char *path) {\n    mz_zip_writer *writer = (mz_zip_writer *)handle;\n    void *file_stream = NULL;\n    int64_t file_size = 0;\n    int32_t err = 0;\n\n    mz_zip_writer_close(handle);\n\n    mz_stream_os_create(&file_stream);\n\n    err = mz_stream_os_open(file_stream, path, MZ_OPEN_MODE_READ);\n\n    if (err != MZ_OK) {\n        mz_stream_os_delete(&file_stream);\n        mz_zip_writer_close(handle);\n        return err;\n    }\n\n    mz_stream_os_seek(file_stream, 0, MZ_SEEK_END);\n    file_size = mz_stream_os_tell(file_stream);\n    mz_stream_os_seek(file_stream, 0, MZ_SEEK_SET);\n\n    if ((file_size <= 0) || (file_size > UINT32_MAX)) {\n        /* Memory size is too large or too small */\n\n        mz_stream_os_close(file_stream);\n        mz_stream_os_delete(&file_stream);\n        mz_zip_writer_close(handle);\n        return MZ_MEM_ERROR;\n    }\n\n    mz_stream_mem_create(&writer->mem_stream);\n    mz_stream_mem_set_grow_size(writer->mem_stream, (int32_t)file_size);\n    mz_stream_mem_open(writer->mem_stream, NULL, MZ_OPEN_MODE_CREATE);\n\n    err = mz_stream_copy(writer->mem_stream, file_stream, (int32_t)file_size);\n\n    mz_stream_os_close(file_stream);\n    mz_stream_os_delete(&file_stream);\n\n    if (err == MZ_OK)\n        err = mz_zip_writer_open(handle, writer->mem_stream, 1);\n    if (err != MZ_OK)\n        mz_zip_writer_close(handle);\n\n    return err;\n}\n\nint32_t mz_zip_writer_close(void *handle) {\n    mz_zip_writer *writer = (mz_zip_writer *)handle;\n    int32_t err = MZ_OK;\n\n    if (writer->zip_handle) {\n        mz_zip_set_version_madeby(writer->zip_handle, MZ_VERSION_MADEBY);\n        if (writer->comment)\n            mz_zip_set_comment(writer->zip_handle, writer->comment);\n        if (writer->zip_cd)\n            mz_zip_writer_zip_cd(writer);\n\n        err = mz_zip_close(writer->zip_handle);\n        mz_zip_delete(&writer->zip_handle);\n    }\n\n    if (writer->split_stream) {\n        mz_stream_split_close(writer->split_stream);\n        mz_stream_split_delete(&writer->split_stream);\n    }\n\n    if (writer->buffered_stream)\n        mz_stream_buffered_delete(&writer->buffered_stream);\n\n    if (writer->file_stream)\n        mz_stream_os_delete(&writer->file_stream);\n\n    if (writer->mem_stream) {\n        mz_stream_mem_close(writer->mem_stream);\n        mz_stream_mem_delete(&writer->mem_stream);\n    }\n\n    return err;\n}\n\n/***************************************************************************/\n\nint32_t mz_zip_writer_entry_open(void *handle, mz_zip_file *file_info) {\n    mz_zip_writer *writer = (mz_zip_writer *)handle;\n    int32_t err = MZ_OK;\n    const char *password = NULL;\n    char password_buf[120];\n\n    /* Copy file info to access data upon close */\n    memcpy(&writer->file_info, file_info, sizeof(mz_zip_file));\n\n    if (writer->entry_cb)\n        writer->entry_cb(handle, writer->entry_userdata, &writer->file_info);\n\n    password = writer->password;\n\n    /* Check if we need a password and ask for it if we need to */\n    if (!password && writer->password_cb && (writer->file_info.flag & MZ_ZIP_FLAG_ENCRYPTED)) {\n        writer->password_cb(handle, writer->password_userdata, &writer->file_info,\n            password_buf, sizeof(password_buf));\n        password = password_buf;\n    }\n\n#ifndef MZ_ZIP_NO_CRYPTO\n    if (mz_zip_attrib_is_dir(writer->file_info.external_fa, writer->file_info.version_madeby) != MZ_OK) {\n        /* Start calculating sha256 */\n        mz_crypt_sha_create(&writer->sha256);\n        mz_crypt_sha_set_algorithm(writer->sha256, MZ_HASH_SHA256);\n        mz_crypt_sha_begin(writer->sha256);\n    }\n#endif\n\n    /* Open entry in zip */\n    err = mz_zip_entry_write_open(writer->zip_handle, &writer->file_info, writer->compress_level,\n        writer->raw, password);\n\n    return err;\n}\n\n#if !defined(MZ_ZIP_NO_CRYPTO) && defined(MZ_ZIP_SIGNING)\nint32_t mz_zip_writer_entry_sign(void *handle, uint8_t *message, int32_t message_size,\n    uint8_t *cert_data, int32_t cert_data_size, const char *cert_pwd) {\n    mz_zip_writer *writer = (mz_zip_writer *)handle;\n    int32_t err = MZ_OK;\n    int32_t signature_size = 0;\n    uint8_t *signature = NULL;\n\n    if (!writer || !cert_data || cert_data_size <= 0)\n        return MZ_PARAM_ERROR;\n    if (mz_zip_entry_is_open(writer->zip_handle) != MZ_OK)\n        return MZ_PARAM_ERROR;\n\n    /* Sign message with certificate */\n    err = mz_crypt_sign(message, message_size, cert_data, cert_data_size, cert_pwd,\n        &signature, &signature_size);\n\n    if (err == MZ_OK && signature) {\n        /* Write signature zip extra field */\n        err = mz_zip_extrafield_write(writer->file_extra_stream, MZ_ZIP_EXTENSION_SIGN,\n            (uint16_t)signature_size);\n\n        if (err == MZ_OK) {\n            if (mz_stream_write(writer->file_extra_stream, signature, signature_size) != signature_size)\n                err = MZ_WRITE_ERROR;\n        }\n\n        free(signature);\n    }\n\n    return err;\n}\n#endif\n\nint32_t mz_zip_writer_entry_close(void *handle) {\n    mz_zip_writer *writer = (mz_zip_writer *)handle;\n    int32_t err = MZ_OK;\n#ifndef MZ_ZIP_NO_CRYPTO\n    const uint8_t *extrafield = NULL;\n    int32_t extrafield_size = 0;\n    int16_t field_length_hash = 0;\n    uint8_t sha256[MZ_HASH_SHA256_SIZE];\n\n    if (writer->sha256) {\n        mz_crypt_sha_end(writer->sha256, sha256, sizeof(sha256));\n        mz_crypt_sha_delete(&writer->sha256);\n\n        /* Copy extrafield so we can append our own fields before close */\n        mz_stream_mem_create(&writer->file_extra_stream);\n        mz_stream_mem_open(writer->file_extra_stream, NULL, MZ_OPEN_MODE_CREATE);\n\n        /* Write sha256 hash to extrafield */\n        field_length_hash = 4 + MZ_HASH_SHA256_SIZE;\n        err = mz_zip_extrafield_write(writer->file_extra_stream, MZ_ZIP_EXTENSION_HASH, field_length_hash);\n        if (err == MZ_OK)\n            err = mz_stream_write_uint16(writer->file_extra_stream, MZ_HASH_SHA256);\n        if (err == MZ_OK)\n            err = mz_stream_write_uint16(writer->file_extra_stream, MZ_HASH_SHA256_SIZE);\n        if (err == MZ_OK) {\n            if (mz_stream_write(writer->file_extra_stream, sha256, sizeof(sha256)) != MZ_HASH_SHA256_SIZE)\n                err = MZ_WRITE_ERROR;\n        }\n\n#ifdef MZ_ZIP_SIGNING\n        if ((err == MZ_OK) && (writer->cert_data) && (writer->cert_data_size > 0)) {\n            /* Sign entry if not zipping cd or if it is cd being zipped */\n            if (!writer->zip_cd || strcmp(writer->file_info.filename, MZ_ZIP_CD_FILENAME) == 0) {\n                err = mz_zip_writer_entry_sign(handle, sha256, sizeof(sha256),\n                    writer->cert_data, writer->cert_data_size, writer->cert_pwd);\n            }\n        }\n#endif\n\n        if ((writer->file_info.extrafield) && (writer->file_info.extrafield_size > 0))\n            mz_stream_mem_write(writer->file_extra_stream, writer->file_info.extrafield,\n                writer->file_info.extrafield_size);\n\n        /* Update extra field for central directory after adding extra fields */\n        mz_stream_mem_get_buffer(writer->file_extra_stream, (const void **)&extrafield);\n        mz_stream_mem_get_buffer_length(writer->file_extra_stream, &extrafield_size);\n\n        mz_zip_entry_set_extrafield(writer->zip_handle, extrafield, (uint16_t)extrafield_size);\n    }\n#endif\n\n    if (err == MZ_OK) {\n        if (writer->raw)\n            err = mz_zip_entry_close_raw(writer->zip_handle, writer->file_info.uncompressed_size,\n                writer->file_info.crc);\n        else\n            err = mz_zip_entry_close(writer->zip_handle);\n    }\n\n    if (writer->file_extra_stream)\n        mz_stream_mem_delete(&writer->file_extra_stream);\n\n    return err;\n}\n\nint32_t mz_zip_writer_entry_write(void *handle, const void *buf, int32_t len) {\n    mz_zip_writer *writer = (mz_zip_writer *)handle;\n    int32_t written = 0;\n    written = mz_zip_entry_write(writer->zip_handle, buf, len);\n#ifndef MZ_ZIP_NO_CRYPTO\n    if (written > 0 && writer->sha256)\n        mz_crypt_sha_update(writer->sha256, buf, written);\n#endif\n    return written;\n}\n/***************************************************************************/\n\nint32_t mz_zip_writer_add_process(void *handle, void *stream, mz_stream_read_cb read_cb) {\n    mz_zip_writer *writer = (mz_zip_writer *)handle;\n    int32_t read = 0;\n    int32_t written = 0;\n    int32_t err = MZ_OK;\n\n    if (mz_zip_writer_is_open(writer) != MZ_OK)\n        return MZ_PARAM_ERROR;\n    /* If the entry isn't open for writing, open it */\n    if (mz_zip_entry_is_open(writer->zip_handle) != MZ_OK)\n        return MZ_PARAM_ERROR;\n    if (!read_cb)\n        return MZ_PARAM_ERROR;\n\n    read = read_cb(stream, writer->buffer, sizeof(writer->buffer));\n    if (read == 0)\n        return MZ_END_OF_STREAM;\n    if (read < 0) {\n        err = read;\n        return err;\n    }\n\n    written = mz_zip_writer_entry_write(handle, writer->buffer, read);\n    if (written != read)\n        return MZ_WRITE_ERROR;\n\n    return written;\n}\n\nint32_t mz_zip_writer_add(void *handle, void *stream, mz_stream_read_cb read_cb) {\n    mz_zip_writer *writer = (mz_zip_writer *)handle;\n    uint64_t current_time = 0;\n    uint64_t update_time = 0;\n    int64_t current_pos = 0;\n    int64_t update_pos = 0;\n    int32_t err = MZ_OK;\n    int32_t written = 0;\n\n    /* Update the progress at the beginning */\n    if (writer->progress_cb)\n        writer->progress_cb(handle, writer->progress_userdata, &writer->file_info, current_pos);\n\n    /* Write data to stream until done */\n    while (err == MZ_OK) {\n        written = mz_zip_writer_add_process(handle, stream, read_cb);\n        if (written == MZ_END_OF_STREAM)\n            break;\n        if (written > 0)\n            current_pos += written;\n        if (written < 0)\n            err = written;\n\n        /* Update progress if enough time have passed */\n        current_time = mz_os_ms_time();\n        if ((current_time - update_time) > writer->progress_cb_interval_ms) {\n            if (writer->progress_cb)\n                writer->progress_cb(handle, writer->progress_userdata, &writer->file_info, current_pos);\n\n            update_pos = current_pos;\n            update_time = current_time;\n        }\n    }\n\n    /* Update the progress at the end */\n    if (writer->progress_cb && update_pos != current_pos)\n        writer->progress_cb(handle, writer->progress_userdata, &writer->file_info, current_pos);\n\n    return err;\n}\n\nint32_t mz_zip_writer_add_info(void *handle, void *stream, mz_stream_read_cb read_cb, mz_zip_file *file_info) {\n    mz_zip_writer *writer = (mz_zip_writer *)handle;\n    int32_t err = MZ_OK;\n\n    if (mz_zip_writer_is_open(handle) != MZ_OK)\n        return MZ_PARAM_ERROR;\n    if (!file_info)\n        return MZ_PARAM_ERROR;\n\n    /* Add to zip */\n    err = mz_zip_writer_entry_open(handle, file_info);\n    if (err != MZ_OK)\n        return err;\n\n    if (stream) {\n        if (mz_zip_attrib_is_dir(writer->file_info.external_fa, writer->file_info.version_madeby) != MZ_OK) {\n            err = mz_zip_writer_add(handle, stream, read_cb);\n            if (err != MZ_OK)\n                return err;\n        }\n    }\n\n    err = mz_zip_writer_entry_close(handle);\n\n    return err;\n}\n\nint32_t mz_zip_writer_add_buffer(void *handle, void *buf, int32_t len, mz_zip_file *file_info) {\n    void *mem_stream = NULL;\n    int32_t err = MZ_OK;\n\n    if (mz_zip_writer_is_open(handle) != MZ_OK)\n        return MZ_PARAM_ERROR;\n    if (!buf)\n        return MZ_PARAM_ERROR;\n\n    /* Create a memory stream backed by our buffer and add from it */\n    mz_stream_mem_create(&mem_stream);\n    mz_stream_mem_set_buffer(mem_stream, buf, len);\n\n    err = mz_stream_mem_open(mem_stream, NULL, MZ_OPEN_MODE_READ);\n    if (err == MZ_OK)\n        err = mz_zip_writer_add_info(handle, mem_stream, mz_stream_mem_read, file_info);\n\n    mz_stream_mem_delete(&mem_stream);\n    return err;\n}\n\nint32_t mz_zip_writer_add_file(void *handle, const char *path, const char *filename_in_zip) {\n    mz_zip_writer *writer = (mz_zip_writer *)handle;\n    mz_zip_file file_info;\n    uint32_t target_attrib = 0;\n    uint32_t src_attrib = 0;\n    int32_t err = MZ_OK;\n    uint8_t src_sys = 0;\n    void *stream = NULL;\n    char link_path[1024];\n    const char *filename = filename_in_zip;\n\n    if (mz_zip_writer_is_open(handle) != MZ_OK)\n        return MZ_PARAM_ERROR;\n    if (!path)\n        return MZ_PARAM_ERROR;\n\n    if (!filename) {\n        err = mz_path_get_filename(path, &filename);\n        if (err != MZ_OK)\n            return err;\n    }\n\n    memset(&file_info, 0, sizeof(file_info));\n\n    /* The path name saved, should not include a leading slash. */\n    /* If it did, windows/xp and dynazip couldn't read the zip file. */\n\n    while (filename[0] == '\\\\' || filename[0] == '/')\n        filename += 1;\n\n    /* Get information about the file on disk so we can store it in zip */\n\n    file_info.version_madeby = MZ_VERSION_MADEBY;\n    file_info.compression_method = writer->compress_method;\n    file_info.filename = filename;\n    file_info.uncompressed_size = mz_os_get_file_size(path);\n    file_info.flag = MZ_ZIP_FLAG_UTF8;\n\n    if (writer->zip_cd)\n        file_info.flag |= MZ_ZIP_FLAG_MASK_LOCAL_INFO;\n    if (writer->aes)\n        file_info.aes_version = MZ_AES_VERSION;\n\n    mz_os_get_file_date(path, &file_info.modified_date, &file_info.accessed_date,\n        &file_info.creation_date);\n    mz_os_get_file_attribs(path, &src_attrib);\n\n    src_sys = MZ_HOST_SYSTEM(file_info.version_madeby);\n\n    if ((src_sys != MZ_HOST_SYSTEM_MSDOS) && (src_sys != MZ_HOST_SYSTEM_WINDOWS_NTFS)) {\n        /* High bytes are OS specific attributes, low byte is always DOS attributes */\n        if (mz_zip_attrib_convert(src_sys, src_attrib, MZ_HOST_SYSTEM_MSDOS, &target_attrib) == MZ_OK)\n            file_info.external_fa = target_attrib;\n        file_info.external_fa |= (src_attrib << 16);\n    } else {\n        file_info.external_fa = src_attrib;\n    }\n\n    if (writer->store_links && mz_os_is_symlink(path) == MZ_OK) {\n        err = mz_os_read_symlink(path, link_path, sizeof(link_path));\n        if (err == MZ_OK)\n            file_info.linkname = link_path;\n    } else if (mz_os_is_dir(path) != MZ_OK) {\n        mz_stream_os_create(&stream);\n        err = mz_stream_os_open(stream, path, MZ_OPEN_MODE_READ);\n    }\n\n    if (err == MZ_OK)\n        err = mz_zip_writer_add_info(handle, stream, mz_stream_read, &file_info);\n\n    if (stream) {\n        mz_stream_close(stream);\n        mz_stream_delete(&stream);\n    }\n\n    return err;\n}\n\nint32_t mz_zip_writer_add_path(void *handle, const char *path, const char *root_path,\n    uint8_t include_path, uint8_t recursive) {\n    mz_zip_writer *writer = (mz_zip_writer *)handle;\n    DIR *dir = NULL;\n    struct dirent *entry = NULL;\n    int32_t err = MZ_OK;\n    int16_t is_dir = 0;\n    const char *filename = NULL;\n    const char *filenameinzip = path;\n    char *wildcard_ptr = NULL;\n    char full_path[1024];\n    char path_dir[1024];\n\n    if (strrchr(path, '*')) {\n        strncpy(path_dir, path, sizeof(path_dir) - 1);\n        path_dir[sizeof(path_dir) - 1] = 0;\n        mz_path_remove_filename(path_dir);\n        wildcard_ptr = path_dir + strlen(path_dir) + 1;\n        root_path = path = path_dir;\n    } else {\n        if (mz_os_is_dir(path) == MZ_OK)\n            is_dir = 1;\n\n        /* Construct the filename that our file will be stored in the zip as */\n        if (!root_path)\n            root_path = path;\n\n        /* Should the file be stored with any path info at all? */\n        if (!include_path) {\n            if (!is_dir && root_path == path) {\n                if (mz_path_get_filename(filenameinzip, &filename) == MZ_OK)\n                    filenameinzip = filename;\n            } else {\n                filenameinzip += strlen(root_path);\n            }\n        }\n\n        if (!writer->store_links && !writer->follow_links) {\n            if (mz_os_is_symlink(path) == MZ_OK)\n                return err;\n        }\n\n        if (*filenameinzip != 0)\n            err = mz_zip_writer_add_file(handle, path, filenameinzip);\n\n        if (!is_dir)\n            return err;\n\n        if (writer->store_links) {\n            if (mz_os_is_symlink(path) == MZ_OK)\n                return err;\n        }\n    }\n\n    dir = mz_os_open_dir(path);\n\n    if (!dir)\n        return MZ_EXIST_ERROR;\n\n    while ((entry = mz_os_read_dir(dir))) {\n        if (strcmp(entry->d_name, \".\") == 0 || strcmp(entry->d_name, \"..\") == 0)\n            continue;\n\n        full_path[0] = 0;\n        mz_path_combine(full_path, path, sizeof(full_path));\n        mz_path_combine(full_path, entry->d_name, sizeof(full_path));\n\n        if (!recursive && mz_os_is_dir(full_path) == MZ_OK)\n            continue;\n\n        if ((wildcard_ptr) && (mz_path_compare_wc(entry->d_name, wildcard_ptr, 1) != MZ_OK))\n            continue;\n\n        err = mz_zip_writer_add_path(handle, full_path, root_path, include_path, recursive);\n        if (err != MZ_OK)\n            break;\n    }\n\n    mz_os_close_dir(dir);\n    return err;\n}\n\nint32_t mz_zip_writer_copy_from_reader(void *handle, void *reader) {\n    mz_zip_writer *writer = (mz_zip_writer *)handle;\n    mz_zip_file *file_info = NULL;\n    int64_t compressed_size = 0;\n    int64_t uncompressed_size = 0;\n    uint32_t crc32 = 0;\n    int32_t err = MZ_OK;\n    uint8_t original_raw = 0;\n    void *reader_zip_handle = NULL;\n    void *writer_zip_handle = NULL;\n\n    if (mz_zip_reader_is_open(reader) != MZ_OK)\n        return MZ_PARAM_ERROR;\n    if (mz_zip_writer_is_open(writer) != MZ_OK)\n        return MZ_PARAM_ERROR;\n\n    err = mz_zip_reader_entry_get_info(reader, &file_info);\n\n    if (err != MZ_OK)\n        return err;\n\n    mz_zip_reader_get_zip_handle(reader, &reader_zip_handle);\n    mz_zip_writer_get_zip_handle(writer, &writer_zip_handle);\n\n    /* Open entry for raw reading */\n    err = mz_zip_entry_read_open(reader_zip_handle, 1, NULL);\n\n    if (err == MZ_OK) {\n        /* Write entry raw, save original raw value */\n        original_raw = writer->raw;\n        writer->raw = 1;\n\n        err = mz_zip_writer_entry_open(writer, file_info);\n\n        if ((err == MZ_OK) &&\n            (mz_zip_attrib_is_dir(writer->file_info.external_fa, writer->file_info.version_madeby) != MZ_OK)) {\n            err = mz_zip_writer_add(writer, reader_zip_handle, mz_zip_entry_read);\n        }\n\n        if (err == MZ_OK) {\n            err = mz_zip_entry_read_close(reader_zip_handle, &crc32, &compressed_size, &uncompressed_size);\n            if (err == MZ_OK)\n                err = mz_zip_entry_write_close(writer_zip_handle, crc32, compressed_size, uncompressed_size);\n        }\n\n        if (mz_zip_entry_is_open(reader_zip_handle) == MZ_OK)\n            mz_zip_entry_close(reader_zip_handle);\n\n        if (mz_zip_entry_is_open(writer_zip_handle) == MZ_OK)\n            mz_zip_entry_close(writer_zip_handle);\n\n        writer->raw = original_raw;\n    }\n\n    return err;\n}\n\n/***************************************************************************/\n\nvoid mz_zip_writer_set_password(void *handle, const char *password) {\n    mz_zip_writer *writer = (mz_zip_writer *)handle;\n    writer->password = password;\n}\n\nvoid mz_zip_writer_set_comment(void *handle, const char *comment) {\n    mz_zip_writer *writer = (mz_zip_writer *)handle;\n    writer->comment = comment;\n}\n\nvoid mz_zip_writer_set_raw(void *handle, uint8_t raw) {\n    mz_zip_writer *writer = (mz_zip_writer *)handle;\n    writer->raw = raw;\n}\n\nint32_t mz_zip_writer_get_raw(void *handle, uint8_t *raw) {\n    mz_zip_writer *writer = (mz_zip_writer *)handle;\n    if (!raw)\n        return MZ_PARAM_ERROR;\n    *raw = writer->raw;\n    return MZ_OK;\n}\n\nvoid mz_zip_writer_set_aes(void *handle, uint8_t aes) {\n    mz_zip_writer *writer = (mz_zip_writer *)handle;\n    writer->aes = aes;\n}\n\nvoid mz_zip_writer_set_compress_method(void *handle, uint16_t compress_method) {\n    mz_zip_writer *writer = (mz_zip_writer *)handle;\n    writer->compress_method = compress_method;\n}\n\nvoid mz_zip_writer_set_compress_level(void *handle, int16_t compress_level) {\n    mz_zip_writer *writer = (mz_zip_writer *)handle;\n    writer->compress_level = compress_level;\n}\n\nvoid mz_zip_writer_set_follow_links(void *handle, uint8_t follow_links) {\n    mz_zip_writer *writer = (mz_zip_writer *)handle;\n    writer->follow_links = follow_links;\n}\n\nvoid mz_zip_writer_set_store_links(void *handle, uint8_t store_links) {\n    mz_zip_writer *writer = (mz_zip_writer *)handle;\n    writer->store_links = store_links;\n}\n\nvoid mz_zip_writer_set_zip_cd(void *handle, uint8_t zip_cd) {\n    mz_zip_writer *writer = (mz_zip_writer *)handle;\n    writer->zip_cd = zip_cd;\n}\n\nint32_t mz_zip_writer_set_certificate(void *handle, const char *cert_path, const char *cert_pwd) {\n    mz_zip_writer *writer = (mz_zip_writer *)handle;\n    void *cert_stream = NULL;\n    uint8_t *cert_data = NULL;\n    int32_t cert_data_size = 0;\n    int32_t err = MZ_OK;\n\n    if (!cert_path)\n        return MZ_PARAM_ERROR;\n\n    cert_data_size = (int32_t)mz_os_get_file_size(cert_path);\n\n    if (cert_data_size == 0)\n        return MZ_PARAM_ERROR;\n\n    if (writer->cert_data) {\n        free(writer->cert_data);\n        writer->cert_data = NULL;\n    }\n\n    cert_data = (uint8_t *)malloc(cert_data_size);\n\n    /* Read pkcs12 certificate from disk */\n    mz_stream_os_create(&cert_stream);\n    err = mz_stream_os_open(cert_stream, cert_path, MZ_OPEN_MODE_READ);\n    if (err == MZ_OK) {\n        if (mz_stream_os_read(cert_stream, cert_data, cert_data_size) != cert_data_size)\n            err = MZ_READ_ERROR;\n        mz_stream_os_close(cert_stream);\n    }\n    mz_stream_os_delete(&cert_stream);\n\n    if (err == MZ_OK) {\n        writer->cert_data = cert_data;\n        writer->cert_data_size = cert_data_size;\n        writer->cert_pwd = cert_pwd;\n    } else {\n        free(cert_data);\n    }\n\n    return err;\n}\n\nvoid mz_zip_writer_set_overwrite_cb(void *handle, void *userdata, mz_zip_writer_overwrite_cb cb) {\n    mz_zip_writer *writer = (mz_zip_writer *)handle;\n    writer->overwrite_cb = cb;\n    writer->overwrite_userdata = userdata;\n}\n\nvoid mz_zip_writer_set_password_cb(void *handle, void *userdata, mz_zip_writer_password_cb cb) {\n    mz_zip_writer *writer = (mz_zip_writer *)handle;\n    writer->password_cb = cb;\n    writer->password_userdata = userdata;\n}\n\nvoid mz_zip_writer_set_progress_cb(void *handle, void *userdata, mz_zip_writer_progress_cb cb) {\n    mz_zip_writer *writer = (mz_zip_writer *)handle;\n    writer->progress_cb = cb;\n    writer->progress_userdata = userdata;\n}\n\nvoid mz_zip_writer_set_progress_interval(void *handle, uint32_t milliseconds) {\n    mz_zip_writer *writer = (mz_zip_writer *)handle;\n    writer->progress_cb_interval_ms = milliseconds;\n}\n\nvoid mz_zip_writer_set_entry_cb(void *handle, void *userdata, mz_zip_writer_entry_cb cb) {\n    mz_zip_writer *writer = (mz_zip_writer *)handle;\n    writer->entry_cb = cb;\n    writer->entry_userdata = userdata;\n}\n\nint32_t mz_zip_writer_get_zip_handle(void *handle, void **zip_handle) {\n    mz_zip_writer *writer = (mz_zip_writer *)handle;\n    if (!zip_handle)\n        return MZ_PARAM_ERROR;\n    *zip_handle = writer->zip_handle;\n    if (!*zip_handle)\n        return MZ_EXIST_ERROR;\n    return MZ_OK;\n}\n\n/***************************************************************************/\n\nvoid *mz_zip_writer_create(void **handle) {\n    mz_zip_writer *writer = NULL;\n\n    writer = (mz_zip_writer *)calloc(1, sizeof(mz_zip_writer));\n    if (writer) {\n#if defined(HAVE_WZAES)\n        writer->aes = 1;\n#endif\n#if defined(HAVE_ZLIB) || defined(HAVE_LIBCOMP)\n        writer->compress_method = MZ_COMPRESS_METHOD_DEFLATE;\n#elif defined(HAVE_BZIP2)\n        writer->compress_method = MZ_COMPRESS_METHOD_BZIP2;\n#elif defined(HAVE_LZMA)\n        writer->compress_method = MZ_COMPRESS_METHOD_LZMA;\n#else\n        writer->compress_method = MZ_COMPRESS_METHOD_STORE;\n#endif\n        writer->compress_level = MZ_COMPRESS_LEVEL_BEST;\n        writer->progress_cb_interval_ms = MZ_DEFAULT_PROGRESS_INTERVAL;\n    }\n    if (handle)\n        *handle = writer;\n\n    return writer;\n}\n\nvoid mz_zip_writer_delete(void **handle) {\n    mz_zip_writer *writer = NULL;\n    if (!handle)\n        return;\n    writer = (mz_zip_writer *)*handle;\n    if (writer) {\n        mz_zip_writer_close(writer);\n\n        if (writer->cert_data)\n            free(writer->cert_data);\n\n        writer->cert_data = NULL;\n        writer->cert_data_size = 0;\n\n        free(writer);\n    }\n    *handle = NULL;\n}\n\n/***************************************************************************/\n"
  },
  {
    "path": "ios/CodePush/SSZipArchive/minizip/mz_zip_rw.h",
    "content": "/* mz_zip_rw.h -- Zip reader/writer\n   part of the minizip-ng project\n\n   Copyright (C) Nathan Moinvaziri\n     https://github.com/zlib-ng/minizip-ng\n\n   This program is distributed under the terms of the same license as zlib.\n   See the accompanying LICENSE file for the full text of the license.\n*/\n\n#ifndef MZ_ZIP_RW_H\n#define MZ_ZIP_RW_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/***************************************************************************/\n\ntypedef int32_t (*mz_zip_reader_overwrite_cb)(void *handle, void *userdata, mz_zip_file *file_info, const char *path);\ntypedef int32_t (*mz_zip_reader_password_cb)(void *handle, void *userdata, mz_zip_file *file_info, char *password, int32_t max_password);\ntypedef int32_t (*mz_zip_reader_progress_cb)(void *handle, void *userdata, mz_zip_file *file_info, int64_t position);\ntypedef int32_t (*mz_zip_reader_entry_cb)(void *handle, void *userdata, mz_zip_file *file_info, const char *path);\n\n/***************************************************************************/\n\nint32_t mz_zip_reader_is_open(void *handle);\n/* Checks to see if the zip file is open */\n\nint32_t mz_zip_reader_open(void *handle, void *stream);\n/* Opens zip file from stream */\n\nint32_t mz_zip_reader_open_file(void *handle, const char *path);\n/* Opens zip file from a file path */\n\nint32_t mz_zip_reader_open_file_in_memory(void *handle, const char *path);\n/* Opens zip file from a file path into memory for faster access */\n\nint32_t mz_zip_reader_open_buffer(void *handle, uint8_t *buf, int32_t len, uint8_t copy);\n/* Opens zip file from memory buffer */\n\nint32_t mz_zip_reader_close(void *handle);\n/* Closes the zip file */\n\n/***************************************************************************/\n\nint32_t mz_zip_reader_unzip_cd(void *handle);\n/* Unzip the central directory */\n\n/***************************************************************************/\n\nint32_t mz_zip_reader_goto_first_entry(void *handle);\n/* Goto the first entry in the zip file that matches the pattern */\n\nint32_t mz_zip_reader_goto_next_entry(void *handle);\n/* Goto the next entry in the zip file that matches the pattern */\n\nint32_t mz_zip_reader_locate_entry(void *handle, const char *filename, uint8_t ignore_case);\n/* Locates an entry by filename */\n\nint32_t mz_zip_reader_entry_open(void *handle);\n/* Opens an entry for reading */\n\nint32_t mz_zip_reader_entry_close(void *handle);\n/* Closes an entry */\n\nint32_t mz_zip_reader_entry_read(void *handle, void *buf, int32_t len);\n/* Reads and entry after being opened */\n\nint32_t mz_zip_reader_entry_has_sign(void *handle);\n/* Checks to see if the entry has a signature  */\n\nint32_t mz_zip_reader_entry_sign_verify(void *handle);\n/* Verifies a signature stored with the entry */\n\nint32_t mz_zip_reader_entry_get_hash(void *handle, uint16_t algorithm, uint8_t *digest, int32_t digest_size);\n/* Gets a hash algorithm from the entry's extra field */\n\nint32_t mz_zip_reader_entry_get_first_hash(void *handle, uint16_t *algorithm, uint16_t *digest_size);\n/* Gets the most secure hash algorithm from the entry's extra field */\n\nint32_t mz_zip_reader_entry_get_info(void *handle, mz_zip_file **file_info);\n/* Gets the current entry file info */\n\nint32_t mz_zip_reader_entry_is_dir(void *handle);\n/* Gets the current entry is a directory */\n\nint32_t mz_zip_reader_entry_save(void *handle, void *stream, mz_stream_write_cb write_cb);\n/* Save the current entry to a stream */\n\nint32_t mz_zip_reader_entry_save_process(void *handle, void *stream, mz_stream_write_cb write_cb);\n/* Saves a portion of the current entry to a stream callback */\n\nint32_t mz_zip_reader_entry_save_file(void *handle, const char *path);\n/* Save the current entry to a file */\n\nint32_t mz_zip_reader_entry_save_buffer(void *handle, void *buf, int32_t len);\n/* Save the current entry to a memory buffer */\n\nint32_t mz_zip_reader_entry_save_buffer_length(void *handle);\n/* Gets the length of the buffer required to save */\n\n/***************************************************************************/\n\nint32_t mz_zip_reader_save_all(void *handle, const char *destination_dir);\n/* Save all files into a directory */\n\n/***************************************************************************/\n\nvoid    mz_zip_reader_set_pattern(void *handle, const char *pattern, uint8_t ignore_case);\n/* Sets the match pattern for entries in the zip file, if null all entries are matched */\n\nvoid    mz_zip_reader_set_password(void *handle, const char *password);\n/* Sets the password required for extraction */\n\nvoid    mz_zip_reader_set_raw(void *handle, uint8_t raw);\n/* Sets whether or not it should save the entry raw */\n\nint32_t mz_zip_reader_get_raw(void *handle, uint8_t *raw);\n/* Gets whether or not it should save the entry raw */\n\nint32_t mz_zip_reader_get_zip_cd(void *handle, uint8_t *zip_cd);\n/* Gets whether or not the archive has a zipped central directory */\n\nint32_t mz_zip_reader_get_comment(void *handle, const char **comment);\n/* Gets the comment for the central directory */\n\nint32_t mz_zip_reader_set_recover(void *handle, uint8_t recover);\n/* Sets the ability to recover the central dir by reading local file headers */\n\nvoid    mz_zip_reader_set_encoding(void *handle, int32_t encoding);\n/* Sets whether or not it should support a special character encoding in zip file names. */\n\nvoid    mz_zip_reader_set_sign_required(void *handle, uint8_t sign_required);\n/* Sets whether or not it a signature is required  */\n\nvoid    mz_zip_reader_set_overwrite_cb(void *handle, void *userdata, mz_zip_reader_overwrite_cb cb);\n/* Callback for what to do when a file is being overwritten */\n\nvoid    mz_zip_reader_set_password_cb(void *handle, void *userdata, mz_zip_reader_password_cb cb);\n/* Callback for when a password is required and hasn't been set */\n\nvoid    mz_zip_reader_set_progress_cb(void *handle, void *userdata, mz_zip_reader_progress_cb cb);\n/* Callback for extraction progress */\n\nvoid    mz_zip_reader_set_progress_interval(void *handle, uint32_t milliseconds);\n/* Let at least milliseconds pass between calls to progress callback */\n\nvoid    mz_zip_reader_set_entry_cb(void *handle, void *userdata, mz_zip_reader_entry_cb cb);\n/* Callback for zip file entries */\n\nint32_t mz_zip_reader_get_zip_handle(void *handle, void **zip_handle);\n/* Gets the underlying zip instance handle */\n\nvoid*   mz_zip_reader_create(void **handle);\n/* Create new instance of zip reader */\n\nvoid    mz_zip_reader_delete(void **handle);\n/* Delete instance of zip reader */\n\n/***************************************************************************/\n\ntypedef int32_t (*mz_zip_writer_overwrite_cb)(void *handle, void *userdata, const char *path);\ntypedef int32_t (*mz_zip_writer_password_cb)(void *handle, void *userdata, mz_zip_file *file_info, char *password, int32_t max_password);\ntypedef int32_t (*mz_zip_writer_progress_cb)(void *handle, void *userdata, mz_zip_file *file_info, int64_t position);\ntypedef int32_t (*mz_zip_writer_entry_cb)(void *handle, void *userdata, mz_zip_file *file_info);\n\n/***************************************************************************/\n\nint32_t mz_zip_writer_is_open(void *handle);\n/* Checks to see if the zip file is open */\n\nint32_t mz_zip_writer_open(void *handle, void *stream, uint8_t append);\n/* Opens zip file from stream */\n\nint32_t mz_zip_writer_open_file(void *handle, const char *path, int64_t disk_size, uint8_t append);\n/* Opens zip file from a file path */\n\nint32_t mz_zip_writer_open_file_in_memory(void *handle, const char *path);\n/* Opens zip file from a file path into memory for faster access */\n\nint32_t mz_zip_writer_close(void *handle);\n/* Closes the zip file */\n\n/***************************************************************************/\n\nint32_t mz_zip_writer_entry_open(void *handle, mz_zip_file *file_info);\n/* Opens an entry in the zip file for writing */\n\nint32_t mz_zip_writer_entry_close(void *handle);\n/* Closes entry in zip file */\n\nint32_t mz_zip_writer_entry_write(void *handle, const void *buf, int32_t len);\n/* Writes data into entry for zip */\n\n/***************************************************************************/\n\nint32_t mz_zip_writer_add(void *handle, void *stream, mz_stream_read_cb read_cb);\n/* Writes all data to the currently open entry in the zip */\n\nint32_t mz_zip_writer_add_process(void *handle, void *stream, mz_stream_read_cb read_cb);\n/* Writes a portion of data to the currently open entry in the zip */\n\nint32_t mz_zip_writer_add_info(void *handle, void *stream, mz_stream_read_cb read_cb, mz_zip_file *file_info);\n/* Adds an entry to the zip based on the info */\n\nint32_t mz_zip_writer_add_buffer(void *handle, void *buf, int32_t len, mz_zip_file *file_info);\n/* Adds an entry to the zip with a memory buffer */\n\nint32_t mz_zip_writer_add_file(void *handle, const char *path, const char *filename_in_zip);\n/* Adds an entry to the zip from a file */\n\nint32_t mz_zip_writer_add_path(void *handle, const char *path, const char *root_path, uint8_t include_path,\n    uint8_t recursive);\n/* Enumerates a directory or pattern and adds entries to the zip */\n\nint32_t mz_zip_writer_copy_from_reader(void *handle, void *reader);\n/* Adds an entry from a zip reader instance */\n\n/***************************************************************************/\n\nvoid    mz_zip_writer_set_password(void *handle, const char *password);\n/* Password to use for encrypting files in the zip */\n\nvoid    mz_zip_writer_set_comment(void *handle, const char *comment);\n/* Comment to use for the archive */\n\nvoid    mz_zip_writer_set_raw(void *handle, uint8_t raw);\n/* Sets whether or not we should write the entry raw */\n\nint32_t mz_zip_writer_get_raw(void *handle, uint8_t *raw);\n/* Gets whether or not we should write the entry raw */\n\nvoid    mz_zip_writer_set_aes(void *handle, uint8_t aes);\n/* Use aes encryption when adding files in zip */\n\nvoid    mz_zip_writer_set_compress_method(void *handle, uint16_t compress_method);\n/* Sets the compression method when adding files in zip */\n\nvoid    mz_zip_writer_set_compress_level(void *handle, int16_t compress_level);\n/* Sets the compression level when adding files in zip */\n\nvoid    mz_zip_writer_set_follow_links(void *handle, uint8_t follow_links);\n/* Follow symbolic links when traversing directories and files to add */\n\nvoid    mz_zip_writer_set_store_links(void *handle, uint8_t store_links);\n/* Store symbolic links in zip file */\n\nvoid    mz_zip_writer_set_zip_cd(void *handle, uint8_t zip_cd);\n/* Sets whether or not central directory should be zipped */\n\nint32_t mz_zip_writer_set_certificate(void *handle, const char *cert_path, const char *cert_pwd);\n/* Sets the certificate and timestamp url to use for signing when adding files in zip */\n\nvoid    mz_zip_writer_set_overwrite_cb(void *handle, void *userdata, mz_zip_writer_overwrite_cb cb);\n/* Callback for what to do when zip file already exists */\n\nvoid    mz_zip_writer_set_password_cb(void *handle, void *userdata, mz_zip_writer_password_cb cb);\n/* Callback for ask if a password is required for adding */\n\nvoid    mz_zip_writer_set_progress_cb(void *handle, void *userdata, mz_zip_writer_progress_cb cb);\n/* Callback for compression progress */\n\nvoid    mz_zip_writer_set_progress_interval(void *handle, uint32_t milliseconds);\n/* Let at least milliseconds pass between calls to progress callback */\n\nvoid    mz_zip_writer_set_entry_cb(void *handle, void *userdata, mz_zip_writer_entry_cb cb);\n/* Callback for zip file entries */\n\nint32_t mz_zip_writer_get_zip_handle(void *handle, void **zip_handle);\n/* Gets the underlying zip handle */\n\nvoid*   mz_zip_writer_create(void **handle);\n/* Create new instance of zip writer */\n\nvoid    mz_zip_writer_delete(void **handle);\n/* Delete instance of zip writer */\n\n/***************************************************************************/\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "ios/CodePush.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\t13BE3DEE1AC21097009241FE /* CodePush.m in Sources */ = {isa = PBXBuildFile; fileRef = 13BE3DED1AC21097009241FE /* CodePush.m */; };\n\t\t1B23B9141BF9267B000BB2F0 /* RCTConvert+CodePushInstallMode.m in Sources */ = {isa = PBXBuildFile; fileRef = 1B23B9131BF9267B000BB2F0 /* RCTConvert+CodePushInstallMode.m */; };\n\t\t1B762E901C9A5E9A006EF800 /* CodePushErrorUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 1B762E8F1C9A5E9A006EF800 /* CodePushErrorUtils.m */; };\n\t\t1BCC09A71CC19EB700DDC0DD /* RCTConvert+CodePushUpdateState.m in Sources */ = {isa = PBXBuildFile; fileRef = 1BCC09A61CC19EB700DDC0DD /* RCTConvert+CodePushUpdateState.m */; };\n\t\t3221E4512C8ABE1300268379 /* ZipArchive.h in Headers */ = {isa = PBXBuildFile; fileRef = 3221E42A2C8ABE1300268379 /* ZipArchive.h */; };\n\t\t3221E4522C8ABE1300268379 /* ZipArchive.h in Headers */ = {isa = PBXBuildFile; fileRef = 3221E42A2C8ABE1300268379 /* ZipArchive.h */; };\n\t\t3221E4532C8ABE1300268379 /* mz_strm_os_posix.c in Sources */ = {isa = PBXBuildFile; fileRef = 3221E42C2C8ABE1300268379 /* mz_strm_os_posix.c */; };\n\t\t3221E4542C8ABE1300268379 /* mz_strm_os_posix.c in Sources */ = {isa = PBXBuildFile; fileRef = 3221E42C2C8ABE1300268379 /* mz_strm_os_posix.c */; };\n\t\t3221E4552C8ABE1300268379 /* mz_strm_pkcrypt.c in Sources */ = {isa = PBXBuildFile; fileRef = 3221E42D2C8ABE1300268379 /* mz_strm_pkcrypt.c */; };\n\t\t3221E4562C8ABE1300268379 /* mz_strm_pkcrypt.c in Sources */ = {isa = PBXBuildFile; fileRef = 3221E42D2C8ABE1300268379 /* mz_strm_pkcrypt.c */; };\n\t\t3221E4572C8ABE1300268379 /* mz_strm_wzaes.h in Headers */ = {isa = PBXBuildFile; fileRef = 3221E42E2C8ABE1300268379 /* mz_strm_wzaes.h */; };\n\t\t3221E4582C8ABE1300268379 /* mz_strm_wzaes.h in Headers */ = {isa = PBXBuildFile; fileRef = 3221E42E2C8ABE1300268379 /* mz_strm_wzaes.h */; };\n\t\t3221E4592C8ABE1300268379 /* mz_compat.h in Headers */ = {isa = PBXBuildFile; fileRef = 3221E42F2C8ABE1300268379 /* mz_compat.h */; };\n\t\t3221E45A2C8ABE1300268379 /* mz_compat.h in Headers */ = {isa = PBXBuildFile; fileRef = 3221E42F2C8ABE1300268379 /* mz_compat.h */; };\n\t\t3221E45B2C8ABE1300268379 /* mz_strm_zlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 3221E4302C8ABE1300268379 /* mz_strm_zlib.c */; };\n\t\t3221E45C2C8ABE1300268379 /* mz_strm_zlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 3221E4302C8ABE1300268379 /* mz_strm_zlib.c */; };\n\t\t3221E45D2C8ABE1300268379 /* mz_zip.c in Sources */ = {isa = PBXBuildFile; fileRef = 3221E4312C8ABE1300268379 /* mz_zip.c */; };\n\t\t3221E45E2C8ABE1300268379 /* mz_zip.c in Sources */ = {isa = PBXBuildFile; fileRef = 3221E4312C8ABE1300268379 /* mz_zip.c */; };\n\t\t3221E45F2C8ABE1300268379 /* mz_os.h in Headers */ = {isa = PBXBuildFile; fileRef = 3221E4322C8ABE1300268379 /* mz_os.h */; };\n\t\t3221E4602C8ABE1300268379 /* mz_os.h in Headers */ = {isa = PBXBuildFile; fileRef = 3221E4322C8ABE1300268379 /* mz_os.h */; };\n\t\t3221E4612C8ABE1300268379 /* mz_zip_rw.c in Sources */ = {isa = PBXBuildFile; fileRef = 3221E4342C8ABE1300268379 /* mz_zip_rw.c */; };\n\t\t3221E4622C8ABE1300268379 /* mz_zip_rw.c in Sources */ = {isa = PBXBuildFile; fileRef = 3221E4342C8ABE1300268379 /* mz_zip_rw.c */; };\n\t\t3221E4632C8ABE1300268379 /* mz_strm_split.h in Headers */ = {isa = PBXBuildFile; fileRef = 3221E4352C8ABE1300268379 /* mz_strm_split.h */; };\n\t\t3221E4642C8ABE1300268379 /* mz_strm_split.h in Headers */ = {isa = PBXBuildFile; fileRef = 3221E4352C8ABE1300268379 /* mz_strm_split.h */; };\n\t\t3221E4652C8ABE1300268379 /* mz_strm_buf.h in Headers */ = {isa = PBXBuildFile; fileRef = 3221E4362C8ABE1300268379 /* mz_strm_buf.h */; };\n\t\t3221E4662C8ABE1300268379 /* mz_strm_buf.h in Headers */ = {isa = PBXBuildFile; fileRef = 3221E4362C8ABE1300268379 /* mz_strm_buf.h */; };\n\t\t3221E4672C8ABE1300268379 /* mz_crypt_apple.c in Sources */ = {isa = PBXBuildFile; fileRef = 3221E4372C8ABE1300268379 /* mz_crypt_apple.c */; };\n\t\t3221E4682C8ABE1300268379 /* mz_crypt_apple.c in Sources */ = {isa = PBXBuildFile; fileRef = 3221E4372C8ABE1300268379 /* mz_crypt_apple.c */; };\n\t\t3221E4692C8ABE1300268379 /* mz_strm.h in Headers */ = {isa = PBXBuildFile; fileRef = 3221E4382C8ABE1300268379 /* mz_strm.h */; };\n\t\t3221E46A2C8ABE1300268379 /* mz_strm.h in Headers */ = {isa = PBXBuildFile; fileRef = 3221E4382C8ABE1300268379 /* mz_strm.h */; };\n\t\t3221E46B2C8ABE1300268379 /* mz_strm_mem.c in Sources */ = {isa = PBXBuildFile; fileRef = 3221E4392C8ABE1300268379 /* mz_strm_mem.c */; };\n\t\t3221E46C2C8ABE1300268379 /* mz_strm_mem.c in Sources */ = {isa = PBXBuildFile; fileRef = 3221E4392C8ABE1300268379 /* mz_strm_mem.c */; };\n\t\t3221E46D2C8ABE1300268379 /* mz_crypt.c in Sources */ = {isa = PBXBuildFile; fileRef = 3221E43A2C8ABE1300268379 /* mz_crypt.c */; };\n\t\t3221E46E2C8ABE1300268379 /* mz_crypt.c in Sources */ = {isa = PBXBuildFile; fileRef = 3221E43A2C8ABE1300268379 /* mz_crypt.c */; };\n\t\t3221E46F2C8ABE1300268379 /* mz_strm_wzaes.c in Sources */ = {isa = PBXBuildFile; fileRef = 3221E43B2C8ABE1300268379 /* mz_strm_wzaes.c */; };\n\t\t3221E4702C8ABE1300268379 /* mz_strm_wzaes.c in Sources */ = {isa = PBXBuildFile; fileRef = 3221E43B2C8ABE1300268379 /* mz_strm_wzaes.c */; };\n\t\t3221E4712C8ABE1300268379 /* mz_strm_zlib.h in Headers */ = {isa = PBXBuildFile; fileRef = 3221E43C2C8ABE1300268379 /* mz_strm_zlib.h */; };\n\t\t3221E4722C8ABE1300268379 /* mz_strm_zlib.h in Headers */ = {isa = PBXBuildFile; fileRef = 3221E43C2C8ABE1300268379 /* mz_strm_zlib.h */; };\n\t\t3221E4732C8ABE1300268379 /* mz_compat.c in Sources */ = {isa = PBXBuildFile; fileRef = 3221E43D2C8ABE1300268379 /* mz_compat.c */; };\n\t\t3221E4742C8ABE1300268379 /* mz_compat.c in Sources */ = {isa = PBXBuildFile; fileRef = 3221E43D2C8ABE1300268379 /* mz_compat.c */; };\n\t\t3221E4752C8ABE1300268379 /* mz_strm_pkcrypt.h in Headers */ = {isa = PBXBuildFile; fileRef = 3221E43E2C8ABE1300268379 /* mz_strm_pkcrypt.h */; };\n\t\t3221E4762C8ABE1300268379 /* mz_strm_pkcrypt.h in Headers */ = {isa = PBXBuildFile; fileRef = 3221E43E2C8ABE1300268379 /* mz_strm_pkcrypt.h */; };\n\t\t3221E4772C8ABE1300268379 /* mz_zip_rw.h in Headers */ = {isa = PBXBuildFile; fileRef = 3221E43F2C8ABE1300268379 /* mz_zip_rw.h */; };\n\t\t3221E4782C8ABE1300268379 /* mz_zip_rw.h in Headers */ = {isa = PBXBuildFile; fileRef = 3221E43F2C8ABE1300268379 /* mz_zip_rw.h */; };\n\t\t3221E4792C8ABE1300268379 /* mz_os.c in Sources */ = {isa = PBXBuildFile; fileRef = 3221E4402C8ABE1300268379 /* mz_os.c */; };\n\t\t3221E47A2C8ABE1300268379 /* mz_os.c in Sources */ = {isa = PBXBuildFile; fileRef = 3221E4402C8ABE1300268379 /* mz_os.c */; };\n\t\t3221E47B2C8ABE1400268379 /* mz_zip.h in Headers */ = {isa = PBXBuildFile; fileRef = 3221E4412C8ABE1300268379 /* mz_zip.h */; };\n\t\t3221E47C2C8ABE1400268379 /* mz_zip.h in Headers */ = {isa = PBXBuildFile; fileRef = 3221E4412C8ABE1300268379 /* mz_zip.h */; };\n\t\t3221E47D2C8ABE1400268379 /* mz_os_posix.c in Sources */ = {isa = PBXBuildFile; fileRef = 3221E4422C8ABE1300268379 /* mz_os_posix.c */; };\n\t\t3221E47E2C8ABE1400268379 /* mz_os_posix.c in Sources */ = {isa = PBXBuildFile; fileRef = 3221E4422C8ABE1300268379 /* mz_os_posix.c */; };\n\t\t3221E47F2C8ABE1400268379 /* mz.h in Headers */ = {isa = PBXBuildFile; fileRef = 3221E4432C8ABE1300268379 /* mz.h */; };\n\t\t3221E4802C8ABE1400268379 /* mz.h in Headers */ = {isa = PBXBuildFile; fileRef = 3221E4432C8ABE1300268379 /* mz.h */; };\n\t\t3221E4812C8ABE1400268379 /* mz_strm_buf.c in Sources */ = {isa = PBXBuildFile; fileRef = 3221E4442C8ABE1300268379 /* mz_strm_buf.c */; };\n\t\t3221E4822C8ABE1400268379 /* mz_strm_buf.c in Sources */ = {isa = PBXBuildFile; fileRef = 3221E4442C8ABE1300268379 /* mz_strm_buf.c */; };\n\t\t3221E4832C8ABE1400268379 /* mz_strm_split.c in Sources */ = {isa = PBXBuildFile; fileRef = 3221E4452C8ABE1300268379 /* mz_strm_split.c */; };\n\t\t3221E4842C8ABE1400268379 /* mz_strm_split.c in Sources */ = {isa = PBXBuildFile; fileRef = 3221E4452C8ABE1300268379 /* mz_strm_split.c */; };\n\t\t3221E4852C8ABE1400268379 /* mz_crypt.h in Headers */ = {isa = PBXBuildFile; fileRef = 3221E4462C8ABE1300268379 /* mz_crypt.h */; };\n\t\t3221E4862C8ABE1400268379 /* mz_crypt.h in Headers */ = {isa = PBXBuildFile; fileRef = 3221E4462C8ABE1300268379 /* mz_crypt.h */; };\n\t\t3221E4872C8ABE1400268379 /* mz_strm_mem.h in Headers */ = {isa = PBXBuildFile; fileRef = 3221E4472C8ABE1300268379 /* mz_strm_mem.h */; };\n\t\t3221E4882C8ABE1400268379 /* mz_strm_mem.h in Headers */ = {isa = PBXBuildFile; fileRef = 3221E4472C8ABE1300268379 /* mz_strm_mem.h */; };\n\t\t3221E4892C8ABE1400268379 /* mz_strm.c in Sources */ = {isa = PBXBuildFile; fileRef = 3221E4482C8ABE1300268379 /* mz_strm.c */; };\n\t\t3221E48A2C8ABE1400268379 /* mz_strm.c in Sources */ = {isa = PBXBuildFile; fileRef = 3221E4482C8ABE1300268379 /* mz_strm.c */; };\n\t\t3221E48B2C8ABE1400268379 /* mz_strm_os.h in Headers */ = {isa = PBXBuildFile; fileRef = 3221E4492C8ABE1300268379 /* mz_strm_os.h */; };\n\t\t3221E48C2C8ABE1400268379 /* mz_strm_os.h in Headers */ = {isa = PBXBuildFile; fileRef = 3221E4492C8ABE1300268379 /* mz_strm_os.h */; };\n\t\t3221E48D2C8ABE1400268379 /* SSZipArchive.h in Headers */ = {isa = PBXBuildFile; fileRef = 3221E44A2C8ABE1300268379 /* SSZipArchive.h */; };\n\t\t3221E48E2C8ABE1400268379 /* SSZipArchive.h in Headers */ = {isa = PBXBuildFile; fileRef = 3221E44A2C8ABE1300268379 /* SSZipArchive.h */; };\n\t\t3221E48F2C8ABE1400268379 /* SSZipCommon.h in Headers */ = {isa = PBXBuildFile; fileRef = 3221E44E2C8ABE1300268379 /* SSZipCommon.h */; };\n\t\t3221E4902C8ABE1400268379 /* SSZipCommon.h in Headers */ = {isa = PBXBuildFile; fileRef = 3221E44E2C8ABE1300268379 /* SSZipCommon.h */; };\n\t\t3221E4912C8ABE1400268379 /* SSZipArchive.m in Sources */ = {isa = PBXBuildFile; fileRef = 3221E44F2C8ABE1300268379 /* SSZipArchive.m */; };\n\t\t3221E4922C8ABE1400268379 /* SSZipArchive.m in Sources */ = {isa = PBXBuildFile; fileRef = 3221E44F2C8ABE1300268379 /* SSZipArchive.m */; };\n\t\t540D20121C7684FE00D6EF41 /* CodePushUpdateUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 540D20111C7684FE00D6EF41 /* CodePushUpdateUtils.m */; };\n\t\t5421FE311C58AD5A00986A55 /* CodePushTelemetryManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 5421FE301C58AD5A00986A55 /* CodePushTelemetryManager.m */; };\n\t\t5498D8F61D21F14100B5EB43 /* CodePushUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 5498D8F51D21F14100B5EB43 /* CodePushUtils.m */; };\n\t\t54FFEDE01BF550630061DD23 /* CodePushDownloadHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 54FFEDDF1BF550630061DD23 /* CodePushDownloadHandler.m */; };\n\t\t6463C82D1EBA0CFB0095B8CD /* CodePushUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 5498D8F51D21F14100B5EB43 /* CodePushUtils.m */; };\n\t\t6463C82E1EBA0CFB0095B8CD /* CodePush.m in Sources */ = {isa = PBXBuildFile; fileRef = 13BE3DED1AC21097009241FE /* CodePush.m */; };\n\t\t6463C82F1EBA0CFB0095B8CD /* CodePushConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 81D51F391B6181C2000DA084 /* CodePushConfig.m */; };\n\t\t6463C8301EBA0CFB0095B8CD /* CodePushDownloadHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 54FFEDDF1BF550630061DD23 /* CodePushDownloadHandler.m */; };\n\t\t6463C8311EBA0CFB0095B8CD /* CodePushErrorUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 1B762E8F1C9A5E9A006EF800 /* CodePushErrorUtils.m */; };\n\t\t6463C8321EBA0CFB0095B8CD /* CodePushPackage.m in Sources */ = {isa = PBXBuildFile; fileRef = 810D4E6C1B96935000B397E9 /* CodePushPackage.m */; };\n\t\t6463C8331EBA0CFB0095B8CD /* CodePushTelemetryManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 5421FE301C58AD5A00986A55 /* CodePushTelemetryManager.m */; };\n\t\t6463C8341EBA0CFB0095B8CD /* CodePushUpdateUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 540D20111C7684FE00D6EF41 /* CodePushUpdateUtils.m */; };\n\t\t6463C8351EBA0CFB0095B8CD /* RCTConvert+CodePushInstallMode.m in Sources */ = {isa = PBXBuildFile; fileRef = 1B23B9131BF9267B000BB2F0 /* RCTConvert+CodePushInstallMode.m */; };\n\t\t6463C8361EBA0CFB0095B8CD /* RCTConvert+CodePushUpdateState.m in Sources */ = {isa = PBXBuildFile; fileRef = 1BCC09A61CC19EB700DDC0DD /* RCTConvert+CodePushUpdateState.m */; };\n\t\t6463C8451EBA0D1F0095B8CD /* CodePush.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 13BE3DEC1AC21097009241FE /* CodePush.h */; };\n\t\t6463C8471EBA0D290095B8CD /* CodePush.h in Headers */ = {isa = PBXBuildFile; fileRef = 13BE3DEC1AC21097009241FE /* CodePush.h */; };\n\t\t810D4E6D1B96935000B397E9 /* CodePushPackage.m in Sources */ = {isa = PBXBuildFile; fileRef = 810D4E6C1B96935000B397E9 /* CodePushPackage.m */; };\n\t\t81D51F3A1B6181C2000DA084 /* CodePushConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 81D51F391B6181C2000DA084 /* CodePushConfig.m */; };\n\t\t8482F84C1E24C58300F793DB /* CodePush.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 13BE3DEC1AC21097009241FE /* CodePush.h */; };\n\t\t8482F84E1E24C66300F793DB /* CodePush.h in Headers */ = {isa = PBXBuildFile; fileRef = 13BE3DEC1AC21097009241FE /* CodePush.h */; };\n\t\tF85736761F4F03BF00C9C00A /* MF_Base64Additions.h in Headers */ = {isa = PBXBuildFile; fileRef = F85736731F4F03BF00C9C00A /* MF_Base64Additions.h */; };\n\t\tF85736771F4F03BF00C9C00A /* MF_Base64Additions.m in Sources */ = {isa = PBXBuildFile; fileRef = F85736741F4F03BF00C9C00A /* MF_Base64Additions.m */; };\n\t\tF886644D1F4AD1EE0036D01B /* JWTAlgorithm.h in Headers */ = {isa = PBXBuildFile; fileRef = F88664151F4AD1EE0036D01B /* JWTAlgorithm.h */; };\n\t\tF886644E1F4AD1EE0036D01B /* JWTAlgorithmFactory.h in Headers */ = {isa = PBXBuildFile; fileRef = F88664161F4AD1EE0036D01B /* JWTAlgorithmFactory.h */; };\n\t\tF886644F1F4AD1EE0036D01B /* JWTAlgorithmFactory.m in Sources */ = {isa = PBXBuildFile; fileRef = F88664171F4AD1EE0036D01B /* JWTAlgorithmFactory.m */; };\n\t\tF88664501F4AD1EE0036D01B /* JWTAlgorithmNone.h in Headers */ = {isa = PBXBuildFile; fileRef = F88664181F4AD1EE0036D01B /* JWTAlgorithmNone.h */; };\n\t\tF88664511F4AD1EE0036D01B /* JWTAlgorithmNone.m in Sources */ = {isa = PBXBuildFile; fileRef = F88664191F4AD1EE0036D01B /* JWTAlgorithmNone.m */; };\n\t\tF88664521F4AD1EE0036D01B /* JWTAlgorithmESBase.h in Headers */ = {isa = PBXBuildFile; fileRef = F886641B1F4AD1EE0036D01B /* JWTAlgorithmESBase.h */; };\n\t\tF88664531F4AD1EE0036D01B /* JWTAlgorithmESBase.m in Sources */ = {isa = PBXBuildFile; fileRef = F886641C1F4AD1EE0036D01B /* JWTAlgorithmESBase.m */; };\n\t\tF88664541F4AD1EE0036D01B /* JWTAlgorithmDataHolder.h in Headers */ = {isa = PBXBuildFile; fileRef = F886641E1F4AD1EE0036D01B /* JWTAlgorithmDataHolder.h */; };\n\t\tF88664551F4AD1EE0036D01B /* JWTAlgorithmDataHolder.m in Sources */ = {isa = PBXBuildFile; fileRef = F886641F1F4AD1EE0036D01B /* JWTAlgorithmDataHolder.m */; };\n\t\tF88664561F4AD1EE0036D01B /* JWTAlgorithmDataHolderChain.h in Headers */ = {isa = PBXBuildFile; fileRef = F88664201F4AD1EE0036D01B /* JWTAlgorithmDataHolderChain.h */; };\n\t\tF88664571F4AD1EE0036D01B /* JWTAlgorithmDataHolderChain.m in Sources */ = {isa = PBXBuildFile; fileRef = F88664211F4AD1EE0036D01B /* JWTAlgorithmDataHolderChain.m */; };\n\t\tF88664581F4AD1EE0036D01B /* JWTAlgorithmHSBase.h in Headers */ = {isa = PBXBuildFile; fileRef = F88664231F4AD1EE0036D01B /* JWTAlgorithmHSBase.h */; };\n\t\tF88664591F4AD1EE0036D01B /* JWTAlgorithmHSBase.m in Sources */ = {isa = PBXBuildFile; fileRef = F88664241F4AD1EE0036D01B /* JWTAlgorithmHSBase.m */; };\n\t\tF886645A1F4AD1EE0036D01B /* JWTAlgorithmRSBase.h in Headers */ = {isa = PBXBuildFile; fileRef = F88664261F4AD1EE0036D01B /* JWTAlgorithmRSBase.h */; };\n\t\tF886645B1F4AD1EE0036D01B /* JWTAlgorithmRSBase.m in Sources */ = {isa = PBXBuildFile; fileRef = F88664271F4AD1EE0036D01B /* JWTAlgorithmRSBase.m */; };\n\t\tF886645C1F4AD1EE0036D01B /* JWTRSAlgorithm.h in Headers */ = {isa = PBXBuildFile; fileRef = F88664281F4AD1EE0036D01B /* JWTRSAlgorithm.h */; };\n\t\tF886645D1F4AD1EE0036D01B /* JWTCryptoKey.h in Headers */ = {isa = PBXBuildFile; fileRef = F886642A1F4AD1EE0036D01B /* JWTCryptoKey.h */; };\n\t\tF886645E1F4AD1EE0036D01B /* JWTCryptoKey.m in Sources */ = {isa = PBXBuildFile; fileRef = F886642B1F4AD1EE0036D01B /* JWTCryptoKey.m */; };\n\t\tF886645F1F4AD1EE0036D01B /* JWTCryptoKeyExtractor.h in Headers */ = {isa = PBXBuildFile; fileRef = F886642C1F4AD1EE0036D01B /* JWTCryptoKeyExtractor.h */; };\n\t\tF88664601F4AD1EE0036D01B /* JWTCryptoKeyExtractor.m in Sources */ = {isa = PBXBuildFile; fileRef = F886642D1F4AD1EE0036D01B /* JWTCryptoKeyExtractor.m */; };\n\t\tF88664611F4AD1EE0036D01B /* JWTCryptoSecurity.h in Headers */ = {isa = PBXBuildFile; fileRef = F886642E1F4AD1EE0036D01B /* JWTCryptoSecurity.h */; };\n\t\tF88664621F4AD1EE0036D01B /* JWTCryptoSecurity.m in Sources */ = {isa = PBXBuildFile; fileRef = F886642F1F4AD1EE0036D01B /* JWTCryptoSecurity.m */; };\n\t\tF88664631F4AD1EE0036D01B /* JWTClaim.h in Headers */ = {isa = PBXBuildFile; fileRef = F88664311F4AD1EE0036D01B /* JWTClaim.h */; };\n\t\tF88664641F4AD1EE0036D01B /* JWTClaim.m in Sources */ = {isa = PBXBuildFile; fileRef = F88664321F4AD1EE0036D01B /* JWTClaim.m */; };\n\t\tF88664651F4AD1EE0036D01B /* JWTClaimsSet.h in Headers */ = {isa = PBXBuildFile; fileRef = F88664331F4AD1EE0036D01B /* JWTClaimsSet.h */; };\n\t\tF88664661F4AD1EE0036D01B /* JWTClaimsSet.m in Sources */ = {isa = PBXBuildFile; fileRef = F88664341F4AD1EE0036D01B /* JWTClaimsSet.m */; };\n\t\tF88664671F4AD1EE0036D01B /* JWTClaimsSetSerializer.h in Headers */ = {isa = PBXBuildFile; fileRef = F88664351F4AD1EE0036D01B /* JWTClaimsSetSerializer.h */; };\n\t\tF88664681F4AD1EE0036D01B /* JWTClaimsSetSerializer.m in Sources */ = {isa = PBXBuildFile; fileRef = F88664361F4AD1EE0036D01B /* JWTClaimsSetSerializer.m */; };\n\t\tF88664691F4AD1EE0036D01B /* JWTClaimsSetVerifier.h in Headers */ = {isa = PBXBuildFile; fileRef = F88664371F4AD1EE0036D01B /* JWTClaimsSetVerifier.h */; };\n\t\tF886646A1F4AD1EE0036D01B /* JWTClaimsSetVerifier.m in Sources */ = {isa = PBXBuildFile; fileRef = F88664381F4AD1EE0036D01B /* JWTClaimsSetVerifier.m */; };\n\t\tF886646B1F4AD1EE0036D01B /* JWTCoding+ResultTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = F886643A1F4AD1EE0036D01B /* JWTCoding+ResultTypes.h */; };\n\t\tF886646C1F4AD1EE0036D01B /* JWTCoding+ResultTypes.m in Sources */ = {isa = PBXBuildFile; fileRef = F886643B1F4AD1EE0036D01B /* JWTCoding+ResultTypes.m */; };\n\t\tF886646D1F4AD1EE0036D01B /* JWTCoding+VersionOne.h in Headers */ = {isa = PBXBuildFile; fileRef = F886643C1F4AD1EE0036D01B /* JWTCoding+VersionOne.h */; };\n\t\tF886646E1F4AD1EE0036D01B /* JWTCoding+VersionOne.m in Sources */ = {isa = PBXBuildFile; fileRef = F886643D1F4AD1EE0036D01B /* JWTCoding+VersionOne.m */; };\n\t\tF886646F1F4AD1EE0036D01B /* JWTCoding+VersionThree.h in Headers */ = {isa = PBXBuildFile; fileRef = F886643E1F4AD1EE0036D01B /* JWTCoding+VersionThree.h */; };\n\t\tF88664701F4AD1EE0036D01B /* JWTCoding+VersionThree.m in Sources */ = {isa = PBXBuildFile; fileRef = F886643F1F4AD1EE0036D01B /* JWTCoding+VersionThree.m */; };\n\t\tF88664711F4AD1EE0036D01B /* JWTCoding+VersionTwo.h in Headers */ = {isa = PBXBuildFile; fileRef = F88664401F4AD1EE0036D01B /* JWTCoding+VersionTwo.h */; };\n\t\tF88664721F4AD1EE0036D01B /* JWTCoding+VersionTwo.m in Sources */ = {isa = PBXBuildFile; fileRef = F88664411F4AD1EE0036D01B /* JWTCoding+VersionTwo.m */; };\n\t\tF88664731F4AD1EE0036D01B /* JWTCoding.h in Headers */ = {isa = PBXBuildFile; fileRef = F88664421F4AD1EE0036D01B /* JWTCoding.h */; };\n\t\tF88664741F4AD1EE0036D01B /* JWTCoding.m in Sources */ = {isa = PBXBuildFile; fileRef = F88664431F4AD1EE0036D01B /* JWTCoding.m */; };\n\t\tF88664751F4AD1EE0036D01B /* JWT.h in Headers */ = {isa = PBXBuildFile; fileRef = F88664451F4AD1EE0036D01B /* JWT.h */; };\n\t\tF88664761F4AD1EE0036D01B /* JWTBase64Coder.h in Headers */ = {isa = PBXBuildFile; fileRef = F88664481F4AD1EE0036D01B /* JWTBase64Coder.h */; };\n\t\tF88664771F4AD1EE0036D01B /* JWTBase64Coder.m in Sources */ = {isa = PBXBuildFile; fileRef = F88664491F4AD1EE0036D01B /* JWTBase64Coder.m */; };\n\t\tF88664781F4AD1EE0036D01B /* JWTDeprecations.h in Headers */ = {isa = PBXBuildFile; fileRef = F886644A1F4AD1EE0036D01B /* JWTDeprecations.h */; };\n\t\tF88664791F4AD1EE0036D01B /* JWTErrorDescription.h in Headers */ = {isa = PBXBuildFile; fileRef = F886644B1F4AD1EE0036D01B /* JWTErrorDescription.h */; };\n\t\tF886647A1F4AD1EF0036D01B /* JWTErrorDescription.m in Sources */ = {isa = PBXBuildFile; fileRef = F886644C1F4AD1EE0036D01B /* JWTErrorDescription.m */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXCopyFilesBuildPhase section */\n\t\t58B511D91A9E6C8500147676 /* CopyFiles */ = {\n\t\t\tisa = PBXCopyFilesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tdstPath = include/CodePush;\n\t\t\tdstSubfolderSpec = 16;\n\t\t\tfiles = (\n\t\t\t\t8482F84C1E24C58300F793DB /* CodePush.h in CopyFiles */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t6463C8221EBA0CB60095B8CD /* CopyFiles */ = {\n\t\t\tisa = PBXCopyFilesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tdstPath = \"include/$(PRODUCT_NAME)\";\n\t\t\tdstSubfolderSpec = 16;\n\t\t\tfiles = (\n\t\t\t\t6463C8451EBA0D1F0095B8CD /* CodePush.h in CopyFiles */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXCopyFilesBuildPhase section */\n\n/* Begin PBXFileReference section */\n\t\t134814201AA4EA6300B7C361 /* libCodePush.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libCodePush.a; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t13BE3DEC1AC21097009241FE /* CodePush.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CodePush.h; path = CodePush/CodePush.h; sourceTree = \"<group>\"; };\n\t\t13BE3DED1AC21097009241FE /* CodePush.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CodePush.m; path = CodePush/CodePush.m; sourceTree = \"<group>\"; };\n\t\t1B23B9131BF9267B000BB2F0 /* RCTConvert+CodePushInstallMode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = \"RCTConvert+CodePushInstallMode.m\"; path = \"CodePush/RCTConvert+CodePushInstallMode.m\"; sourceTree = \"<group>\"; };\n\t\t1B762E8F1C9A5E9A006EF800 /* CodePushErrorUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CodePushErrorUtils.m; path = CodePush/CodePushErrorUtils.m; sourceTree = \"<group>\"; };\n\t\t1BCC09A61CC19EB700DDC0DD /* RCTConvert+CodePushUpdateState.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = \"RCTConvert+CodePushUpdateState.m\"; path = \"CodePush/RCTConvert+CodePushUpdateState.m\"; sourceTree = \"<group>\"; };\n\t\t3221E42A2C8ABE1300268379 /* ZipArchive.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZipArchive.h; sourceTree = \"<group>\"; };\n\t\t3221E42C2C8ABE1300268379 /* mz_strm_os_posix.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mz_strm_os_posix.c; sourceTree = \"<group>\"; };\n\t\t3221E42D2C8ABE1300268379 /* mz_strm_pkcrypt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mz_strm_pkcrypt.c; sourceTree = \"<group>\"; };\n\t\t3221E42E2C8ABE1300268379 /* mz_strm_wzaes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mz_strm_wzaes.h; sourceTree = \"<group>\"; };\n\t\t3221E42F2C8ABE1300268379 /* mz_compat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mz_compat.h; sourceTree = \"<group>\"; };\n\t\t3221E4302C8ABE1300268379 /* mz_strm_zlib.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mz_strm_zlib.c; sourceTree = \"<group>\"; };\n\t\t3221E4312C8ABE1300268379 /* mz_zip.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mz_zip.c; sourceTree = \"<group>\"; };\n\t\t3221E4322C8ABE1300268379 /* mz_os.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mz_os.h; sourceTree = \"<group>\"; };\n\t\t3221E4332C8ABE1300268379 /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = \"<group>\"; };\n\t\t3221E4342C8ABE1300268379 /* mz_zip_rw.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mz_zip_rw.c; sourceTree = \"<group>\"; };\n\t\t3221E4352C8ABE1300268379 /* mz_strm_split.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mz_strm_split.h; sourceTree = \"<group>\"; };\n\t\t3221E4362C8ABE1300268379 /* mz_strm_buf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mz_strm_buf.h; sourceTree = \"<group>\"; };\n\t\t3221E4372C8ABE1300268379 /* mz_crypt_apple.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mz_crypt_apple.c; sourceTree = \"<group>\"; };\n\t\t3221E4382C8ABE1300268379 /* mz_strm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mz_strm.h; sourceTree = \"<group>\"; };\n\t\t3221E4392C8ABE1300268379 /* mz_strm_mem.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mz_strm_mem.c; sourceTree = \"<group>\"; };\n\t\t3221E43A2C8ABE1300268379 /* mz_crypt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mz_crypt.c; sourceTree = \"<group>\"; };\n\t\t3221E43B2C8ABE1300268379 /* mz_strm_wzaes.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mz_strm_wzaes.c; sourceTree = \"<group>\"; };\n\t\t3221E43C2C8ABE1300268379 /* mz_strm_zlib.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mz_strm_zlib.h; sourceTree = \"<group>\"; };\n\t\t3221E43D2C8ABE1300268379 /* mz_compat.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mz_compat.c; sourceTree = \"<group>\"; };\n\t\t3221E43E2C8ABE1300268379 /* mz_strm_pkcrypt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mz_strm_pkcrypt.h; sourceTree = \"<group>\"; };\n\t\t3221E43F2C8ABE1300268379 /* mz_zip_rw.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mz_zip_rw.h; sourceTree = \"<group>\"; };\n\t\t3221E4402C8ABE1300268379 /* mz_os.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mz_os.c; sourceTree = \"<group>\"; };\n\t\t3221E4412C8ABE1300268379 /* mz_zip.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mz_zip.h; sourceTree = \"<group>\"; };\n\t\t3221E4422C8ABE1300268379 /* mz_os_posix.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mz_os_posix.c; sourceTree = \"<group>\"; };\n\t\t3221E4432C8ABE1300268379 /* mz.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mz.h; sourceTree = \"<group>\"; };\n\t\t3221E4442C8ABE1300268379 /* mz_strm_buf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mz_strm_buf.c; sourceTree = \"<group>\"; };\n\t\t3221E4452C8ABE1300268379 /* mz_strm_split.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mz_strm_split.c; sourceTree = \"<group>\"; };\n\t\t3221E4462C8ABE1300268379 /* mz_crypt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mz_crypt.h; sourceTree = \"<group>\"; };\n\t\t3221E4472C8ABE1300268379 /* mz_strm_mem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mz_strm_mem.h; sourceTree = \"<group>\"; };\n\t\t3221E4482C8ABE1300268379 /* mz_strm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mz_strm.c; sourceTree = \"<group>\"; };\n\t\t3221E4492C8ABE1300268379 /* mz_strm_os.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mz_strm_os.h; sourceTree = \"<group>\"; };\n\t\t3221E44A2C8ABE1300268379 /* SSZipArchive.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SSZipArchive.h; sourceTree = \"<group>\"; };\n\t\t3221E44B2C8ABE1300268379 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = \"<group>\"; };\n\t\t3221E44D2C8ABE1300268379 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = \"<group>\"; };\n\t\t3221E44E2C8ABE1300268379 /* SSZipCommon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SSZipCommon.h; sourceTree = \"<group>\"; };\n\t\t3221E44F2C8ABE1300268379 /* SSZipArchive.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SSZipArchive.m; sourceTree = \"<group>\"; };\n\t\t3221E4502C8ABE1300268379 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t540D20111C7684FE00D6EF41 /* CodePushUpdateUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CodePushUpdateUtils.m; path = CodePush/CodePushUpdateUtils.m; sourceTree = \"<group>\"; };\n\t\t5421FE301C58AD5A00986A55 /* CodePushTelemetryManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CodePushTelemetryManager.m; path = CodePush/CodePushTelemetryManager.m; sourceTree = \"<group>\"; };\n\t\t5498D8F51D21F14100B5EB43 /* CodePushUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CodePushUtils.m; path = CodePush/CodePushUtils.m; sourceTree = \"<group>\"; };\n\t\t54FFEDDF1BF550630061DD23 /* CodePushDownloadHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CodePushDownloadHandler.m; path = CodePush/CodePushDownloadHandler.m; sourceTree = \"<group>\"; };\n\t\t810D4E6C1B96935000B397E9 /* CodePushPackage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CodePushPackage.m; path = CodePush/CodePushPackage.m; sourceTree = \"<group>\"; };\n\t\t81D51F391B6181C2000DA084 /* CodePushConfig.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CodePushConfig.m; path = CodePush/CodePushConfig.m; sourceTree = \"<group>\"; };\n\t\tF85736731F4F03BF00C9C00A /* MF_Base64Additions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MF_Base64Additions.h; sourceTree = \"<group>\"; };\n\t\tF85736741F4F03BF00C9C00A /* MF_Base64Additions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MF_Base64Additions.m; sourceTree = \"<group>\"; };\n\t\tF85736751F4F03BF00C9C00A /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = \"<group>\"; };\n\t\tF85736791F4F155300C9C00A /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = \"<group>\"; };\n\t\tF857367A1F4F155300C9C00A /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = \"<group>\"; };\n\t\tF88664151F4AD1EE0036D01B /* JWTAlgorithm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JWTAlgorithm.h; sourceTree = \"<group>\"; };\n\t\tF88664161F4AD1EE0036D01B /* JWTAlgorithmFactory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JWTAlgorithmFactory.h; sourceTree = \"<group>\"; };\n\t\tF88664171F4AD1EE0036D01B /* JWTAlgorithmFactory.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JWTAlgorithmFactory.m; sourceTree = \"<group>\"; };\n\t\tF88664181F4AD1EE0036D01B /* JWTAlgorithmNone.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JWTAlgorithmNone.h; sourceTree = \"<group>\"; };\n\t\tF88664191F4AD1EE0036D01B /* JWTAlgorithmNone.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JWTAlgorithmNone.m; sourceTree = \"<group>\"; };\n\t\tF886641B1F4AD1EE0036D01B /* JWTAlgorithmESBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JWTAlgorithmESBase.h; sourceTree = \"<group>\"; };\n\t\tF886641C1F4AD1EE0036D01B /* JWTAlgorithmESBase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JWTAlgorithmESBase.m; sourceTree = \"<group>\"; };\n\t\tF886641E1F4AD1EE0036D01B /* JWTAlgorithmDataHolder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JWTAlgorithmDataHolder.h; sourceTree = \"<group>\"; };\n\t\tF886641F1F4AD1EE0036D01B /* JWTAlgorithmDataHolder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JWTAlgorithmDataHolder.m; sourceTree = \"<group>\"; };\n\t\tF88664201F4AD1EE0036D01B /* JWTAlgorithmDataHolderChain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JWTAlgorithmDataHolderChain.h; sourceTree = \"<group>\"; };\n\t\tF88664211F4AD1EE0036D01B /* JWTAlgorithmDataHolderChain.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JWTAlgorithmDataHolderChain.m; sourceTree = \"<group>\"; };\n\t\tF88664231F4AD1EE0036D01B /* JWTAlgorithmHSBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JWTAlgorithmHSBase.h; sourceTree = \"<group>\"; };\n\t\tF88664241F4AD1EE0036D01B /* JWTAlgorithmHSBase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JWTAlgorithmHSBase.m; sourceTree = \"<group>\"; };\n\t\tF88664261F4AD1EE0036D01B /* JWTAlgorithmRSBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JWTAlgorithmRSBase.h; sourceTree = \"<group>\"; };\n\t\tF88664271F4AD1EE0036D01B /* JWTAlgorithmRSBase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JWTAlgorithmRSBase.m; sourceTree = \"<group>\"; };\n\t\tF88664281F4AD1EE0036D01B /* JWTRSAlgorithm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JWTRSAlgorithm.h; sourceTree = \"<group>\"; };\n\t\tF886642A1F4AD1EE0036D01B /* JWTCryptoKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JWTCryptoKey.h; sourceTree = \"<group>\"; };\n\t\tF886642B1F4AD1EE0036D01B /* JWTCryptoKey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JWTCryptoKey.m; sourceTree = \"<group>\"; };\n\t\tF886642C1F4AD1EE0036D01B /* JWTCryptoKeyExtractor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JWTCryptoKeyExtractor.h; sourceTree = \"<group>\"; };\n\t\tF886642D1F4AD1EE0036D01B /* JWTCryptoKeyExtractor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JWTCryptoKeyExtractor.m; sourceTree = \"<group>\"; };\n\t\tF886642E1F4AD1EE0036D01B /* JWTCryptoSecurity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JWTCryptoSecurity.h; sourceTree = \"<group>\"; };\n\t\tF886642F1F4AD1EE0036D01B /* JWTCryptoSecurity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JWTCryptoSecurity.m; sourceTree = \"<group>\"; };\n\t\tF88664311F4AD1EE0036D01B /* JWTClaim.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JWTClaim.h; sourceTree = \"<group>\"; };\n\t\tF88664321F4AD1EE0036D01B /* JWTClaim.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JWTClaim.m; sourceTree = \"<group>\"; };\n\t\tF88664331F4AD1EE0036D01B /* JWTClaimsSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JWTClaimsSet.h; sourceTree = \"<group>\"; };\n\t\tF88664341F4AD1EE0036D01B /* JWTClaimsSet.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JWTClaimsSet.m; sourceTree = \"<group>\"; };\n\t\tF88664351F4AD1EE0036D01B /* JWTClaimsSetSerializer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JWTClaimsSetSerializer.h; sourceTree = \"<group>\"; };\n\t\tF88664361F4AD1EE0036D01B /* JWTClaimsSetSerializer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JWTClaimsSetSerializer.m; sourceTree = \"<group>\"; };\n\t\tF88664371F4AD1EE0036D01B /* JWTClaimsSetVerifier.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JWTClaimsSetVerifier.h; sourceTree = \"<group>\"; };\n\t\tF88664381F4AD1EE0036D01B /* JWTClaimsSetVerifier.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JWTClaimsSetVerifier.m; sourceTree = \"<group>\"; };\n\t\tF886643A1F4AD1EE0036D01B /* JWTCoding+ResultTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = \"JWTCoding+ResultTypes.h\"; sourceTree = \"<group>\"; };\n\t\tF886643B1F4AD1EE0036D01B /* JWTCoding+ResultTypes.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = \"JWTCoding+ResultTypes.m\"; sourceTree = \"<group>\"; };\n\t\tF886643C1F4AD1EE0036D01B /* JWTCoding+VersionOne.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = \"JWTCoding+VersionOne.h\"; sourceTree = \"<group>\"; };\n\t\tF886643D1F4AD1EE0036D01B /* JWTCoding+VersionOne.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = \"JWTCoding+VersionOne.m\"; sourceTree = \"<group>\"; };\n\t\tF886643E1F4AD1EE0036D01B /* JWTCoding+VersionThree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = \"JWTCoding+VersionThree.h\"; sourceTree = \"<group>\"; };\n\t\tF886643F1F4AD1EE0036D01B /* JWTCoding+VersionThree.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = \"JWTCoding+VersionThree.m\"; sourceTree = \"<group>\"; };\n\t\tF88664401F4AD1EE0036D01B /* JWTCoding+VersionTwo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = \"JWTCoding+VersionTwo.h\"; sourceTree = \"<group>\"; };\n\t\tF88664411F4AD1EE0036D01B /* JWTCoding+VersionTwo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = \"JWTCoding+VersionTwo.m\"; sourceTree = \"<group>\"; };\n\t\tF88664421F4AD1EE0036D01B /* JWTCoding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JWTCoding.h; sourceTree = \"<group>\"; };\n\t\tF88664431F4AD1EE0036D01B /* JWTCoding.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JWTCoding.m; sourceTree = \"<group>\"; };\n\t\tF88664451F4AD1EE0036D01B /* JWT.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JWT.h; sourceTree = \"<group>\"; };\n\t\tF88664461F4AD1EE0036D01B /* Map.modulemap */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = \"sourcecode.module-map\"; path = Map.modulemap; sourceTree = \"<group>\"; };\n\t\tF88664481F4AD1EE0036D01B /* JWTBase64Coder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JWTBase64Coder.h; sourceTree = \"<group>\"; };\n\t\tF88664491F4AD1EE0036D01B /* JWTBase64Coder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JWTBase64Coder.m; sourceTree = \"<group>\"; };\n\t\tF886644A1F4AD1EE0036D01B /* JWTDeprecations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JWTDeprecations.h; sourceTree = \"<group>\"; };\n\t\tF886644B1F4AD1EE0036D01B /* JWTErrorDescription.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JWTErrorDescription.h; sourceTree = \"<group>\"; };\n\t\tF886644C1F4AD1EE0036D01B /* JWTErrorDescription.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JWTErrorDescription.m; sourceTree = \"<group>\"; };\n\t\tF886647B1F4ADB500036D01B /* libCodePush.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libCodePush.a; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tFF90DEF92C5A808600CA8692 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t58B511D81A9E6C8500147676 /* 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\t6463C8211EBA0CB60095B8CD /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t134814211AA4EA7D00B7C361 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t134814201AA4EA6300B7C361 /* libCodePush.a */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t3221E4282C8ABE1300268379 /* SSZipArchive */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t3221E4292C8ABE1300268379 /* include */,\n\t\t\t\t3221E42B2C8ABE1300268379 /* minizip */,\n\t\t\t\t3221E44A2C8ABE1300268379 /* SSZipArchive.h */,\n\t\t\t\t3221E44B2C8ABE1300268379 /* README.md */,\n\t\t\t\t3221E44C2C8ABE1300268379 /* Supporting Files */,\n\t\t\t\t3221E44E2C8ABE1300268379 /* SSZipCommon.h */,\n\t\t\t\t3221E44F2C8ABE1300268379 /* SSZipArchive.m */,\n\t\t\t\t3221E4502C8ABE1300268379 /* Info.plist */,\n\t\t\t);\n\t\t\tname = SSZipArchive;\n\t\t\tpath = CodePush/SSZipArchive;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t3221E4292C8ABE1300268379 /* include */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t3221E42A2C8ABE1300268379 /* ZipArchive.h */,\n\t\t\t);\n\t\t\tpath = include;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t3221E42B2C8ABE1300268379 /* minizip */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t3221E42C2C8ABE1300268379 /* mz_strm_os_posix.c */,\n\t\t\t\t3221E42D2C8ABE1300268379 /* mz_strm_pkcrypt.c */,\n\t\t\t\t3221E42E2C8ABE1300268379 /* mz_strm_wzaes.h */,\n\t\t\t\t3221E42F2C8ABE1300268379 /* mz_compat.h */,\n\t\t\t\t3221E4302C8ABE1300268379 /* mz_strm_zlib.c */,\n\t\t\t\t3221E4312C8ABE1300268379 /* mz_zip.c */,\n\t\t\t\t3221E4322C8ABE1300268379 /* mz_os.h */,\n\t\t\t\t3221E4332C8ABE1300268379 /* LICENSE */,\n\t\t\t\t3221E4342C8ABE1300268379 /* mz_zip_rw.c */,\n\t\t\t\t3221E4352C8ABE1300268379 /* mz_strm_split.h */,\n\t\t\t\t3221E4362C8ABE1300268379 /* mz_strm_buf.h */,\n\t\t\t\t3221E4372C8ABE1300268379 /* mz_crypt_apple.c */,\n\t\t\t\t3221E4382C8ABE1300268379 /* mz_strm.h */,\n\t\t\t\t3221E4392C8ABE1300268379 /* mz_strm_mem.c */,\n\t\t\t\t3221E43A2C8ABE1300268379 /* mz_crypt.c */,\n\t\t\t\t3221E43B2C8ABE1300268379 /* mz_strm_wzaes.c */,\n\t\t\t\t3221E43C2C8ABE1300268379 /* mz_strm_zlib.h */,\n\t\t\t\t3221E43D2C8ABE1300268379 /* mz_compat.c */,\n\t\t\t\t3221E43E2C8ABE1300268379 /* mz_strm_pkcrypt.h */,\n\t\t\t\t3221E43F2C8ABE1300268379 /* mz_zip_rw.h */,\n\t\t\t\t3221E4402C8ABE1300268379 /* mz_os.c */,\n\t\t\t\t3221E4412C8ABE1300268379 /* mz_zip.h */,\n\t\t\t\t3221E4422C8ABE1300268379 /* mz_os_posix.c */,\n\t\t\t\t3221E4432C8ABE1300268379 /* mz.h */,\n\t\t\t\t3221E4442C8ABE1300268379 /* mz_strm_buf.c */,\n\t\t\t\t3221E4452C8ABE1300268379 /* mz_strm_split.c */,\n\t\t\t\t3221E4462C8ABE1300268379 /* mz_crypt.h */,\n\t\t\t\t3221E4472C8ABE1300268379 /* mz_strm_mem.h */,\n\t\t\t\t3221E4482C8ABE1300268379 /* mz_strm.c */,\n\t\t\t\t3221E4492C8ABE1300268379 /* mz_strm_os.h */,\n\t\t\t);\n\t\t\tpath = minizip;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t3221E44C2C8ABE1300268379 /* Supporting Files */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t3221E44D2C8ABE1300268379 /* PrivacyInfo.xcprivacy */,\n\t\t\t);\n\t\t\tpath = \"Supporting Files\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t58B511D21A9E6C8500147676 = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tFF90DEF92C5A808600CA8692 /* PrivacyInfo.xcprivacy */,\n\t\t\t\t5498D8F51D21F14100B5EB43 /* CodePushUtils.m */,\n\t\t\t\t13BE3DEC1AC21097009241FE /* CodePush.h */,\n\t\t\t\t13BE3DED1AC21097009241FE /* CodePush.m */,\n\t\t\t\t81D51F391B6181C2000DA084 /* CodePushConfig.m */,\n\t\t\t\t54FFEDDF1BF550630061DD23 /* CodePushDownloadHandler.m */,\n\t\t\t\t1B762E8F1C9A5E9A006EF800 /* CodePushErrorUtils.m */,\n\t\t\t\t810D4E6C1B96935000B397E9 /* CodePushPackage.m */,\n\t\t\t\t5421FE301C58AD5A00986A55 /* CodePushTelemetryManager.m */,\n\t\t\t\t540D20111C7684FE00D6EF41 /* CodePushUpdateUtils.m */,\n\t\t\t\t1B23B9131BF9267B000BB2F0 /* RCTConvert+CodePushInstallMode.m */,\n\t\t\t\t1BCC09A61CC19EB700DDC0DD /* RCTConvert+CodePushUpdateState.m */,\n\t\t\t\tF85736711F4F03BF00C9C00A /* Base64 */,\n\t\t\t\tF88664111F4AD1EE0036D01B /* JWT */,\n\t\t\t\t3221E4282C8ABE1300268379 /* SSZipArchive */,\n\t\t\t\t134814211AA4EA7D00B7C361 /* Products */,\n\t\t\t\tC31BB4D5018A48D5288C5137 /* Frameworks */,\n\t\t\t\tF886647B1F4ADB500036D01B /* libCodePush.a */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tC31BB4D5018A48D5288C5137 /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t);\n\t\t\tname = Frameworks;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tF85736711F4F03BF00C9C00A /* Base64 */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tF85736721F4F03BF00C9C00A /* Base64 */,\n\t\t\t\tF85736751F4F03BF00C9C00A /* README.md */,\n\t\t\t);\n\t\t\tname = Base64;\n\t\t\tpath = CodePush/Base64;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tF85736721F4F03BF00C9C00A /* Base64 */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tF85736731F4F03BF00C9C00A /* MF_Base64Additions.h */,\n\t\t\t\tF85736741F4F03BF00C9C00A /* MF_Base64Additions.m */,\n\t\t\t);\n\t\t\tpath = Base64;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tF88664111F4AD1EE0036D01B /* JWT */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tF85736791F4F155300C9C00A /* LICENSE */,\n\t\t\t\tF857367A1F4F155300C9C00A /* README.md */,\n\t\t\t\tF88664121F4AD1EE0036D01B /* Core */,\n\t\t\t);\n\t\t\tname = JWT;\n\t\t\tpath = CodePush/JWT;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tF88664121F4AD1EE0036D01B /* Core */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tF88664131F4AD1EE0036D01B /* Algorithms */,\n\t\t\t\tF88664301F4AD1EE0036D01B /* ClaimSet */,\n\t\t\t\tF88664391F4AD1EE0036D01B /* Coding */,\n\t\t\t\tF88664441F4AD1EE0036D01B /* FrameworkSupplement */,\n\t\t\t\tF88664471F4AD1EE0036D01B /* Supplement */,\n\t\t\t);\n\t\t\tpath = Core;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tF88664131F4AD1EE0036D01B /* Algorithms */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tF88664141F4AD1EE0036D01B /* Base */,\n\t\t\t\tF886641A1F4AD1EE0036D01B /* ESFamily */,\n\t\t\t\tF886641D1F4AD1EE0036D01B /* Holders */,\n\t\t\t\tF88664221F4AD1EE0036D01B /* HSFamily */,\n\t\t\t\tF88664251F4AD1EE0036D01B /* RSFamily */,\n\t\t\t);\n\t\t\tpath = Algorithms;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tF88664141F4AD1EE0036D01B /* Base */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tF88664151F4AD1EE0036D01B /* JWTAlgorithm.h */,\n\t\t\t\tF88664161F4AD1EE0036D01B /* JWTAlgorithmFactory.h */,\n\t\t\t\tF88664171F4AD1EE0036D01B /* JWTAlgorithmFactory.m */,\n\t\t\t\tF88664181F4AD1EE0036D01B /* JWTAlgorithmNone.h */,\n\t\t\t\tF88664191F4AD1EE0036D01B /* JWTAlgorithmNone.m */,\n\t\t\t);\n\t\t\tpath = Base;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tF886641A1F4AD1EE0036D01B /* ESFamily */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tF886641B1F4AD1EE0036D01B /* JWTAlgorithmESBase.h */,\n\t\t\t\tF886641C1F4AD1EE0036D01B /* JWTAlgorithmESBase.m */,\n\t\t\t);\n\t\t\tpath = ESFamily;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tF886641D1F4AD1EE0036D01B /* Holders */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tF886641E1F4AD1EE0036D01B /* JWTAlgorithmDataHolder.h */,\n\t\t\t\tF886641F1F4AD1EE0036D01B /* JWTAlgorithmDataHolder.m */,\n\t\t\t\tF88664201F4AD1EE0036D01B /* JWTAlgorithmDataHolderChain.h */,\n\t\t\t\tF88664211F4AD1EE0036D01B /* JWTAlgorithmDataHolderChain.m */,\n\t\t\t);\n\t\t\tpath = Holders;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tF88664221F4AD1EE0036D01B /* HSFamily */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tF88664231F4AD1EE0036D01B /* JWTAlgorithmHSBase.h */,\n\t\t\t\tF88664241F4AD1EE0036D01B /* JWTAlgorithmHSBase.m */,\n\t\t\t);\n\t\t\tpath = HSFamily;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tF88664251F4AD1EE0036D01B /* RSFamily */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tF88664261F4AD1EE0036D01B /* JWTAlgorithmRSBase.h */,\n\t\t\t\tF88664271F4AD1EE0036D01B /* JWTAlgorithmRSBase.m */,\n\t\t\t\tF88664281F4AD1EE0036D01B /* JWTRSAlgorithm.h */,\n\t\t\t\tF88664291F4AD1EE0036D01B /* RSKeys */,\n\t\t\t);\n\t\t\tpath = RSFamily;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tF88664291F4AD1EE0036D01B /* RSKeys */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tF886642A1F4AD1EE0036D01B /* JWTCryptoKey.h */,\n\t\t\t\tF886642B1F4AD1EE0036D01B /* JWTCryptoKey.m */,\n\t\t\t\tF886642C1F4AD1EE0036D01B /* JWTCryptoKeyExtractor.h */,\n\t\t\t\tF886642D1F4AD1EE0036D01B /* JWTCryptoKeyExtractor.m */,\n\t\t\t\tF886642E1F4AD1EE0036D01B /* JWTCryptoSecurity.h */,\n\t\t\t\tF886642F1F4AD1EE0036D01B /* JWTCryptoSecurity.m */,\n\t\t\t);\n\t\t\tpath = RSKeys;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tF88664301F4AD1EE0036D01B /* ClaimSet */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tF88664311F4AD1EE0036D01B /* JWTClaim.h */,\n\t\t\t\tF88664321F4AD1EE0036D01B /* JWTClaim.m */,\n\t\t\t\tF88664331F4AD1EE0036D01B /* JWTClaimsSet.h */,\n\t\t\t\tF88664341F4AD1EE0036D01B /* JWTClaimsSet.m */,\n\t\t\t\tF88664351F4AD1EE0036D01B /* JWTClaimsSetSerializer.h */,\n\t\t\t\tF88664361F4AD1EE0036D01B /* JWTClaimsSetSerializer.m */,\n\t\t\t\tF88664371F4AD1EE0036D01B /* JWTClaimsSetVerifier.h */,\n\t\t\t\tF88664381F4AD1EE0036D01B /* JWTClaimsSetVerifier.m */,\n\t\t\t);\n\t\t\tpath = ClaimSet;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tF88664391F4AD1EE0036D01B /* Coding */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tF886643A1F4AD1EE0036D01B /* JWTCoding+ResultTypes.h */,\n\t\t\t\tF886643B1F4AD1EE0036D01B /* JWTCoding+ResultTypes.m */,\n\t\t\t\tF886643C1F4AD1EE0036D01B /* JWTCoding+VersionOne.h */,\n\t\t\t\tF886643D1F4AD1EE0036D01B /* JWTCoding+VersionOne.m */,\n\t\t\t\tF886643E1F4AD1EE0036D01B /* JWTCoding+VersionThree.h */,\n\t\t\t\tF886643F1F4AD1EE0036D01B /* JWTCoding+VersionThree.m */,\n\t\t\t\tF88664401F4AD1EE0036D01B /* JWTCoding+VersionTwo.h */,\n\t\t\t\tF88664411F4AD1EE0036D01B /* JWTCoding+VersionTwo.m */,\n\t\t\t\tF88664421F4AD1EE0036D01B /* JWTCoding.h */,\n\t\t\t\tF88664431F4AD1EE0036D01B /* JWTCoding.m */,\n\t\t\t);\n\t\t\tpath = Coding;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tF88664441F4AD1EE0036D01B /* FrameworkSupplement */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tF88664451F4AD1EE0036D01B /* JWT.h */,\n\t\t\t\tF88664461F4AD1EE0036D01B /* Map.modulemap */,\n\t\t\t);\n\t\t\tpath = FrameworkSupplement;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tF88664471F4AD1EE0036D01B /* Supplement */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tF88664481F4AD1EE0036D01B /* JWTBase64Coder.h */,\n\t\t\t\tF88664491F4AD1EE0036D01B /* JWTBase64Coder.m */,\n\t\t\t\tF886644A1F4AD1EE0036D01B /* JWTDeprecations.h */,\n\t\t\t\tF886644B1F4AD1EE0036D01B /* JWTErrorDescription.h */,\n\t\t\t\tF886644C1F4AD1EE0036D01B /* JWTErrorDescription.m */,\n\t\t\t);\n\t\t\tpath = Supplement;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXHeadersBuildPhase section */\n\t\t6463C8461EBA0D230095B8CD /* Headers */ = {\n\t\t\tisa = PBXHeadersBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t3221E4662C8ABE1300268379 /* mz_strm_buf.h in Headers */,\n\t\t\t\t3221E48E2C8ABE1400268379 /* SSZipArchive.h in Headers */,\n\t\t\t\t3221E4762C8ABE1300268379 /* mz_strm_pkcrypt.h in Headers */,\n\t\t\t\t3221E4642C8ABE1300268379 /* mz_strm_split.h in Headers */,\n\t\t\t\t6463C8471EBA0D290095B8CD /* CodePush.h in Headers */,\n\t\t\t\t3221E46A2C8ABE1300268379 /* mz_strm.h in Headers */,\n\t\t\t\t3221E4782C8ABE1300268379 /* mz_zip_rw.h in Headers */,\n\t\t\t\t3221E4802C8ABE1400268379 /* mz.h in Headers */,\n\t\t\t\t3221E4602C8ABE1300268379 /* mz_os.h in Headers */,\n\t\t\t\t3221E4882C8ABE1400268379 /* mz_strm_mem.h in Headers */,\n\t\t\t\t3221E4862C8ABE1400268379 /* mz_crypt.h in Headers */,\n\t\t\t\t3221E4902C8ABE1400268379 /* SSZipCommon.h in Headers */,\n\t\t\t\t3221E4582C8ABE1300268379 /* mz_strm_wzaes.h in Headers */,\n\t\t\t\t3221E4522C8ABE1300268379 /* ZipArchive.h in Headers */,\n\t\t\t\t3221E4722C8ABE1300268379 /* mz_strm_zlib.h in Headers */,\n\t\t\t\t3221E45A2C8ABE1300268379 /* mz_compat.h in Headers */,\n\t\t\t\t3221E47C2C8ABE1400268379 /* mz_zip.h in Headers */,\n\t\t\t\t3221E48C2C8ABE1400268379 /* mz_strm_os.h in Headers */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t8482F84D1E24C65E00F793DB /* Headers */ = {\n\t\t\tisa = PBXHeadersBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t3221E4712C8ABE1300268379 /* mz_strm_zlib.h in Headers */,\n\t\t\t\t3221E48B2C8ABE1400268379 /* mz_strm_os.h in Headers */,\n\t\t\t\tF88664791F4AD1EE0036D01B /* JWTErrorDescription.h in Headers */,\n\t\t\t\tF85736761F4F03BF00C9C00A /* MF_Base64Additions.h in Headers */,\n\t\t\t\tF88664541F4AD1EE0036D01B /* JWTAlgorithmDataHolder.h in Headers */,\n\t\t\t\tF88664501F4AD1EE0036D01B /* JWTAlgorithmNone.h in Headers */,\n\t\t\t\tF88664671F4AD1EE0036D01B /* JWTClaimsSetSerializer.h in Headers */,\n\t\t\t\tF88664521F4AD1EE0036D01B /* JWTAlgorithmESBase.h in Headers */,\n\t\t\t\tF88664781F4AD1EE0036D01B /* JWTDeprecations.h in Headers */,\n\t\t\t\t3221E4852C8ABE1400268379 /* mz_crypt.h in Headers */,\n\t\t\t\t3221E4512C8ABE1300268379 /* ZipArchive.h in Headers */,\n\t\t\t\tF88664631F4AD1EE0036D01B /* JWTClaim.h in Headers */,\n\t\t\t\tF886645A1F4AD1EE0036D01B /* JWTAlgorithmRSBase.h in Headers */,\n\t\t\t\tF886645F1F4AD1EE0036D01B /* JWTCryptoKeyExtractor.h in Headers */,\n\t\t\t\tF88664651F4AD1EE0036D01B /* JWTClaimsSet.h in Headers */,\n\t\t\t\tF886644E1F4AD1EE0036D01B /* JWTAlgorithmFactory.h in Headers */,\n\t\t\t\tF886645C1F4AD1EE0036D01B /* JWTRSAlgorithm.h in Headers */,\n\t\t\t\tF88664731F4AD1EE0036D01B /* JWTCoding.h in Headers */,\n\t\t\t\t3221E45F2C8ABE1300268379 /* mz_os.h in Headers */,\n\t\t\t\t3221E4872C8ABE1400268379 /* mz_strm_mem.h in Headers */,\n\t\t\t\t3221E48D2C8ABE1400268379 /* SSZipArchive.h in Headers */,\n\t\t\t\tF88664581F4AD1EE0036D01B /* JWTAlgorithmHSBase.h in Headers */,\n\t\t\t\tF886646D1F4AD1EE0036D01B /* JWTCoding+VersionOne.h in Headers */,\n\t\t\t\t3221E47F2C8ABE1400268379 /* mz.h in Headers */,\n\t\t\t\tF88664761F4AD1EE0036D01B /* JWTBase64Coder.h in Headers */,\n\t\t\t\tF88664561F4AD1EE0036D01B /* JWTAlgorithmDataHolderChain.h in Headers */,\n\t\t\t\t3221E4592C8ABE1300268379 /* mz_compat.h in Headers */,\n\t\t\t\tF886644D1F4AD1EE0036D01B /* JWTAlgorithm.h in Headers */,\n\t\t\t\tF88664611F4AD1EE0036D01B /* JWTCryptoSecurity.h in Headers */,\n\t\t\t\t3221E48F2C8ABE1400268379 /* SSZipCommon.h in Headers */,\n\t\t\t\tF88664751F4AD1EE0036D01B /* JWT.h in Headers */,\n\t\t\t\tF886645D1F4AD1EE0036D01B /* JWTCryptoKey.h in Headers */,\n\t\t\t\t3221E4692C8ABE1300268379 /* mz_strm.h in Headers */,\n\t\t\t\t3221E4772C8ABE1300268379 /* mz_zip_rw.h in Headers */,\n\t\t\t\tF886646F1F4AD1EE0036D01B /* JWTCoding+VersionThree.h in Headers */,\n\t\t\t\tF88664691F4AD1EE0036D01B /* JWTClaimsSetVerifier.h in Headers */,\n\t\t\t\t3221E4572C8ABE1300268379 /* mz_strm_wzaes.h in Headers */,\n\t\t\t\t3221E4632C8ABE1300268379 /* mz_strm_split.h in Headers */,\n\t\t\t\t3221E4752C8ABE1300268379 /* mz_strm_pkcrypt.h in Headers */,\n\t\t\t\t8482F84E1E24C66300F793DB /* CodePush.h in Headers */,\n\t\t\t\tF88664711F4AD1EE0036D01B /* JWTCoding+VersionTwo.h in Headers */,\n\t\t\t\tF886646B1F4AD1EE0036D01B /* JWTCoding+ResultTypes.h in Headers */,\n\t\t\t\t3221E4652C8ABE1300268379 /* mz_strm_buf.h in Headers */,\n\t\t\t\t3221E47B2C8ABE1400268379 /* mz_zip.h in Headers */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXHeadersBuildPhase section */\n\n/* Begin PBXNativeTarget section */\n\t\t58B511DA1A9E6C8500147676 /* CodePush */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget \"CodePush\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t58B511D71A9E6C8500147676 /* Sources */,\n\t\t\t\t58B511D81A9E6C8500147676 /* Frameworks */,\n\t\t\t\t58B511D91A9E6C8500147676 /* CopyFiles */,\n\t\t\t\t8482F84D1E24C65E00F793DB /* Headers */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = CodePush;\n\t\t\tproductName = RCTDataManager;\n\t\t\tproductReference = 134814201AA4EA6300B7C361 /* libCodePush.a */;\n\t\t\tproductType = \"com.apple.product-type.library.static\";\n\t\t};\n\t\t6463C8231EBA0CB60095B8CD /* CodePush-tvOS */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 6463C82C1EBA0CB60095B8CD /* Build configuration list for PBXNativeTarget \"CodePush-tvOS\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t6463C8201EBA0CB60095B8CD /* Sources */,\n\t\t\t\t6463C8211EBA0CB60095B8CD /* Frameworks */,\n\t\t\t\t6463C8221EBA0CB60095B8CD /* CopyFiles */,\n\t\t\t\t6463C8461EBA0D230095B8CD /* Headers */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = \"CodePush-tvOS\";\n\t\t\tproductName = \"CodePush-tvOS\";\n\t\t\tproductReference = F886647B1F4ADB500036D01B /* libCodePush.a */;\n\t\t\tproductType = \"com.apple.product-type.library.static\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t58B511D31A9E6C8500147676 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastUpgradeCheck = 1000;\n\t\t\t\tORGANIZATIONNAME = Microsoft;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t58B511DA1A9E6C8500147676 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 6.1.1;\n\t\t\t\t\t};\n\t\t\t\t\t6463C8231EBA0CB60095B8CD = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 8.3.2;\n\t\t\t\t\t\tProvisioningStyle = Automatic;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject \"CodePush\" */;\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\tEnglish,\n\t\t\t\ten,\n\t\t\t);\n\t\t\tmainGroup = 58B511D21A9E6C8500147676;\n\t\t\tproductRefGroup = 58B511D21A9E6C8500147676;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t58B511DA1A9E6C8500147676 /* CodePush */,\n\t\t\t\t6463C8231EBA0CB60095B8CD /* CodePush-tvOS */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t58B511D71A9E6C8500147676 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t3221E47D2C8ABE1400268379 /* mz_os_posix.c in Sources */,\n\t\t\t\t3221E4792C8ABE1300268379 /* mz_os.c in Sources */,\n\t\t\t\tF88664621F4AD1EE0036D01B /* JWTCryptoSecurity.m in Sources */,\n\t\t\t\tF88664701F4AD1EE0036D01B /* JWTCoding+VersionThree.m in Sources */,\n\t\t\t\t540D20121C7684FE00D6EF41 /* CodePushUpdateUtils.m in Sources */,\n\t\t\t\t3221E4812C8ABE1400268379 /* mz_strm_buf.c in Sources */,\n\t\t\t\t3221E46D2C8ABE1300268379 /* mz_crypt.c in Sources */,\n\t\t\t\tF886646E1F4AD1EE0036D01B /* JWTCoding+VersionOne.m in Sources */,\n\t\t\t\t1BCC09A71CC19EB700DDC0DD /* RCTConvert+CodePushUpdateState.m in Sources */,\n\t\t\t\tF88664661F4AD1EE0036D01B /* JWTClaimsSet.m in Sources */,\n\t\t\t\t3221E4892C8ABE1400268379 /* mz_strm.c in Sources */,\n\t\t\t\t1B23B9141BF9267B000BB2F0 /* RCTConvert+CodePushInstallMode.m in Sources */,\n\t\t\t\tF886645E1F4AD1EE0036D01B /* JWTCryptoKey.m in Sources */,\n\t\t\t\t81D51F3A1B6181C2000DA084 /* CodePushConfig.m in Sources */,\n\t\t\t\t3221E4732C8ABE1300268379 /* mz_compat.c in Sources */,\n\t\t\t\tF886646A1F4AD1EE0036D01B /* JWTClaimsSetVerifier.m in Sources */,\n\t\t\t\t3221E45B2C8ABE1300268379 /* mz_strm_zlib.c in Sources */,\n\t\t\t\t3221E46B2C8ABE1300268379 /* mz_strm_mem.c in Sources */,\n\t\t\t\t54FFEDE01BF550630061DD23 /* CodePushDownloadHandler.m in Sources */,\n\t\t\t\t3221E4672C8ABE1300268379 /* mz_crypt_apple.c in Sources */,\n\t\t\t\t3221E4912C8ABE1400268379 /* SSZipArchive.m in Sources */,\n\t\t\t\tF88664551F4AD1EE0036D01B /* JWTAlgorithmDataHolder.m in Sources */,\n\t\t\t\tF88664681F4AD1EE0036D01B /* JWTClaimsSetSerializer.m in Sources */,\n\t\t\t\t5421FE311C58AD5A00986A55 /* CodePushTelemetryManager.m in Sources */,\n\t\t\t\tF886646C1F4AD1EE0036D01B /* JWTCoding+ResultTypes.m in Sources */,\n\t\t\t\t3221E46F2C8ABE1300268379 /* mz_strm_wzaes.c in Sources */,\n\t\t\t\tF88664601F4AD1EE0036D01B /* JWTCryptoKeyExtractor.m in Sources */,\n\t\t\t\tF88664571F4AD1EE0036D01B /* JWTAlgorithmDataHolderChain.m in Sources */,\n\t\t\t\t13BE3DEE1AC21097009241FE /* CodePush.m in Sources */,\n\t\t\t\tF85736771F4F03BF00C9C00A /* MF_Base64Additions.m in Sources */,\n\t\t\t\tF88664641F4AD1EE0036D01B /* JWTClaim.m in Sources */,\n\t\t\t\tF88664741F4AD1EE0036D01B /* JWTCoding.m in Sources */,\n\t\t\t\t3221E45D2C8ABE1300268379 /* mz_zip.c in Sources */,\n\t\t\t\t1B762E901C9A5E9A006EF800 /* CodePushErrorUtils.m in Sources */,\n\t\t\t\tF886645B1F4AD1EE0036D01B /* JWTAlgorithmRSBase.m in Sources */,\n\t\t\t\t3221E4832C8ABE1400268379 /* mz_strm_split.c in Sources */,\n\t\t\t\tF886647A1F4AD1EF0036D01B /* JWTErrorDescription.m in Sources */,\n\t\t\t\tF886644F1F4AD1EE0036D01B /* JWTAlgorithmFactory.m in Sources */,\n\t\t\t\tF88664591F4AD1EE0036D01B /* JWTAlgorithmHSBase.m in Sources */,\n\t\t\t\tF88664771F4AD1EE0036D01B /* JWTBase64Coder.m in Sources */,\n\t\t\t\tF88664511F4AD1EE0036D01B /* JWTAlgorithmNone.m in Sources */,\n\t\t\t\t5498D8F61D21F14100B5EB43 /* CodePushUtils.m in Sources */,\n\t\t\t\t3221E4612C8ABE1300268379 /* mz_zip_rw.c in Sources */,\n\t\t\t\t810D4E6D1B96935000B397E9 /* CodePushPackage.m in Sources */,\n\t\t\t\t3221E4552C8ABE1300268379 /* mz_strm_pkcrypt.c in Sources */,\n\t\t\t\tF88664531F4AD1EE0036D01B /* JWTAlgorithmESBase.m in Sources */,\n\t\t\t\t3221E4532C8ABE1300268379 /* mz_strm_os_posix.c in Sources */,\n\t\t\t\tF88664721F4AD1EE0036D01B /* JWTCoding+VersionTwo.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t6463C8201EBA0CB60095B8CD /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t3221E47E2C8ABE1400268379 /* mz_os_posix.c in Sources */,\n\t\t\t\t3221E46C2C8ABE1300268379 /* mz_strm_mem.c in Sources */,\n\t\t\t\t3221E4922C8ABE1400268379 /* SSZipArchive.m in Sources */,\n\t\t\t\t3221E4822C8ABE1400268379 /* mz_strm_buf.c in Sources */,\n\t\t\t\t3221E45E2C8ABE1300268379 /* mz_zip.c in Sources */,\n\t\t\t\t6463C82D1EBA0CFB0095B8CD /* CodePushUtils.m in Sources */,\n\t\t\t\t6463C82E1EBA0CFB0095B8CD /* CodePush.m in Sources */,\n\t\t\t\t6463C82F1EBA0CFB0095B8CD /* CodePushConfig.m in Sources */,\n\t\t\t\t6463C8301EBA0CFB0095B8CD /* CodePushDownloadHandler.m in Sources */,\n\t\t\t\t6463C8311EBA0CFB0095B8CD /* CodePushErrorUtils.m in Sources */,\n\t\t\t\t3221E46E2C8ABE1300268379 /* mz_crypt.c in Sources */,\n\t\t\t\t6463C8321EBA0CFB0095B8CD /* CodePushPackage.m in Sources */,\n\t\t\t\t6463C8331EBA0CFB0095B8CD /* CodePushTelemetryManager.m in Sources */,\n\t\t\t\t6463C8341EBA0CFB0095B8CD /* CodePushUpdateUtils.m in Sources */,\n\t\t\t\t3221E45C2C8ABE1300268379 /* mz_strm_zlib.c in Sources */,\n\t\t\t\t3221E4682C8ABE1300268379 /* mz_crypt_apple.c in Sources */,\n\t\t\t\t3221E4842C8ABE1400268379 /* mz_strm_split.c in Sources */,\n\t\t\t\t3221E48A2C8ABE1400268379 /* mz_strm.c in Sources */,\n\t\t\t\t6463C8351EBA0CFB0095B8CD /* RCTConvert+CodePushInstallMode.m in Sources */,\n\t\t\t\t3221E4742C8ABE1300268379 /* mz_compat.c in Sources */,\n\t\t\t\t3221E4542C8ABE1300268379 /* mz_strm_os_posix.c in Sources */,\n\t\t\t\t3221E4702C8ABE1300268379 /* mz_strm_wzaes.c in Sources */,\n\t\t\t\t3221E4562C8ABE1300268379 /* mz_strm_pkcrypt.c in Sources */,\n\t\t\t\t3221E47A2C8ABE1300268379 /* mz_os.c in Sources */,\n\t\t\t\t3221E4622C8ABE1300268379 /* mz_zip_rw.c in Sources */,\n\t\t\t\t6463C8361EBA0CFB0095B8CD /* RCTConvert+CodePushUpdateState.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin XCBuildConfiguration section */\n\t\t58B511ED1A9E6C8500147676 /* 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_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = 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_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_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\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\tUSER_HEADER_SEARCH_PATHS = \"\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t58B511EE1A9E6C8500147676 /* 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_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = 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_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\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_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 9.0;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tUSER_HEADER_SEARCH_PATHS = \"\";\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t58B511F01A9E6C8500147676 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\tHAVE_INTTYPES_H,\n\t\t\t\t\tHAVE_PKCRYPT,\n\t\t\t\t\tHAVE_STDINT_H,\n\t\t\t\t\tHAVE_WZAES,\n\t\t\t\t\tHAVE_ZLIB,\n\t\t\t\t\tZLIB_COMPAT,\n\t\t\t\t);\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)/../../react-native/React/**\",\n\t\t\t\t\t\"$(SRC_ROOT)/JWT/**\",\n\t\t\t\t);\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 15.5;\n\t\t\t\tLIBRARY_SEARCH_PATHS = \"$(inherited)\";\n\t\t\t\tOTHER_LDFLAGS = (\n\t\t\t\t\t\"-ObjC\",\n\t\t\t\t\t\"-lz\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_NAME = CodePush;\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t58B511F11A9E6C8500147676 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\tHAVE_INTTYPES_H,\n\t\t\t\t\tHAVE_PKCRYPT,\n\t\t\t\t\tHAVE_STDINT_H,\n\t\t\t\t\tHAVE_WZAES,\n\t\t\t\t\tHAVE_ZLIB,\n\t\t\t\t\tZLIB_COMPAT,\n\t\t\t\t);\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)/../../react-native/React/**\",\n\t\t\t\t\t\"$(SRC_ROOT)/JWT/**\",\n\t\t\t\t);\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 15.5;\n\t\t\t\tLIBRARY_SEARCH_PATHS = \"$(inherited)\";\n\t\t\t\tOTHER_LDFLAGS = (\n\t\t\t\t\t\"-ObjC\",\n\t\t\t\t\t\"-lz\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_NAME = CodePush;\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t6463C82A1EBA0CB60095B8CD /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tOTHER_LDFLAGS = \"-ObjC\";\n\t\t\t\tPRODUCT_NAME = CodePush;\n\t\t\t\tSDKROOT = appletvos;\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t\tTVOS_DEPLOYMENT_TARGET = 10.2;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t6463C82B1EBA0CB60095B8CD /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tOTHER_LDFLAGS = \"-ObjC\";\n\t\t\t\tPRODUCT_NAME = CodePush;\n\t\t\t\tSDKROOT = appletvos;\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t\tTVOS_DEPLOYMENT_TARGET = 10.2;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t58B511D61A9E6C8500147676 /* Build configuration list for PBXProject \"CodePush\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t58B511ED1A9E6C8500147676 /* Debug */,\n\t\t\t\t58B511EE1A9E6C8500147676 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget \"CodePush\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t58B511F01A9E6C8500147676 /* Debug */,\n\t\t\t\t58B511F11A9E6C8500147676 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t6463C82C1EBA0CB60095B8CD /* Build configuration list for PBXNativeTarget \"CodePush-tvOS\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t6463C82A1EBA0CB60095B8CD /* Debug */,\n\t\t\t\t6463C82B1EBA0CB60095B8CD /* 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 = 58B511D31A9E6C8500147676 /* Project object */;\n}\n"
  },
  {
    "path": "ios/CodePush.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"self:\">\n   </FileRef>\n</Workspace>\n"
  },
  {
    "path": "ios/CodePush.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.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>IDEDidComputeMac32BitWarning</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "ios/PrivacyInfo.xcprivacy",
    "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\t<dict>\n\t\t<key>NSPrivacyTracking</key>\n\t\t<false />\n\t\t<key>NSPrivacyCollectedDataTypes</key>\n\t\t<array />\n\t\t<key>NSPrivacyTrackingDomains</key>\n\t\t<array />\n\t\t<key>NSPrivacyAccessedAPITypes</key>\n\t\t<array>\n\t\t\t<dict>\n\t\t\t\t<key>NSPrivacyAccessedAPIType</key>\n\t\t\t\t<string>NSPrivacyAccessedAPICategoryFileTimestamp</string>\n\t\t\t\t<key>NSPrivacyAccessedAPITypeReasons</key>\n\t\t\t\t<array>\n\t\t\t\t\t<string>0A2A.1</string>\n\t\t\t\t</array>\n\t\t\t</dict>\n\t\t\t<dict>\n\t\t\t\t<key>NSPrivacyAccessedAPIType</key>\n\t\t\t\t<string>NSPrivacyAccessedAPICategoryUserDefaults</string>\n\t\t\t\t<key>NSPrivacyAccessedAPITypeReasons</key>\n\t\t\t\t<array>\n\t\t\t\t\t<string>CA92.1</string>\n\t\t\t\t</array>\n\t\t\t</dict>\n\t\t</array>\n\t</dict>\n</plist>"
  },
  {
    "path": "logging.js",
    "content": "/* Logs messages to console with the [CodePush] prefix */\nfunction log(message) {\n  console.log(`[CodePush] ${message}`);\n}\n\nmodule.exports = log;\n"
  },
  {
    "path": "package-mixins.js",
    "content": "import { NativeEventEmitter } from \"react-native\";\nimport log from \"./logging\";\n\n// This function is used to augment remote and local\n// package objects with additional functionality/properties\n// beyond what is included in the metadata sent by the server.\nmodule.exports = (NativeCodePush) => {\n  const remote = (reportStatusDownload) => {\n    return {\n      async download(downloadProgressCallback) {\n        if (!this.downloadUrl) {\n          throw new Error(\"Cannot download an update without a download url\");\n        }\n\n        let downloadProgressSubscription;\n        if (downloadProgressCallback) {\n          const codePushEventEmitter = new NativeEventEmitter(NativeCodePush);\n          // Use event subscription to obtain download progress.\n          downloadProgressSubscription = codePushEventEmitter.addListener(\n            \"CodePushDownloadProgress\",\n            downloadProgressCallback\n          );\n        }\n\n        // Use the downloaded package info. Native code will save the package info\n        // so that the client knows what the current package version is.\n        try {\n          const updatePackageCopy = Object.assign({}, this);\n          Object.keys(updatePackageCopy).forEach((key) => (typeof updatePackageCopy[key] === 'function') && delete updatePackageCopy[key]);\n\n          const downloadedPackage = await NativeCodePush.downloadUpdate(updatePackageCopy, !!downloadProgressCallback);\n\n          if (reportStatusDownload) {\n            reportStatusDownload(this)\n            .catch((err) => {\n              log(`Report download status failed: ${err}`);\n            });\n          }\n\n          return { ...downloadedPackage, ...local };\n        } finally {\n          downloadProgressSubscription && downloadProgressSubscription.remove();\n        }\n      },\n\n      isPending: false // A remote package could never be in a pending state\n    };\n  };\n\n  const local = {\n    async install(installMode = NativeCodePush.codePushInstallModeOnNextRestart, minimumBackgroundDuration = 0, updateInstalledCallback) {\n      const localPackage = this;\n      const localPackageCopy = Object.assign({}, localPackage); // In dev mode, React Native deep freezes any object queued over the bridge\n      await NativeCodePush.installUpdate(localPackageCopy, installMode, minimumBackgroundDuration);\n      updateInstalledCallback && updateInstalledCallback();\n      if (installMode == NativeCodePush.codePushInstallModeImmediate) {\n        NativeCodePush.restartApp(false);\n      } else {\n        NativeCodePush.clearPendingRestart();\n        localPackage.isPending = true; // Mark the package as pending since it hasn't been applied yet\n      }\n    },\n\n    isPending: false // A local package wouldn't be pending until it was installed\n  };\n\n  return { local, remote };\n};"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"react-native-code-push\",\n  \"version\": \"9.0.1\",\n  \"description\": \"React Native plugin for the CodePush service\",\n  \"main\": \"CodePush.js\",\n  \"typings\": \"typings/react-native-code-push.d.ts\",\n  \"homepage\": \"https://microsoft.github.io/code-push\",\n  \"keywords\": [\n    \"react-native\",\n    \"code\",\n    \"push\"\n  ],\n  \"author\": \"Microsoft Corporation\",\n  \"license\": \"MIT\",\n  \"scripts\": {\n    \"clean\": \"shx rm -rf bin\",\n    \"setup\": \"npm install --quiet --no-progress\",\n    \"prebuild:tests\": \"npm run clean && npm run tslint\",\n    \"build:tests\": \"tsc\",\n    \"test\": \"npm run build:tests && npm run test:setup && npm run test:fast\",\n    \"test:android\": \"npm run build:tests && npm run test:setup:android && npm run test:fast:android\",\n    \"test:ios\": \"npm run build:tests && npm run test:setup:ios && npm run test:fast:ios\",\n    \"test:setup\": \"mocha --recursive bin/test --android --ios --setup\",\n    \"test:setup:android\": \"mocha --recursive bin/test --android --setup\",\n    \"test:setup:ios\": \"mocha --recursive bin/test --ios --setup\",\n    \"test:fast\": \"mocha --recursive bin/test --android --ios\",\n    \"test:fast:android\": \"mocha --recursive bin/test --android\",\n    \"test:fast:ios\": \"mocha --recursive bin/test --ios\",\n    \"test:debugger:android\": \"mocha --recursive --inspect-brk=0.0.0.0 bin/test --android\",\n    \"test:debugger:ios\": \"mocha --recursive --inspect-brk=0.0.0.0 bin/test --ios\",\n    \"tslint\": \"tslint -c tslint.json test/**/*.ts\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/microsoft/react-native-code-push\"\n  },\n  \"dependencies\": {\n    \"code-push\": \"4.2.3\",\n    \"glob\": \"^7.1.7\",\n    \"hoist-non-react-statics\": \"^3.3.2\",\n    \"inquirer\": \"^8.1.5\",\n    \"plist\": \"^3.0.4\",\n    \"semver\": \"^7.3.5\",\n    \"xcode\": \"3.0.1\"\n  },\n  \"devDependencies\": {\n    \"@types/assert\": \"^1.5.2\",\n    \"@types/mkdirp\": \"^1.0.1\",\n    \"@types/mocha\": \"^9.0.0\",\n    \"@types/node\": \"^14.0.27\",\n    \"@types/q\": \"^1.5.4\",\n    \"archiver\": \"latest\",\n    \"body-parser\": \"latest\",\n    \"code-push-plugin-testing-framework\": \"file:./code-push-plugin-testing-framework\",\n    \"del\": \"v6.0.0\",\n    \"express\": \"latest\",\n    \"mkdirp\": \"latest\",\n    \"mocha\": \"^9.2.0\",\n    \"q\": \"^1.5.1\",\n    \"run-sequence\": \"latest\",\n    \"shx\": \"^0.3.4\",\n    \"slash\": \"^3.0.0\",\n    \"tslint\": \"^6.1.3\",\n    \"typescript\": \"^4.4.3\"\n  },\n  \"rnpm\": {\n    \"android\": {\n      \"packageInstance\": \"new CodePush(getResources().getString(R.string.CodePushDeploymentKey), getApplicationContext(), BuildConfig.DEBUG)\"\n    },\n    \"ios\": {\n      \"sharedLibraries\": [\n        \"libz\"\n      ]\n    },\n    \"commands\": {\n      \"postlink\": \"node node_modules/react-native-code-push/scripts/postlink/run\",\n      \"postunlink\": \"node node_modules/react-native-code-push/scripts/postunlink/run\"\n    }\n  }\n}\n"
  },
  {
    "path": "react-native.config.js",
    "content": "module.exports = {\n    dependency: {\n        platforms: {\n            android: {\n                packageInstance:\n                    \"new CodePush(getResources().getString(R.string.CodePushDeploymentKey), getApplicationContext(), BuildConfig.DEBUG)\"\n            }\n        }\n    }\n};\n"
  },
  {
    "path": "request-fetch-adapter.js",
    "content": "const packageJson = require(\"./package.json\");\n\nmodule.exports = {\n  async request(verb, url, requestBody, callback) {\n    if (typeof requestBody === \"function\") {\n      callback = requestBody;\n      requestBody = null;\n    }\n\n    const headers = {\n      \"Accept\": \"application/json\",\n      \"Content-Type\": \"application/json\",\n      \"X-CodePush-Plugin-Name\": packageJson.name,\n      \"X-CodePush-Plugin-Version\": packageJson.version,\n      \"X-CodePush-SDK-Version\": packageJson.dependencies[\"code-push\"]\n    };\n\n    if (requestBody && typeof requestBody === \"object\") {\n      requestBody = JSON.stringify(requestBody);\n    }\n\n    try {\n      const response = await fetch(url, {\n        method: getHttpMethodName(verb),\n        headers: headers,\n        body: requestBody\n      });\n\n      const statusCode = response.status;\n      const body = await response.text();\n      callback(null, { statusCode, body });\n    } catch (err) {\n      callback(err);\n    }\n  }\n};\n\nfunction getHttpMethodName(verb) {\n  // Note: This should stay in sync with the enum definition in\n  // https://github.com/microsoft/code-push/blob/master/sdk/script/acquisition-sdk.ts#L6\n  return [\n    \"GET\",\n    \"HEAD\",\n    \"POST\",\n    \"PUT\",\n    \"DELETE\",\n    \"TRACE\",\n    \"OPTIONS\",\n    \"CONNECT\",\n    \"PATCH\"\n  ][verb];\n}"
  },
  {
    "path": "scripts/generateBundledResourcesHash.js",
    "content": "/*\n * This script generates a hash of all the React Native bundled assets and writes it into\n * into the APK. The hash in \"updateCheck\" requests to prevent downloading an identical\n * update to the one already present in the binary.\n *\n * It first creates a snapshot of the contents in the resource directory by creating\n * a map with the modified time of all the files in the directory. It then compares this\n * snapshot with the one saved earlier in \"recordFilesBeforeBundleCommand.js\" to figure\n * out which files were generated by the \"react-native bundle\" command. It then computes\n * the hash for each file to generate a manifest, and then computes a hash over the entire\n * manifest to generate the final hash, which is saved to the APK's assets directory.\n */\n\nvar crypto = require(\"crypto\");\nvar fs = require(\"fs\");\nvar path = require(\"path\");\n\nvar getFilesInFolder = require(\"./getFilesInFolder\");\n\nvar CODE_PUSH_FOLDER_PREFIX = \"CodePush\";\nvar CODE_PUSH_HASH_FILE_NAME = \"CodePushHash\";\nvar CODE_PUSH_HASH_OLD_FILE_NAME = \"CodePushHash.json\";\nvar HASH_ALGORITHM = \"sha256\";\n\nvar resourcesDir = process.argv[2];\nvar jsBundleFilePath = process.argv[3];\nvar assetsDir = process.argv[4];\nvar tempFileName = process.argv[5];\n\nvar oldFileToModifiedTimeMap = {};\nvar tempFileLocalPath = null;\nif (tempFileName) {\n    tempFileLocalPath = path.join(require(\"os\").tmpdir(), tempFileName);\n    oldFileToModifiedTimeMap = require(tempFileLocalPath);\n}\nvar resourceFiles = [];\n\ngetFilesInFolder(resourcesDir, resourceFiles);\n\nvar newFileToModifiedTimeMap = {};\n\nresourceFiles.forEach(function(resourceFile) {\n    newFileToModifiedTimeMap[resourceFile.path.substring(resourcesDir.length)] = resourceFile.mtime;\n});\n\nvar bundleGeneratedAssetFiles = [];\n\nfor (var newFilePath in newFileToModifiedTimeMap) {\n    if (!oldFileToModifiedTimeMap[newFilePath] || oldFileToModifiedTimeMap[newFilePath] < newFileToModifiedTimeMap[newFilePath].getTime()) {\n        bundleGeneratedAssetFiles.push(newFilePath);\n    }\n}\n\nvar manifest = [];\n\nif (bundleGeneratedAssetFiles.length) {\n    bundleGeneratedAssetFiles.forEach(function(assetFile) {\n        // Generate hash for each asset file\n        addFileToManifest(resourcesDir, assetFile, manifest, function() {\n            if (manifest.length === bundleGeneratedAssetFiles.length) {\n                addJsBundleAndMetaToManifest();\n            }\n        });\n    });\n} else {\n    addJsBundleAndMetaToManifest();\n}\n\nfunction addJsBundleAndMetaToManifest() {\n    addFileToManifest(path.dirname(jsBundleFilePath), path.basename(jsBundleFilePath), manifest, function() {\n        var jsBundleMetaFilePath = jsBundleFilePath + \".meta\";\n        addFileToManifest(path.dirname(jsBundleMetaFilePath), path.basename(jsBundleMetaFilePath), manifest, function() {\n            manifest = manifest.sort();\n            var finalHash = crypto.createHash(HASH_ALGORITHM)\n                .update(JSON.stringify(manifest))\n                .digest(\"hex\");\n\n            console.log(finalHash);\n\n            var savedResourcesManifestPath = assetsDir + \"/\" + CODE_PUSH_HASH_FILE_NAME;\n            fs.writeFileSync(savedResourcesManifestPath, finalHash);\n\n            // \"CodePushHash.json\" file name breaks flow type checking.\n            // To fix the issue we need to delete \"CodePushHash.json\" file and\n            // use \"CodePushHash\" file name instead to store the hash value.\n            // Relates to https://github.com/microsoft/react-native-code-push/issues/577\n            var oldSavedResourcesManifestPath = assetsDir + \"/\" + CODE_PUSH_HASH_OLD_FILE_NAME;\n            if (fs.existsSync(oldSavedResourcesManifestPath)) {\n                fs.unlinkSync(oldSavedResourcesManifestPath);\n            }\n        });\n    });\n}\n\nfunction addFileToManifest(folder, assetFile, manifest, done) {\n    var fullFilePath = path.join(folder, assetFile);\n    if (!fileExists(fullFilePath)) {\n        done();\n        return;\n    }\n\n    var readStream = fs.createReadStream(path.join(folder, assetFile));\n    var hashStream = crypto.createHash(HASH_ALGORITHM);\n\n    readStream.pipe(hashStream)\n        .on(\"error\", function(error) {\n            throw error;\n        })\n        .on(\"finish\", function() {\n            hashStream.end();\n            var buffer = hashStream.read();\n            var fileHash = buffer.toString(\"hex\");\n            manifest.push(path.join(CODE_PUSH_FOLDER_PREFIX, assetFile).replace(/\\\\/g, \"/\") + \":\" + fileHash);\n            done();\n        });\n}\n\nfunction fileExists(file) {\n    try { return fs.statSync(file).isFile(); }\n    catch (e) { return false; }\n}\n\nif (tempFileLocalPath) {\n    fs.unlinkSync(tempFileLocalPath);\n}"
  },
  {
    "path": "scripts/getFilesInFolder.js",
    "content": "var fs = require(\"fs\");\nvar path = require(\"path\");\n\n// Utility function that collects the stats of every file in a directory\n// as well as in its subdirectories.\nfunction getFilesInFolder(folderName, fileList) {\n    var folderFiles = fs.readdirSync(folderName);\n    folderFiles.forEach(function(file) {\n        var fileStats = fs.statSync(path.join(folderName, file));\n        if (fileStats.isDirectory()) {\n            getFilesInFolder(path.join(folderName, file), fileList);\n        } else {\n            fileStats.path = path.join(folderName, file);\n            fileList.push(fileStats);\n        }\n    });\n}\n\nmodule.exports = getFilesInFolder;"
  },
  {
    "path": "scripts/postlink/android/postlink.js",
    "content": "var linkTools = require('../../tools/linkToolsAndroid');\nvar fs = require(\"fs\");\nvar inquirer = require('inquirer');\n\nmodule.exports = () => {\n\n    console.log(\"Running android postlink script\");\n\n    var buildGradlePath = linkTools.getBuildGradlePath();\n    var mainApplicationPath = linkTools.getMainApplicationLocation();\n\n    // 1. Add the getJSBundleFile override\n    var getJSBundleFileOverride = linkTools.getJSBundleFileOverride;\n\n    if (mainApplicationPath) {\n        var mainApplicationContents = fs.readFileSync(mainApplicationPath, \"utf8\");\n        if (linkTools.isJsBundleOverridden(mainApplicationContents)) {\n            console.log(`\"getJSBundleFile\" is already overridden`);\n        } else {\n            var reactNativeHostInstantiation = linkTools.reactNativeHostInstantiation;\n            mainApplicationContents = mainApplicationContents.replace(reactNativeHostInstantiation,\n                `${reactNativeHostInstantiation}${getJSBundleFileOverride}`);\n            fs.writeFileSync(mainApplicationPath, mainApplicationContents);\n        }\n    } else {\n        var mainActivityPath = linkTools.getMainActivityPath();\n        if (mainActivityPath) {\n            var mainActivityContents = fs.readFileSync(mainActivityPath, \"utf8\");\n            if (linkTools.isJsBundleOverridden(mainActivityContents)) {\n                console.log(`\"getJSBundleFile\" is already overridden`);\n            } else {\n                var mainActivityClassDeclaration = linkTools.mainActivityClassDeclaration;\n                mainActivityContents = mainActivityContents.replace(mainActivityClassDeclaration,\n                    `${mainActivityClassDeclaration}${getJSBundleFileOverride}`);\n                fs.writeFileSync(mainActivityPath, mainActivityContents);\n            }\n        } else {\n            return Promise.reject(`Couldn't find Android application entry point. You might need to update it manually. \\\n    Please refer to plugin configuration section for Android at \\\n    https://github.com/microsoft/react-native-code-push/blob/master/docs/setup-android.md#plugin-configuration-for-react-native-lower-than-060-android for more details`);\n        }\n    }\n\n    if (!fs.existsSync(buildGradlePath)) {\n        return Promise.reject(`Couldn't find build.gradle file. You might need to update it manually. \\\n    Please refer to plugin installation section for Android at \\\n    https://github.com/microsoft/react-native-code-push/blob/master/docs/setup-android.md#plugin-installation-android---manual`);\n    }\n\n    // 2. Add the codepush.gradle build task definitions\n    var buildGradleContents = fs.readFileSync(buildGradlePath, \"utf8\");\n    var reactGradleLink = buildGradleContents.match(/\\napply from: [\"'].*?react\\.gradle[\"']/)[0];\n    var codePushGradleLink = linkTools.codePushGradleLink;\n    if (~buildGradleContents.indexOf(codePushGradleLink)) {\n        console.log(`\"codepush.gradle\" is already linked in the build definition`);\n    } else {\n        buildGradleContents = buildGradleContents.replace(reactGradleLink,\n            `${reactGradleLink}${codePushGradleLink}`);\n        fs.writeFileSync(buildGradlePath, buildGradleContents);\n    }\n\n    //3. Add deployment key\n    var stringsResourcesPath = linkTools.getStringsResourcesPath();\n    if (!stringsResourcesPath) {\n        return Promise.reject(new Error(`Couldn't find strings.xml. You might need to update it manually.`));\n    } else {\n        var stringsResourcesContent = fs.readFileSync(stringsResourcesPath, \"utf8\");\n        var deploymentKeyName = linkTools.deploymentKeyName;\n        if (~stringsResourcesContent.indexOf(deploymentKeyName)) {\n            console.log(`${deploymentKeyName} already specified in the strings.xml`);\n        } else {\n            return inquirer.prompt({\n                \"type\": \"input\",\n                \"name\": \"androidDeploymentKey\",\n                \"message\": \"What is your CodePush deployment key for Android (hit <ENTER> to ignore)\"\n            }).then(function(answer) {\n                var insertAfterString = \"<resources>\";\n                var deploymentKeyString = `\\t<string moduleConfig=\"true\" name=\"${deploymentKeyName}\">${answer.androidDeploymentKey || \"deployment-key-here\"}</string>`;\n                stringsResourcesContent = stringsResourcesContent.replace(insertAfterString,`${insertAfterString}\\n${deploymentKeyString}`);\n                fs.writeFileSync(stringsResourcesPath, stringsResourcesContent);\n                return Promise.resolve();\n            });\n        }\n    }\n\n    return Promise.resolve();\n}\n"
  },
  {
    "path": "scripts/postlink/ios/postlink.js",
    "content": "\nvar linkTools = require('../../tools/linkToolsIos');\nvar fs = require(\"fs\");\nvar inquirer = require('inquirer');\nvar plist = require(\"plist\");\nvar semver = require('semver');\n\nvar package = require('../../../../../package.json');\n\nmodule.exports = () => {\n\n    console.log(\"Running ios postlink script\");\n\n    var appDelegatePath = linkTools.getAppDeletePath();\n\n    if (!appDelegatePath) {\n        return Promise.reject(`Couldn't find AppDelegate. You might need to update it manually \\\n    Please refer to plugin configuration section for iOS at \\\n    https://github.com/microsoft/react-native-code-push#plugin-configuration-ios`);\n    }\n\n    var appDelegateContents = fs.readFileSync(appDelegatePath, \"utf8\");\n\n    // 1. Add the header import statement\n    if (~appDelegateContents.indexOf(linkTools.codePushHeaderImportStatement)) {\n        console.log(`\"CodePush.h\" header already imported.`);\n    } else {\n        var appDelegateHeaderImportStatement = `#import \"AppDelegate.h\"`;\n        appDelegateContents = appDelegateContents.replace(appDelegateHeaderImportStatement,\n            `${appDelegateHeaderImportStatement}${linkTools.codePushHeaderImportStatementFormatted}`);\n    }\n\n    // 2. Modify jsCodeLocation value assignment\n    var reactNativeVersion = package && package.dependencies && package.dependencies[\"react-native\"];\n\n    if (!reactNativeVersion) {\n        console.log(`Can't take react-native version from package.json`);\n    } else if (semver.gte(semver.coerce(reactNativeVersion), \"0.59.0\")) {\n        var oldBundleUrl = linkTools.oldBundleUrl;\n        var codePushBundleUrl = linkTools.codePushBundleUrl;\n\n        if (~appDelegateContents.indexOf(codePushBundleUrl)) {\n            console.log(`\"BundleUrl\" already pointing to \"[CodePush bundleURL]\".`);\n        } else {\n            if (~appDelegateContents.indexOf(oldBundleUrl)) {\n                appDelegateContents = appDelegateContents.replace(oldBundleUrl, codePushBundleUrl);\n            } else {\n                console.log(`AppDelegate isn't compatible for linking`);\n            }\n        }\n    } else {\n        var jsCodeLocations = appDelegateContents.match(/(jsCodeLocation = .*)/g);\n\n        if (!jsCodeLocations) {\n            console.log('Couldn\\'t find jsCodeLocation setting in AppDelegate.');\n        }\n\n        var newJsCodeLocationAssignmentStatement = linkTools.codePushGradleLink;\n        if (~appDelegateContents.indexOf(newJsCodeLocationAssignmentStatement)) {\n            console.log(`\"jsCodeLocation\" already pointing to \"[CodePush bundleURL]\".`);\n        } else {\n            if (jsCodeLocations.length === 1) {\n                // If there is one `jsCodeLocation` it means that react-native app version is not the 0.57.8 or 0.57.0 and lower than 0.59 \n                // and we should replace this line with DEBUG ifdef statement and add CodePush call for Release case\n\n                var oldJsCodeLocationAssignmentStatement = jsCodeLocations[0];\n                var jsCodeLocationPatch = linkTools.getJsCodeLocationPatch(oldJsCodeLocationAssignmentStatement);\n                appDelegateContents = appDelegateContents.replace(oldJsCodeLocationAssignmentStatement,\n                    jsCodeLocationPatch);\n            } else if (jsCodeLocations.length === 2) {\n                // If there are two `jsCodeLocation` it means that react-native app version is higher than 0.57.8 or equal\n                // and we should replace the second one(Release case) with CodePush call\n\n                appDelegateContents = appDelegateContents.replace(jsCodeLocations[1],\n                    newJsCodeLocationAssignmentStatement);\n            } else {\n                console.log(`AppDelegate isn't compatible for linking`);\n            }\n        }\n    }\n\n    var plistPath = linkTools.getPlistPath();\n\n    if (!plistPath) {\n        return Promise.reject(`Couldn't find .plist file. You might need to update it manually \\\n    Please refer to plugin configuration section for iOS at \\\n    https://github.com/microsoft/react-native-code-push#plugin-configuration-ios`);\n    }\n\n    var plistContents = fs.readFileSync(plistPath, \"utf8\");\n\n    // 3. Add CodePushDeploymentKey to plist file\n    var parsedInfoPlist = plist.parse(plistContents);\n    if (parsedInfoPlist.CodePushDeploymentKey) {\n        console.log(`\"CodePushDeploymentKey\" already specified in the plist file.`);\n        writePatches();\n        return Promise.resolve();\n    } else {\n        return inquirer.prompt({\n            \"type\": \"input\",\n            \"name\": \"iosDeploymentKey\",\n            \"message\": \"What is your CodePush deployment key for iOS (hit <ENTER> to ignore)\"\n        }).then(function(answer) {\n            parsedInfoPlist.CodePushDeploymentKey = answer.iosDeploymentKey || \"deployment-key-here\";\n            plistContents = plist.build(parsedInfoPlist);\n\n            writePatches();\n            return Promise.resolve();\n        });\n    }\n\n    function writePatches() {\n        fs.writeFileSync(appDelegatePath, appDelegateContents);\n        fs.writeFileSync(plistPath, plistContents);\n    }\n}\n"
  },
  {
    "path": "scripts/postlink/run.js",
    "content": "var postlinks = [\n    require(\"./android/postlink\"),\n    require(\"./ios/postlink\")\n];\n\n//run them sequentially\npostlinks\n    .reduce((p, fn) => p.then(fn), Promise.resolve())\n    .catch((err) => {\n        console.error(err.message);\n    }); "
  },
  {
    "path": "scripts/postunlink/android/postunlink.js",
    "content": "var linkTools = require('../../tools/linkToolsAndroid');\nvar fs = require(\"fs\");\n\nmodule.exports = () => {\n\n    console.log(\"Running android postunlink script\");\n\n    var mainApplicationPath = linkTools.getMainApplicationLocation();\n\n    // 1. Remove the getJSBundleFile override\n    var getJSBundleFileOverride = linkTools.getJSBundleFileOverride;\n\n    if (mainApplicationPath) {\n        var mainApplicationContents = fs.readFileSync(mainApplicationPath, \"utf8\");\n        if (!linkTools.isJsBundleOverridden(mainApplicationContents)) {\n            console.log(`\"getJSBundleFile\" is already removed`);\n        } else {\n            mainApplicationContents = mainApplicationContents.replace(`${getJSBundleFileOverride}`, \"\");\n            fs.writeFileSync(mainApplicationPath, mainApplicationContents);\n        }\n    } else {\n        var mainActivityPath = linkTools.getMainActivityPath();\n        if (mainActivityPath) {\n            var mainActivityContents = fs.readFileSync(mainActivityPath, \"utf8\");\n            if (!linkTools.isJsBundleOverridden(mainActivityContents)) {\n                console.log(`\"getJSBundleFile\" is already removed`);\n            } else {\n                mainActivityContents = mainActivityContents.replace(getJSBundleFileOverride, \"\");\n                fs.writeFileSync(mainActivityPath, mainActivityContents);\n            }\n        } else {\n            console.log(`Couldn't find Android application entry point. You might need to update it manually. \\\n    Please refer to plugin configuration section for Android at \\\n    https://github.com/microsoft/react-native-code-push/blob/master/docs/setup-android.md#plugin-configuration-for-react-native-lower-than-060-android for more details`);\n        }\n    }\n\n    // 2. Remove the codepush.gradle build task definitions\n    var buildGradlePath = linkTools.getBuildGradlePath();\n\n    if (!fs.existsSync(buildGradlePath)) {\n        console.log(`Couldn't find build.gradle file. You might need to update it manually. \\\n    Please refer to plugin installation section for Android at \\\n    https://github.com/microsoft/react-native-code-push/blob/master/docs/setup-android.md#plugin-installation-android---manual`);\n    } else {\n        var buildGradleContents = fs.readFileSync(buildGradlePath, \"utf8\");\n        var codePushGradleLink = linkTools.codePushGradleLink;\n        if (!~buildGradleContents.indexOf(codePushGradleLink)) {\n            console.log(`\"codepush.gradle\" is already unlinked in the build definition`);\n        } else {\n            buildGradleContents = buildGradleContents.replace(`${codePushGradleLink}`,\"\");\n            fs.writeFileSync(buildGradlePath, buildGradleContents);\n        }\n    }\n\n    // 3. Remove deployment key\n    var stringsResourcesPath = linkTools.getStringsResourcesPath();\n    if (!stringsResourcesPath) {\n        return Promise.reject(new Error(\"Couldn't find strings.xml. You might need to update it manually.\"));\n    } else {\n        var stringsResourcesContent = fs.readFileSync(stringsResourcesPath, \"utf8\");\n        var deploymentKeyName = linkTools.deploymentKeyName;\n        if (!~stringsResourcesContent.indexOf(deploymentKeyName)) {\n            console.log(`${deploymentKeyName} already removed from the strings.xml`);\n        } else {\n            var AndroidDeploymentKey = stringsResourcesContent.match(/(<string moduleConfig=\"true\" name=\"CodePushDeploymentKey\">.*<\\/string>)/);\n            if (AndroidDeploymentKey) {\n                stringsResourcesContent = stringsResourcesContent.replace(`\\n\\t${AndroidDeploymentKey[0]}`,\"\");\n                fs.writeFileSync(stringsResourcesPath, stringsResourcesContent);\n            }\n        }\n    }\n    return Promise.resolve();\n}\n"
  },
  {
    "path": "scripts/postunlink/ios/postunlink.js",
    "content": "\nvar linkTools = require('../../tools/linkToolsIos');\nvar fs = require(\"fs\");\nvar plist = require(\"plist\");\nvar semver = require('semver');\nvar packageFile = require('../../../../../package.json');\n\nmodule.exports = () => {\n\n    console.log(\"Running ios postunlink script\");\n\n    var appDelegatePath = linkTools.getAppDeletePath();\n\n    if (!appDelegatePath) {\n        console.log(`Couldn't find AppDelegate. You might need to update it manually \\\n    Please refer to plugin configuration section for iOS at \\\n    https://github.com/microsoft/react-native-code-push#plugin-configuration-ios`);\n    } else {\n        var appDelegateContents = fs.readFileSync(appDelegatePath, \"utf8\");\n\n        // 1. Remove the header import statement\n        if (!~appDelegateContents.indexOf(linkTools.codePushHeaderImportStatement)) {\n            console.log(`\"CodePush.h\" header already removed.`);\n        } else {\n            appDelegateContents = appDelegateContents.replace(linkTools.codePushHeaderImportStatementFormatted, \"\");\n        }\n\n        // 2. Modify jsCodeLocation value assignment\n        var codePushBundleUrl = linkTools.codePushBundleUrl;\n        if (!~appDelegateContents.indexOf(codePushBundleUrl)) {\n            console.log(`\"jsCodeLocation\" already not pointing to \"[CodePush bundleURL]\".`);\n        } else {\n            var reactNativeVersion = packageFile && packageFile.dependencies && packageFile.dependencies[\"react-native\"];\n            if (!reactNativeVersion) {\n                console.log(`Can't take react-native version from package.json`);\n            } else if (semver.gte(semver.coerce(reactNativeVersion), \"0.59.0\")) {\n                var oldBundleUrl = linkTools.oldBundleUrl;\n                appDelegateContents = appDelegateContents.replace(codePushBundleUrl, oldBundleUrl);\n                fs.writeFileSync(appDelegatePath, appDelegateContents);\n            } else {\n                var linkedJsCodeLocationAssignmentStatement = linkTools.linkedJsCodeLocationAssignmentStatement;\n                var jsCodeLocations = appDelegateContents.match(/(jsCodeLocation = .*)/g);\n                if (!jsCodeLocations || jsCodeLocations.length !== 2 || !~appDelegateContents.indexOf(linkedJsCodeLocationAssignmentStatement)) {\n                    console.log(`AppDelegate isn't compatible for unlinking`);\n                } else {\n                    if (semver.eq(semver.coerce(reactNativeVersion), \"0.57.8\") || semver.eq(semver.coerce(reactNativeVersion), \"0.57.0\")) {\n                        // If version of react-native application is 0.57.8 or 0.57 then by default there are two different\n                        // jsCodeLocation for debug and release and we should replace only release\n                        var unlinkedJsCodeLocations = `jsCodeLocation = [[NSBundle mainBundle] URLForResource:@\"main\" withExtension:@\"jsbundle\"];`;\n                        appDelegateContents = appDelegateContents.replace(linkedJsCodeLocationAssignmentStatement,\n                            unlinkedJsCodeLocations);\n                    } else {\n                        // If version of react-native application is not 0.57.8 or 0.57 and lower than 0.59.0 then by default there is only one\n                        // jsCodeLocation and we should stay on only it\n                        var defaultJsCodeLocationAssignmentStatement = jsCodeLocations[0];\n                        var linkedCodeLocationPatch = linkTools.getJsCodeLocationPatch(defaultJsCodeLocationAssignmentStatement);\n                        appDelegateContents = appDelegateContents.replace(linkedCodeLocationPatch,\n                            defaultJsCodeLocationAssignmentStatement);\n                    }\n                    fs.writeFileSync(appDelegatePath, appDelegateContents);\n                }\n            }\n        }\n    }\n\n    var plistPath = linkTools.getPlistPath();\n\n    if (!plistPath) {\n        return Promise.reject(`Couldn't find .plist file. You might need to update it manually \\\n    Please refer to plugin configuration section for iOS at \\\n    https://github.com/microsoft/react-native-code-push#plugin-configuration-ios`);\n    }\n\n    var plistContents = fs.readFileSync(plistPath, \"utf8\");\n\n    // 3. Remove CodePushDeploymentKey from plist file\n    var parsedInfoPlist = plist.parse(plistContents);\n    if (!parsedInfoPlist.CodePushDeploymentKey) {\n        console.log(`\"CodePushDeploymentKey\" already removed from the plist file.`);\n    } else {\n        delete parsedInfoPlist.CodePushDeploymentKey;\n        plistContents = plist.build(parsedInfoPlist);\n        fs.writeFileSync(plistPath, plistContents);\n    }\n\n    return Promise.resolve();\n}\n"
  },
  {
    "path": "scripts/postunlink/run.js",
    "content": "var postunlinks = [\n    require(\"./ios/postunlink\"),\n    require(\"./android/postunlink\")\n];\n\n//run them sequentially\npostunlinks\n    .reduce((p, fn) => p.then(fn), Promise.resolve())\n    .catch((err) => {\n        console.error(err.message);\n    });\n"
  },
  {
    "path": "scripts/recordFilesBeforeBundleCommand.js",
    "content": "/*\n * This script creates a snapshot of the contents in the resource directory\n * by creating a map with the modified time of all the files in the directory\n * and saving it to a temp file. This snapshot is later referenced in \n * \"generatePackageHash.js\" to figure out which files have changed or were\n * newly generated by the \"react-native bundle\" command.\n */\n\nvar fs = require(\"fs\");\nvar path = require(\"path\");\n\nvar getFilesInFolder = require(\"./getFilesInFolder\");\n\n\nvar resourcesDir = process.argv[2];\nvar tempFileName = process.argv[3];\n\nvar tempFileLocalPath = path.join(require(\"os\").tmpdir(), tempFileName);\nvar resourceFiles = [];\n\ntry {\n    getFilesInFolder(resourcesDir, resourceFiles);\n} catch(error) {\n    var targetPathNotFoundExceptionMessage = \"\\nResources directory path does not exist.\\n\";\n    targetPathNotFoundExceptionMessage += \"Unable to find '\" + resourcesDir;\n    targetPathNotFoundExceptionMessage += \"' directory. Please check version of Android Plugin for Gradle.\";\n    error.message += targetPathNotFoundExceptionMessage;\n    throw error;\n}\n\nvar fileToModifiedTimeMap = {};\n\nresourceFiles.forEach(function(resourceFile) {\n    fileToModifiedTimeMap[resourceFile.path.substring(resourcesDir.length)] = resourceFile.mtime.getTime();\n});\n\nfs.writeFile(tempFileLocalPath, JSON.stringify(fileToModifiedTimeMap), function(err) {\n    if (err) {\n        throw err;\n    }\n}); "
  },
  {
    "path": "scripts/tools/linkToolsAndroid.js",
    "content": "var fs = require(\"fs\");\nvar glob = require(\"glob\");\nvar path = require(\"path\");\n\nvar ignoreFolders = { ignore: [\"node_modules/**\", \"**/build/**\"] };\nvar manifestPath = glob.sync(\"**/AndroidManifest.xml\", ignoreFolders)[0];\n\nexports.getJSBundleFileOverride = `\n    @Override\n    protected String getJSBundleFile(){\n      return CodePush.getJSBundleFile();\n    }\n`;\nexports.reactNativeHostInstantiation = \"new ReactNativeHost(this) {\";\nexports.mainActivityClassDeclaration = \"public class MainActivity extends ReactActivity {\";\nexports.codePushGradleLink = `\\napply from: \"../../node_modules/react-native-code-push/android/codepush.gradle\"`;\nexports.deploymentKeyName = \"CodePushDeploymentKey\";\n\nexports.getMainApplicationLocation = function () {\n    return findMainApplication() || glob.sync(\"**/MainApplication.java\", ignoreFolders)[0];\n}\n\nexports.getMainActivityPath = function () {\n    return glob.sync(\"**/MainActivity.java\", ignoreFolders)[0]\n}\n\nexports.getStringsResourcesPath = function () {\n    return glob.sync(\"**/strings.xml\", ignoreFolders)[0];\n}\n\nexports.getBuildGradlePath = function () {\n    return path.join(\"android\", \"app\", \"build.gradle\");\n}\n\nexports.isJsBundleOverridden = function (codeContents) {\n    return /@Override\\s*\\n\\s*protected String getJSBundleFile\\(\\)\\s*\\{[\\s\\S]*?\\}/.test(codeContents);\n}\n\nfunction findMainApplication() {\n    if (!manifestPath) {\n        return null;\n    }\n\n    var manifest = fs.readFileSync(manifestPath, \"utf8\");\n\n    // Android manifest must include single 'application' element\n    var matchResult = manifest.match(/application\\s+android:name\\s*=\\s*\"(.*?)\"/);\n    if (matchResult) {\n        var appName = matchResult[1];\n    } else {\n        return null;\n    }\n\n    var nameParts = appName.split('.');\n    var searchPath = glob.sync(\"**/\" + nameParts[nameParts.length - 1] + \".java\", ignoreFolders)[0];\n    return searchPath;\n}\n"
  },
  {
    "path": "scripts/tools/linkToolsIos.js",
    "content": "var glob = require(\"glob\");\nvar path = require(\"path\");\nvar xcode = require(\"xcode\");\nvar packageFile = require('../../../../package.json');\n\nvar ignoreNodeModules = { ignore: \"node_modules/**\" };\nvar ignoreNodeModulesAndPods = { ignore: [\"node_modules/**\", \"ios/Pods/**\"] };\nvar appDelegatePaths = glob.sync(\"**/AppDelegate.+(mm|m)\", ignoreNodeModules);\n\nexports.codePushHeaderImportStatement = `#import <CodePush/CodePush.h>`;\nexports.codePushHeaderImportStatementFormatted = `\\n${this.codePushHeaderImportStatement}`;\nexports.codePushBundleUrl = \"[CodePush bundleURL]\";\nexports.oldBundleUrl = \"[[NSBundle mainBundle] URLForResource:@\\\"main\\\" withExtension:@\\\"jsbundle\\\"]\";\nexports.linkedJsCodeLocationAssignmentStatement = \"jsCodeLocation = [CodePush bundleURL];\";\n\nexports.getJsCodeLocationPatch = function(defaultJsCodeLocationAssignmentStatement) {\n    return `\n  #ifdef DEBUG\n    ${defaultJsCodeLocationAssignmentStatement}\n  #else\n    ${this.linkedJsCodeLocationAssignmentStatement}\n  #endif`;\n}\n\n// Fix for https://github.com/microsoft/react-native-code-push/issues/477\n// Typical location of AppDelegate.m for newer RN versions: $PROJECT_ROOT/ios/<project_name>/AppDelegate.m\n// Let's try to find that path by filtering the whole array for any path containing <project_name>\n// If we can't find it there, play dumb and pray it is the first path we find.\nexports.getAppDeletePath = function() {\n    return findFileByAppName(appDelegatePaths, packageFile ? packageFile.name : null) || appDelegatePaths[0];\n}\n\nexports.getPlistPath = function() {\n    var xcodeProjectPaths = glob.sync(`**/*.xcodeproj/project.pbxproj`, ignoreNodeModulesAndPods);\n    if (!xcodeProjectPaths){\n        return getDefaultPlistPath();\n    }\n\n    if (xcodeProjectPaths.length !== 1) {\n        console.log('Could not determine correct xcode proj path to retrieve related plist file, there are multiple xcodeproj under the solution.');\n        return getDefaultPlistPath();\n    }\n\n    var xcodeProjectPath = xcodeProjectPaths[0];\n    var parsedXCodeProj;\n\n    try {\n        var proj = xcode.project(xcodeProjectPath);\n        //use sync version because there are some problems with async version of xcode lib as of current version\n        parsedXCodeProj = proj.parseSync();\n    }\n    catch(e) {\n        console.log('Couldn\\'t read info.plist path from xcode project - error: ' + e.message);\n        return getDefaultPlistPath();\n    }\n\n    var INFO_PLIST_PROJECT_KEY = 'INFOPLIST_FILE';\n    var RELEASE_BUILD_PROPERTY_NAME = \"Release\";\n    var targetProductName = packageFile ? packageFile.name : null;\n\n    //Try to get 'Release' build of ProductName matching the package name first and if it doesn't exist then try to get any other if existing\n    var plistPathValue = getBuildSettingsPropertyMatchingTargetProductName(parsedXCodeProj, INFO_PLIST_PROJECT_KEY, targetProductName, RELEASE_BUILD_PROPERTY_NAME) ||\n        getBuildSettingsPropertyMatchingTargetProductName(parsedXCodeProj, INFO_PLIST_PROJECT_KEY, targetProductName) ||\n        getBuildSettingsPropertyMatchingTargetProductName(parsedXCodeProj, INFO_PLIST_PROJECT_KEY, null, RELEASE_BUILD_PROPERTY_NAME) ||\n        getBuildSettingsPropertyMatchingTargetProductName(parsedXCodeProj, INFO_PLIST_PROJECT_KEY) ||\n        parsedXCodeProj.getBuildProperty(INFO_PLIST_PROJECT_KEY, RELEASE_BUILD_PROPERTY_NAME) ||\n        parsedXCodeProj.getBuildProperty(INFO_PLIST_PROJECT_KEY);\n\n    if (!plistPathValue){\n        return getDefaultPlistPath();\n    }\n\n    //also remove surrounding quotes from plistPathValue to get correct path resolved\n    //(see https://github.com/microsoft/react-native-code-push/issues/534#issuecomment-302069326 for details)\n    return path.resolve(path.dirname(xcodeProjectPath), '..', plistPathValue.replace(/^\"(.*)\"$/, '$1'));\n}\n\n// Helper that filters an array with AppDelegate.m paths for a path with the app name inside it\n// Should cover nearly all cases\nfunction findFileByAppName(array, appName) {\n    if (array.length === 0 || !appName) return null;\n\n    for (var i = 0; i < array.length; i++) {\n        var path = array[i];\n        if (path && path.indexOf(appName) !== -1) {\n            return path;\n        }\n    }\n\n    return null;\n}\n\nfunction getDefaultPlistPath() {\n    //this is old logic in case we are unable to find PLIST from xcode/pbxproj - at least we can fallback to default solution\n    return glob.sync(`**/${packageFile.name}/*Info.plist`, ignoreNodeModules)[0];\n}\n\n// This is enhanced version of standard implementation of xcode 'getBuildProperty' function\n// but allows us to narrow results by PRODUCT_NAME property also.\n// So we suppose that proj name should be the same as package name, otherwise fallback to default plist path searching logic\nfunction getBuildSettingsPropertyMatchingTargetProductName(parsedXCodeProj, prop, targetProductName, build) {\n    var target;\n    var COMMENT_KEY = /_comment$/;\n    var PRODUCT_NAME_PROJECT_KEY = 'PRODUCT_NAME';\n    var TV_OS_DEPLOYMENT_TARGET_PROPERTY_NAME = 'TVOS_DEPLOYMENT_TARGET';\n    var TEST_HOST_PROPERTY_NAME = 'TEST_HOST';\n\n    var configs = parsedXCodeProj.pbxXCBuildConfigurationSection();\n    for (var configName in configs) {\n        if (!COMMENT_KEY.test(configName)) {\n            var config = configs[configName];\n            if ( (build && config.name === build) || (build === undefined) ) {\n                if (targetProductName) {\n                    if (config.buildSettings[prop] !== undefined && config.buildSettings[PRODUCT_NAME_PROJECT_KEY] == targetProductName) {\n                        target = config.buildSettings[prop];\n                    }\n                } else {\n                    if (config.buildSettings[prop] !== undefined  &&\n                    //exclude tvOS projects\n                    config.buildSettings[TV_OS_DEPLOYMENT_TARGET_PROPERTY_NAME] == undefined &&\n                    //exclude test app\n                    config.buildSettings[TEST_HOST_PROPERTY_NAME] == undefined) {\n                        target = config.buildSettings[prop];\n                    }\n                }\n            }\n        }\n    }\n    return target;\n}\n"
  },
  {
    "path": "test/template/android/app/src/main/java/com/testcodepush/MainApplication.java",
    "content": "package com.testcodepush;\n\nimport android.app.Application;\nimport com.microsoft.codepush.react.CodePush;\nimport android.content.Context;\nimport com.facebook.react.PackageList;\nimport com.facebook.react.ReactApplication;\nimport com.facebook.react.ReactNativeHost;\nimport com.facebook.react.ReactPackage;\nimport com.facebook.soloader.SoLoader;\nimport java.lang.reflect.InvocationTargetException;\nimport java.util.List;\n\npublic class MainApplication extends Application implements ReactApplication {\n\n  private final ReactNativeHost mReactNativeHost =\n      new ReactNativeHost(this) {\n        @Override\n        public boolean getUseDeveloperSupport() {\n          return BuildConfig.DEBUG;\n        }\n\n        @Override\n        protected String getJSBundleFile() {\n            return CodePush.getJSBundleFile();\n        }\n\n        @Override\n        protected List<ReactPackage> getPackages() {\n          @SuppressWarnings(\"UnnecessaryLocalVariable\")\n          List<ReactPackage> packages = new PackageList(this).getPackages();\n          // Packages that cannot be autolinked yet can be added manually here, for example:\n          // packages.add(new MyReactNativePackage());\n          return packages;\n        }\n\n        @Override\n        protected String getJSMainModuleName() {\n          return \"index\";\n        }\n      };\n\n  @Override\n  public ReactNativeHost getReactNativeHost() {\n    return mReactNativeHost;\n  }\n\n  @Override\n  public void onCreate() {\n    super.onCreate();\n    SoLoader.init(this, /* native exopackage */ false);\n    initializeFlipper(this); // Remove this line if you don't want Flipper enabled\n  }\n\n  /**\n   * Loads Flipper in React Native templates.\n   *\n   * @param context\n   */\n  private static void initializeFlipper(Context context) {\n    if (BuildConfig.DEBUG) {\n      try {\n        /*\n         We use reflection here to pick up the class that initializes Flipper,\n        since Flipper library is not available in release mode\n        */\n        Class<?> aClass = Class.forName(\"com.facebook.flipper.ReactNativeFlipper\");\n        aClass.getMethod(\"initializeFlipper\", Context.class).invoke(null, context);\n      } catch (ClassNotFoundException e) {\n        e.printStackTrace();\n      } catch (NoSuchMethodException e) {\n        e.printStackTrace();\n      } catch (IllegalAccessException e) {\n        e.printStackTrace();\n      } catch (InvocationTargetException e) {\n        e.printStackTrace();\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "test/template/android/app/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">TestCodePush</string>\n    <string moduleConfig=\"true\" name=\"CodePushDeploymentKey\">CODE_PUSH_ANDROID_DEPLOYMENT_KEY</string>\n    <string moduleConfig=\"true\" name=\"CodePushServerUrl\">CODE_PUSH_SERVER_URL</string>\n</resources>\n"
  },
  {
    "path": "test/template/codePushWrapper.js",
    "content": "import CodePush from \"react-native-code-push\";\n\n// This module wraps CodePush API calls to add test message callbacks to every function for simpler test code.\n\nmodule.exports = {\n    checkForUpdate: function (testApp, onSuccess, onError, deploymentKey) {\n        return CodePush.checkForUpdate(deploymentKey)\n            .then((remotePackage) => {\n                return testApp.checkUpdateSuccess(remotePackage).then(() => { return onSuccess && onSuccess(remotePackage); });\n            }, (error) => {\n                return testApp.checkUpdateError(error).then(() => { return onError && onError(error); });\n            });\n    },\n\n    download: function (testApp, onSuccess, onError, remotePackage) {\n        return remotePackage.download()\n            .then((localPackage) => {\n                return testApp.downloadSuccess(localPackage).then(() => { return onSuccess && onSuccess(localPackage); });\n            }, (error) => {\n                return testApp.downloadError(error).then(() => { return onError && onError(error); });\n            });\n    },\n\n    install: function (testApp, onSuccess, onError, installMode, minBackgroundDuration, disallowRestart, localPackage) {\n        return localPackage.install(installMode, minBackgroundDuration)\n            .then(() => {\n                // Since immediate installs cannot be reliably logged (due to async network calls), we only log \"UPDATE_INSTALLED\" if it is a resume or restart update.\n                if (installMode !== CodePush.InstallMode.IMMEDIATE || disallowRestart) return testApp.installSuccess().then(() => { return onSuccess && onSuccess(); });\n                return onSuccess && onSuccess();\n            }, () => {\n                return testApp.installError().then(() => { return onError && onError(); });\n            });\n    },\n\n    checkAndInstall: function (testApp, onSuccess, onError, installMode, minBackgroundDuration, disallowRestart) {\n        var installUpdate = this.install.bind(this, testApp, onSuccess, onError, installMode, minBackgroundDuration, disallowRestart);\n        var downloadUpdate = this.download.bind(this, testApp, installUpdate, onError);\n        return this.checkForUpdate(testApp, downloadUpdate, onError);\n    },\n\n    sync: function (testApp, onSyncStatus, onSyncError, options) {\n        return CodePush.checkForUpdate()\n            .then(\n                (remotePackage) => {\n                    // Since immediate installs cannot be reliably logged (due to async network calls), we don't log \"UPDATE_INSTALLED\" when the installation is immediate.\n                    // However, to determine this, we must first figure out whether or not the package is mandatory because mandatory packages use a different install mode than regular updates.\n                    // This requires an additional call to checkForUpdate before syncing.\n                    var regularUpdateIsImmediate = options && options.installMode === CodePush.InstallMode.IMMEDIATE;\n                    var mandatoryUpdateIsImmediate = !options || (options && (!options.mandatoryInstallMode || options.mandatoryInstallMode === CodePush.InstallMode.IMMEDIATE));\n                    var isInstallImmediate = (remotePackage && remotePackage.isMandatory) ? mandatoryUpdateIsImmediate : regularUpdateIsImmediate;\n\n                    return CodePush.sync(options)\n                        .then((status) => {\n                            if (!(isInstallImmediate && status === CodePush.SyncStatus.UPDATE_INSTALLED)) {\n                                return testApp.onSyncStatus(status).then(() => { return onSyncStatus(status); });\n                            }\n                            return onSyncStatus(status);\n                        }, (error) => {\n                            return testApp.onSyncError(error).then(() => { return onSyncError(error); });\n                        });\n                },\n                (error) => {\n                    return CodePush.sync(options)\n                        .then((status) => {\n                            // Should fail because the check for update failed, so no need to check whether the install is immediate.\n                            return testApp.onSyncStatus(status).then(() => { return onSyncStatus(status); });\n                        }, (error) => {\n                            return testApp.onSyncError(error).then(() => { return onSyncError(error); });\n                        });\n                }\n            );\n    }\n}"
  },
  {
    "path": "test/template/index.js",
    "content": "/**\n * CodePush React-Native Test App\n */\n\nimport React, {\n    Component\n} from 'react';\n\nimport {\n    AppRegistry,\n    StyleSheet,\n    Text,\n    View\n} from 'react-native';\n\nimport CodePush from \"react-native-code-push\";\n\nvar testScenario = require(\"./CODE_PUSH_INDEX_JS_PATH\");\n\n/** A promise that maintains synchronous sending of the test messages. */\nvar testMessageQueue;\n\nclass CODE_PUSH_TEST_APP_NAME extends Component {\n    // CodePush API Callbacks\n    constructor() {\n        super();\n        this.state = { message: '' };\n    }\n    // checkForUpdate\n    checkUpdateSuccess(remotePackage) {\n        if (remotePackage) {\n            if (!remotePackage.failedInstall) {\n                return this.setStateAndSendMessage(\"There is an update available. Remote package:\" + JSON.stringify(remotePackage), \"CHECK_UPDATE_AVAILABLE\", [remotePackage]);\n            } else {\n                return this.setStateAndSendMessage(\"An update is available but failed previously. Remote package:\" + JSON.stringify(remotePackage), \"UPDATE_FAILED_PREVIOUSLY\");\n            }\n        } else {\n            return this.setStateAndSendMessage(\"The application is up to date.\", \"CHECK_UP_TO_DATE\");\n        }\n    }\n    checkUpdateError(error) {\n        return this.setStateAndSendMessage(\"An error occured while checking for updates:\\n\" + error, \"CHECK_ERROR\");\n    }\n\n    // remotePackage.download\n    downloadSuccess(localPackage) {\n        return this.setStateAndSendMessage(\"Download succeeded.\", \"DOWNLOAD_SUCCEEDED\", [localPackage]);\n    }\n    downloadError(error) {\n        return this.setStateAndSendMessage(\"Download error:\\n\" + error, \"DOWNLOAD_ERROR\");\n    }\n\n    // localPackage.install\n    installSuccess() {\n        return this.setStateAndSendMessage(\"Update installed.\", \"UPDATE_INSTALLED\");\n    }\n    installError() {\n        return this.setStateAndSendMessage(\"Install error.\", \"INSTALL_ERROR\");\n    }\n\n    // sync\n    onSyncStatus(status) {\n        return this.setStateAndSendMessage(\"Sync status \" + status + \" received.\", \"SYNC_STATUS\", [status]);\n    }\n    onSyncError(error) {\n        return this.setStateAndSendMessage(\"Sync error \" + error + \" received.\", \"SYNC_STATUS\", [CodePush.SyncStatus.UNKNOWN_ERROR]);\n    }\n\n\n    // Test Output Methods\n\n    readyAfterUpdate(callback) {\n        return this.setStateAndSendMessage(\"Ready after update.\", \"DEVICE_READY_AFTER_UPDATE\", undefined, callback);\n    }\n\n    sendCurrentAndPendingPackage() {\n        return CodePush.getUpdateMetadata(CodePush.UpdateState.PENDING)\n            .then((pendingPackage) => {\n                this.setStateAndSendMessage(\"Pending package: \" + pendingPackage, \"PENDING_PACKAGE\", [pendingPackage ? pendingPackage.packageHash : null]);\n                return CodePush.getUpdateMetadata(CodePush.UpdateState.RUNNING);\n            })\n            .then((currentPackage) => {\n                return this.setStateAndSendMessage(\"Current package: \" + currentPackage, \"CURRENT_PACKAGE\", [currentPackage ? currentPackage.packageHash : null]);\n            });\n    }\n\n    setStateAndSendMessage(message, testMessage, args, callback) {\n        this.setState({\n            message: this.state.message + \"\\n...\\n\" + message\n        });\n        return this.sendTestMessage(testMessage, args, callback);\n    }\n\n    sendTestMessage(message, args, callback) {\n        function makeNetworkCall() {\n            return new Promise(function (resolve, reject) {\n                var xhr = new XMLHttpRequest();\n\n                xhr.onreadystatechange = function () {\n                    if (xhr.readyState == 4 && xhr.status == 200) {\n                        callback && callback(xhr.response);\n                        resolve();\n                    }\n                };\n\n                xhr.open(\"POST\", \"CODE_PUSH_SERVER_URL/reportTestMessage\", true);\n                var body = JSON.stringify({ message: message, args: args });\n                console.log(\"Sending test message body: \" + body);\n\n                xhr.setRequestHeader(\"Content-type\", \"application/json\");\n\n                xhr.send(body);\n            });\n        }\n\n        if (!testMessageQueue) testMessageQueue = makeNetworkCall();\n        else testMessageQueue = testMessageQueue.then(makeNetworkCall);\n\n        return testMessageQueue;\n    }\n\n\n    // Test Setup Methods\n\n    componentDidMount() {\n        testScenario.startTest(this);\n    }\n\n    getInitialState() {\n        return {\n            message: \"\"\n        };\n    }\n\n    render() {\n        return (\n            <View style={styles.container}>\n                <Text style={styles.welcome}>\n                    CodePush React-Native Plugin Tests\n            </Text>\n                <Text style={styles.instructions}>\n                    {testScenario.getScenarioName()}{this.state.message}\n                </Text>\n            </View>\n        );\n    }\n};\n\nconst styles = StyleSheet.create({\n    container: {\n        flex: 1,\n        justifyContent: 'center',\n        alignItems: 'center',\n        backgroundColor: '#F5FCFF',\n    },\n    welcome: {\n        fontSize: 20,\n        textAlign: 'center',\n        margin: 10,\n    },\n    instructions: {\n        textAlign: 'center',\n        color: '#333333',\n        marginBottom: 5,\n    },\n});\n\nAppRegistry.registerComponent('CODE_PUSH_TEST_APP_NAME', () => CODE_PUSH_TEST_APP_NAME);"
  },
  {
    "path": "test/template/ios/TestCodePush/AppDelegate.mm",
    "content": "#import \"AppDelegate.h\"\n\n#import <CodePush/CodePush.h>\n\n#import <React/RCTBundleURLProvider.h>\n#import <React/RCTBridge.h>\n#import <React/RCTRootView.h>\n\n@implementation AppDelegate\n\n- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions\n{\n  RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];\n  RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge\n                                                   moduleName:@\"CODE_PUSH_TEST_APP_NAME\"\n                                            initialProperties:nil];\n\n  self.moduleName = @\"TestCodePush\";\n  // You can add your custom initial props in the dictionary below.\n  // They will be passed down to the ViewController used by React Native.\n  self.initialProps = @{};\n\n  return [super application:application didFinishLaunchingWithOptions:launchOptions];\n}\n\n- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge\n{\n  return [CodePush bundleURL];\n}\n\n/// This method controls whether the `concurrentRoot`feature of React18 is turned on or off.\n///\n/// @see: https://reactjs.org/blog/2022/03/29/react-v18.html\n/// @note: This requires to be rendering on Fabric (i.e. on the New Architecture).\n/// @return: `true` if the `concurrentRoot` feature is enabled. Otherwise, it returns `false`.\n- (BOOL)concurrentRootEnabled\n{\n  return true;\n}\n\n@end\n"
  },
  {
    "path": "test/template/scenarios/scenarioCheckForUpdate.js",
    "content": "var CodePushWrapper = require(\"../codePushWrapper.js\");\n\nmodule.exports = {\n    startTest: function (testApp) {\n        CodePushWrapper.checkForUpdate(testApp);\n    },\n\n    getScenarioName: function () {\n        return \"Check for Update\";\n    }\n}; "
  },
  {
    "path": "test/template/scenarios/scenarioCheckForUpdateCustomKey.js",
    "content": "var CodePushWrapper = require(\"../codePushWrapper.js\");\n\nmodule.exports = {\n    startTest: function (testApp) {\n        CodePushWrapper.checkForUpdate(testApp, undefined, undefined, \"CUSTOM-DEPLOYMENT-KEY\");\n    },\n\n    getScenarioName: function () {\n        return \"Check for Update Custom Key\";\n    }\n};"
  },
  {
    "path": "test/template/scenarios/scenarioDisallowRestartImmediate.js",
    "content": "var CodePushWrapper = require(\"../codePushWrapper.js\");\nimport CodePush from \"react-native-code-push\";\n\nmodule.exports = {\n    startTest: function (testApp) {\n        CodePush.disallowRestart();\n        CodePushWrapper.checkAndInstall(testApp,\n            () => {\n                CodePush.allowRestart();\n            },\n            undefined,\n            CodePush.InstallMode.IMMEDIATE,\n            undefined,\n            true\n        );\n    },\n\n    getScenarioName: function () {\n        return \"disallowRestart\";\n    }\n};\n"
  },
  {
    "path": "test/template/scenarios/scenarioDisallowRestartOnResume.js",
    "content": "var CodePushWrapper = require(\"../codePushWrapper.js\");\nimport CodePush from \"react-native-code-push\";\n\nmodule.exports = {\n    startTest: function (testApp) {\n        CodePush.disallowRestart();\n        CodePushWrapper.checkAndInstall(testApp,\n            undefined,\n            undefined,\n            CodePush.InstallMode.ON_NEXT_RESUME,\n            undefined,\n            true\n        );\n    },\n\n    getScenarioName: function () {\n        return \"disallowRestart\";\n    }\n};\n"
  },
  {
    "path": "test/template/scenarios/scenarioDisallowRestartOnSuspend.js",
    "content": "var CodePushWrapper = require(\"../codePushWrapper.js\");\nimport CodePush from \"react-native-code-push\";\n\nmodule.exports = {\n    startTest: function (testApp) {\n        CodePush.disallowRestart();\n        CodePushWrapper.checkAndInstall(testApp,\n            undefined,\n            undefined,\n            CodePush.InstallMode.ON_NEXT_SUSPEND,\n            undefined,\n            true\n        );\n    },\n\n    getScenarioName: function () {\n        return \"disallowRestart\";\n    }\n};\n"
  },
  {
    "path": "test/template/scenarios/scenarioDownloadUpdate.js",
    "content": "var CodePushWrapper = require(\"../codePushWrapper.js\");\n\nmodule.exports = {\n    startTest: function (testApp) {\n        CodePushWrapper.checkForUpdate(testApp,\n            CodePushWrapper.download.bind(undefined, testApp, undefined, undefined));\n    },\n\n    getScenarioName: function () {\n        return \"Download Update\";\n    }\n};"
  },
  {
    "path": "test/template/scenarios/scenarioInstall.js",
    "content": "var CodePushWrapper = require(\"../codePushWrapper.js\");\nimport CodePush from \"react-native-code-push\";\n\nmodule.exports = {\n    startTest: function (testApp) {\n        CodePushWrapper.checkAndInstall(testApp, undefined, undefined, CodePush.InstallMode.IMMEDIATE);\n    },\n\n    getScenarioName: function () {\n        return \"Install\";\n    }\n};"
  },
  {
    "path": "test/template/scenarios/scenarioInstallOnRestartWithRevert.js",
    "content": "var CodePushWrapper = require(\"../codePushWrapper.js\");\nimport CodePush from \"react-native-code-push\";\n\nmodule.exports = {\n    startTest: function (testApp) {\n        CodePushWrapper.checkAndInstall(testApp, undefined, undefined, CodePush.InstallMode.ON_NEXT_RESTART);\n    },\n\n    getScenarioName: function () {\n        return \"Install on Restart with Revert\";\n    }\n};"
  },
  {
    "path": "test/template/scenarios/scenarioInstallOnResumeWithRevert.js",
    "content": "var CodePushWrapper = require(\"../codePushWrapper.js\");\nimport CodePush from \"react-native-code-push\";\n\nmodule.exports = {\n    startTest: function (testApp) {\n        CodePushWrapper.checkAndInstall(testApp, undefined, undefined, CodePush.InstallMode.ON_NEXT_RESUME);\n    },\n\n    getScenarioName: function () {\n        return \"Install on Resume with Revert\";\n    }\n};"
  },
  {
    "path": "test/template/scenarios/scenarioInstallOnSuspendWithRevert.js",
    "content": "var CodePushWrapper = require(\"../codePushWrapper.js\");\nimport CodePush from \"react-native-code-push\";\n\nmodule.exports = {\n    startTest: function (testApp) {\n        CodePushWrapper.checkAndInstall(testApp, undefined, undefined, CodePush.InstallMode.ON_NEXT_SUSPEND);\n    },\n\n    getScenarioName: function () {\n        return \"Install on Suspend with Revert\";\n    }\n};\n"
  },
  {
    "path": "test/template/scenarios/scenarioInstallRestart2x.js",
    "content": "var CodePushWrapper = require(\"../codePushWrapper.js\");\nimport CodePush from \"react-native-code-push\";\n\nmodule.exports = {\n    startTest: function (testApp) {\n        CodePushWrapper.checkAndInstall(testApp,\n            () => {\n                CodePush.restartApp();\n                CodePush.restartApp();\n            }\n        );\n    },\n\n    getScenarioName: function () {\n        return \"Install and Restart 2x\";\n    }\n};"
  },
  {
    "path": "test/template/scenarios/scenarioInstallWithRevert.js",
    "content": "var CodePushWrapper = require(\"../codePushWrapper.js\");\nimport CodePush from \"react-native-code-push\";\n\nmodule.exports = {\n    startTest: function (testApp) {\n        CodePushWrapper.checkAndInstall(testApp, undefined, undefined, CodePush.InstallMode.IMMEDIATE);\n    },\n\n    getScenarioName: function () {\n        return \"Install with Revert\";\n    }\n};"
  },
  {
    "path": "test/template/scenarios/scenarioRestart.js",
    "content": "var CodePushWrapper = require(\"../codePushWrapper.js\");\nimport CodePush from \"react-native-code-push\";\n\nmodule.exports = {\n    startTest: function (testApp) {\n        testApp.sendCurrentAndPendingPackage()\n            .then(() => {\n                CodePushWrapper.sync(testApp, (status) => {\n                    if (status === CodePush.SyncStatus.UPDATE_INSTALLED) {\n                        testApp.sendCurrentAndPendingPackage().then(CodePush.restartApp);\n                    }\n                }, undefined, { installMode: CodePush.InstallMode.ON_NEXT_RESTART });\n            });\n    },\n\n    getScenarioName: function () {\n        return \"Restart\";\n    }\n};"
  },
  {
    "path": "test/template/scenarios/scenarioRestart2x.js",
    "content": "var CodePushWrapper = require(\"../codePushWrapper.js\");\nimport CodePush from \"react-native-code-push\";\n\nmodule.exports = {\n    startTest: function (testApp) {\n        CodePush.restartApp(true);\n        CodePushWrapper.checkAndInstall(testApp,\n            () => {\n                CodePush.restartApp(true);\n            }\n        );\n    },\n\n    getScenarioName: function () {\n        return \"Restart2x\";\n    }\n};"
  },
  {
    "path": "test/template/scenarios/scenarioSync.js",
    "content": "var CodePushWrapper = require(\"../codePushWrapper.js\");\nimport CodePush from \"react-native-code-push\";\n\nmodule.exports = {\n    startTest: function (testApp) {\n        CodePushWrapper.sync(testApp, undefined, undefined, { installMode: CodePush.InstallMode.IMMEDIATE });\n    },\n\n    getScenarioName: function () {\n        return \"Sync\";\n    }\n};"
  },
  {
    "path": "test/template/scenarios/scenarioSync2x.js",
    "content": "var CodePushWrapper = require(\"../codePushWrapper.js\");\nimport CodePush from \"react-native-code-push\";\n\nmodule.exports = {\n    startTest: function (testApp) {\n        CodePushWrapper.sync(testApp, undefined, undefined, { installMode: CodePush.InstallMode.IMMEDIATE });\n        CodePushWrapper.sync(testApp, undefined, undefined, { installMode: CodePush.InstallMode.IMMEDIATE });\n    },\n\n    getScenarioName: function () {\n        return \"Sync 2x\";\n    }\n};"
  },
  {
    "path": "test/template/scenarios/scenarioSyncMandatoryDefault.js",
    "content": "var CodePushWrapper = require(\"../codePushWrapper.js\");\nimport CodePush from \"react-native-code-push\";\n\nmodule.exports = {\n    startTest: function (testApp) {\n        CodePushWrapper.sync(testApp, undefined, undefined, { installMode: CodePush.InstallMode.ON_NEXT_RESTART });\n    },\n\n    getScenarioName: function () {\n        return \"Sync Mandatory Default\";\n    }\n};"
  },
  {
    "path": "test/template/scenarios/scenarioSyncMandatoryRestart.js",
    "content": "var CodePushWrapper = require(\"../codePushWrapper.js\");\nimport CodePush from \"react-native-code-push\";\n\nmodule.exports = {\n    startTest: function (testApp) {\n        CodePushWrapper.sync(testApp, undefined, undefined,\n            {\n                installMode: CodePush.InstallMode.IMMEDIATE,\n                mandatoryInstallMode: CodePush.InstallMode.ON_NEXT_RESTART\n            });\n    },\n\n    getScenarioName: function () {\n        return \"Sync Mandatory Restart\";\n    }\n};"
  },
  {
    "path": "test/template/scenarios/scenarioSyncMandatoryResume.js",
    "content": "var CodePushWrapper = require(\"../codePushWrapper.js\");\nimport CodePush from \"react-native-code-push\";\n\nmodule.exports = {\n    startTest: function (testApp) {\n        CodePushWrapper.sync(testApp, undefined, undefined,\n            {\n                installMode: CodePush.InstallMode.ON_NEXT_RESTART,\n                mandatoryInstallMode: CodePush.InstallMode.ON_NEXT_RESUME\n            });\n    },\n\n    getScenarioName: function () {\n        return \"Sync Mandatory Resume\";\n    }\n};"
  },
  {
    "path": "test/template/scenarios/scenarioSyncMandatorySuspend.js",
    "content": "var CodePushWrapper = require(\"../codePushWrapper.js\");\nimport CodePush from \"react-native-code-push\";\n\nmodule.exports = {\n    startTest: function (testApp) {\n        CodePushWrapper.sync(testApp, undefined, undefined,\n            {\n                installMode: CodePush.InstallMode.IMMEDIATE,\n                mandatoryInstallMode: CodePush.InstallMode.ON_NEXT_SUSPEND\n            });\n    },\n\n    getScenarioName: function () {\n        return \"Sync Mandatory Suspend\";\n    }\n};\n"
  },
  {
    "path": "test/template/scenarios/scenarioSyncRestartDelay.js",
    "content": "var CodePushWrapper = require(\"../codePushWrapper.js\");\nimport CodePush from \"react-native-code-push\";\n\nmodule.exports = {\n    startTest: function (testApp) {\n        CodePushWrapper.sync(testApp, undefined, undefined,\n            {\n                installMode: CodePush.InstallMode.ON_NEXT_RESTART,\n                minimumBackgroundDuration: 15\n            });\n    },\n\n    getScenarioName: function () {\n        return \"Sync Restart Delay\";\n    }\n};"
  },
  {
    "path": "test/template/scenarios/scenarioSyncResume.js",
    "content": "var CodePushWrapper = require(\"../codePushWrapper.js\");\nimport CodePush from \"react-native-code-push\";\n\nmodule.exports = {\n    startTest: function (testApp) {\n        CodePushWrapper.sync(testApp, undefined, undefined,\n            { installMode: CodePush.InstallMode.ON_NEXT_RESUME });\n    },\n\n    getScenarioName: function () {\n        return \"Sync Resume\";\n    }\n};"
  },
  {
    "path": "test/template/scenarios/scenarioSyncResumeDelay.js",
    "content": "var CodePushWrapper = require(\"../codePushWrapper.js\");\nimport CodePush from \"react-native-code-push\";\n\nmodule.exports = {\n    startTest: function (testApp) {\n        CodePushWrapper.sync(testApp, undefined, undefined,\n            {\n                installMode: CodePush.InstallMode.ON_NEXT_RESUME,\n                minimumBackgroundDuration: 5\n            });\n    },\n\n    getScenarioName: function () {\n        return \"Sync Resume Delay\";\n    }\n};"
  },
  {
    "path": "test/template/scenarios/scenarioSyncSuspend.js",
    "content": "var CodePushWrapper = require(\"../codePushWrapper.js\");\nimport CodePush from \"react-native-code-push\";\n\nmodule.exports = {\n    startTest: function (testApp) {\n        CodePushWrapper.sync(testApp, undefined, undefined,\n            { installMode: CodePush.InstallMode.ON_NEXT_SUSPEND });\n    },\n\n    getScenarioName: function () {\n        return \"Sync Suspend\";\n    }\n};\n"
  },
  {
    "path": "test/template/scenarios/scenarioSyncSuspendDelay.js",
    "content": "var CodePushWrapper = require(\"../codePushWrapper.js\");\nimport CodePush from \"react-native-code-push\";\n\nmodule.exports = {\n    startTest: function (testApp) {\n        CodePushWrapper.sync(testApp, undefined, undefined,\n            {\n                installMode: CodePush.InstallMode.ON_NEXT_SUSPEND,\n                minimumBackgroundDuration: 5\n            });\n    },\n\n    getScenarioName: function () {\n        return \"Sync Suspend Delay\";\n    }\n};\n"
  },
  {
    "path": "test/template/scenarios/updateDeviceReady.js",
    "content": "var CodePushWrapper = require(\"../codePushWrapper.js\");\n\nmodule.exports = {\n    startTest: function (testApp) {\n        testApp.readyAfterUpdate();\n    },\n\n    getScenarioName: function () {\n        return \"Bad Update\";\n    }\n};"
  },
  {
    "path": "test/template/scenarios/updateNARConditional.js",
    "content": "var CodePushWrapper = require(\"../codePushWrapper.js\");\nimport CodePush from \"react-native-code-push\";\n\nmodule.exports = {\n    startTest: function (testApp) {\n        testApp.readyAfterUpdate((responseBody) => {\n            if (responseBody !== \"SKIP_NOTIFY_APPLICATION_READY\") {\n                CodePush.notifyAppReady();\n                CodePushWrapper.checkAndInstall(testApp, undefined, undefined, CodePush.InstallMode.ON_NEXT_RESTART);\n            } else {\n                testApp.setStateAndSendMessage(\"Skipping notifyApplicationReady!\", \"SKIPPED_NOTIFY_APPLICATION_READY\");\n            }\n        });\n    },\n\n    getScenarioName: function () {\n        return \"Conditional Update\";\n    }\n};"
  },
  {
    "path": "test/template/scenarios/updateNotifyApplicationReady.js",
    "content": "var CodePushWrapper = require(\"../codePushWrapper.js\");\nimport CodePush from \"react-native-code-push\";\n\nmodule.exports = {\n    startTest: function (testApp) {\n        testApp.readyAfterUpdate();\n        CodePush.notifyAppReady();\n    },\n\n    getScenarioName: function () {\n        return \"Good Update\";\n    }\n};"
  },
  {
    "path": "test/template/scenarios/updateSync.js",
    "content": "var CodePushWrapper = require(\"../codePushWrapper.js\");\n\nmodule.exports = {\n    startTest: function (testApp) {\n        testApp.readyAfterUpdate();\n        CodePushWrapper.sync(testApp);\n    },\n\n    getScenarioName: function () {\n        return \"Good Update (w/ Sync)\";\n    }\n};"
  },
  {
    "path": "test/template/scenarios/updateSync2x.js",
    "content": "var CodePushWrapper = require(\"../codePushWrapper.js\");\n\nmodule.exports = {\n    startTest: function (testApp) {\n        testApp.readyAfterUpdate();\n        CodePushWrapper.sync(testApp);\n        CodePushWrapper.sync(testApp);\n    },\n\n    getScenarioName: function () {\n        return \"Good Update (w/ Sync 2x)\";\n    }\n};"
  },
  {
    "path": "test/test.ts",
    "content": "\"use strict\";\n\nimport assert = require(\"assert\");\nimport fs = require(\"fs\");\nimport mkdirp = require(\"mkdirp\");\nimport path = require(\"path\");\nimport slash = require(\"slash\");\n\nimport { Platform, PluginTestingFramework, ProjectManager, setupTestRunScenario, setupUpdateScenario, ServerUtil, TestBuilder, TestConfig, TestUtil } from \"code-push-plugin-testing-framework\";\n\nimport Q = require(\"q\");\n\nimport del = require(\"del\");\n\n//////////////////////////////////////////////////////////////////////////////////////////\n// Create the platforms to run the tests on.\n\ninterface RNPlatform {\n    /**\n     * Returns the name of the bundle to be created for this platform.\n     */\n    getBundleName(): string;\n\n    /**\n    * Returns whether or not this platform supports diffs.\n    */\n    isDiffsSupported(): boolean;\n\n    /**\n     * Returns the path to the binary of the given project on this platform.\n     */\n    getBinaryPath(projectDirectory: string): string;\n\n    /**\n     * Installs the platform on the given project.\n     */\n    installPlatform(projectDirectory: string): Q.Promise<void>;\n\n    /**\n     * Installs the binary of the given project on this platform.\n     */\n    installApp(projectDirectory: string): Q.Promise<void>;\n\n    /**\n     * Builds the binary of the project on this platform.\n     */\n    buildApp(projectDirectory: string): Q.Promise<void>;\n}\n\nclass RNAndroid extends Platform.Android implements RNPlatform {\n    constructor() {\n        super(new Platform.AndroidEmulatorManager());\n    }\n\n    /**\n     * Returns the name of the bundle to be created for this platform.\n     */\n    getBundleName(): string {\n        return \"index.android.bundle\";\n    }\n\n    /**\n     * Returns whether or not this platform supports diffs.\n     */\n    isDiffsSupported(): boolean {\n        return false;\n    }\n\n    /**\n     * Returns the path to the binary of the given project on this platform.\n     */\n    getBinaryPath(projectDirectory: string): string {\n        return path.join(projectDirectory, TestConfig.TestAppName, \"android\", \"app\", \"build\", \"outputs\", \"apk\", \"release\", \"app-release.apk\");\n    }\n\n    /**\n     * Installs the platform on the given project.\n     */\n    installPlatform(projectDirectory: string): Q.Promise<void> {\n        const innerprojectDirectory: string = path.join(projectDirectory, TestConfig.TestAppName);\n        const gradleContent: string = slash(path.join(innerprojectDirectory, \"node_modules\", \"react-native-code-push\", \"android\", \"codepush.gradle\"));\n\n        //// Set up gradle to build CodePush with the app\n        // Add CodePush to android/app/build.gradle\n        const buildGradle = path.join(innerprojectDirectory, \"android\", \"app\", \"build.gradle\");\n\n        TestUtil.replaceString(buildGradle,\n            \"apply from: file\\\\(\\\"../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle\\\"\\\\); applyNativeModulesAppBuildGradle\\\\(project\\\\)\",\n            \"apply from: file(\\\"../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle\\\"); applyNativeModulesAppBuildGradle(project)\\napply from: \\\"\" + gradleContent + \"\\\"\");\n\n        // Add CodePush to android/settings.gradle\n        const settingsGradle = path.join(innerprojectDirectory, \"android\", \"settings.gradle\");\n        TestUtil.replaceString(settingsGradle,\n            \"include ':app'\",\n            \"include ':app', ':react-native-code-push'\\nproject(':react-native-code-push').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-code-push/android/app')\");\n\n        //// Set the app version to 1.0.0 instead of 1.0\n        // Set the app version to 1.0.0 in android/app/build.gradle\n        TestUtil.replaceString(buildGradle, \"versionName \\\"1.0\\\"\", \"versionName \\\"1.0.0\\\"\");\n        // Set the app version to 1.0.0 in AndroidManifest.xml\n        TestUtil.replaceString(path.join(innerprojectDirectory, \"android\", \"app\", \"src\", \"main\", \"AndroidManifest.xml\"), \"android:versionName=\\\"1.0\\\"\", \"android:versionName=\\\"1.0.0\\\"\");\n\n        //// Replace the MainApplication.java with the correct server url and deployment key\n        const string = path.join(innerprojectDirectory, \"android\", \"app\", \"src\", \"main\", \"res\", \"values\", \"strings.xml\");\n        const AndroidManifest = path.join(innerprojectDirectory, \"android\", \"app\", \"src\", \"main\", \"AndroidManifest.xml\");\n        TestUtil.replaceString(string, TestUtil.SERVER_URL_PLACEHOLDER, this.getServerUrl());\n        TestUtil.replaceString(string, TestUtil.ANDROID_KEY_PLACEHOLDER, this.getDefaultDeploymentKey());\n        TestUtil.replaceString(AndroidManifest, \"android:allowBackup=\\\"false\\\"\", \"android:allowBackup=\\\"false\\\"\" + \"\\n\\t\" + \"android:usesCleartextTraffic=\\\"true\\\"\");\n\n\n        return Q<void>(null);\n    }\n\n    /**\n     * Installs the binary of the given project on this platform.\n     */\n    installApp(projectDirectory: string): Q.Promise<void> {\n        const androidDirectory: string = path.join(projectDirectory, TestConfig.TestAppName, \"android\");\n        return TestUtil.getProcessOutput(\"adb install -r \" + this.getBinaryPath(projectDirectory), { cwd: androidDirectory }).then(() => { return null; });\n    }\n\n    /** \n     * Build function of the test application, the command depends on the OS \n    */\n    buildFunction(androidDirectory: string): Q.Promise<void> {\n        const gradlewCommand = process.platform === \"darwin\" || process.platform === \"linux\" ? \"./gradlew\" : \"gradlew\";\n        return TestUtil.getProcessOutput(`${gradlewCommand} clean`, { noLogStdOut: true, cwd: androidDirectory })\n                .then(() => TestUtil.getProcessOutput(`${gradlewCommand} assembleRelease --daemon`, { noLogStdOut: true, cwd: androidDirectory }))\n                .then(() => { return null; });\n    }\n\n    /**\n     * Builds the binary of the project on this platform.\n     */\n    buildApp(projectDirectory: string): Q.Promise<void> {\n        // In order to run on Android without the package manager, we must create a release APK and then sign it with the debug certificate.\n        const androidDirectory: string = path.join(projectDirectory, TestConfig.TestAppName, \"android\");\n        // If the build fails for the first time, try  rebuild app again\n        try {\n            return this.buildFunction(androidDirectory);\n        } catch {\n            return this.buildFunction(androidDirectory);\n        }\n    }\n}\n\nclass RNIOS extends Platform.IOS implements RNPlatform {\n    constructor() {\n        super(new Platform.IOSEmulatorManager());\n    }\n\n    /**\n     * Returns the name of the bundle to be created for this platform.\n     */\n    getBundleName(): string {\n        return \"main.jsbundle\";\n    }\n\n    /**\n     * Returns whether or not this platform supports diffs.\n     */\n    isDiffsSupported(): boolean {\n        return true;\n    }\n\n    /**\n     * Returns the path to the binary of the given project on this platform.\n     */\n    getBinaryPath(projectDirectory: string): string {\n        return path.join(projectDirectory, TestConfig.TestAppName, \"ios\", \"build\", \"Build\", \"Products\", \"Release-iphonesimulator\", TestConfig.TestAppName + \".app\");\n    }\n\n    /**\n     * Installs the platform on the given project.\n     */\n    installPlatform(projectDirectory: string): Q.Promise<void> {\n        const iOSProject: string = path.join(projectDirectory, TestConfig.TestAppName, \"ios\");\n        const infoPlistPath: string = path.join(iOSProject, TestConfig.TestAppName, \"Info.plist\");\n        const appDelegatePath: string = path.join(iOSProject, TestConfig.TestAppName, \"AppDelegate.mm\");\n\n\n        // Install the Podfile\n        return TestUtil.getProcessOutput(\"pod install\", { cwd: iOSProject })\n            // Put the IOS deployment key in the Info.plist\n            .then(TestUtil.replaceString.bind(undefined, infoPlistPath,\n                \"</dict>\\n</plist>\",\n                \"<key>CodePushDeploymentKey</key>\\n\\t<string>\" + this.getDefaultDeploymentKey() + \"</string>\\n\\t<key>CodePushServerURL</key>\\n\\t<string>\" + this.getServerUrl() + \"</string>\\n\\t</dict>\\n</plist>\"))\n            // Set the app version to 1.0.0 instead of 1.0 in the Info.plist\n            .then(TestUtil.replaceString.bind(undefined, infoPlistPath, \"1.0\", \"1.0.0\"))\n            // Remove dependence of CFBundleShortVersionString from project.pbxproj\n            .then(TestUtil.replaceString.bind(undefined, infoPlistPath, \"\\\\$\\\\(MARKETING_VERSION\\\\)\", \"1.0.0\"))\n            // Fix the linker flag list in project.pbxproj (pod install adds an extra comma)\n            .then(TestUtil.replaceString.bind(undefined, path.join(iOSProject, TestConfig.TestAppName + \".xcodeproj\", \"project.pbxproj\"),\n                \"\\\"[$][(]inherited[)]\\\",\\\\s*[)];\", \"\\\"$(inherited)\\\"\\n\\t\\t\\t\\t);\"))\n            // Add the correct bundle identifier\n            .then(TestUtil.replaceString.bind(undefined, path.join(iOSProject, TestConfig.TestAppName + \".xcodeproj\", \"project.pbxproj\"),\n                \"PRODUCT_BUNDLE_IDENTIFIER = [^;]*\", \"PRODUCT_BUNDLE_IDENTIFIER = \\\"\" + TestConfig.TestNamespace + \"\\\"\"))\n            // Copy the AppDelegate.mm to the project\n            .then(TestUtil.copyFile.bind(undefined,\n                path.join(TestConfig.templatePath, \"ios\", TestConfig.TestAppName, \"AppDelegate.mm\"),\n                appDelegatePath, true))\n            .then<void>(TestUtil.replaceString.bind(undefined, appDelegatePath, TestUtil.CODE_PUSH_TEST_APP_NAME_PLACEHOLDER, TestConfig.TestAppName));\n    }\n\n    /**\n     * Installs the binary of the given project on this platform.\n     */\n    installApp(projectDirectory: string): Q.Promise<void> {\n        return TestUtil.getProcessOutput(\"xcrun simctl install booted \" + this.getBinaryPath(projectDirectory)).then(() => { return null; });\n    }\n\n    /**\n     * Maps project directories to whether or not they have built an IOS project before.\n     * \n     * The first build of an IOS project does not always succeed, so we always try again when it fails.\n     *\n     *  EXAMPLE:\n     *  {\n     *      \"TEMP_DIR/test-run\": true,\n     *      \"TEMP_DIR/updates\": false\n     *  }\n     */\n    private static iosFirstBuild: any = {};\n\n    /**\n     * Builds the binary of the project on this platform.\n     */\n    buildApp(projectDirectory: string): Q.Promise<void> {\n        const iOSProject: string = path.join(projectDirectory, TestConfig.TestAppName, \"ios\");\n\n        return this.getEmulatorManager().getTargetEmulator()\n            .then((targetEmulator: string) => {\n                return TestUtil.getProcessOutput(\"xcodebuild -workspace \" + path.join(iOSProject, TestConfig.TestAppName) + \".xcworkspace -scheme \" + TestConfig.TestAppName +\n                    \" -configuration Release -destination \\\"platform=iOS Simulator,id=\" + targetEmulator + \"\\\" -derivedDataPath build EXCLUDED_ARCHS=arm64\", { cwd: iOSProject, timeout: 30 * 60 * 1000, maxBuffer: 1024 * 1024 * 5000, noLogStdOut: true });\n            })\n            .then<void>(\n                () => { return null; },\n                (error: any) => {\n                    console.info(error);\n                    // The first time an iOS project is built, it fails because it does not finish building libReact.a before it builds the test app.\n                    // Simply build again to fix the issue.\n                    if (!RNIOS.iosFirstBuild[projectDirectory]) {\n                        const iosBuildFolder = path.join(iOSProject, \"build\");\n                        if (fs.existsSync(iosBuildFolder)) {\n                            del.sync([iosBuildFolder], { force: true });\n                        }\n                        RNIOS.iosFirstBuild[projectDirectory] = true;\n                        return this.buildApp(projectDirectory);\n                    }\n                    return null;\n                });\n    }\n}\n\nconst supportedTargetPlatforms: Platform.IPlatform[] = [new RNAndroid(), new RNIOS()];\n\n//////////////////////////////////////////////////////////////////////////////////////////\n// Create the ProjectManager to use for the tests.\n\nclass RNProjectManager extends ProjectManager {\n    /**\n     * Returns the name of the plugin being tested, ie Cordova or React-Native\n     */\n    public getPluginName(): string {\n        return \"React-Native\";\n    }\n\n    /**\n     * Copies over the template files into the specified project, overwriting existing files.\n     */\n    public copyTemplate(templatePath: string, projectDirectory: string): Q.Promise<void> {\n        function copyDirectoryRecursively(directoryFrom: string, directoryTo: string): Q.Promise<void> {\n            const promises: Q.Promise<void>[] = [];\n\n            fs.readdirSync(directoryFrom).forEach(file => {\n                let fileStats: fs.Stats;\n                const fileInFrom: string = path.join(directoryFrom, file);\n                const fileInTo: string = path.join(directoryTo, file);\n\n                try { fileStats = fs.statSync(fileInFrom); } catch (e) { /* fs.statSync throws if the file doesn't exist. */ }\n\n                // If it is a file, just copy directly\n                if (fileStats && fileStats.isFile()) {\n                    promises.push(TestUtil.copyFile(fileInFrom, fileInTo, true));\n                }\n                else {\n                    // If it is a directory, create the directory if it doesn't exist on the target and then copy over\n                    if (!fs.existsSync(fileInTo)) mkdirp.sync(fileInTo);\n                    promises.push(copyDirectoryRecursively(fileInFrom, fileInTo));\n                }\n            });\n\n            // Chain promise so that it maintains Q.Promise<void> type instead of Q.Promise<void[]>\n            return Q.all<void>(promises).then(() => { return null; });\n        }\n\n        return copyDirectoryRecursively(templatePath, path.join(projectDirectory, TestConfig.TestAppName));\n    }\n\n    /**\n     * Creates a new test application at the specified path, and configures it\n     * with the given server URL, android and ios deployment keys.\n     */\n    public setupProject(projectDirectory: string, templatePath: string, appName: string, appNamespace: string, version?: string): Q.Promise<void> {\n        if (fs.existsSync(projectDirectory)) {\n            del.sync([projectDirectory], { force: true });\n        }\n        mkdirp.sync(projectDirectory);\n\n        return TestUtil.getProcessOutput(\"npx react-native init \" + appName + \" --version 0.71.3 --install-pods\", { cwd: projectDirectory, timeout: 30 * 60 * 1000 })\n            .then((e) => { console.log(`\"npx react-native init ${appName}\" success. cwd=${projectDirectory}`); return e; })\n            .then(this.copyTemplate.bind(this, templatePath, projectDirectory))\n            .then<void>(TestUtil.getProcessOutput.bind(undefined, TestConfig.thisPluginInstallString, { cwd: path.join(projectDirectory, TestConfig.TestAppName) }))\n            .then(() => { return null; })\n            .catch((error) => {\n                console.log(`\"npx react-native init ${appName} failed\". cwd=${projectDirectory}`, error);\n                throw new Error(error);\n            });\n    }\n\n    /** JSON mapping project directories to the current scenario\n     *\n     *  EXAMPLE:\n     *  {\n     *      \"TEMP_DIR/test-run\": \"scenarios/scenarioCheckForUpdate.js\",\n     *      \"TEMP_DIR/updates\": \"scenarios/updateSync.js\"\n     *  }\n     */\n    private static currentScenario: any = {};\n\n    /** JSON mapping project directories to whether or not they've built the current scenario\n     *\n     *  EXAMPLE:\n     *  {\n     *      \"TEMP_DIR/test-run\": \"true\",\n     *      \"TEMP_DIR/updates\": \"false\"\n     *  }\n     */\n    private static currentScenarioHasBuilt: any = {};\n\n    /**\n     * Sets up the scenario for a test in an already existing project.\n     */\n    public setupScenario(projectDirectory: string, appId: string, templatePath: string, jsPath: string, targetPlatform: Platform.IPlatform, version?: string): Q.Promise<void> {\n        // We don't need to anything if it is the current scenario.\n        if (RNProjectManager.currentScenario[projectDirectory] === jsPath) return Q<void>(null);\n        RNProjectManager.currentScenario[projectDirectory] = jsPath;\n        RNProjectManager.currentScenarioHasBuilt[projectDirectory] = false;\n\n        const indexHtml = \"index.js\";\n        const templateIndexPath = path.join(templatePath, indexHtml);\n        const destinationIndexPath = path.join(projectDirectory, TestConfig.TestAppName, indexHtml);\n\n        const scenarioJs = \"scenarios/\" + jsPath;\n\n        console.log(\"Setting up scenario \" + jsPath + \" in \" + projectDirectory);\n\n        // Copy index html file and replace\n        return TestUtil.copyFile(templateIndexPath, destinationIndexPath, true)\n            .then<void>(TestUtil.replaceString.bind(undefined, destinationIndexPath, TestUtil.CODE_PUSH_TEST_APP_NAME_PLACEHOLDER, TestConfig.TestAppName))\n            .then<void>(TestUtil.replaceString.bind(undefined, destinationIndexPath, TestUtil.SERVER_URL_PLACEHOLDER, targetPlatform.getServerUrl()))\n            .then<void>(TestUtil.replaceString.bind(undefined, destinationIndexPath, TestUtil.INDEX_JS_PLACEHOLDER, scenarioJs))\n            .then<void>(TestUtil.replaceString.bind(undefined, destinationIndexPath, TestUtil.CODE_PUSH_APP_VERSION_PLACEHOLDER, version));\n    }\n\n    /**\n     * Creates a CodePush update package zip for a project.\n     */\n    public createUpdateArchive(projectDirectory: string, targetPlatform: Platform.IPlatform, isDiff?: boolean): Q.Promise<string> {\n        const bundleFolder: string = path.join(projectDirectory, TestConfig.TestAppName, \"CodePush/\");\n        const bundleName: string = (<RNPlatform><any>targetPlatform).getBundleName();\n        const bundlePath: string = path.join(bundleFolder, bundleName);\n        const deferred = Q.defer<string>();\n        fs.exists(bundleFolder, (exists) => {\n            if (exists) del.sync([bundleFolder], { force: true });\n            mkdirp.sync(bundleFolder);\n            deferred.resolve(undefined);\n        });\n        return deferred.promise\n            .then(TestUtil.getProcessOutput.bind(undefined, \"npx react-native bundle --entry-file index.js --platform \" + targetPlatform.getName() + \" --bundle-output \" + bundlePath + \" --assets-dest \" + bundleFolder + \" --dev false\",\n                { cwd: path.join(projectDirectory, TestConfig.TestAppName) }))\n            .then<string>(TestUtil.archiveFolder.bind(undefined, bundleFolder, \"\", path.join(projectDirectory, TestConfig.TestAppName, \"update.zip\"), isDiff));\n    }\n\n    /** JSON file containing the platforms the plugin is currently installed for.\n     *  Keys must match targetPlatform.getName()!\n     *\n     *  EXAMPLE:\n     *  {\n     *      \"android\": true,\n     *      \"ios\": false\n     *  }\n     */\n    private static platformsJSON: string = \"platforms.json\";\n\n    /**\n     * Prepares a specific platform for tests.\n     */\n    public preparePlatform(projectDirectory: string, targetPlatform: Platform.IPlatform): Q.Promise<void> {\n        const deferred = Q.defer<string>();\n\n        const platformsJSONPath = path.join(projectDirectory, RNProjectManager.platformsJSON);\n\n        // We create a JSON file in the project folder to contain the installed platforms.\n        // Check the file to see if the plugin for this platform has been installed and update the file appropriately.\n        fs.exists(platformsJSONPath, (exists) => {\n            if (!exists) {\n                fs.writeFileSync(platformsJSONPath, \"{}\");\n            }\n\n            const platformJSON = eval(\"(\" + fs.readFileSync(platformsJSONPath, \"utf8\") + \")\");\n            if (platformJSON[targetPlatform.getName()] === true) deferred.reject(\"Platform \" + targetPlatform.getName() + \" is already installed in \" + projectDirectory + \"!\");\n            else {\n                platformJSON[targetPlatform.getName()] = true;\n                fs.writeFileSync(platformsJSONPath, JSON.stringify(platformJSON));\n                deferred.resolve(undefined);\n            }\n        });\n\n        return deferred.promise\n            .then<void>(() => {\n                return (<RNPlatform><any>targetPlatform).installPlatform(projectDirectory);\n            }, (error: any) => { /* The platform is already installed! */ console.log(error); return null; });\n    }\n\n    /**\n     * Cleans up a specific platform after tests.\n     */\n    public cleanupAfterPlatform(projectDirectory: string, targetPlatform: Platform.IPlatform): Q.Promise<void> {\n        // Can't uninstall from command line, so noop.\n        return Q<void>(null);\n    }\n\n    /**\n     * Runs the test app on the given target / platform.\n     */\n    public runApplication(projectDirectory: string, targetPlatform: Platform.IPlatform): Q.Promise<void> {\n        console.log(\"Running project in \" + projectDirectory + \" on \" + targetPlatform.getName());\n\n        return Q<void>(null)\n            .then(() => {\n                // Build if this scenario has not yet been built.\n                if (!RNProjectManager.currentScenarioHasBuilt[projectDirectory]) {\n                    RNProjectManager.currentScenarioHasBuilt[projectDirectory] = true;\n                    return (<RNPlatform><any>targetPlatform).buildApp(projectDirectory);\n                }\n            })\n            .then(() => {\n                // Uninstall the app so that the installation is clean and no files are left around for each test.\n                return targetPlatform.getEmulatorManager().uninstallApplication(TestConfig.TestNamespace);\n            })\n            .then(() => {\n                // Install and launch the app.\n                return (<RNPlatform><any>targetPlatform).installApp(projectDirectory)\n                    .then<void>(targetPlatform.getEmulatorManager().launchInstalledApplication.bind(undefined, TestConfig.TestNamespace));\n            });\n    }\n}\n\n//////////////////////////////////////////////////////////////////////////////////////////\n// Scenarios used in the tests.\n\nconst ScenarioCheckForUpdatePath = \"scenarioCheckForUpdate.js\";\nconst ScenarioCheckForUpdateCustomKey = \"scenarioCheckForUpdateCustomKey.js\";\nconst ScenarioDisallowRestartImmediate = \"scenarioDisallowRestartImmediate.js\";\nconst ScenarioDisallowRestartOnResume = \"scenarioDisallowRestartOnResume.js\";\nconst ScenarioDisallowRestartOnSuspend = \"scenarioDisallowRestartOnSuspend.js\";\nconst ScenarioDownloadUpdate = \"scenarioDownloadUpdate.js\";\nconst ScenarioInstall = \"scenarioInstall.js\";\nconst ScenarioInstallOnResumeWithRevert = \"scenarioInstallOnResumeWithRevert.js\";\nconst ScenarioInstallOnSuspendWithRevert = \"scenarioInstallOnSuspendWithRevert.js\";\nconst ScenarioInstallOnRestartWithRevert = \"scenarioInstallOnRestartWithRevert.js\";\nconst ScenarioInstallWithRevert = \"scenarioInstallWithRevert.js\";\nconst ScenarioInstallRestart2x = \"scenarioInstallRestart2x.js\";\nconst ScenarioSync1x = \"scenarioSync.js\";\nconst ScenarioSyncResume = \"scenarioSyncResume.js\";\nconst ScenarioSyncSuspend = \"scenarioSyncSuspend.js\";\nconst ScenarioSyncResumeDelay = \"scenarioSyncResumeDelay.js\";\nconst ScenarioSyncRestartDelay = \"scenarioSyncRestartDelay.js\";\nconst ScenarioSyncSuspendDelay = \"scenarioSyncSuspendDelay.js\";\nconst ScenarioSync2x = \"scenarioSync2x.js\";\nconst ScenarioRestart = \"scenarioRestart.js\";\nconst ScenarioRestart2x = \"scenarioRestart2x.js\";\nconst ScenarioSyncMandatoryDefault = \"scenarioSyncMandatoryDefault.js\";\nconst ScenarioSyncMandatoryResume = \"scenarioSyncMandatoryResume.js\";\nconst ScenarioSyncMandatoryRestart = \"scenarioSyncMandatoryRestart.js\";\nconst ScenarioSyncMandatorySuspend = \"scenarioSyncMandatorySuspend.js\";\n\nconst UpdateDeviceReady = \"updateDeviceReady.js\";\nconst UpdateNotifyApplicationReady = \"updateNotifyApplicationReady.js\";\nconst UpdateSync = \"updateSync.js\";\nconst UpdateSync2x = \"updateSync2x.js\";\nconst UpdateNotifyApplicationReadyConditional = \"updateNARConditional.js\";\n\n//////////////////////////////////////////////////////////////////////////////////////////\n// Initialize the tests.\n\nPluginTestingFramework.initializeTests(new RNProjectManager(), supportedTargetPlatforms,\n    (projectManager: ProjectManager, targetPlatform: Platform.IPlatform) => {\n        TestBuilder.describe(\"#window.codePush.checkForUpdate\",\n            () => {\n                TestBuilder.it(\"window.codePush.checkForUpdate.noUpdate\", false,\n                    (done: Mocha.Done) => {\n                        const noUpdateResponse = ServerUtil.createDefaultResponse();\n                        noUpdateResponse.is_available = false;\n                        noUpdateResponse.target_binary_range = \"0.0.1\";\n                        ServerUtil.updateResponse = { update_info: noUpdateResponse };\n\n                        ServerUtil.testMessageCallback = (requestBody: any) => {\n                            try {\n                                assert.strictEqual(requestBody.message, ServerUtil.TestMessage.CHECK_UP_TO_DATE);\n                                done();\n                            } catch (e) {\n                                done(e);\n                            }\n                        };\n\n                        projectManager.runApplication(TestConfig.testRunDirectory, targetPlatform);\n                    });\n\n                TestBuilder.it(\"window.codePush.checkForUpdate.sendsBinaryHash\", false,\n                    (done: Mocha.Done) => {\n                        if (!(<RNPlatform><any>targetPlatform).isDiffsSupported()) {\n                            console.log(targetPlatform.getName() + \" does not send a binary hash!\");\n                            done();\n                            return;\n                        }\n\n                        const noUpdateResponse = ServerUtil.createDefaultResponse();\n                        noUpdateResponse.is_available = false;\n                        noUpdateResponse.target_binary_range = \"0.0.1\";\n\n                        ServerUtil.updateCheckCallback = (request: any) => {\n                            try {\n                                assert(request.query.package_hash);\n                            } catch (e) {\n                                done(e);\n                            }\n                        };\n\n                        ServerUtil.updateResponse = { update_info: noUpdateResponse };\n\n                        ServerUtil.testMessageCallback = (requestBody: any) => {\n                            try {\n                                assert.strictEqual(requestBody.message, ServerUtil.TestMessage.CHECK_UP_TO_DATE);\n                                done();\n                            } catch (e) {\n                                done(e);\n                            }\n                        };\n\n                        projectManager.runApplication(TestConfig.testRunDirectory, targetPlatform);\n                    });\n\n                TestBuilder.it(\"window.codePush.checkForUpdate.noUpdate.updateAppVersion\", false,\n                    (done: Mocha.Done) => {\n                        const updateAppVersionResponse = ServerUtil.createDefaultResponse();\n                        updateAppVersionResponse.is_available = true;\n                        updateAppVersionResponse.target_binary_range = \"2.0.0\";\n                        updateAppVersionResponse.update_app_version = true;\n\n                        ServerUtil.updateResponse = { update_info: updateAppVersionResponse };\n\n                        ServerUtil.testMessageCallback = (requestBody: any) => {\n                            try {\n                                assert.strictEqual(requestBody.message, ServerUtil.TestMessage.CHECK_UP_TO_DATE);\n                                done();\n                            } catch (e) {\n                                done(e);\n                            }\n                        };\n\n                        projectManager.runApplication(TestConfig.testRunDirectory, targetPlatform);\n                    });\n\n                TestBuilder.it(\"window.codePush.checkForUpdate.update\", true,\n                    (done: Mocha.Done) => {\n                        const updateResponse = ServerUtil.createUpdateResponse();\n                        ServerUtil.updateResponse = { update_info: updateResponse };\n\n                        ServerUtil.testMessageCallback = (requestBody: any) => {\n                            try {\n                                assert.strictEqual(requestBody.message, ServerUtil.TestMessage.CHECK_UPDATE_AVAILABLE);\n                                assert.notStrictEqual(requestBody.args[0], null);\n                                const remotePackage: any = requestBody.args[0];\n                                assert.strictEqual(remotePackage.downloadUrl, updateResponse.download_url);\n                                assert.strictEqual(remotePackage.isMandatory, updateResponse.is_mandatory);\n                                assert.strictEqual(remotePackage.label, updateResponse.label);\n                                assert.strictEqual(remotePackage.packageHash, updateResponse.package_hash);\n                                assert.strictEqual(remotePackage.packageSize, updateResponse.package_size);\n                                assert.strictEqual(remotePackage.deploymentKey, targetPlatform.getDefaultDeploymentKey());\n                                done();\n                            } catch (e) {\n                                done(e);\n                            }\n                        };\n\n                        ServerUtil.updateCheckCallback = (request: any) => {\n                            try {\n                                assert.notStrictEqual(null, request);\n                                assert.strictEqual(request.query.deployment_key, targetPlatform.getDefaultDeploymentKey());\n                            } catch (e) {\n                                done(e);\n                            }\n                        };\n\n                        projectManager.runApplication(TestConfig.testRunDirectory, targetPlatform);\n                    });\n\n                TestBuilder.it(\"window.codePush.checkForUpdate.error\", false,\n                    (done: Mocha.Done) => {\n                        ServerUtil.updateResponse = \"invalid {{ json\";\n\n                        ServerUtil.testMessageCallback = (requestBody: any) => {\n                            try {\n                                assert.strictEqual(requestBody.message, ServerUtil.TestMessage.CHECK_ERROR);\n                                done();\n                            } catch (e) {\n                                done(e);\n                            }\n                        };\n\n                        projectManager.runApplication(TestConfig.testRunDirectory, targetPlatform);\n                    });\n            }, ScenarioCheckForUpdatePath);\n\n        TestBuilder.describe(\"#window.codePush.checkForUpdate.customKey\",\n            () => {\n                TestBuilder.it(\"window.codePush.checkForUpdate.customKey.update\", false,\n                    (done: Mocha.Done) => {\n                        const updateResponse = ServerUtil.createUpdateResponse();\n                        ServerUtil.updateResponse = { update_info: updateResponse };\n\n                        ServerUtil.updateCheckCallback = (request: any) => {\n                            try {\n                                assert.notStrictEqual(null, request);\n                                assert.strictEqual(request.query.deployment_key, \"CUSTOM-DEPLOYMENT-KEY\");\n                                done();\n                            } catch (e) {\n                                done(e);\n                            }\n                        };\n\n                        projectManager.runApplication(TestConfig.testRunDirectory, targetPlatform);\n                    });\n            }, ScenarioCheckForUpdateCustomKey);\n\n        TestBuilder.describe(\"#remotePackage.download\",\n            () => {\n                TestBuilder.it(\"remotePackage.download.success\", false,\n                    (done: Mocha.Done) => {\n                        ServerUtil.updateResponse = { update_info: ServerUtil.createUpdateResponse(false, targetPlatform) };\n\n                        /* pass the path to any file for download (here, index.js) to make sure the download completed callback is invoked */\n                        ServerUtil.updatePackagePath = path.join(TestConfig.templatePath, \"index.js\");\n\n                        projectManager.runApplication(TestConfig.testRunDirectory, targetPlatform);\n\n                        ServerUtil.expectTestMessages([\n                            ServerUtil.TestMessage.CHECK_UPDATE_AVAILABLE,\n                            ServerUtil.TestMessage.DOWNLOAD_SUCCEEDED])\n                            .then(() => { done(); }, (e) => { done(e); });\n                    });\n\n                TestBuilder.it(\"remotePackage.download.error\", false,\n                    (done: Mocha.Done) => {\n                        ServerUtil.updateResponse = { update_info: ServerUtil.createUpdateResponse(false, targetPlatform) };\n\n                        /* pass an invalid update url */\n                        ServerUtil.updateResponse.update_info.download_url = \"http://invalid_url\";\n\n                        projectManager.runApplication(TestConfig.testRunDirectory, targetPlatform);\n\n                        ServerUtil.expectTestMessages([\n                            ServerUtil.TestMessage.CHECK_UPDATE_AVAILABLE,\n                            ServerUtil.TestMessage.DOWNLOAD_ERROR])\n                            .then(() => { done(); }, (e) => { done(e); });\n                    });\n            }, ScenarioDownloadUpdate);\n\n        TestBuilder.describe(\"#localPackage.install\",\n            () => {\n                // // CHANGE THIS TEST CASE, accepts both a jsbundle and a zip\n                // TestBuilder.it(\"localPackage.install.unzip.error\",\n                //     (done: Mocha.Done) => {\n                //         ServerUtil.updateResponse = { update_info: ServerUtil.createUpdateResponse(false, targetPlatform) };\n\n                //         /* pass an invalid zip file, here, index.js */\n                //         ServerUtil.updatePackagePath = path.join(TestConfig.templatePath, \"index.js\");\n\n                //         var deferred = Q.defer<void>();\n                //         deferred.promise.then(() => { done(); }, (e) => { done(e); });\n\n                //         ServerUtil.testMessageCallback = PluginTestingFramework.verifyMessages([\n                //             ServerUtil.TestMessage.CHECK_UPDATE_AVAILABLE,\n                //             ServerUtil.TestMessage.DOWNLOAD_SUCCEEDED,\n                //             ServerUtil.TestMessage.INSTALL_ERROR], deferred);\n\n                //         projectManager.runApplication(TestConfig.testRunDirectory, targetPlatform);\n                //     }, false),\n\n                TestBuilder.it(\"localPackage.install.handlesDiff.againstBinary\", false,\n                    (done: Mocha.Done) => {\n                        ServerUtil.updateResponse = { update_info: ServerUtil.createUpdateResponse(false, targetPlatform) };\n\n                        /* create an update */\n                        setupUpdateScenario(projectManager, targetPlatform, UpdateNotifyApplicationReady, \"Diff Update 1\")\n                            .then<void>((updatePath: string) => {\n                                ServerUtil.updatePackagePath = updatePath;\n                                projectManager.runApplication(TestConfig.testRunDirectory, targetPlatform);\n                                return ServerUtil.expectTestMessages([\n                                    ServerUtil.TestMessage.CHECK_UPDATE_AVAILABLE,\n                                    ServerUtil.TestMessage.DOWNLOAD_SUCCEEDED,\n                                    ServerUtil.TestMessage.DEVICE_READY_AFTER_UPDATE]);\n                            })\n                            .then<void>(() => {\n                                /* run the app again to ensure it was not reverted */\n                                targetPlatform.getEmulatorManager().restartApplication(TestConfig.TestNamespace);\n                                return ServerUtil.expectTestMessages([\n                                    ServerUtil.TestMessage.DEVICE_READY_AFTER_UPDATE]);\n                            })\n                            .done(() => { done(); }, (e) => { done(e); });\n                    });\n\n                TestBuilder.it(\"localPackage.install.immediately\", false,\n                    (done: Mocha.Done) => {\n                        ServerUtil.updateResponse = { update_info: ServerUtil.createUpdateResponse(false, targetPlatform) };\n\n                        /* create an update */\n                        setupUpdateScenario(projectManager, targetPlatform, UpdateNotifyApplicationReady, \"Update 1\")\n                            .then<void>((updatePath: string) => {\n                                ServerUtil.updatePackagePath = updatePath;\n                                projectManager.runApplication(TestConfig.testRunDirectory, targetPlatform);\n                                return ServerUtil.expectTestMessages([\n                                    ServerUtil.TestMessage.CHECK_UPDATE_AVAILABLE,\n                                    ServerUtil.TestMessage.DOWNLOAD_SUCCEEDED,\n                                    ServerUtil.TestMessage.DEVICE_READY_AFTER_UPDATE]);\n                            })\n                            .then<void>(() => {\n                                /* run the app again to ensure it was not reverted */\n                                targetPlatform.getEmulatorManager().restartApplication(TestConfig.TestNamespace);\n                                return ServerUtil.expectTestMessages([\n                                    ServerUtil.TestMessage.DEVICE_READY_AFTER_UPDATE]);\n                            })\n                            .done(() => { done(); }, (e) => { done(e); });\n                    });\n            }, ScenarioInstall);\n\n        TestBuilder.describe(\"#localPackage.install.revert\",\n            () => {\n                TestBuilder.it(\"localPackage.install.revert.dorevert\", false,\n                    (done: Mocha.Done) => {\n                        ServerUtil.updateResponse = { update_info: ServerUtil.createUpdateResponse(false, targetPlatform) };\n\n                        /* create an update */\n                        setupUpdateScenario(projectManager, targetPlatform, UpdateDeviceReady, \"Update 1 (bad update)\")\n                            .then<void>((updatePath: string) => {\n                                ServerUtil.updatePackagePath = updatePath;\n                                projectManager.runApplication(TestConfig.testRunDirectory, targetPlatform);\n                                return ServerUtil.expectTestMessages([\n                                    ServerUtil.TestMessage.CHECK_UPDATE_AVAILABLE,\n                                    ServerUtil.TestMessage.DOWNLOAD_SUCCEEDED,\n                                    ServerUtil.TestMessage.DEVICE_READY_AFTER_UPDATE]);\n                            })\n                            .then<void>(() => {\n                                /* restart the app to ensure it was reverted and send it another update */\n                                ServerUtil.updateResponse = { update_info: ServerUtil.createUpdateResponse(false, targetPlatform) };\n                                targetPlatform.getEmulatorManager().restartApplication(TestConfig.TestNamespace);\n                                return ServerUtil.expectTestMessages([\n                                    ServerUtil.TestMessage.CHECK_UPDATE_AVAILABLE,\n                                    ServerUtil.TestMessage.DOWNLOAD_SUCCEEDED,\n                                    ServerUtil.TestMessage.DEVICE_READY_AFTER_UPDATE]);\n                            })\n                            .then<void>(() => {\n                                /* restart the app again to ensure it was reverted again and send the same update and expect it to reject it */\n                                targetPlatform.getEmulatorManager().restartApplication(TestConfig.TestNamespace);\n                                return ServerUtil.expectTestMessages([ServerUtil.TestMessage.UPDATE_FAILED_PREVIOUSLY]);\n                            })\n                            .done(() => { done(); }, (e) => { done(e); });\n                    });\n\n                TestBuilder.it(\"localPackage.install.revert.norevert\", false,\n                    (done: Mocha.Done) => {\n                        ServerUtil.updateResponse = { update_info: ServerUtil.createUpdateResponse(false, targetPlatform) };\n\n                        /* create an update */\n                        setupUpdateScenario(projectManager, targetPlatform, UpdateNotifyApplicationReady, \"Update 1 (good update)\")\n                            .then<void>((updatePath: string) => {\n                                ServerUtil.updatePackagePath = updatePath;\n                                projectManager.runApplication(TestConfig.testRunDirectory, targetPlatform);\n                                return ServerUtil.expectTestMessages([\n                                    ServerUtil.TestMessage.CHECK_UPDATE_AVAILABLE,\n                                    ServerUtil.TestMessage.DOWNLOAD_SUCCEEDED,\n                                    ServerUtil.TestMessage.DEVICE_READY_AFTER_UPDATE]);\n                            })\n                            .then<void>(() => {\n                                /* run the app again to ensure it was not reverted */\n                                targetPlatform.getEmulatorManager().restartApplication(TestConfig.TestNamespace);\n                                return ServerUtil.expectTestMessages([ServerUtil.TestMessage.DEVICE_READY_AFTER_UPDATE]);\n                            })\n                            .done(() => { done(); }, (e) => { done(e); });\n                    });\n            }, ScenarioInstallWithRevert);\n\n        TestBuilder.describe(\"#localPackage.installOnNextResume\",\n            () => {\n                TestBuilder.it(\"localPackage.installOnNextResume.dorevert\", true,\n                    (done: Mocha.Done) => {\n                        ServerUtil.updateResponse = { update_info: ServerUtil.createUpdateResponse(false, targetPlatform) };\n\n                        setupUpdateScenario(projectManager, targetPlatform, UpdateDeviceReady, \"Update 1\")\n                            .then<void>((updatePath: string) => {\n                                ServerUtil.updatePackagePath = updatePath;\n                                projectManager.runApplication(TestConfig.testRunDirectory, targetPlatform);\n                                return ServerUtil.expectTestMessages([\n                                    ServerUtil.TestMessage.CHECK_UPDATE_AVAILABLE,\n                                    ServerUtil.TestMessage.DOWNLOAD_SUCCEEDED,\n                                    ServerUtil.TestMessage.UPDATE_INSTALLED]);\n                            })\n                            .then<void>(() => {\n                                /* resume the application */\n                                targetPlatform.getEmulatorManager().resumeApplication(TestConfig.TestNamespace);\n                                return ServerUtil.expectTestMessages([ServerUtil.TestMessage.DEVICE_READY_AFTER_UPDATE]);\n                            })\n                            .then<void>(() => {\n                                /* restart to revert it */\n                                targetPlatform.getEmulatorManager().restartApplication(TestConfig.TestNamespace);\n                                return ServerUtil.expectTestMessages([ServerUtil.TestMessage.UPDATE_FAILED_PREVIOUSLY]);\n                            })\n                            .done(() => { done(); }, (e) => { done(e); });\n                    });\n\n                TestBuilder.it(\"localPackage.installOnNextResume.norevert\", false,\n                    (done: Mocha.Done) => {\n                        ServerUtil.updateResponse = { update_info: ServerUtil.createUpdateResponse(false, targetPlatform) };\n\n                        /* create an update */\n                        setupUpdateScenario(projectManager, targetPlatform, UpdateNotifyApplicationReady, \"Update 1 (good update)\")\n                            .then<void>((updatePath: string) => {\n                                ServerUtil.updatePackagePath = updatePath;\n                                projectManager.runApplication(TestConfig.testRunDirectory, targetPlatform);\n                                return ServerUtil.expectTestMessages([\n                                    ServerUtil.TestMessage.CHECK_UPDATE_AVAILABLE,\n                                    ServerUtil.TestMessage.DOWNLOAD_SUCCEEDED,\n                                    ServerUtil.TestMessage.UPDATE_INSTALLED]);\n                            })\n                            .then<void>(() => {\n                                /* resume the application */\n                                targetPlatform.getEmulatorManager().resumeApplication(TestConfig.TestNamespace);\n                                return ServerUtil.expectTestMessages([ServerUtil.TestMessage.DEVICE_READY_AFTER_UPDATE]);\n                            })\n                            .then<void>(() => {\n                                /* restart to make sure it did not revert */\n                                targetPlatform.getEmulatorManager().restartApplication(TestConfig.TestNamespace);\n                                return ServerUtil.expectTestMessages([ServerUtil.TestMessage.DEVICE_READY_AFTER_UPDATE]);\n                            })\n                            .done(() => { done(); }, (e) => { done(e); });\n                    });\n            }, ScenarioInstallOnResumeWithRevert);\n\n        TestBuilder.describe(\"#localPackage.installOnNextSuspend\",\n            () => {\n                TestBuilder.it(\"localPackage.installOnNextSuspend.dorevert\", true,\n                    (done: Mocha.Done) => {\n                        ServerUtil.updateResponse = { update_info: ServerUtil.createUpdateResponse(false, targetPlatform) };\n\n                        setupUpdateScenario(projectManager, targetPlatform, UpdateDeviceReady, \"Update 1\")\n                            .then<void>((updatePath: string) => {\n                                ServerUtil.updatePackagePath = updatePath;\n                                projectManager.runApplication(TestConfig.testRunDirectory, targetPlatform);\n                                return ServerUtil.expectTestMessages([\n                                    ServerUtil.TestMessage.CHECK_UPDATE_AVAILABLE,\n                                    ServerUtil.TestMessage.DOWNLOAD_SUCCEEDED,\n                                    ServerUtil.TestMessage.UPDATE_INSTALLED]);\n                            })\n                            .then<void>(() => {\n                                /* resume the application */\n                                targetPlatform.getEmulatorManager().resumeApplication(TestConfig.TestNamespace);\n                                return ServerUtil.expectTestMessages([ServerUtil.TestMessage.DEVICE_READY_AFTER_UPDATE]);\n                            })\n                            .then<void>(() => {\n                                /* restart to revert it */\n                                targetPlatform.getEmulatorManager().restartApplication(TestConfig.TestNamespace);\n                                return ServerUtil.expectTestMessages([ServerUtil.TestMessage.UPDATE_FAILED_PREVIOUSLY]);\n                            })\n                            .done(() => { done(); }, (e) => { done(e); });\n                    });\n\n                TestBuilder.it(\"localPackage.installOnNextSuspend.norevert\", false,\n                    (done: Mocha.Done) => {\n                        ServerUtil.updateResponse = { update_info: ServerUtil.createUpdateResponse(false, targetPlatform) };\n\n                        /* create an update */\n                        setupUpdateScenario(projectManager, targetPlatform, UpdateNotifyApplicationReady, \"Update 1 (good update)\")\n                            .then<void>((updatePath: string) => {\n                                ServerUtil.updatePackagePath = updatePath;\n                                projectManager.runApplication(TestConfig.testRunDirectory, targetPlatform);\n                                return ServerUtil.expectTestMessages([\n                                    ServerUtil.TestMessage.CHECK_UPDATE_AVAILABLE,\n                                    ServerUtil.TestMessage.DOWNLOAD_SUCCEEDED,\n                                    ServerUtil.TestMessage.UPDATE_INSTALLED]);\n                            })\n                            .then<void>(() => {\n                                /* resume the application */\n                                targetPlatform.getEmulatorManager().resumeApplication(TestConfig.TestNamespace);\n                                return ServerUtil.expectTestMessages([ServerUtil.TestMessage.DEVICE_READY_AFTER_UPDATE]);\n                            })\n                            .then<void>(() => {\n                                /* restart to make sure it did not revert */\n                                targetPlatform.getEmulatorManager().restartApplication(TestConfig.TestNamespace);\n                                return ServerUtil.expectTestMessages([ServerUtil.TestMessage.DEVICE_READY_AFTER_UPDATE]);\n                            })\n                            .done(() => { done(); }, (e) => { done(e); });\n                    });\n            }, ScenarioInstallOnSuspendWithRevert);\n\n        TestBuilder.describe(\"localPackage installOnNextRestart\",\n            () => {\n                TestBuilder.it(\"localPackage.installOnNextRestart.dorevert\", false,\n                    (done: Mocha.Done) => {\n                        ServerUtil.updateResponse = { update_info: ServerUtil.createUpdateResponse(false, targetPlatform) };\n\n                        setupUpdateScenario(projectManager, targetPlatform, UpdateDeviceReady, \"Update 1\")\n                            .then<void>((updatePath: string) => {\n                                ServerUtil.updatePackagePath = updatePath;\n                                projectManager.runApplication(TestConfig.testRunDirectory, targetPlatform);\n                                return ServerUtil.expectTestMessages([\n                                    ServerUtil.TestMessage.CHECK_UPDATE_AVAILABLE,\n                                    ServerUtil.TestMessage.DOWNLOAD_SUCCEEDED,\n                                    ServerUtil.TestMessage.UPDATE_INSTALLED]);\n                            })\n                            .then<void>(() => {\n                                /* restart the application */\n                                console.log(\"Update hash: \" + ServerUtil.updateResponse.update_info.package_hash);\n                                targetPlatform.getEmulatorManager().restartApplication(TestConfig.TestNamespace);\n                                return ServerUtil.expectTestMessages([ServerUtil.TestMessage.DEVICE_READY_AFTER_UPDATE]);\n                            })\n                            .then<void>(() => {\n                                /* restart the application */\n                                console.log(\"Update hash: \" + ServerUtil.updateResponse.update_info.package_hash);\n                                targetPlatform.getEmulatorManager().restartApplication(TestConfig.TestNamespace);\n                                return ServerUtil.expectTestMessages([ServerUtil.TestMessage.UPDATE_FAILED_PREVIOUSLY]);\n                            })\n                            .done(() => { done(); }, (e) => { done(e); });\n                    });\n\n                TestBuilder.it(\"localPackage.installOnNextRestart.norevert\", true,\n                    (done: Mocha.Done) => {\n                        ServerUtil.updateResponse = { update_info: ServerUtil.createUpdateResponse(false, targetPlatform) };\n\n                        /* create an update */\n                        setupUpdateScenario(projectManager, targetPlatform, UpdateNotifyApplicationReady, \"Update 1 (good update)\")\n                            .then<void>((updatePath: string) => {\n                                ServerUtil.updatePackagePath = updatePath;\n                                projectManager.runApplication(TestConfig.testRunDirectory, targetPlatform);\n                                return ServerUtil.expectTestMessages([\n                                    ServerUtil.TestMessage.CHECK_UPDATE_AVAILABLE,\n                                    ServerUtil.TestMessage.DOWNLOAD_SUCCEEDED,\n                                    ServerUtil.TestMessage.UPDATE_INSTALLED]);\n                            })\n                            .then<void>(() => {\n                                /* \"resume\" the application - run it again */\n                                targetPlatform.getEmulatorManager().restartApplication(TestConfig.TestNamespace);\n                                return ServerUtil.expectTestMessages([ServerUtil.TestMessage.DEVICE_READY_AFTER_UPDATE]);\n                            })\n                            .then<void>(() => {\n                                /* run again to make sure it did not revert */\n                                targetPlatform.getEmulatorManager().restartApplication(TestConfig.TestNamespace);\n                                return ServerUtil.expectTestMessages([ServerUtil.TestMessage.DEVICE_READY_AFTER_UPDATE]);\n                            })\n                            .done(() => { done(); }, (e) => { done(e); });\n                    });\n\n                TestBuilder.it(\"localPackage.installOnNextRestart.revertToPrevious\", false,\n                    (done: Mocha.Done) => {\n                        ServerUtil.updateResponse = { update_info: ServerUtil.createUpdateResponse(false, targetPlatform) };\n\n                        /* create an update */\n                        setupUpdateScenario(projectManager, targetPlatform, UpdateNotifyApplicationReadyConditional, \"Update 1 (good update)\")\n                            .then<void>((updatePath: string) => {\n                                ServerUtil.updatePackagePath = updatePath;\n                                projectManager.runApplication(TestConfig.testRunDirectory, targetPlatform);\n                                return ServerUtil.expectTestMessages([\n                                    ServerUtil.TestMessage.CHECK_UPDATE_AVAILABLE,\n                                    ServerUtil.TestMessage.DOWNLOAD_SUCCEEDED,\n                                    ServerUtil.TestMessage.UPDATE_INSTALLED]);\n                            })\n                            .then<void>(() => {\n                                /* run good update, set up another (bad) update */\n                                ServerUtil.updateResponse = { update_info: ServerUtil.createUpdateResponse(false, targetPlatform) };\n                                setupUpdateScenario(projectManager, targetPlatform, UpdateDeviceReady, \"Update 2 (bad update)\")\n                                    .then(() => { return targetPlatform.getEmulatorManager().restartApplication(TestConfig.TestNamespace); });\n                                return ServerUtil.expectTestMessages([\n                                    ServerUtil.TestMessage.DEVICE_READY_AFTER_UPDATE,\n                                    ServerUtil.TestMessage.CHECK_UPDATE_AVAILABLE,\n                                    ServerUtil.TestMessage.DOWNLOAD_SUCCEEDED,\n                                    ServerUtil.TestMessage.UPDATE_INSTALLED]);\n                            })\n                            .then<void>(() => {\n                                /* run the bad update without calling notifyApplicationReady */\n                                targetPlatform.getEmulatorManager().restartApplication(TestConfig.TestNamespace);\n                                return ServerUtil.expectTestMessages([ServerUtil.TestMessage.DEVICE_READY_AFTER_UPDATE]);\n                            })\n                            .then<void>(() => {\n                                /* run the good update and don't call notifyApplicationReady - it should not revert */\n                                ServerUtil.testMessageResponse = ServerUtil.TestMessageResponse.SKIP_NOTIFY_APPLICATION_READY;\n                                targetPlatform.getEmulatorManager().restartApplication(TestConfig.TestNamespace);\n                                return ServerUtil.expectTestMessages([\n                                    ServerUtil.TestMessage.DEVICE_READY_AFTER_UPDATE,\n                                    ServerUtil.TestMessage.SKIPPED_NOTIFY_APPLICATION_READY]);\n                            })\n                            .then<void>(() => {\n                                /* run the application again */\n                                ServerUtil.testMessageResponse = undefined;\n                                targetPlatform.getEmulatorManager().restartApplication(TestConfig.TestNamespace);\n                                return ServerUtil.expectTestMessages([\n                                    ServerUtil.TestMessage.DEVICE_READY_AFTER_UPDATE,\n                                    ServerUtil.TestMessage.UPDATE_FAILED_PREVIOUSLY]);\n                            })\n                            .done(() => { done(); }, (e) => { done(e); });\n                    });\n            }, ScenarioInstallOnRestartWithRevert);\n\n        TestBuilder.describe(\"#codePush.restartApplication\",\n            () => {\n                TestBuilder.it(\"codePush.restartApplication.checkPackages\", true,\n                    (done: Mocha.Done) => {\n                        ServerUtil.updateResponse = { update_info: ServerUtil.createUpdateResponse(false, targetPlatform) };\n\n                        setupUpdateScenario(projectManager, targetPlatform, UpdateNotifyApplicationReady, \"Update 1\")\n                            .then<void>((updatePath: string) => {\n                                ServerUtil.updatePackagePath = updatePath;\n                                projectManager.runApplication(TestConfig.testRunDirectory, targetPlatform);\n                                return ServerUtil.expectTestMessages([\n                                    new ServerUtil.AppMessage(ServerUtil.TestMessage.PENDING_PACKAGE, [null]),\n                                    new ServerUtil.AppMessage(ServerUtil.TestMessage.CURRENT_PACKAGE, [null]),\n                                    new ServerUtil.AppMessage(ServerUtil.TestMessage.SYNC_STATUS, [ServerUtil.TestMessage.SYNC_UPDATE_INSTALLED]),\n                                    new ServerUtil.AppMessage(ServerUtil.TestMessage.PENDING_PACKAGE, [ServerUtil.updateResponse.update_info.package_hash]),\n                                    new ServerUtil.AppMessage(ServerUtil.TestMessage.CURRENT_PACKAGE, [null]),\n                                    ServerUtil.TestMessage.DEVICE_READY_AFTER_UPDATE]);\n                            })\n                            .then<void>(() => {\n                                /* restart the application */\n                                targetPlatform.getEmulatorManager().restartApplication(TestConfig.TestNamespace);\n                                return ServerUtil.expectTestMessages([ServerUtil.TestMessage.DEVICE_READY_AFTER_UPDATE]);\n                            })\n                            .done(() => { done(); }, (e) => { done(e); });\n                    });\n            }, ScenarioRestart);\n\n        TestBuilder.describe(\"#codePush.restartApplication.2x\",\n            () => {\n                TestBuilder.it(\"blocks when a restart is in progress and doesn't crash if there is a pending package\", false,\n                    (done: Mocha.Done) => {\n                        ServerUtil.updateResponse = { update_info: ServerUtil.createUpdateResponse(false, targetPlatform) };\n                        setupTestRunScenario(projectManager, targetPlatform, ScenarioInstallRestart2x)\n                            .then(setupUpdateScenario.bind(this, projectManager, targetPlatform, UpdateDeviceReady, \"Update 1\"))\n                            .then<void>((updatePath: string) => {\n                                ServerUtil.updatePackagePath = updatePath;\n                                projectManager.runApplication(TestConfig.testRunDirectory, targetPlatform);\n                                return ServerUtil.expectTestMessages([\n                                    ServerUtil.TestMessage.CHECK_UPDATE_AVAILABLE,\n                                    ServerUtil.TestMessage.DOWNLOAD_SUCCEEDED,\n                                    ServerUtil.TestMessage.UPDATE_INSTALLED,\n                                    ServerUtil.TestMessage.DEVICE_READY_AFTER_UPDATE]);\n                            })\n                            .done(() => { done(); }, (e) => { done(e); });\n                    });\n\n                TestBuilder.it(\"doesn't block when the restart is ignored\", false,\n                    (done: Mocha.Done) => {\n                        ServerUtil.updateResponse = { update_info: ServerUtil.createUpdateResponse(false, targetPlatform) };\n                        setupTestRunScenario(projectManager, targetPlatform, ScenarioRestart2x)\n                            .then(setupUpdateScenario.bind(this, projectManager, targetPlatform, UpdateDeviceReady, \"Update 1\"))\n                            .then<void>((updatePath: string) => {\n                                ServerUtil.updatePackagePath = updatePath;\n                                projectManager.runApplication(TestConfig.testRunDirectory, targetPlatform);\n                                return ServerUtil.expectTestMessages([\n                                    ServerUtil.TestMessage.CHECK_UPDATE_AVAILABLE,\n                                    ServerUtil.TestMessage.DOWNLOAD_SUCCEEDED,\n                                    ServerUtil.TestMessage.UPDATE_INSTALLED,\n                                    ServerUtil.TestMessage.DEVICE_READY_AFTER_UPDATE]);\n                            })\n                            .done(() => { done(); }, (e) => { done(e); });\n                    });\n            });\n\n        TestBuilder.describe(\"#window.codePush.sync\",\n            () => {\n                // We test the functionality with sync twice--first, with sync only called once,\n                // then, with sync called again while the first sync is still running.\n                TestBuilder.describe(\"#window.codePush.sync 1x\",\n                    () => {\n                        // Tests where sync is called just once\n                        TestBuilder.it(\"window.codePush.sync.noupdate\", false,\n                            (done: Mocha.Done) => {\n                                const noUpdateResponse = ServerUtil.createDefaultResponse();\n                                noUpdateResponse.is_available = false;\n                                noUpdateResponse.target_binary_range = \"0.0.1\";\n                                ServerUtil.updateResponse = { update_info: noUpdateResponse };\n\n                                Q({})\n                                    .then<void>(p => {\n                                        projectManager.runApplication(TestConfig.testRunDirectory, targetPlatform);\n                                        return ServerUtil.expectTestMessages([\n                                            new ServerUtil.AppMessage(ServerUtil.TestMessage.SYNC_STATUS, [ServerUtil.TestMessage.SYNC_UP_TO_DATE])]);\n                                    })\n                                    .done(() => { done(); }, (e) => { done(e); });\n                            });\n\n                        TestBuilder.it(\"window.codePush.sync.checkerror\", false,\n                            (done: Mocha.Done) => {\n                                ServerUtil.updateResponse = \"invalid {{ json\";\n\n                                Q({})\n                                    .then<void>(p => {\n                                        projectManager.runApplication(TestConfig.testRunDirectory, targetPlatform);\n                                        return ServerUtil.expectTestMessages([\n                                            new ServerUtil.AppMessage(ServerUtil.TestMessage.SYNC_STATUS, [ServerUtil.TestMessage.SYNC_ERROR])]);\n                                    })\n                                    .done(() => { done(); }, (e) => { done(e); });\n                            });\n\n                        TestBuilder.it(\"window.codePush.sync.downloaderror\", false,\n                            (done: Mocha.Done) => {\n                                const invalidUrlResponse = ServerUtil.createUpdateResponse();\n                                invalidUrlResponse.download_url = \"http://\" + path.join(TestConfig.templatePath, \"invalid_path.zip\");\n                                ServerUtil.updateResponse = { update_info: invalidUrlResponse };\n\n                                Q({})\n                                    .then<void>(p => {\n                                        projectManager.runApplication(TestConfig.testRunDirectory, targetPlatform);\n                                        return ServerUtil.expectTestMessages([\n                                            new ServerUtil.AppMessage(ServerUtil.TestMessage.SYNC_STATUS, [ServerUtil.TestMessage.SYNC_ERROR])]);\n                                    })\n                                    .done(() => { done(); }, (e) => { done(e); });\n                            });\n\n                        TestBuilder.it(\"window.codePush.sync.dorevert\", false,\n                            (done: Mocha.Done) => {\n                                ServerUtil.updateResponse = { update_info: ServerUtil.createUpdateResponse(false, targetPlatform) };\n\n                                /* create an update */\n                                setupUpdateScenario(projectManager, targetPlatform, UpdateDeviceReady, \"Update 1 (bad update)\")\n                                    .then<void>((updatePath: string) => {\n                                        ServerUtil.updatePackagePath = updatePath;\n                                        projectManager.runApplication(TestConfig.testRunDirectory, targetPlatform);\n                                        return ServerUtil.expectTestMessages([ServerUtil.TestMessage.DEVICE_READY_AFTER_UPDATE]);\n                                    })\n                                    .then<void>(() => {\n                                        targetPlatform.getEmulatorManager().restartApplication(TestConfig.TestNamespace);\n                                        return ServerUtil.expectTestMessages([\n                                            new ServerUtil.AppMessage(ServerUtil.TestMessage.SYNC_STATUS, [ServerUtil.TestMessage.SYNC_UP_TO_DATE])]);\n                                    })\n                                    .done(() => { done(); }, (e) => { done(e); });\n                            });\n\n                        TestBuilder.it(\"window.codePush.sync.update\", false,\n                            (done: Mocha.Done) => {\n                                ServerUtil.updateResponse = { update_info: ServerUtil.createUpdateResponse(false, targetPlatform) };\n\n                                /* create an update */\n                                setupUpdateScenario(projectManager, targetPlatform, UpdateSync, \"Update 1 (good update)\")\n                                    .then<void>((updatePath: string) => {\n                                        ServerUtil.updatePackagePath = updatePath;\n                                        projectManager.runApplication(TestConfig.testRunDirectory, targetPlatform);\n                                        return ServerUtil.expectTestMessages([\n                                            ServerUtil.TestMessage.DEVICE_READY_AFTER_UPDATE,\n                                            new ServerUtil.AppMessage(ServerUtil.TestMessage.SYNC_STATUS, [ServerUtil.TestMessage.SYNC_UP_TO_DATE])]);\n                                    })\n                                    .then<void>(() => {\n                                        // restart the app and make sure it didn't roll out!\n                                        const noUpdateResponse = ServerUtil.createDefaultResponse();\n                                        noUpdateResponse.is_available = false;\n                                        noUpdateResponse.target_binary_range = \"0.0.1\";\n                                        ServerUtil.updateResponse = { update_info: noUpdateResponse };\n                                        targetPlatform.getEmulatorManager().restartApplication(TestConfig.TestNamespace);\n                                        return ServerUtil.expectTestMessages([\n                                            ServerUtil.TestMessage.DEVICE_READY_AFTER_UPDATE,\n                                            new ServerUtil.AppMessage(ServerUtil.TestMessage.SYNC_STATUS, [ServerUtil.TestMessage.SYNC_UP_TO_DATE])]);\n                                    })\n                                    .done(() => { done(); }, (e) => { done(e); });\n                            });\n\n                    }, ScenarioSync1x);\n\n                TestBuilder.describe(\"#window.codePush.sync 2x\",\n                    () => {\n                        // Tests where sync is called again before the first sync finishes\n                        TestBuilder.it(\"window.codePush.sync.2x.noupdate\", false,\n                            (done: Mocha.Done) => {\n                                const noUpdateResponse = ServerUtil.createDefaultResponse();\n                                noUpdateResponse.is_available = false;\n                                noUpdateResponse.target_binary_range = \"0.0.1\";\n                                ServerUtil.updateResponse = { update_info: noUpdateResponse };\n\n                                Q({})\n                                    .then<void>(p => {\n                                        projectManager.runApplication(TestConfig.testRunDirectory, targetPlatform);\n                                        return ServerUtil.expectTestMessages([\n                                            new ServerUtil.AppMessage(ServerUtil.TestMessage.SYNC_STATUS, [ServerUtil.TestMessage.SYNC_IN_PROGRESS]),\n                                            new ServerUtil.AppMessage(ServerUtil.TestMessage.SYNC_STATUS, [ServerUtil.TestMessage.SYNC_UP_TO_DATE])]);\n                                    })\n                                    .done(() => { done(); }, (e) => { done(e); });\n                            });\n\n                        TestBuilder.it(\"window.codePush.sync.2x.checkerror\", false,\n                            (done: Mocha.Done) => {\n                                ServerUtil.updateResponse = \"invalid {{ json\";\n\n                                Q({})\n                                    .then<void>(p => {\n                                        projectManager.runApplication(TestConfig.testRunDirectory, targetPlatform);\n                                        return ServerUtil.expectTestMessages([\n                                            new ServerUtil.AppMessage(ServerUtil.TestMessage.SYNC_STATUS, [ServerUtil.TestMessage.SYNC_IN_PROGRESS]),\n                                            new ServerUtil.AppMessage(ServerUtil.TestMessage.SYNC_STATUS, [ServerUtil.TestMessage.SYNC_ERROR])]);\n                                    })\n                                    .done(() => { done(); }, (e) => { done(e); });\n                            });\n\n                        TestBuilder.it(\"window.codePush.sync.2x.downloaderror\", false,\n                            (done: Mocha.Done) => {\n                                const invalidUrlResponse = ServerUtil.createUpdateResponse();\n                                invalidUrlResponse.download_url = \"http://\" + path.join(TestConfig.templatePath, \"invalid_path.zip\");\n                                ServerUtil.updateResponse = { update_info: invalidUrlResponse };\n\n                                Q({})\n                                    .then<void>(p => {\n                                        projectManager.runApplication(TestConfig.testRunDirectory, targetPlatform);\n                                        return ServerUtil.expectTestMessages([\n                                            new ServerUtil.AppMessage(ServerUtil.TestMessage.SYNC_STATUS, [ServerUtil.TestMessage.SYNC_IN_PROGRESS]),\n                                            new ServerUtil.AppMessage(ServerUtil.TestMessage.SYNC_STATUS, [ServerUtil.TestMessage.SYNC_ERROR])]);\n                                    })\n                                    .done(() => { done(); }, (e) => { done(e); });\n                            });\n\n                        TestBuilder.it(\"window.codePush.sync.2x.dorevert\", false,\n                            (done: Mocha.Done) => {\n                                ServerUtil.updateResponse = { update_info: ServerUtil.createUpdateResponse(false, targetPlatform) };\n\n                                /* create an update */\n                                setupUpdateScenario(projectManager, targetPlatform, UpdateDeviceReady, \"Update 1 (bad update)\")\n                                    .then<void>((updatePath: string) => {\n                                        ServerUtil.updatePackagePath = updatePath;\n                                        projectManager.runApplication(TestConfig.testRunDirectory, targetPlatform);\n                                        return ServerUtil.expectTestMessages([\n                                            new ServerUtil.AppMessage(ServerUtil.TestMessage.SYNC_STATUS, [ServerUtil.TestMessage.SYNC_IN_PROGRESS]),\n                                            ServerUtil.TestMessage.DEVICE_READY_AFTER_UPDATE]);\n                                    })\n                                    .then<void>(() => {\n                                        targetPlatform.getEmulatorManager().restartApplication(TestConfig.TestNamespace);\n                                        return ServerUtil.expectTestMessages([\n                                            new ServerUtil.AppMessage(ServerUtil.TestMessage.SYNC_STATUS, [ServerUtil.TestMessage.SYNC_IN_PROGRESS]),\n                                            new ServerUtil.AppMessage(ServerUtil.TestMessage.SYNC_STATUS, [ServerUtil.TestMessage.SYNC_UP_TO_DATE])]);\n                                    })\n                                    .done(() => { done(); }, (e) => { done(e); });\n                            });\n\n                        TestBuilder.it(\"window.codePush.sync.2x.update\", true,\n                            (done: Mocha.Done) => {\n                                ServerUtil.updateResponse = { update_info: ServerUtil.createUpdateResponse(false, targetPlatform) };\n\n                                /* create an update */\n                                setupUpdateScenario(projectManager, targetPlatform, UpdateSync2x, \"Update 1 (good update)\")\n                                    .then<void>((updatePath: string) => {\n                                        ServerUtil.updatePackagePath = updatePath;\n                                        projectManager.runApplication(TestConfig.testRunDirectory, targetPlatform);\n                                        return ServerUtil.expectTestMessages([\n                                            new ServerUtil.AppMessage(ServerUtil.TestMessage.SYNC_STATUS, [ServerUtil.TestMessage.SYNC_IN_PROGRESS]),\n                                            ServerUtil.TestMessage.DEVICE_READY_AFTER_UPDATE,\n                                            new ServerUtil.AppMessage(ServerUtil.TestMessage.SYNC_STATUS, [ServerUtil.TestMessage.SYNC_IN_PROGRESS]),\n                                            new ServerUtil.AppMessage(ServerUtil.TestMessage.SYNC_STATUS, [ServerUtil.TestMessage.SYNC_UP_TO_DATE])]);\n                                    })\n                                    .then<void>(() => {\n                                        // restart the app and make sure it didn't roll out!\n                                        const noUpdateResponse = ServerUtil.createDefaultResponse();\n                                        noUpdateResponse.is_available = false;\n                                        noUpdateResponse.target_binary_range = \"0.0.1\";\n                                        ServerUtil.updateResponse = { update_info: noUpdateResponse };\n                                        targetPlatform.getEmulatorManager().restartApplication(TestConfig.TestNamespace);\n                                        return ServerUtil.expectTestMessages([\n                                            ServerUtil.TestMessage.DEVICE_READY_AFTER_UPDATE,\n                                            new ServerUtil.AppMessage(ServerUtil.TestMessage.SYNC_STATUS, [ServerUtil.TestMessage.SYNC_IN_PROGRESS]),\n                                            new ServerUtil.AppMessage(ServerUtil.TestMessage.SYNC_STATUS, [ServerUtil.TestMessage.SYNC_UP_TO_DATE])]);\n                                    })\n                                    .done(() => { done(); }, (e) => { done(e); });\n                            });\n                    }, ScenarioSync2x);\n            });\n\n        TestBuilder.describe(\"#window.codePush.sync minimum background duration tests\",\n            () => {\n                TestBuilder.it(\"defaults to no minimum for Resume mode\", false,\n                    (done: Mocha.Done) => {\n                        ServerUtil.updateResponse = { update_info: ServerUtil.createUpdateResponse(false, targetPlatform) };\n\n                        setupTestRunScenario(projectManager, targetPlatform, ScenarioSyncResume).then<string>(() => {\n                            return setupUpdateScenario(projectManager, targetPlatform, UpdateSync, \"Update 1 (good update)\");\n                        })\n                            .then<void>((updatePath: string) => {\n                                ServerUtil.updatePackagePath = updatePath;\n                                projectManager.runApplication(TestConfig.testRunDirectory, targetPlatform);\n                                return ServerUtil.expectTestMessages([\n                                    new ServerUtil.AppMessage(ServerUtil.TestMessage.SYNC_STATUS, [ServerUtil.TestMessage.SYNC_UPDATE_INSTALLED])]);\n                            })\n                            .then<void>(() => {\n                                const noUpdateResponse = ServerUtil.createDefaultResponse();\n                                noUpdateResponse.is_available = false;\n                                noUpdateResponse.target_binary_range = \"0.0.1\";\n                                ServerUtil.updateResponse = { update_info: noUpdateResponse };\n                                targetPlatform.getEmulatorManager().resumeApplication(TestConfig.TestNamespace);\n                                return ServerUtil.expectTestMessages([\n                                    ServerUtil.TestMessage.DEVICE_READY_AFTER_UPDATE,\n                                    new ServerUtil.AppMessage(ServerUtil.TestMessage.SYNC_STATUS, [ServerUtil.TestMessage.SYNC_UP_TO_DATE])]);\n                            })\n                            .done(() => { done(); }, (e) => { done(e); });\n                    });\n\n                TestBuilder.it(\"min background duration 5s for Resume mode\", false,\n                    (done: Mocha.Done) => {\n                        ServerUtil.updateResponse = { update_info: ServerUtil.createUpdateResponse(false, targetPlatform) };\n\n                        setupTestRunScenario(projectManager, targetPlatform, ScenarioSyncResumeDelay).then<string>(() => {\n                            return setupUpdateScenario(projectManager, targetPlatform, UpdateSync, \"Update 1 (good update)\");\n                        })\n                            .then((updatePath: string) => {\n                                ServerUtil.updatePackagePath = updatePath;\n                                projectManager.runApplication(TestConfig.testRunDirectory, targetPlatform);\n                                return ServerUtil.expectTestMessages([\n                                    new ServerUtil.AppMessage(ServerUtil.TestMessage.SYNC_STATUS, [ServerUtil.TestMessage.SYNC_UPDATE_INSTALLED])]);\n                            })\n                            .then(() => {\n                                const noUpdateResponse = ServerUtil.createDefaultResponse();\n                                noUpdateResponse.is_available = false;\n                                noUpdateResponse.target_binary_range = \"0.0.1\";\n                                ServerUtil.updateResponse = { update_info: noUpdateResponse };\n                                return targetPlatform.getEmulatorManager().resumeApplication(TestConfig.TestNamespace, 3 * 1000);\n                            })\n                            .then(() => {\n                                targetPlatform.getEmulatorManager().resumeApplication(TestConfig.TestNamespace, 6 * 1000);\n                                return ServerUtil.expectTestMessages([\n                                    ServerUtil.TestMessage.DEVICE_READY_AFTER_UPDATE,\n                                    new ServerUtil.AppMessage(ServerUtil.TestMessage.SYNC_STATUS, [ServerUtil.TestMessage.SYNC_UP_TO_DATE])]);\n                            })\n                            .done(() => { done(); }, (e) => { done(e); });\n                    });\n\n                TestBuilder.it(\"defaults to no minimum for Suspend mode\", false,\n                    (done: Mocha.Done) => {\n                        ServerUtil.updateResponse = { update_info: ServerUtil.createUpdateResponse(false, targetPlatform) };\n\n                        setupTestRunScenario(projectManager, targetPlatform, ScenarioSyncSuspend).then<string>(() => {\n                            return setupUpdateScenario(projectManager, targetPlatform, UpdateSync, \"Update 1 (good update)\");\n                        })\n                            .then<void>((updatePath: string) => {\n                                ServerUtil.updatePackagePath = updatePath;\n                                projectManager.runApplication(TestConfig.testRunDirectory, targetPlatform);\n                                return ServerUtil.expectTestMessages([\n                                    new ServerUtil.AppMessage(ServerUtil.TestMessage.SYNC_STATUS, [ServerUtil.TestMessage.SYNC_UPDATE_INSTALLED])]);\n                            })\n                            .then<void>(() => {\n                                const noUpdateResponse = ServerUtil.createDefaultResponse();\n                                noUpdateResponse.is_available = false;\n                                noUpdateResponse.target_binary_range = \"0.0.1\";\n                                ServerUtil.updateResponse = { update_info: noUpdateResponse };\n                                targetPlatform.getEmulatorManager().resumeApplication(TestConfig.TestNamespace);\n                                return ServerUtil.expectTestMessages([\n                                    ServerUtil.TestMessage.DEVICE_READY_AFTER_UPDATE,\n                                    new ServerUtil.AppMessage(ServerUtil.TestMessage.SYNC_STATUS, [ServerUtil.TestMessage.SYNC_UP_TO_DATE])]);\n                            })\n                            .done(() => { done(); }, (e) => { done(e); });\n                    });\n\n                TestBuilder.it(\"min background duration 5s for Suspend mode\", false,\n                    (done: Mocha.Done) => {\n                        ServerUtil.updateResponse = { update_info: ServerUtil.createUpdateResponse(false, targetPlatform) };\n\n                        setupTestRunScenario(projectManager, targetPlatform, ScenarioSyncSuspendDelay).then<string>(() => {\n                            return setupUpdateScenario(projectManager, targetPlatform, UpdateSync, \"Update 1 (good update)\");\n                        })\n                            .then((updatePath: string) => {\n                                ServerUtil.updatePackagePath = updatePath;\n                                projectManager.runApplication(TestConfig.testRunDirectory, targetPlatform);\n                                return ServerUtil.expectTestMessages([\n                                    new ServerUtil.AppMessage(ServerUtil.TestMessage.SYNC_STATUS, [ServerUtil.TestMessage.SYNC_UPDATE_INSTALLED])]);\n                            })\n                            .then(() => {\n                                const noUpdateResponse = ServerUtil.createDefaultResponse();\n                                noUpdateResponse.is_available = false;\n                                noUpdateResponse.target_binary_range = \"0.0.1\";\n                                ServerUtil.updateResponse = { update_info: noUpdateResponse };\n                                return targetPlatform.getEmulatorManager().resumeApplication(TestConfig.TestNamespace, 3 * 1000);\n                            })\n                            .then(() => {\n                                targetPlatform.getEmulatorManager().resumeApplication(TestConfig.TestNamespace, 6 * 1000);\n                                return ServerUtil.expectTestMessages([\n                                    ServerUtil.TestMessage.DEVICE_READY_AFTER_UPDATE,\n                                    new ServerUtil.AppMessage(ServerUtil.TestMessage.SYNC_STATUS, [ServerUtil.TestMessage.SYNC_UP_TO_DATE])]);\n                            })\n                            .done(() => { done(); }, (e) => { done(e); });\n                    });\n\n                TestBuilder.it(\"has no effect on restart\", false,\n                    (done: Mocha.Done) => {\n                        ServerUtil.updateResponse = { update_info: ServerUtil.createUpdateResponse(false, targetPlatform) };\n\n                        setupTestRunScenario(projectManager, targetPlatform, ScenarioSyncRestartDelay).then<string>(() => {\n                            return setupUpdateScenario(projectManager, targetPlatform, UpdateSync, \"Update 1 (good update)\");\n                        })\n                            .then<void>((updatePath: string) => {\n                                ServerUtil.updatePackagePath = updatePath;\n                                projectManager.runApplication(TestConfig.testRunDirectory, targetPlatform);\n                                return ServerUtil.expectTestMessages([\n                                    new ServerUtil.AppMessage(ServerUtil.TestMessage.SYNC_STATUS, [ServerUtil.TestMessage.SYNC_UPDATE_INSTALLED])]);\n                            })\n                            .then<void>(() => {\n                                const noUpdateResponse = ServerUtil.createDefaultResponse();\n                                noUpdateResponse.is_available = false;\n                                noUpdateResponse.target_binary_range = \"0.0.1\";\n                                ServerUtil.updateResponse = { update_info: noUpdateResponse };\n                                targetPlatform.getEmulatorManager().restartApplication(TestConfig.TestNamespace);\n                                return ServerUtil.expectTestMessages([\n                                    ServerUtil.TestMessage.DEVICE_READY_AFTER_UPDATE,\n                                    new ServerUtil.AppMessage(ServerUtil.TestMessage.SYNC_STATUS, [ServerUtil.TestMessage.SYNC_UP_TO_DATE])]);\n                            })\n                            .done(() => { done(); }, (e) => { done(e); });\n                    });\n            });\n\n        TestBuilder.describe(\"#window.codePush.sync mandatory install mode tests\",\n            () => {\n                TestBuilder.it(\"defaults to IMMEDIATE\", false,\n                    (done: Mocha.Done) => {\n                        ServerUtil.updateResponse = { update_info: ServerUtil.createUpdateResponse(true, targetPlatform) };\n\n                        setupTestRunScenario(projectManager, targetPlatform, ScenarioSyncMandatoryDefault).then<string>(() => {\n                            return setupUpdateScenario(projectManager, targetPlatform, UpdateDeviceReady, \"Update 1 (good update)\");\n                        })\n                            .then<void>((updatePath: string) => {\n                                ServerUtil.updatePackagePath = updatePath;\n                                projectManager.runApplication(TestConfig.testRunDirectory, targetPlatform);\n                                return ServerUtil.expectTestMessages([ServerUtil.TestMessage.DEVICE_READY_AFTER_UPDATE]);\n                            })\n                            .done(() => { done(); }, (e) => { done(e); });\n                    });\n\n                TestBuilder.it(\"works correctly when update is mandatory and mandatory install mode is Resume\", false,\n                    (done: Mocha.Done) => {\n                        ServerUtil.updateResponse = { update_info: ServerUtil.createUpdateResponse(true, targetPlatform) };\n\n                        setupTestRunScenario(projectManager, targetPlatform, ScenarioSyncMandatoryResume).then<string>(() => {\n                            return setupUpdateScenario(projectManager, targetPlatform, UpdateDeviceReady, \"Update 1 (good update)\");\n                        })\n                            .then<void>((updatePath: string) => {\n                                ServerUtil.updatePackagePath = updatePath;\n                                projectManager.runApplication(TestConfig.testRunDirectory, targetPlatform);\n                                return ServerUtil.expectTestMessages([\n                                    new ServerUtil.AppMessage(ServerUtil.TestMessage.SYNC_STATUS, [ServerUtil.TestMessage.SYNC_UPDATE_INSTALLED])]);\n                            })\n                            .then<void>(() => {\n                                const noUpdateResponse = ServerUtil.createDefaultResponse();\n                                noUpdateResponse.is_available = false;\n                                noUpdateResponse.target_binary_range = \"0.0.1\";\n                                ServerUtil.updateResponse = { update_info: noUpdateResponse };\n                                targetPlatform.getEmulatorManager().resumeApplication(TestConfig.TestNamespace, 5 * 1000);\n                                return ServerUtil.expectTestMessages([\n                                    ServerUtil.TestMessage.DEVICE_READY_AFTER_UPDATE]);\n                            })\n                            .done(() => { done(); }, (e) => { done(e); });\n                    });\n\n                TestBuilder.it(\"works correctly when update is mandatory and mandatory install mode is Suspend\", false,\n                    (done: Mocha.Done) => {\n                        ServerUtil.updateResponse = { update_info: ServerUtil.createUpdateResponse(true, targetPlatform) };\n\n                        setupTestRunScenario(projectManager, targetPlatform, ScenarioSyncMandatorySuspend).then<string>(() => {\n                            return setupUpdateScenario(projectManager, targetPlatform, UpdateDeviceReady, \"Update 1 (good update)\");\n                        })\n                            .then<void>((updatePath: string) => {\n                                ServerUtil.updatePackagePath = updatePath;\n                                projectManager.runApplication(TestConfig.testRunDirectory, targetPlatform);\n                                return ServerUtil.expectTestMessages([\n                                    new ServerUtil.AppMessage(ServerUtil.TestMessage.SYNC_STATUS, [ServerUtil.TestMessage.SYNC_UPDATE_INSTALLED])]);\n                            })\n                            .then<void>(() => {\n                                const noUpdateResponse = ServerUtil.createDefaultResponse();\n                                noUpdateResponse.is_available = false;\n                                noUpdateResponse.target_binary_range = \"0.0.1\";\n                                ServerUtil.updateResponse = { update_info: noUpdateResponse };\n                                targetPlatform.getEmulatorManager().resumeApplication(TestConfig.TestNamespace);\n                                return ServerUtil.expectTestMessages([\n                                    ServerUtil.TestMessage.DEVICE_READY_AFTER_UPDATE]);\n                            })\n                            .done(() => { done(); }, (e) => { done(e); });\n                    });\n\n                TestBuilder.it(\"has no effect on updates that are not mandatory\", false,\n                    (done: Mocha.Done) => {\n                        ServerUtil.updateResponse = { update_info: ServerUtil.createUpdateResponse(false, targetPlatform) };\n\n                        setupTestRunScenario(projectManager, targetPlatform, ScenarioSyncMandatoryRestart).then<string>(() => {\n                            return setupUpdateScenario(projectManager, targetPlatform, UpdateDeviceReady, \"Update 1 (good update)\");\n                        })\n                            .then<void>((updatePath: string) => {\n                                ServerUtil.updatePackagePath = updatePath;\n                                projectManager.runApplication(TestConfig.testRunDirectory, targetPlatform);\n                                return ServerUtil.expectTestMessages([ServerUtil.TestMessage.DEVICE_READY_AFTER_UPDATE]);\n                            })\n                            .done(() => { done(); }, (e) => { done(e); });\n                    });\n            });\n\n        TestBuilder.describe(\"#codePush.disallowRestart\",\n            () => {\n                TestBuilder.it(\"disallowRestart with IMMEDIATE install mode\", false,\n                    (done: Mocha.Done) => {\n                        ServerUtil.updateResponse = { update_info: ServerUtil.createUpdateResponse(false, targetPlatform) };\n                        setupTestRunScenario(projectManager, targetPlatform, ScenarioDisallowRestartImmediate)\n                            .then(setupUpdateScenario.bind(this, projectManager, targetPlatform, UpdateNotifyApplicationReady, \"Update 1\"))\n                            .then<void>((updatePath: string) => {\n                                ServerUtil.updatePackagePath = updatePath;\n                                projectManager.runApplication(TestConfig.testRunDirectory, targetPlatform);\n                                return ServerUtil.expectTestMessages([\n                                    ServerUtil.TestMessage.CHECK_UPDATE_AVAILABLE,\n                                    ServerUtil.TestMessage.DOWNLOAD_SUCCEEDED,\n                                    ServerUtil.TestMessage.UPDATE_INSTALLED,\n                                    ServerUtil.TestMessage.DEVICE_READY_AFTER_UPDATE\n                                ]);\n                            })\n                            .done(() => { done(); }, (e) => { done(e); });\n                    });\n\n                TestBuilder.it(\"disallowRestart with ON_NEXT_RESUME install mode\", false,\n                    (done: Mocha.Done) => {\n                        ServerUtil.updateResponse = { update_info: ServerUtil.createUpdateResponse(false, targetPlatform) };\n                        setupTestRunScenario(projectManager, targetPlatform, ScenarioDisallowRestartOnResume)\n                            .then(setupUpdateScenario.bind(this, projectManager, targetPlatform, UpdateDeviceReady, \"Update 1\"))\n                            .then<void>((updatePath: string) => {\n                                ServerUtil.updatePackagePath = updatePath;\n                                projectManager.runApplication(TestConfig.testRunDirectory, targetPlatform);\n                                return ServerUtil.expectTestMessages([\n                                    ServerUtil.TestMessage.CHECK_UPDATE_AVAILABLE,\n                                    ServerUtil.TestMessage.DOWNLOAD_SUCCEEDED,\n                                    ServerUtil.TestMessage.UPDATE_INSTALLED\n                                ]);\n                            })\n                            .then<void>(() => {\n                                /* resume the application */\n                                return targetPlatform.getEmulatorManager().resumeApplication(TestConfig.TestNamespace);\n                            })\n                            .then<void>(() => {\n                                /* restart the application */\n                                targetPlatform.getEmulatorManager().restartApplication(TestConfig.TestNamespace);\n                                return ServerUtil.expectTestMessages([ServerUtil.TestMessage.DEVICE_READY_AFTER_UPDATE]);\n                            })\n                            .done(() => { done(); }, (e) => { done(e); });\n                    });\n\n                TestBuilder.it(\"disallowRestart with ON_NEXT_SUSPEND install mode\", false,\n                    (done: Mocha.Done) => {\n                        ServerUtil.updateResponse = { update_info: ServerUtil.createUpdateResponse(false, targetPlatform) };\n                        setupTestRunScenario(projectManager, targetPlatform, ScenarioDisallowRestartOnSuspend)\n                            .then(setupUpdateScenario.bind(this, projectManager, targetPlatform, UpdateDeviceReady, \"Update 1\"))\n                            .then<void>((updatePath: string) => {\n                                ServerUtil.updatePackagePath = updatePath;\n                                projectManager.runApplication(TestConfig.testRunDirectory, targetPlatform);\n                                return ServerUtil.expectTestMessages([\n                                    ServerUtil.TestMessage.CHECK_UPDATE_AVAILABLE,\n                                    ServerUtil.TestMessage.DOWNLOAD_SUCCEEDED,\n                                    ServerUtil.TestMessage.UPDATE_INSTALLED\n                                ]);\n                            })\n                            .then<void>(() => {\n                                /* resume the application */\n                                return targetPlatform.getEmulatorManager().resumeApplication(TestConfig.TestNamespace);\n                            })\n                            .then<void>(() => {\n                                /* restart the application */\n                                targetPlatform.getEmulatorManager().restartApplication(TestConfig.TestNamespace);\n                                return ServerUtil.expectTestMessages([ServerUtil.TestMessage.DEVICE_READY_AFTER_UPDATE]);\n                            })\n                            .done(() => { done(); }, (e) => { done(e); });\n                    });\n            });\n    });\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n    \"compilerOptions\": {\n        \"target\": \"ES5\",\n        \"module\": \"commonjs\",\n        \"lib\": [\"es6\"],\n        \"noImplicitAny\": true,\n        \"noEmitOnError\": true,\n        \"moduleResolution\": \"node\",\n        \"sourceMap\": true,\n        \"rootDir\": \"test\",\n        \"outDir\": \"bin\",\n        \"removeComments\": true\n    }\n}\n"
  },
  {
    "path": "tslint.json",
    "content": "{\n    \"defaultSeverity\": \"error\",\n    \"rules\": {\n        \"class-name\": true,\n        \"comment-format\": [true,\n            \"check-space\"\n        ],\n        \"indent\": [true,\n            \"spaces\"\n        ],\n        \"one-line\": [true,\n            \"check-open-brace\"\n        ],\n        \"quotemark\": [true,\n            \"double\"\n        ],\n        \"semicolon\": true,\n        \"whitespace\": [true,\n            \"check-branch\",\n            \"check-operator\",\n            \"check-separator\",\n            \"check-type\"\n        ],\n        \"typedef-whitespace\": [true, {\n            \"call-signature\": \"nospace\",\n            \"index-signature\": \"nospace\",\n            \"parameter\": \"nospace\",\n            \"property-declaration\": \"nospace\",\n            \"variable-declaration\": \"nospace\"\n        }]\n    }\n}\n"
  },
  {
    "path": "typings/react-native-code-push.d.ts",
    "content": "export type DownloadProgressCallback = (progress: DownloadProgress) => void;\nexport type SyncStatusChangedCallback = (status: CodePush.SyncStatus) => void;\nexport type HandleBinaryVersionMismatchCallback = (update: RemotePackage) => void;\n\nexport interface CodePushOptions extends SyncOptions {\n    /**\n     * Specifies when you would like to synchronize updates with the CodePush server.\n     * Defaults to codePush.CheckFrequency.ON_APP_START.\n     */\n    checkFrequency: CodePush.CheckFrequency;\n}\n\nexport interface DownloadProgress {\n    /**\n     * The total number of bytes expected to be received for this update.\n     */\n    totalBytes: number;\n\n    /**\n     * The number of bytes downloaded thus far.\n     */\n    receivedBytes: number;\n}\n\nexport interface LocalPackage extends Package {\n    /**\n     * Installs the update by saving it to the location on disk where the runtime expects to find the latest version of the app.\n     *\n     * @param installMode Indicates when you would like the update changes to take affect for the end-user.\n     * @param minimumBackgroundDuration For resume-based installs, this specifies the number of seconds the app needs to be in the background before forcing a restart. Defaults to 0 if unspecified.\n     */\n    install(installMode: CodePush.InstallMode, minimumBackgroundDuration?: number): Promise<void>;\n}\n\nexport interface Package {\n    /**\n     * The app binary version that this update is dependent on. This is the value that was\n     * specified via the appStoreVersion parameter when calling the CLI's release command.\n     */\n    appVersion: string;\n\n    /**\n     * The deployment key that was used to originally download this update.\n     */\n    deploymentKey: string;\n\n    /**\n     * The description of the update. This is the same value that you specified in the CLI when you released the update.\n     */\n    description: string;\n\n    /**\n     * Indicates whether this update has been previously installed but was rolled back.\n     */\n    failedInstall: boolean;\n\n    /**\n     * Indicates whether this is the first time the update has been run after being installed.\n     */\n    isFirstRun: boolean;\n\n    /**\n     * Indicates whether the update is considered mandatory. This is the value that was specified in the CLI when the update was released.\n     */\n    isMandatory: boolean;\n\n    /**\n     * Indicates whether this update is in a \"pending\" state. When true, that means the update has been downloaded and installed, but the app restart\n     * needed to apply it hasn't occurred yet, and therefore, its changes aren't currently visible to the end-user.\n     */\n    isPending: boolean;\n\n    /**\n     * The internal label automatically given to the update by the CodePush server. This value uniquely identifies the update within its deployment.\n     */\n    label: string;\n\n    /**\n     * The SHA hash value of the update.\n     */\n    packageHash: string;\n\n    /**\n     * The size of the code contained within the update, in bytes.\n     */\n    packageSize: number;\n}\n\nexport interface RemotePackage extends Package {\n    /**\n     * Downloads the available update from the CodePush service.\n     *\n     * @param downloadProgressCallback An optional callback that allows tracking the progress of the update while it is being downloaded.\n     */\n    download(downloadProgressCallback?: DownloadProgressCallback): Promise<LocalPackage>;\n\n    /**\n     * The URL at which the package is available for download.\n     */\n    downloadUrl: string;\n}\n\nexport interface SyncOptions {\n    /**\n     * Specifies the deployment key you want to query for an update against. By default, this value is derived from the Info.plist\n     * file (iOS) and MainActivity.java file (Android), but this option allows you to override it from the script-side if you need to\n     * dynamically use a different deployment for a specific call to sync.\n     */\n    deploymentKey?: string;\n\n    /**\n     * Specifies when you would like to install optional updates (i.e. those that aren't marked as mandatory).\n     * Defaults to codePush.InstallMode.ON_NEXT_RESTART.\n     */\n    installMode?: CodePush.InstallMode;\n\n    /**\n     * Specifies when you would like to install updates which are marked as mandatory.\n     * Defaults to codePush.InstallMode.IMMEDIATE.\n     */\n    mandatoryInstallMode?: CodePush.InstallMode;\n\n    /**\n     * Specifies the minimum number of seconds that the app needs to have been in the background before restarting the app. This property\n     * only applies to updates which are installed using `InstallMode.ON_NEXT_RESUME` or `InstallMode.ON_NEXT_SUSPEND`, and can be useful \n     * for getting your update in front of end users sooner, without being too obtrusive. Defaults to `0`, which has the effect of applying \n     * the update immediately after a resume or unless the app suspension is long enough to not matter, regardless how long it was in the background.\n     */\n    minimumBackgroundDuration?: number;\n\n    /**\n     * An \"options\" object used to determine whether a confirmation dialog should be displayed to the end user when an update is available,\n     * and if so, what strings to use. Defaults to null, which has the effect of disabling the dialog completely. Setting this to any truthy\n     * value will enable the dialog with the default strings, and passing an object to this parameter allows enabling the dialog as well as\n     * overriding one or more of the default strings.\n     */\n    updateDialog?: UpdateDialog | true;\n\n    /**\n     * The rollback retry mechanism allows the application to attempt to reinstall an update that was previously rolled back (with the restrictions\n     * specified in the options). It is an \"options\" object used to determine whether a rollback retry should occur, and if so, what settings to use\n     * for the rollback retry. This defaults to null, which has the effect of disabling the retry mechanism. Setting this to any truthy value will enable\n     * the retry mechanism with the default settings, and passing an object to this parameter allows enabling the rollback retry as well as overriding\n     * one or more of the default values.\n     */\n    rollbackRetryOptions?: RollbackRetryOptions;\n}\n\nexport interface UpdateDialog {\n    /**\n     * Indicates whether you would like to append the description of an available release to the\n     * notification message which is displayed to the end user. Defaults to false.\n     */\n    appendReleaseDescription?: boolean;\n\n    /**\n     * Indicates the string you would like to prefix the release description with, if any, when\n     * displaying the update notification to the end user. Defaults to \" Description: \"\n     */\n    descriptionPrefix?: string;\n\n    /**\n     * The text to use for the button the end user must press in order to install a mandatory update. Defaults to \"Continue\".\n     */\n    mandatoryContinueButtonLabel?: string;\n\n    /**\n     * The text used as the body of an update notification, when the update is specified as mandatory.\n     * Defaults to \"An update is available that must be installed.\".\n     */\n    mandatoryUpdateMessage?: string;\n\n    /**\n     * The text to use for the button the end user can press in order to ignore an optional update that is available. Defaults to \"Ignore\".\n     */\n    optionalIgnoreButtonLabel?: string;\n\n    /**\n     * The text to use for the button the end user can press in order to install an optional update. Defaults to \"Install\".\n     */\n    optionalInstallButtonLabel?: string;\n\n    /**\n     * The text used as the body of an update notification, when the update is optional. Defaults to \"An update is available. Would you like to install it?\".\n     */\n    optionalUpdateMessage?: string;\n\n    /**\n     * The text used as the header of an update notification that is displayed to the end user. Defaults to \"Update available\".\n     */\n    title?: string;\n}\n\nexport interface RollbackRetryOptions {\n    /**\n     * Specifies the minimum time in hours that the app will wait after the latest rollback\n     * before attempting to reinstall same rolled-back package. Defaults to `24`.\n     */\n    delayInHours?: number;\n\n    /**\n     * Specifies the maximum number of retry attempts that the app can make before it stops trying.\n     * Cannot be less than `1`. Defaults to `1`.\n     */\n    maxRetryAttempts?: number;\n}\n\nexport interface StatusReport {\n    /**\n     * Whether the deployment succeeded or failed.\n     */\n    status: CodePush.DeploymentStatus;\n\n    /**\n     * The version of the app that was deployed (for a native app upgrade).\n     */\n    appVersion?: string;\n\n    /**\n     * Details of the package that was deployed (or attempted to).\n     */\n    package?: Package;\n\n    /**\n     * Deployment key used when deploying the previous package.\n     */\n    previousDeploymentKey?: string;\n\n    /**\n     * The label (v#) of the package that was upgraded from.\n     */\n    previousLabelOrAppVersion?: string;\n}\n\n/**\n * Decorates a React Component configuring it to sync for updates with the CodePush server.\n *\n * @param options Options used to configure the end-user sync and update experience (e.g. when to check for updates?, show an prompt?, install the update immediately?).\n */\ndeclare function CodePush(options?: CodePushOptions): (x: any) => any;\n\n/**\n * Decorates a React Component configuring it to sync for updates with the CodePush server.\n *\n * @param x the React Component that will decorated\n */\ndeclare function CodePush(x: any): any\n\ndeclare namespace CodePush {\n    /**\n     * Represents the default settings that will be used by the sync method if\n     * an update dialog is configured to be displayed.\n     */\n    var DEFAULT_UPDATE_DIALOG: UpdateDialog;\n\n    /**\n     * Asks the CodePush service whether the configured app deployment has an update available.\n     *\n     * @param deploymentKey The deployment key to use to query the CodePush server for an update.\n     * \n     * @param handleBinaryVersionMismatchCallback An optional callback for handling target binary version mismatch\n     */\n    function checkForUpdate(deploymentKey?: string, handleBinaryVersionMismatchCallback?: HandleBinaryVersionMismatchCallback): Promise<RemotePackage | null>;\n\n    /**\n     * Retrieves the metadata for an installed update (e.g. description, mandatory).\n     *\n     * @param updateState The state of the update you want to retrieve the metadata for. Defaults to UpdateState.RUNNING.\n     */\n    function getUpdateMetadata(updateState?: UpdateState) : Promise<LocalPackage|null>;\n\n    /**\n     * Notifies the CodePush runtime that an installed update is considered successful.\n     */\n    function notifyAppReady(): Promise<StatusReport|void>;\n\n    /**\n     * Allow CodePush to restart the app.\n     */\n    function allowRestart(): void;\n\n    /**\n     * Forbid CodePush to restart the app.\n     */\n    function disallowRestart(): void;\n\n    /**\n     * Clear all downloaded CodePush updates.\n     * This is useful when switching to a different deployment which may have an older release than the current package.\n     * Note: we don’t recommend to use this method in scenarios other than that (CodePush will call\n     * this method automatically when needed in other cases) as it could lead to unpredictable behavior.\n     */\n    function clearUpdates(): void;\n\n    /**\n     * Immediately restarts the app.\n     *\n     * @param onlyIfUpdateIsPending Indicates whether you want the restart to no-op if there isn't currently a pending update.\n     */\n    function restartApp(onlyIfUpdateIsPending?: boolean): void;\n\n    /**\n     * Allows checking for an update, downloading it and installing it, all with a single call.\n     *\n     * @param options Options used to configure the end-user update experience (e.g. show an prompt?, install the update immediately?).\n     * @param syncStatusChangedCallback An optional callback that allows tracking the status of the sync operation, as opposed to simply checking the resolved state via the returned Promise.\n     * @param downloadProgressCallback An optional callback that allows tracking the progress of an update while it is being downloaded.\n     * @param handleBinaryVersionMismatchCallback An optional callback for handling target binary version mismatch\n     */\n    function sync(options?: SyncOptions, syncStatusChangedCallback?: SyncStatusChangedCallback, downloadProgressCallback?: DownloadProgressCallback, handleBinaryVersionMismatchCallback?: HandleBinaryVersionMismatchCallback): Promise<SyncStatus>;\n\n    /**\n     * Indicates when you would like an installed update to actually be applied.\n     */\n    enum InstallMode {\n        /**\n         * Indicates that you want to install the update and restart the app immediately.\n         */\n        IMMEDIATE,\n\n        /**\n         * Indicates that you want to install the update, but not forcibly restart the app.\n         */\n        ON_NEXT_RESTART,\n\n        /**\n         * Indicates that you want to install the update, but don't want to restart the app until the next time\n         * the end user resumes it from the background. This way, you don't disrupt their current session,\n         * but you can get the update in front of them sooner then having to wait for the next natural restart. \n         * This value is appropriate for silent installs that can be applied on resume in a non-invasive way.\n         */\n        ON_NEXT_RESUME,\n\n        /**\n         * Indicates that you want to install the update when the app is in the background,\n         * but only after it has been in the background for \"minimumBackgroundDuration\" seconds (0 by default),\n         * so that user context isn't lost unless the app suspension is long enough to not matter.\n         */\n        ON_NEXT_SUSPEND\n    }\n\n    /**\n     * Indicates the current status of a sync operation.\n     */\n    enum SyncStatus {\n        /**\n         * The app is up-to-date with the CodePush server.\n         */\n        UP_TO_DATE,\n            \n        /**\n         * An available update has been installed and will be run either immediately after the\n         * syncStatusChangedCallback function returns or the next time the app resumes/restarts,\n         * depending on the InstallMode specified in SyncOptions\n         */\n        UPDATE_INSTALLED,\n            \n        /**\n         * The app had an optional update which the end user chose to ignore.\n         * (This is only applicable when the updateDialog is used)\n         */\n        UPDATE_IGNORED,\n            \n        /**\n         * The sync operation encountered an unknown error.\n         */\n        UNKNOWN_ERROR,\n        \n        /**\n         * There is an ongoing sync operation running which prevents the current call from being executed.\n         */\n        SYNC_IN_PROGRESS,\n            \n        /**\n         * The CodePush server is being queried for an update.\n         */\n        CHECKING_FOR_UPDATE,\n\n        /**\n         * An update is available, and a confirmation dialog was shown\n         * to the end user. (This is only applicable when the updateDialog is used)\n         */\n        AWAITING_USER_ACTION,\n\n        /**\n         * An available update is being downloaded from the CodePush server.\n         */\n        DOWNLOADING_PACKAGE,\n\n        /**\n         * An available update was downloaded and is about to be installed.\n         */\n        INSTALLING_UPDATE\n    }\n\n    /**\n     * Indicates the state that an update is currently in.\n     */\n    enum UpdateState {\n        /**\n         * Indicates that an update represents the\n         * version of the app that is currently running.\n         */\n        RUNNING,\n\n        /**\n         * Indicates than an update has been installed, but the\n         * app hasn't been restarted yet in order to apply it.\n         */\n        PENDING,\n\n        /**\n         * Indicates than an update represents the latest available\n         * release, and can be either currently running or pending.\n         */\n        LATEST\n    }\n\n    /**\n     * Indicates the status of a deployment (after installing and restarting).\n     */\n    enum DeploymentStatus {\n        /**\n         * The deployment failed (and was rolled back).\n         */\n        FAILED,\n\n        /**\n         * The deployment succeeded.\n         */\n        SUCCEEDED\n    }\n\n    /**\n     * Indicates when you would like to check for (and install) updates from the CodePush server.\n     */\n    enum CheckFrequency {\n        /**\n         * When the app is fully initialized (or more specifically, when the root component is mounted).\n         */\n        ON_APP_START,\n\n        /**\n         * When the app re-enters the foreground.\n         */\n        ON_APP_RESUME,\n\n        /**\n         * Don't automatically check for updates, but only do it when codePush.sync() is manully called inside app code.\n         */\n        MANUAL\n    }\n}\n\nexport default CodePush;\n"
  },
  {
    "path": "windows/.gitignore",
    "content": "## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n##\n## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore\n\n# User-specific files\n*.rsuser\n*.suo\n*.user\n*.userosscache\n*.sln.docstates\n\n# User-specific files (MonoDevelop/Xamarin Studio)\n*.userprefs\n\n# Mono auto generated files\nmono_crash.*\n\n# Build results\n[Dd]ebug/\n[Dd]ebugPublic/\n[Rr]elease/\n[Rr]eleases/\nx64/\nx86/\n[Ww][Ii][Nn]32/\n[Aa][Rr][Mm]/\n[Aa][Rr][Mm]64/\nbld/\n[Bb]in/\n[Oo]bj/\n[Ll]og/\n[Ll]ogs/\n\n# Visual Studio 2015/2017 cache/options directory\n.vs/\n# Uncomment if you have tasks that create the project's static files in wwwroot\n#wwwroot/\n\n# Visual Studio 2017 auto generated files\nGenerated\\ Files/\n\n# MSTest test Results\n[Tt]est[Rr]esult*/\n[Bb]uild[Ll]og.*\n\n# NUnit\n*.VisualState.xml\nTestResult.xml\nnunit-*.xml\n\n# Build Results of an ATL Project\n[Dd]ebugPS/\n[Rr]eleasePS/\ndlldata.c\n\n# Benchmark Results\nBenchmarkDotNet.Artifacts/\n\n# .NET Core\nproject.lock.json\nproject.fragment.lock.json\nartifacts/\n\n# ASP.NET Scaffolding\nScaffoldingReadMe.txt\n\n# StyleCop\nStyleCopReport.xml\n\n# Files built by Visual Studio\n*_i.c\n*_p.c\n*_h.h\n*.ilk\n*.meta\n*.obj\n*.iobj\n*.pch\n*.pdb\n*.ipdb\n*.pgc\n*.pgd\n*.rsp\n*.sbr\n*.tlb\n*.tli\n*.tlh\n*.tmp\n*.tmp_proj\n*_wpftmp.csproj\n*.log\n*.vspscc\n*.vssscc\n.builds\n*.pidb\n*.svclog\n*.scc\n\n# Chutzpah Test files\n_Chutzpah*\n\n# Visual C++ cache files\nipch/\n*.aps\n*.ncb\n*.opendb\n*.opensdf\n*.sdf\n*.cachefile\n*.VC.db\n*.VC.VC.opendb\n\n# Visual Studio profiler\n*.psess\n*.vsp\n*.vspx\n*.sap\n\n# Visual Studio Trace Files\n*.e2e\n\n# TFS 2012 Local Workspace\n$tf/\n\n# Guidance Automation Toolkit\n*.gpState\n\n# ReSharper is a .NET coding add-in\n_ReSharper*/\n*.[Rr]e[Ss]harper\n*.DotSettings.user\n\n# TeamCity is a build add-in\n_TeamCity*\n\n# DotCover is a Code Coverage Tool\n*.dotCover\n\n# AxoCover is a Code Coverage Tool\n.axoCover/*\n!.axoCover/settings.json\n\n# Coverlet is a free, cross platform Code Coverage Tool\ncoverage*.json\ncoverage*.xml\ncoverage*.info\n\n# Visual Studio code coverage results\n*.coverage\n*.coveragexml\n\n# NCrunch\n_NCrunch_*\n.*crunch*.local.xml\nnCrunchTemp_*\n\n# MightyMoose\n*.mm.*\nAutoTest.Net/\n\n# Web workbench (sass)\n.sass-cache/\n\n# Installshield output folder\n[Ee]xpress/\n\n# DocProject is a documentation generator add-in\nDocProject/buildhelp/\nDocProject/Help/*.HxT\nDocProject/Help/*.HxC\nDocProject/Help/*.hhc\nDocProject/Help/*.hhk\nDocProject/Help/*.hhp\nDocProject/Help/Html2\nDocProject/Help/html\n\n# Click-Once directory\npublish/\n\n# Publish Web Output\n*.[Pp]ublish.xml\n*.azurePubxml\n# Note: Comment the next line if you want to checkin your web deploy settings,\n# but database connection strings (with potential passwords) will be unencrypted\n*.pubxml\n*.publishproj\n\n# Microsoft Azure Web App publish settings. Comment the next line if you want to\n# checkin your Azure Web App publish settings, but sensitive information contained\n# in these scripts will be unencrypted\nPublishScripts/\n\n# NuGet Packages\n*.nupkg\n# NuGet Symbol Packages\n*.snupkg\n# The packages folder can be ignored because of Package Restore\n**/[Pp]ackages/*\n# except build/, which is used as an MSBuild target.\n!**/[Pp]ackages/build/\n# Uncomment if necessary however generally it will be regenerated when needed\n#!**/[Pp]ackages/repositories.config\n# NuGet v3's project.json files produces more ignorable files\n*.nuget.props\n*.nuget.targets\n\n# Microsoft Azure Build Output\ncsx/\n*.build.csdef\n\n# Microsoft Azure Emulator\necf/\nrcf/\n\n# Windows Store app package directories and files\nAppPackages/\nBundleArtifacts/\nPackage.StoreAssociation.xml\n_pkginfo.txt\n*.appx\n*.appxbundle\n*.appxupload\n\n# Visual Studio cache files\n# files ending in .cache can be ignored\n*.[Cc]ache\n# but keep track of directories ending in .cache\n!?*.[Cc]ache/\n\n# Others\nClientBin/\n~$*\n*~\n*.dbmdl\n*.dbproj.schemaview\n*.jfm\n*.pfx\n*.publishsettings\norleans.codegen.cs\n\n# Including strong name files can present a security risk\n# (https://github.com/github/gitignore/pull/2483#issue-259490424)\n#*.snk\n\n# Since there are multiple workflows, uncomment next line to ignore bower_components\n# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)\n#bower_components/\n\n# RIA/Silverlight projects\nGenerated_Code/\n\n# Backup & report files from converting an old project file\n# to a newer Visual Studio version. Backup files are not needed,\n# because we have git ;-)\n_UpgradeReport_Files/\nBackup*/\nUpgradeLog*.XML\nUpgradeLog*.htm\nServiceFabricBackup/\n*.rptproj.bak\n\n# SQL Server files\n*.mdf\n*.ldf\n*.ndf\n\n# Business Intelligence projects\n*.rdl.data\n*.bim.layout\n*.bim_*.settings\n*.rptproj.rsuser\n*- [Bb]ackup.rdl\n*- [Bb]ackup ([0-9]).rdl\n*- [Bb]ackup ([0-9][0-9]).rdl\n\n# Microsoft Fakes\nFakesAssemblies/\n\n# GhostDoc plugin setting file\n*.GhostDoc.xml\n\n# Node.js Tools for Visual Studio\n.ntvs_analysis.dat\nnode_modules/\n\n# Visual Studio 6 build log\n*.plg\n\n# Visual Studio 6 workspace options file\n*.opt\n\n# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)\n*.vbw\n\n# Visual Studio LightSwitch build output\n**/*.HTMLClient/GeneratedArtifacts\n**/*.DesktopClient/GeneratedArtifacts\n**/*.DesktopClient/ModelManifest.xml\n**/*.Server/GeneratedArtifacts\n**/*.Server/ModelManifest.xml\n_Pvt_Extensions\n\n# Paket dependency manager\n.paket/paket.exe\npaket-files/\n\n# FAKE - F# Make\n.fake/\n\n# CodeRush personal settings\n.cr/personal\n\n# Python Tools for Visual Studio (PTVS)\n__pycache__/\n*.pyc\n\n# Cake - Uncomment if you are using it\n# tools/**\n# !tools/packages.config\n\n# Tabs Studio\n*.tss\n\n# Telerik's JustMock configuration file\n*.jmconfig\n\n# BizTalk build output\n*.btp.cs\n*.btm.cs\n*.odx.cs\n*.xsd.cs\n\n# OpenCover UI analysis results\nOpenCover/\n\n# Azure Stream Analytics local run output\nASALocalRun/\n\n# MSBuild Binary and Structured Log\n*.binlog\n\n# NVidia Nsight GPU debugger configuration file\n*.nvuser\n\n# MFractors (Xamarin productivity tool) working folder\n.mfractor/\n\n# Local History for Visual Studio\n.localhistory/\n\n# BeatPulse healthcheck temp database\nhealthchecksdb\n\n# Backup folder for Package Reference Convert tool in Visual Studio 2017\nMigrationBackup/\n\n# Ionide (cross platform F# VS Code tools) working folder\n.ionide/\n\n# Fody - auto-generated XML schema\nFodyWeavers.xsd\n"
  },
  {
    "path": "windows/.npmignore",
    "content": "# Make sure we don't publish build artifacts to NPM\nARM/\nDebug/\nx64/\nx86/\nbin/\nobj/\n.vs/\n\n# Don't publish settings used for developement\nDirectory.Build.props\n"
  },
  {
    "path": "windows/CodePush/.npmignore",
    "content": "# Make sure we don't publish build artifacts to NPM\n.vs/\nARM/\nARM64/\nx64/\nx86/\nDebug/\nRelease/\nbin/\nobj/\nGenerated Files/\n"
  },
  {
    "path": "windows/CodePush/CodePush.def",
    "content": "﻿EXPORTS\nDllCanUnloadNow = WINRT_CanUnloadNow                    PRIVATE\nDllGetActivationFactory = WINRT_GetActivationFactory    PRIVATE\n"
  },
  {
    "path": "windows/CodePush/CodePush.vcxproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <Import Project=\"$(SolutionDir)\\packages\\Microsoft.Windows.CppWinRT.2.0.200615.7\\build\\native\\Microsoft.Windows.CppWinRT.props\" Condition=\"Exists('$(SolutionDir)\\packages\\Microsoft.Windows.CppWinRT.2.0.200615.7\\build\\native\\Microsoft.Windows.CppWinRT.props')\" />\n  <PropertyGroup Label=\"Globals\">\n    <CppWinRTOptimized>true</CppWinRTOptimized>\n    <CppWinRTRootNamespaceAutoMerge>true</CppWinRTRootNamespaceAutoMerge>\n    <CppWinRTGenerateWindowsMetadata>true</CppWinRTGenerateWindowsMetadata>\n    <MinimalCoreWin>true</MinimalCoreWin>\n    <ProjectGuid>{a6b6216e-fa3f-45e2-9c8e-40023cce9132}</ProjectGuid>\n    <ProjectName>CodePush</ProjectName>\n    <RootNamespace>Microsoft.CodePush.ReactNative</RootNamespace>\n    <DefaultLanguage>en-US</DefaultLanguage>\n    <MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>\n    <AppContainerApplication>true</AppContainerApplication>\n    <ApplicationType>Windows Store</ApplicationType>\n    <ApplicationTypeRevision>10.0</ApplicationTypeRevision>\n    <WindowsTargetPlatformVersion Condition=\" '$(WindowsTargetPlatformVersion)' == '' \">10.0</WindowsTargetPlatformVersion>\n    <WindowsTargetPlatformMinVersion>10.0.17763.0</WindowsTargetPlatformMinVersion>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Label=\"ReactNativeWindowsProps\">\n    <ReactNativeWindowsDir Condition=\"'$(ReactNativeWindowsDir)' == ''\">$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), 'node_modules\\react-native-windows\\package.json'))\\node_modules\\react-native-windows\\</ReactNativeWindowsDir>\n  </PropertyGroup>\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|ARM\">\n      <Configuration>Debug</Configuration>\n      <Platform>ARM</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|ARM64\">\n      <Configuration>Debug</Configuration>\n      <Platform>ARM64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|ARM\">\n      <Configuration>Release</Configuration>\n      <Platform>ARM</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|ARM64\">\n      <Configuration>Release</Configuration>\n      <Platform>ARM64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Configuration\">\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\n    <PlatformToolset Condition=\"'$(VisualStudioVersion)' == '15.0'\">v141</PlatformToolset>\n    <PlatformToolset Condition=\"'$(VisualStudioVersion)' == '16.0'\">v142</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n    <GenerateManifest>false</GenerateManifest>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)'=='Debug'\" Label=\"Configuration\">\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <LinkIncremental>true</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)'=='Release'\" Label=\"Configuration\">\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <LinkIncremental>false</LinkIncremental>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"Shared\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"PropertySheet.props\" />\n  </ImportGroup>\n  <ImportGroup Label=\"ReactNativeWindowsPropertySheets\">\n    <Import Project=\"$(ReactNativeWindowsDir)\\PropertySheets\\External\\Microsoft.ReactNative.Uwp.CppLib.props\" Condition=\"Exists('$(ReactNativeWindowsDir)\\PropertySheets\\External\\Microsoft.ReactNative.Uwp.CppLib.props')\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup />\n  <ItemDefinitionGroup>\n    <ClCompile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>\n      <PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>\n      <WarningLevel>Level4</WarningLevel>\n      <AdditionalOptions>%(AdditionalOptions) /bigobj</AdditionalOptions>\n      <!--Temporarily disable cppwinrt heap enforcement to work around xaml compiler generated std::shared_ptr use -->\n      <AdditionalOptions Condition=\"'$(CppWinRTHeapEnforcement)'==''\">/DWINRT_NO_MAKE_DETECTION %(AdditionalOptions)</AdditionalOptions>\n      <DisableSpecificWarnings>\n      </DisableSpecificWarnings>\n      <PreprocessorDefinitions>_WINRT_DLL;WIN32_LEAN_AND_MEAN;WINRT_LEAN_AND_MEAN;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <AdditionalUsingDirectories>$(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <GenerateWindowsMetadata>true</GenerateWindowsMetadata>\n      <ModuleDefinitionFile>CodePush.def</ModuleDefinitionFile>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)'=='Debug'\">\n    <ClCompile>\n      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\n    </ClCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)'=='Release'\">\n    <ClCompile>\n      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <Link>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClInclude Include=\"CodePushConfig.h\" />\n    <ClInclude Include=\"CodePushDownloadHandler.h\" />\n    <ClInclude Include=\"CodePushNativeModule.h\" />\n    <ClInclude Include=\"CodePushPackage.h\" />\n    <ClInclude Include=\"CodePushTelemetryManager.h\" />\n    <ClInclude Include=\"CodePushUpdateUtils.h\" />\n    <ClInclude Include=\"CodePushUtils.h\" />\n    <ClInclude Include=\"FileUtils.h\" />\n    <ClInclude Include=\"miniz\\miniz.h\" />\n    <ClInclude Include=\"pch.h\" />\n    <ClInclude Include=\"ReactPackageProvider.h\">\n      <DependentUpon>ReactPackageProvider.idl</DependentUpon>\n    </ClInclude>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"CodePushConfig.cpp\" />\n    <ClCompile Include=\"CodePushDownloadHandler.cpp\" />\n    <ClCompile Include=\"CodePushNativeModule.cpp\" />\n    <ClCompile Include=\"CodePushPackage.cpp\" />\n    <ClCompile Include=\"CodePushTelemetryManager.cpp\" />\n    <ClCompile Include=\"CodePushUpdateUtils.cpp\" />\n    <ClCompile Include=\"CodePushUtils.cpp\" />\n    <ClCompile Include=\"FileUtils.cpp\" />\n    <ClCompile Include=\"miniz\\miniz.c\">\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\n    </ClCompile>\n    <ClCompile Include=\"pch.cpp\">\n      <PrecompiledHeader>Create</PrecompiledHeader>\n    </ClCompile>\n    <ClCompile Include=\"$(GeneratedFilesDir)module.g.cpp\" />\n    <ClCompile Include=\"ReactPackageProvider.cpp\">\n      <DependentUpon>ReactPackageProvider.idl</DependentUpon>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <Midl Include=\"CodePushConfig.idl\" />\n    <Midl Include=\"ReactPackageProvider.idl\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"CodePush.def\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"packages.config\" />\n    <None Include=\"PropertySheet.props\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ReactNativeWindowsTargets\">\n    <Import Project=\"$(ReactNativeWindowsDir)\\PropertySheets\\External\\Microsoft.ReactNative.Uwp.CppLib.targets\" Condition=\"Exists('$(ReactNativeWindowsDir)\\PropertySheets\\External\\Microsoft.ReactNative.Uwp.CppLib.targets')\" />\n  </ImportGroup>\n  <Target Name=\"EnsureReactNativeWindowsTargets\" BeforeTargets=\"PrepareForBuild\">\n    <PropertyGroup>\n      <ErrorText>This project references targets in your node_modules\\react-native-windows folder that are missing. The missing file is {0}.</ErrorText>\n    </PropertyGroup>\n    <Error Condition=\"!Exists('$(ReactNativeWindowsDir)\\PropertySheets\\External\\Microsoft.ReactNative.Uwp.CppLib.props')\" Text=\"$([System.String]::Format('$(ErrorText)', '$(ReactNativeWindowsDir)\\PropertySheets\\External\\Microsoft.ReactNative.Uwp.CppLib.props'))\" />\n    <Error Condition=\"!Exists('$(ReactNativeWindowsDir)\\PropertySheets\\External\\Microsoft.ReactNative.Uwp.CppLib.targets')\" Text=\"$([System.String]::Format('$(ErrorText)', '$(ReactNativeWindowsDir)\\PropertySheets\\External\\Microsoft.ReactNative.Uwp.CppLib.targets'))\" />\n  </Target>\n  <ImportGroup Label=\"ExtensionTargets\">\n    <Import Project=\"$(SolutionDir)\\packages\\Microsoft.Windows.CppWinRT.2.0.200615.7\\build\\native\\Microsoft.Windows.CppWinRT.targets\" Condition=\"Exists('$(SolutionDir)\\packages\\Microsoft.Windows.CppWinRT.2.0.200615.7\\build\\native\\Microsoft.Windows.CppWinRT.targets')\" />\n  </ImportGroup>\n  <Target Name=\"EnsureNuGetPackageBuildImports\" BeforeTargets=\"PrepareForBuild\">\n    <PropertyGroup>\n      <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>\n    </PropertyGroup>\n    <Error Condition=\"!Exists('$(SolutionDir)\\packages\\Microsoft.Windows.CppWinRT.2.0.200615.7\\build\\native\\Microsoft.Windows.CppWinRT.props')\" Text=\"$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\\packages\\Microsoft.Windows.CppWinRT.2.0.200615.7\\build\\native\\Microsoft.Windows.CppWinRT.props'))\" />\n    <Error Condition=\"!Exists('$(SolutionDir)\\packages\\Microsoft.Windows.CppWinRT.2.0.200615.7\\build\\native\\Microsoft.Windows.CppWinRT.targets')\" Text=\"$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\\packages\\Microsoft.Windows.CppWinRT.2.0.200615.7\\build\\native\\Microsoft.Windows.CppWinRT.targets'))\" />\n  </Target>\n  <ItemGroup>\n    <ProjectReference Update=\"$(ReactNativeWindowsDir)\\Microsoft.ReactNative\\Microsoft.ReactNative.vcxproj\">\n      <ReferenceOutputAssembly>true</ReferenceOutputAssembly>\n      <LinkLibraryDependencies>true</LinkLibraryDependencies>\n    </ProjectReference>\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "windows/CodePush/CodePush.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Resources\">\n      <UniqueIdentifier>accd3aa8-1ba0-4223-9bbe-0c431709210b</UniqueIdentifier>\n      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tga;tiff;tif;png;wav;mfcribbon-ms</Extensions>\n    </Filter>\n    <Filter Include=\"CodePush\">\n      <UniqueIdentifier>{c2eae772-39a8-4b12-aad7-60e9ca2072ef}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"miniz\">\n      <UniqueIdentifier>{53513ea0-fe7c-4f69-8d3e-c1a9efbb7333}</UniqueIdentifier>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"pch.cpp\" />\n    <ClCompile Include=\"$(GeneratedFilesDir)module.g.cpp\" />\n    <ClCompile Include=\"miniz\\miniz.c\">\n      <Filter>miniz</Filter>\n    </ClCompile>\n    <ClCompile Include=\"CodePushConfig.cpp\">\n      <Filter>CodePush</Filter>\n    </ClCompile>\n    <ClCompile Include=\"CodePushDownloadHandler.cpp\">\n      <Filter>CodePush</Filter>\n    </ClCompile>\n    <ClCompile Include=\"CodePushNativeModule.cpp\">\n      <Filter>CodePush</Filter>\n    </ClCompile>\n    <ClCompile Include=\"CodePushPackage.cpp\">\n      <Filter>CodePush</Filter>\n    </ClCompile>\n    <ClCompile Include=\"CodePushTelemetryManager.cpp\">\n      <Filter>CodePush</Filter>\n    </ClCompile>\n    <ClCompile Include=\"CodePushUpdateUtils.cpp\">\n      <Filter>CodePush</Filter>\n    </ClCompile>\n    <ClCompile Include=\"CodePushUtils.cpp\">\n      <Filter>CodePush</Filter>\n    </ClCompile>\n    <ClCompile Include=\"FileUtils.cpp\">\n      <Filter>CodePush</Filter>\n    </ClCompile>\n    <ClCompile Include=\"ReactPackageProvider.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"pch.h\" />\n    <ClInclude Include=\"miniz\\miniz.h\">\n      <Filter>miniz</Filter>\n    </ClInclude>\n    <ClInclude Include=\"CodePushConfig.h\">\n      <Filter>CodePush</Filter>\n    </ClInclude>\n    <ClInclude Include=\"CodePushDownloadHandler.h\">\n      <Filter>CodePush</Filter>\n    </ClInclude>\n    <ClInclude Include=\"CodePushNativeModule.h\">\n      <Filter>CodePush</Filter>\n    </ClInclude>\n    <ClInclude Include=\"CodePushPackage.h\">\n      <Filter>CodePush</Filter>\n    </ClInclude>\n    <ClInclude Include=\"CodePushTelemetryManager.h\">\n      <Filter>CodePush</Filter>\n    </ClInclude>\n    <ClInclude Include=\"CodePushUpdateUtils.h\">\n      <Filter>CodePush</Filter>\n    </ClInclude>\n    <ClInclude Include=\"CodePushUtils.h\">\n      <Filter>CodePush</Filter>\n    </ClInclude>\n    <ClInclude Include=\"FileUtils.h\">\n      <Filter>CodePush</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ReactPackageProvider.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"CodePush.def\" />\n    <None Include=\"packages.config\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"PropertySheet.props\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Midl Include=\"ReactPackageProvider.idl\" />\n    <Midl Include=\"CodePushConfig.idl\">\n      <Filter>CodePush</Filter>\n    </Midl>\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "windows/CodePush/CodePushConfig.cpp",
    "content": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\n#include \"pch.h\"\n#include \"CodePushConfig.h\"\n#include \"CodePushConfig.g.cpp\"\n#include \"CodePushNativeModule.h\"\n\n#include \"winrt/Windows.Foundation.Collections.h\"\n#include \"winrt/Windows.Storage.h\"\n\nnamespace winrt::Microsoft::CodePush::ReactNative::implementation\n{\n    using namespace Windows::Storage;\n    using namespace Windows::Data::Json;\n    using namespace Windows::Foundation::Collections;\n\n    CodePushConfig CodePushConfig::s_currentConfig{};\n\n    /*static*/ CodePushConfig& CodePushConfig::Current() noexcept\n    {\n        return s_currentConfig;\n    }\n\n    JsonObject CodePushConfig::GetConfiguration()\n    {\n        JsonObject configObject;\n        for (const auto& pair : m_configuration)\n        {\n            configObject.Insert(pair.Key(), JsonValue::CreateStringValue(pair.Value()));\n        }\n        return configObject;\n    }\n\n    /*static*/ void CodePushConfig::Init(IMap<hstring, hstring> const& configMap) noexcept\n    {\n        std::optional<hstring> appVersion;\n        std::optional<hstring> buildVersion;\n        std::optional<hstring> deploymentKey;\n        std::optional<hstring> publicKey;\n        std::optional<hstring> serverUrl;\n\n        if (configMap != nullptr)\n        {\n            appVersion = configMap.TryLookup(AppVersionConfigKey);\n            buildVersion = configMap.TryLookup(BuildVersionConfigKey);\n            deploymentKey = configMap.TryLookup(DeploymentKeyConfigKey);\n            publicKey = configMap.TryLookup(PublicKeyKey);\n            serverUrl = configMap.TryLookup(ServerURLConfigKey);\n        }\n\n        s_currentConfig.m_configuration = winrt::single_threaded_map<hstring, hstring>();\n        auto addToConfiguration = [=](std::wstring_view key, std::optional<hstring> optValue) {\n            if (optValue.has_value())\n            {\n                s_currentConfig.m_configuration.Insert(key, optValue.value());\n            }\n        };\n\n        auto localSettings{ ::Microsoft::CodePush::ReactNative::CodePushNativeModule::GetLocalSettings() };\n        hstring clientUniqueId;\n        auto clientUniqueIdData{ localSettings.Values().TryLookup(ClientUniqueIDConfigKey) };\n        if (clientUniqueIdData == nullptr)\n        {\n            auto newGuid{ GuidHelper::CreateNewGuid() };\n            clientUniqueId = to_hstring(newGuid);\n            localSettings.Values().Insert(ClientUniqueIDConfigKey, box_value(clientUniqueId));\n        }\n        else\n        {\n            clientUniqueId = unbox_value<hstring>(clientUniqueIdData);\n        }\n\n        addToConfiguration(AppVersionConfigKey, appVersion);\n        addToConfiguration(BuildVersionConfigKey, buildVersion);\n        addToConfiguration(DeploymentKeyConfigKey, deploymentKey);\n        addToConfiguration(PublicKeyKey, publicKey);\n        addToConfiguration(ServerURLConfigKey, serverUrl);\n\n        s_currentConfig.m_configuration.Insert(ClientUniqueIDConfigKey, clientUniqueId);\n\n        if (!serverUrl.has_value())\n        {\n            s_currentConfig.m_configuration.Insert(ServerURLConfigKey, L\"https://codepush.appcenter.ms/\");\n        }\n\n        ::Microsoft::CodePush::ReactNative::CodePushNativeModule::LoadBundle();\n    }\n\n    hstring CodePushConfig::QueryConfig(std::wstring_view key)\n    {\n        auto value{ m_configuration.TryLookup(key) };\n        if (value.has_value())\n        {\n            return value.value();\n        }\n        return L\"\";\n    }\n\n    /*static*/ void CodePushConfig::SetHost(Microsoft::ReactNative::ReactNativeHost const& host) noexcept\n    {\n        ::Microsoft::CodePush::ReactNative::CodePushNativeModule::SetHost(host);\n    }\n}\n"
  },
  {
    "path": "windows/CodePush/CodePushConfig.h",
    "content": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\n#pragma once\n#include \"CodePushConfig.g.h\"\n\n#include \"NativeModules.h\"\n\n#include <string_view>\n#include \"winrt/Microsoft.ReactNative.h\"\n#include \"winrt/Windows.Data.Json.h\"\n#include \"winrt/Windows.Foundation.Collections.h\"\n\nnamespace winrt::Microsoft::CodePush::ReactNative::implementation\n{\n    struct CodePushConfig : CodePushConfigT<CodePushConfig>\n    {\n        CodePushConfig() = default;\n\n        static void Init(Windows::Foundation::Collections::IMap<hstring, hstring> const& configMap) noexcept;\n        static void SetHost(Microsoft::ReactNative::ReactNativeHost const& host) noexcept;\n\n        static CodePushConfig& Current() noexcept;\n\n        hstring GetAppVersion() { return QueryConfig(AppVersionConfigKey); }\n        void SetAppVersion(std::wstring_view appVersion) { m_configuration.Insert(AppVersionConfigKey, appVersion); }\n\n        hstring GetBuildVersion() { return QueryConfig(BuildVersionConfigKey); }\n\n        Windows::Data::Json::JsonObject GetConfiguration();\n\n        hstring GetDeploymentKey() { return QueryConfig(DeploymentKeyConfigKey); }\n        void SetDeploymentKey(std::wstring_view deploymentKey) { m_configuration.Insert(DeploymentKeyConfigKey, deploymentKey); }\n\n        hstring GetServerUrl() { return QueryConfig(ServerURLConfigKey); }\n        void SetServerUrl(std::wstring_view serverUrl) { m_configuration.Insert(ServerURLConfigKey, serverUrl); }\n\n        hstring GetPublicKey() { return QueryConfig(PublicKeyKey); }\n        void SetPublicKey(std::wstring_view publicKey) { m_configuration.Insert(PublicKeyKey, publicKey); }\n\n    private:\n        static constexpr std::wstring_view AppVersionConfigKey{ L\"appVersion\" };\n        static constexpr std::wstring_view BuildVersionConfigKey{ L\"buildVersion\" };\n        static constexpr std::wstring_view ClientUniqueIDConfigKey{ L\"clientUniqueId\" };\n        static constexpr std::wstring_view DeploymentKeyConfigKey{ L\"deploymentKey\" };\n        static constexpr std::wstring_view ServerURLConfigKey{ L\"serverUrl\" };\n        static constexpr std::wstring_view PublicKeyKey{ L\"publicKey\" };\n\n        Windows::Foundation::Collections::IMap<hstring, hstring> m_configuration;\n        static CodePushConfig s_currentConfig;\n\n        hstring QueryConfig(std::wstring_view key);\n    };\n}\n\nnamespace winrt::Microsoft::CodePush::ReactNative::factory_implementation\n{\n    struct CodePushConfig : CodePushConfigT<CodePushConfig, implementation::CodePushConfig>\n    {\n    };\n}\n\nnamespace Microsoft::CodePush::ReactNative\n{\n    using winrt::Microsoft::CodePush::ReactNative::implementation::CodePushConfig;\n}\n"
  },
  {
    "path": "windows/CodePush/CodePushConfig.idl",
    "content": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nnamespace Microsoft.CodePush.ReactNative\n{\n    [webhosthidden]\n    [default_interface]\n    runtimeclass CodePushConfig {\n        static void Init(IMap<String, String> configMap);\n        static void SetHost(Microsoft.ReactNative.ReactNativeHost host);\n    };\n} // namespace CppModule\n"
  },
  {
    "path": "windows/CodePush/CodePushDownloadHandler.cpp",
    "content": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\n#include \"pch.h\"\n\n#include \"winrt/Windows.Data.Json.h\"\n#include \"winrt/Windows.Foundation.h\"\n#include \"winrt/Windows.Storage.h\"\n#include \"winrt/Windows.Storage.Streams.h\"\n#include \"winrt/Windows.Web.Http.h\"\n#include \"winrt/Windows.Web.Http.Headers.h\"\n\n#include \"CodePushDownloadHandler.h\"\n\nnamespace Microsoft::CodePush::ReactNative\n{\n    using namespace winrt;\n    using namespace Windows::Data::Json;\n    using namespace Windows::Foundation;\n    using namespace Windows::Storage;\n    using namespace Windows::Storage::Streams;\n    using namespace Windows::Web::Http;\n\n    CodePushDownloadHandler::CodePushDownloadHandler(\n        StorageFile downloadFile,\n        std::function<void(int64_t, int64_t)> progressCallback) :\n        receivedContentLength(0),\n        expectedContentLength(0),\n        progressCallback(progressCallback),\n        downloadFile(downloadFile) {}\n\n    IAsyncOperation<bool> CodePushDownloadHandler::Download(std::wstring_view url)\n    {\n        HttpClient client;\n\n        auto headers{ client.DefaultRequestHeaders() };\n        headers.Append(L\"Accept-Encoding\", L\"identity\");\n\n        HttpRequestMessage reqm{ HttpMethod::Get(), Uri(url) };\n        auto resm{ co_await client.SendRequestAsync(reqm, HttpCompletionOption::ResponseHeadersRead) };\n        expectedContentLength = resm.Content().Headers().ContentLength().GetInt64();\n        auto inputStream{ co_await resm.Content().ReadAsInputStreamAsync() };\n        auto outputStream{ co_await downloadFile.OpenAsync(FileAccessMode::ReadWrite) };\n\n        uint8_t header[4] = {};\n\n        for (;;)\n        {\n            auto outputBuffer{ co_await inputStream.ReadAsync(Buffer{ BufferSize }, BufferSize, InputStreamOptions::None) };\n\n            if (outputBuffer.Length() == 0)\n            {\n                break;\n            }\n            co_await outputStream.WriteAsync(outputBuffer);\n\n            if (receivedContentLength < ARRAYSIZE(header))\n            {\n                for (uint32_t i{ static_cast<uint32_t>(receivedContentLength) }; i < min(ARRAYSIZE(header), outputBuffer.Length()); i++)\n                {\n                    header[i] = outputBuffer.data()[i];\n                }\n            }\n\n            receivedContentLength += outputBuffer.Length();\n\n            progressCallback(/*expectedContentLength*/ expectedContentLength, /*receivedContentLength*/ receivedContentLength);\n        }\n\n        bool isZip{ header[0] == 'P' && header[1] == 'K' && header[2] == 3 && header[3] == 4 };\n        co_return isZip;\n    }\n}\n"
  },
  {
    "path": "windows/CodePush/CodePushDownloadHandler.h",
    "content": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\n#pragma once\n\n#include \"winrt/Windows.Storage.h\"\n#include \"winrt/Windows.Foundation.h\"\n#include \"winrt/Windows.Data.Json.h\"\n#include <string_view>\n#include <functional>\n\nnamespace Microsoft::CodePush::ReactNative\n{\n\tstruct CodePushDownloadHandler\n\t{\n\t\twinrt::Windows::Storage::StorageFile downloadFile;\n\t\tint64_t expectedContentLength;\n\t\tint64_t receivedContentLength;\n\t\tstd::function<void(int64_t, int64_t)> progressCallback;\n\t\tstd::wstring_view downloadUrl;\n\n\t\tCodePushDownloadHandler(\n\t\t\twinrt::Windows::Storage::StorageFile downloadFile,\n\t\t\tstd::function<void(int64_t, int64_t)> progressCallback);\n\n\t\t// Returns true if the downloaded file is a zip file\n\t\twinrt::Windows::Foundation::IAsyncOperation<bool> Download(std::wstring_view url);\n\n\tprivate:\n\t\tstatic constexpr uint32_t BufferSize{ 256 * 1024 };\n\t};\n}\n"
  },
  {
    "path": "windows/CodePush/CodePushNativeModule.cpp",
    "content": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\n#include \"pch.h\"\n\n#include \"CodePushNativeModule.h\"\n#include \"CodePushUtils.h\"\n#include \"CodePushUpdateUtils.h\"\n#include \"CodePushPackage.h\"\n#include \"CodePushTelemetryManager.h\"\n#include \"CodePushConfig.h\"\n#include \"CodePushUtils.h\"\n\n#include <string_view>\n\n#include \"miniz/miniz.h\"\n\n#include \"winrt/Windows.ApplicationModel.h\"\n#include \"winrt/Windows.Data.Json.h\"\n#include \"winrt/Windows.Storage.FileProperties.h\"\n\n#include \"ReactPackageProvider.h\"\n\nnamespace Microsoft::CodePush::ReactNative\n{\n    using namespace winrt;\n    using namespace winrt::Microsoft::ReactNative;\n    using namespace Windows::Data::Json;\n    using namespace Windows::Storage;\n    using namespace Windows::Foundation;\n\n    ReactNativeHost CodePushNativeModule::s_host{};\n    CodePushNativeModule::CodePushInstallMode CodePushNativeModule::s_installMode{};\n    bool CodePushNativeModule::isRunningBinaryVersion{ false };\n    bool CodePushNativeModule::needToReportRollback{ false };\n    /*static*/ bool CodePushNativeModule::s_initialized{ false };\n    /*static*/ hstring CodePushNativeModule::s_javaScriptBundleFileName{ L\"index.windows\" };\n\n    /*static*/ IAsyncOperation<StorageFile> CodePushNativeModule::GetBinaryBundleAsync()\n    {\n        auto appXFolder{ Windows::ApplicationModel::Package::Current().InstalledLocation() };\n        auto bundleFolder{ (co_await appXFolder.TryGetItemAsync(L\"Bundle\")).try_as<StorageFolder>() };\n        if (bundleFolder == nullptr)\n        {\n            co_return nullptr;\n        }\n\n        auto bundleFile{ (co_await bundleFolder.TryGetItemAsync(s_javaScriptBundleFileName + BundleExtension)).try_as<StorageFile>() };\n        co_return bundleFile;\n    }\n\n    /*static*/ IAsyncOperation<StorageFile> CodePushNativeModule::GetBundleFileAsync()\n    {\n        auto bundleFileName{ s_host.InstanceSettings().JavaScriptBundleFile() };\n        if (!bundleFileName.empty())\n        {\n            s_javaScriptBundleFileName = bundleFileName;\n        }\n\n        auto packageBundle{ co_await CodePushPackage::GetCurrentPackageBundleAsync() };\n        auto binaryBundle{ co_await GetBinaryBundleAsync() };\n\n        if (packageBundle == nullptr)\n        {\n            CodePushUtils::LogBundleUrl(binaryBundle);\n            isRunningBinaryVersion = true;\n            co_return binaryBundle;\n        }\n\n        auto binaryAppVersion{ CodePushConfig::Current().GetAppVersion() };\n        auto currentPackageMetadata{ co_await CodePushPackage::GetCurrentPackageAsync() };\n        if (currentPackageMetadata == nullptr)\n        {\n            CodePushUtils::LogBundleUrl(binaryBundle);\n            isRunningBinaryVersion = true;\n            co_return binaryBundle;\n        }\n\n        auto packageDate{ currentPackageMetadata.GetNamedString(BinaryBundleDateKey, L\"\") };\n        auto packageAppVersion{ currentPackageMetadata.GetNamedString(AppVersionKey, L\"\") };\n\n        if ((co_await CodePushUpdateUtils::ModifiedDateStringOfFileAsync(binaryBundle)) == packageDate && binaryAppVersion == packageAppVersion)\n        {\n            // Return package file because it is newer than the JS bundle in the AppX folder\n            CodePushUtils::LogBundleUrl(packageBundle);\n            isRunningBinaryVersion = false;\n            co_return packageBundle;\n        }\n        else\n        {\n            auto isRelease{ false };\n    #ifndef _DEBUG\n            isRelease = true;\n    #endif\n\n            if (isRelease || binaryAppVersion != packageAppVersion)\n            {\n                co_await ClearUpdatesStaticAsync();\n            }\n\n            CodePushUtils::LogBundleUrl(binaryBundle);\n            isRunningBinaryVersion = true;\n            co_return binaryBundle;\n        }\n    }\n\n    /*static*/ IAsyncOperation<StorageFolder> CodePushNativeModule::GetBundleAssetsFolderAsync()\n    {\n        auto appXFolder{ Windows::ApplicationModel::Package::Current().InstalledLocation() };\n        auto bundleFolder{ (co_await appXFolder.TryGetItemAsync(L\"Bundle\")).try_as<StorageFolder>() };\n        if (bundleFolder != nullptr)\n        {\n            auto bundleAssetsFolder{ (co_await bundleFolder.TryGetItemAsync(CodePushUpdateUtils::AssetsFolderName)).try_as<StorageFolder>() };\n            co_return bundleAssetsFolder;\n        }\n        co_return nullptr;\n    }\n\n    // Rather than store files in the library files, CodePush for ReactNativeWindows will use AppData folders.\n    /*static*/ StorageFolder CodePushNativeModule::GetLocalStorageFolder()\n    {\n        return ApplicationData::Current().LocalFolder();\n    }\n\n    /*static*/ ApplicationDataContainer CodePushNativeModule::GetLocalSettings()\n    {\n        return ApplicationData::Current().LocalSettings();\n    }\n\n    void CodePushNativeModule::OverrideAppVersion(std::wstring_view appVersion) \n    {\n        CodePushConfig::Current().SetAppVersion(appVersion);\n    }\n\n    void CodePushNativeModule::SetDeploymentKey(std::wstring_view deploymentKey) \n    {\n        CodePushConfig::Current().SetDeploymentKey(deploymentKey);\n    }\n\n    /*\n     * This method checks to see whether a specific package hash\n     * has previously failed installation.\n     */\n    bool CodePushNativeModule::IsFailedHash(std::wstring_view packageHash) \n    { \n        auto localSettings{ GetLocalSettings() };\n        auto failedUpdatesData{ localSettings.Values().TryLookup(FailedUpdatesKey) };\n        if (failedUpdatesData == nullptr)\n        {\n            return false;\n        }\n        auto failedUpdatesString{ unbox_value<hstring>(failedUpdatesData) };\n        JsonArray failedUpdates;\n        auto success{ JsonArray::TryParse(failedUpdatesString, failedUpdates) };\n        if (!success || packageHash.empty())\n        {\n            return false;\n        }\n        else\n        {\n            for (const auto& failedPackage : failedUpdates)\n            {\n                // We don't have to worry about backwards compatability, but just to be safe...\n                if (failedPackage.ValueType() == JsonValueType::Object)\n                {\n                    auto failedPackageHash{ failedPackage.GetObject().GetNamedString(PackageHashKey) };\n                    if (packageHash == failedPackageHash)\n                    {\n                        return true;\n                    }\n                }\n            }\n\n            return false;\n        }\n    }\n\n    /*\n     * This method is used to get information about the latest rollback.\n     * This information will be used to decide whether the application\n     * should ignore the update or not.\n     */\n    JsonObject CodePushNativeModule::GetRollbackInfo() { return nullptr; }\n\n    /*\n     * This method is used to get the count of rollback for the package\n     * using the latest rollback information.\n     */\n    int CodePushNativeModule::GetRollbackCountForPackage(std::wstring_view packageHash, const JsonObject& latestRollbackInfo) \n    {\n        auto oldPackageHash{ latestRollbackInfo.GetNamedString(LatestRollbackPackageHashKey, L\"null\") };\n        if (packageHash == oldPackageHash)\n        {\n            auto oldCount{ latestRollbackInfo.GetNamedNumber(LatestRollbackCountKey, 0) };\n            return static_cast<int>(oldCount);\n        }\n        return 0; \n    }\n\n    /*\n     * This method checks to see whether a specific package hash\n     * represents a downloaded and installed update, that hasn't\n     * been applied yet via an app restart.\n     */\n    /*static*/ bool CodePushNativeModule::IsPendingUpdate(std::wstring_view packageHash)\n    { \n        auto localSettings{ GetLocalSettings() };\n        auto pendingUpdateData{ localSettings.Values().TryLookup(PendingUpdateKey) };\n        if (pendingUpdateData != nullptr)\n        {\n            auto pendingUpdateString{ unbox_value<hstring>(pendingUpdateData) };\n            JsonObject pendingUpdate;\n            auto success{ JsonObject::TryParse(pendingUpdateString, pendingUpdate) };\n        \n            // If there is a pending update whose \"state\" isn't loading, then we consider it \"pending\".\n            // Additionally, if a specific hash was provided, we ensure it matches that of the pending update.\n            auto updateIsPending{ success &&\n                pendingUpdate != nullptr &&\n                pendingUpdate.GetNamedBoolean(PendingUpdateIsLoadingKey, false) == false &&\n                (packageHash.empty() || pendingUpdate.GetNamedString(PendingUpdateHashKey, L\"null\") == packageHash) };\n\n            return updateIsPending;\n        }\n        return false;\n    }\n\n    /*\n     * This method is used to clear updates that are installed\n     * under a different app version and hence don't apply anymore,\n     * during a debug run configuration and when React Native Windows is\n     * running the JS bundle from the dev server.\n     */\n    IAsyncAction CodePushNativeModule::ClearDebugUpdates()\n    {\n    #ifndef BUNDLE\n        auto binaryAppVersion{ CodePushConfig::Current().GetAppVersion() };\n        auto currentPackageMetadata{ co_await CodePushPackage::GetCurrentPackageAsync() };\n        if (currentPackageMetadata != nullptr)\n        {\n            auto packageAppVersion{ currentPackageMetadata.GetNamedString(AppVersionKey, L\"\") };\n            if (binaryAppVersion.empty() || binaryAppVersion != packageAppVersion)\n            {\n                co_await ClearUpdatesStaticAsync();\n            }\n        }\n    #endif\n        co_return;\n    }\n\n    /*static*/ IAsyncAction CodePushNativeModule::ClearUpdatesStaticAsync()\n    {\n        co_await CodePushPackage::ClearUpdatesAsync();\n        RemovePendingUpdate();\n        RemoveFailedUpdates();\n    }\n\n    void CodePushNativeModule::DispatchDownloadProgressEvent()\n    {\n        // Notify the script-side about the progress\n        m_context.CallJSFunction(\n            L\"RCTDeviceEventEmitter\",\n            L\"emit\",\n            L\"CodePushDownloadProgress\",\n            JSValueObject{\n                {\"totalBytes\", m_latestExpectedContentLength },\n                {\"receivedBytes\", m_latestReceivedContentLength } });\n    }\n\n    /*static*/ IAsyncAction CodePushNativeModule::LoadBundle()\n    {\n        if (!s_host.InstanceSettings().UseWebDebugger())\n        {\n            auto bundleFile{ co_await GetBundleFileAsync() };\n            if (bundleFile != nullptr)\n            {\n                std::wstring_view bundlePath{ bundleFile.Path() };\n                hstring bundleRootPath{ bundlePath.substr(0, bundlePath.rfind('\\\\')) };\n                s_host.InstanceSettings().BundleRootPath(bundleRootPath);\n            }\n        }\n\n        s_host.ReloadInstance();\n        // The instance will call Initialize() upon reloading this module\n    }\n\n    /*\n     * This method is used when an update has failed installation\n     * and the app needs to be rolled back to the previous bundle.\n     * This method is automatically called when the rollback timer\n     * expires without the app indicating whether the update succeeded,\n     * and therefore, it shouldn't be called directly.\n     */\n    IAsyncAction CodePushNativeModule::RollbackPackage()\n    {\n        auto failedPackage{ co_await CodePushPackage::GetCurrentPackageAsync() };\n        if (failedPackage == nullptr)\n        {\n            CodePushUtils::Log(L\"Attempted to perform a rollback when there is no current update.\");\n        }\n        else\n        {\n            SaveFailedUpdate(failedPackage);\n        }\n\n        // Rollback to the previous version and de-register the new update\n        co_await CodePushPackage::RollbackPackage();\n        RemovePendingUpdate();\n        co_await LoadBundle();\n    }\n\n    /*\n     * This method is used to clear away failed updates in the event that\n     * a new app store binary is installed.\n     */\n\n    /*static*/ void CodePushNativeModule::RemoveFailedUpdates()\n    {\n        auto localSettings{ GetLocalSettings() };\n        localSettings.Values().TryRemove(FailedUpdatesKey);\n    }\n\n    /*\n     * This method is used to register the fact that a pending\n     * update succeeded and therefore can be removed.\n     */\n    /*static*/ void CodePushNativeModule::RemovePendingUpdate()\n    {\n        // remove pending update from LocalSettings\n        auto localSettings{ GetLocalSettings() };\n        localSettings.Values().TryRemove(PendingUpdateKey);\n    }\n\n    IAsyncAction CodePushNativeModule::RestartAppInternal(bool onlyIfUpdateIsPending)\n    {\n        if (m_restartInProgress)\n        {\n            CodePushUtils::Log(L\"Restart request queued until the current restart is completed.\");\n            m_restartQueue.push_back(onlyIfUpdateIsPending);\n        }\n        else if (!m_allowed)\n        {\n            CodePushUtils::Log(L\"Restart request queued until restarts are re-allowed.\");\n            m_restartQueue.push_back(onlyIfUpdateIsPending);\n            co_return;\n        }\n\n        m_restartInProgress = true;\n        if (!onlyIfUpdateIsPending || IsPendingUpdate(L\"\"))\n        {\n            co_await LoadBundle();\n            CodePushUtils::Log(L\"Restarting app.\");\n            co_return;\n        }\n\n        m_restartInProgress = false;\n        if (m_restartQueue.size() > 0)\n        {\n            auto buf{ m_restartQueue[0] };\n            m_restartQueue.erase(m_restartQueue.begin());\n            co_await RestartAppInternal(buf);\n        }\n    }\n\n    /*\n     * When an update failed to apply, this method can be called\n     * to store its hash so that it can be ignored on future\n     * attempts to check the server for an update.\n     */\n    void CodePushNativeModule::SaveFailedUpdate(JsonObject& failedPackage)\n    {\n        if (IsFailedHash(failedPackage.GetNamedString(PackageHashKey)))\n        {\n            return;\n        }\n\n        auto localSettings{ GetLocalSettings() };\n        auto failedUpdates{ localSettings.Values().TryLookup(FailedUpdatesKey).try_as<JsonArray>() };\n        if (failedUpdates == nullptr)\n        {\n            failedUpdates = JsonArray{};\n        }\n\n        failedUpdates.Append(failedPackage);\n        localSettings.Values().Insert(FailedUpdatesKey, box_value(failedUpdates.Stringify()));\n    }\n\n    /*\n     * When an update is installed whose mode isn't Immediate, this method\n     * can be called to store the pending update's metadata (e.g. packageHash)\n     * so that it can be used when the actual update application occurs at a later point.\n     */\n    void CodePushNativeModule::SavePendingUpdate(std::wstring_view packageHash, bool isLoading)\n    {\n        // Since we're not restarting, we need to store the fact that the update\n        // was installed, but hasn't yet become \"active\".\n        auto localSettings{ GetLocalSettings() };\n        JsonObject pendingUpdate{};\n        pendingUpdate.Insert(PendingUpdateHashKey, JsonValue::CreateStringValue(packageHash));\n        pendingUpdate.Insert(PendingUpdateIsLoadingKey, JsonValue::CreateBooleanValue(isLoading));\n        localSettings.Values().Insert(PendingUpdateKey, box_value(pendingUpdate.Stringify()));\n    }\n\n    /*static*/ void CodePushNativeModule::SetHost(const ReactNativeHost& host)\n    {\n        s_host = host;\n    }\n\n    void CodePushNativeModule::Initialize(ReactContext const& reactContext) noexcept\n    {\n        m_context = reactContext;\n        InitializeUpdateAfterRestart();\n    }\n\n    void CodePushNativeModule::GetConstants(winrt::Microsoft::ReactNative::ReactConstantProvider& constants) noexcept\n    {\n        constants.Add(L\"codePushInstallModeImmediate\", CodePushInstallMode::Immediate);\n        constants.Add(L\"codePushInstallModeOnNextRestart\", CodePushInstallMode::OnNextRestart);\n        constants.Add(L\"codePushInstallModeOnNextResume\", CodePushInstallMode::OnNextResume);\n        constants.Add(L\"codePushInstallModeOnNextSuspend\", CodePushInstallMode::OnNextSuspend);\n\n        constants.Add(L\"codePushUpdateStateRunning\", CodePushUpdateState::Running);\n        constants.Add(L\"codePushUpdateStatePending\", CodePushUpdateState::Pending);\n        constants.Add(L\"codePushUpdateStateLatest\", CodePushUpdateState::Latest);\n    }\n\n    /*\n     * This is native-side of the RemotePackage.download method\n     */\n    fire_and_forget CodePushNativeModule::DownloadUpdateAsync(JsonObject updatePackage, bool notifyProgress, ReactPromise<IJsonValue> promise) noexcept\n    {\n        auto binaryBundle{ co_await GetBinaryBundleAsync() };\n        if (binaryBundle != nullptr)\n        {\n            auto modifiedDate{ co_await CodePushUpdateUtils::ModifiedDateStringOfFileAsync(binaryBundle) };\n            updatePackage.Insert(BinaryBundleDateKey, JsonValue::CreateStringValue(modifiedDate));\n        }\n\n        auto publicKey{ CodePushConfig::Current().GetPublicKey() };\n\n        try\n        {\n            co_await CodePushPackage::DownloadPackageAsync(\n                updatePackage,\n                s_javaScriptBundleFileName + BundleExtension,\n                /* publicKey */ publicKey,\n                /* progressCallback */ [=](int64_t expectedContentLength, int64_t receivedContentLength) {\n                    // React-Native-Windows doesn't have a frame observer to my knowledge.\n                    if (notifyProgress)\n                    {\n                        m_latestExpectedContentLength = expectedContentLength;\n                        m_latestReceivedContentLength = receivedContentLength;\n                        DispatchDownloadProgressEvent();\n                    }\n                });\n        }\n        catch (const hresult_error& ex)\n        {\n            SaveFailedUpdate(updatePackage);\n\n            m_didUpdateProgress = false;\n            promise.Reject(ex.message().c_str());\n        }\n\n        auto newPackage{ co_await CodePushPackage::GetPackageAsync(updatePackage.GetNamedString(PackageHashKey)) };\n        if (newPackage == nullptr)\n        {\n            promise.Reject(L\"An error has occurred retreiving the downloaded package.\");\n        }\n        else\n        {\n            promise.Resolve(newPackage);\n        }\n\n        co_return;\n    }\n\n    /*\n     * This is the native side of the CodePush.getConfiguration method. It isn't\n     * currently exposed via the \"react-native-code-push\" module, and is used\n     * internally only by the CodePush.checkForUpdate method in order to get the\n     * app version, as well as the deployment key that was configured in App.cpp.\n     */\n    fire_and_forget CodePushNativeModule::GetConfiguration(ReactPromise<IJsonValue> promise) noexcept \n    {\n        auto configuration{ CodePushConfig::Current().GetConfiguration() };\n        if (isRunningBinaryVersion)\n        {\n            auto errorMessage{ L\"Error: Package hashing is currently unimplemented. Binary hash was not obtained.\" };\n            auto error{ hresult_error(E_NOTIMPL, errorMessage) };\n            CodePushUtils::Log(error);\n            CodePushUtils::Log(L\"Error obtaining hash for binary contents.\");\n            promise.Resolve(configuration);\n            co_return;\n        }\n        promise.Resolve(configuration);\n    }\n\n    /*\n     * This method is the native side of the CodePush.getUpdateMetadata method.\n     */\n    fire_and_forget CodePushNativeModule::GetUpdateMetadataAsync(CodePushUpdateState updateState, ReactPromise<IJsonValue> promise) noexcept \n    {\n        auto package{ co_await CodePushPackage::GetCurrentPackageAsync() };\n        if (package == nullptr)\n        {\n            // The app hasn't downloaded any CodePush updates yet,\n            // so we simply return nil regardless if the user\n            // wanted to retrieve the pending or running update.\n            promise.Resolve(JsonValue::CreateNullValue());\n            co_return;\n        }\n\n        // We have a CodePush update, so let's see if it's currently in a pending state.\n        bool currentUpdateIsPending{ IsPendingUpdate(package.GetNamedString(PackageHashKey)) };\n\n        if (updateState == CodePushUpdateState::Pending && !currentUpdateIsPending) {\n            // The caller wanted a pending update\n            // but there isn't currently one.\n            promise.Resolve(JsonValue::CreateNullValue());\n        }\n        else if (updateState == CodePushUpdateState::Running && currentUpdateIsPending) {\n            // The caller wants the running update, but the current\n            // one is pending, so we need to grab the previous.\n            promise.Resolve(co_await CodePushPackage::GetPreviousPackageAsync());\n        }\n        else {\n            // The current package satisfies the request:\n            // 1) Caller wanted a pending, and there is a pending update\n            // 2) Caller wanted the running update, and there isn't a pending\n            // 3) Caller wants the latest update, regardless if it's pending or not\n            if (isRunningBinaryVersion) {\n                // This only matters in Debug builds. Since we do not clear \"outdated\" updates,\n                // we need to indicate to the JS side that somehow we have a current update on\n                // disk that is not actually running.\n                package.Insert(L\"_isDebugOnly\", JsonValue::CreateBooleanValue(true));\n            }\n\n            // Enable differentiating pending vs. non-pending updates\n            package.Insert(PackageIsPendingKey, JsonValue::CreateBooleanValue(currentUpdateIsPending));\n            promise.Resolve(package);\n        }\n        co_return; \n    }\n\n    /*\n     * This method is the native side of the LocalPackage.install method.\n     */\n    fire_and_forget CodePushNativeModule::InstallUpdateAsync(JsonObject updatePackage, CodePushInstallMode installMode, int minimumBackgroundDuration, ReactPromise<void> promise) noexcept \n    { \n        try\n        {\n            co_await CodePushPackage::InstallPackageAsync(updatePackage, IsPendingUpdate(L\"\"));\n        }\n        catch (const hresult_error& ex)\n        {\n            promise.Reject(ex.message().c_str());\n            co_return;\n        }\n        SavePendingUpdate(updatePackage.GetNamedString(PackageHashKey), false);\n        s_installMode = installMode;\n        if (s_installMode == CodePushInstallMode::OnNextResume || s_installMode == CodePushInstallMode::OnNextSuspend) {\n            // Essentially, for RNW, InstallMode is currently always Immediate\n            auto errorMessage{ L\"Error: ON_NEXT_RESUME and ON_NEXT_SUSPEND install modes are not currently supported.\" };\n            hresult_error error{ E_NOTIMPL, errorMessage };\n            CodePushUtils::Log(error);\n            throw error;\n        }\n\n        // Signal to JS that the update has been applied.\n        promise.Resolve();\n        co_return; \n    }\n\n    /*\n     * This method isn't publicly exposed via the \"react-native-code-push\"\n     * module, and is only used internally to populate the RemotePackage.failedInstall property.\n     */\n    void CodePushNativeModule::IsFailedUpdate(std::wstring packageHash, ReactPromise<bool> promise) noexcept\n    {\n        auto isFailedHash{ IsFailedHash(packageHash) };\n        promise.Resolve(isFailedHash);\n    }\n\n    /*\n     * This method is used to save information about the latest rollback.\n     * This information will be used to decide whether the application\n     * should ignore the update or not.\n     */\n    void CodePushNativeModule::SetLatestRollbackInfo(std::wstring packageHash) noexcept\n    {\n        if (packageHash.empty())\n        {\n            return;\n        }\n\n        auto localSettings{ GetLocalSettings() };\n        JsonObject latestRollbackInfo;\n        auto res{ localSettings.Values().TryLookup(LatestRollbackInfoKey) };\n        if (res != nullptr)\n        {\n            auto infoString{ unbox_value<hstring>(res) };\n            JsonObject::TryParse(infoString, latestRollbackInfo);\n        }\n\n        auto initialRollbackCount{ GetRollbackCountForPackage(packageHash, latestRollbackInfo) };\n        auto count{ initialRollbackCount + 1 };\n        auto currentTimeMillis{ clock::to_time_t(clock::now()) * 1000 };\n\n        latestRollbackInfo.Insert(LatestRollbackCountKey, JsonValue::CreateNumberValue(count));\n        latestRollbackInfo.Insert(LatestRollbackTimeKey, JsonValue::CreateNumberValue(static_cast<double>(currentTimeMillis)));\n        latestRollbackInfo.Insert(LatestRollbackPackageHashKey, JsonValue::CreateStringValue(packageHash));\n\n        localSettings.Values().Insert(LatestRollbackInfoKey, box_value(latestRollbackInfo.Stringify()));\n    }\n\n    /*\n     * This method is used when the app is started to either\n     * initialize a pending update or rollback a faulty update\n     * to the previous version.\n     */\n    IAsyncAction CodePushNativeModule::InitializeUpdateAfterRestart()\n    {\n        if (s_host.InstanceSettings().UseWebDebugger())\n        {\n            co_await ClearDebugUpdates();\n        }\n\n        auto localSettings{ GetLocalSettings() };\n        auto pendingUpdateData{ localSettings.Values().TryLookup(PendingUpdateKey) };\n        if (pendingUpdateData != nullptr)\n        {\n            auto pendingUpdateString{ unbox_value<hstring>(pendingUpdateData) };\n            JsonObject pendingUpdate;\n            auto success{ JsonObject::TryParse(pendingUpdateString, pendingUpdate) };\n            if (success)\n            {\n                m_isFirstRunAfterUpdate = true;\n                auto updateIsLoading{ pendingUpdate.GetNamedBoolean(PendingUpdateIsLoadingKey, false) };\n                if (updateIsLoading)\n                {\n                    // Pending update was initialized, but notifyApplicationReady was not called.\n                    // Therefore, deduce that it is a broken update and rollback.\n                    CodePushUtils::Log(L\"Update did not finish loading the last time, rolling back to a previous version.\");\n                    needToReportRollback = true;\n                    co_await RollbackPackage();\n                }\n                else\n                {\n                    // Mark that we tried to initialize the new update, so that if it crashes,\n                    // we will know that we need to rollback when the app next starts.\n                    SavePendingUpdate(pendingUpdate.GetNamedString(PendingUpdateHashKey, L\"\"), true);\n                }\n            }\n        }\n    }\n\n    /*\n     * This method is used to get information about the latest rollback.\n     * This information will be used to decide whether the application\n     * should ignore the update or not.\n     */\n    void CodePushNativeModule::GetLatestRollbackInfo(ReactPromise<IJsonValue> promise) noexcept \n    {\n        auto localSettings{ GetLocalSettings() };\n        auto res{ localSettings.Values().TryLookup(LatestRollbackInfoKey) };\n        auto infoString{ unbox_value<hstring>(res) };\n        JsonObject latestRollbackInfo;\n        auto success{ JsonObject::TryParse(infoString, latestRollbackInfo) };\n        if (success)\n        {\n            promise.Resolve(latestRollbackInfo);\n        }\n        else\n        {\n            promise.Resolve(JsonValue::CreateNullValue());\n        }\n    }\n\n    /*\n     * This method isn't publicly exposed via the \"react-native-code-push\"\n     * module, and is only used internally to populate the LocalPackage.isFirstRun property.\n     */\n    fire_and_forget CodePushNativeModule::IsFirstRun(std::wstring packageHash, ReactPromise<bool> promise) noexcept\n    {\n        auto isFirstRun = m_isFirstRunAfterUpdate\n            && !packageHash.empty()\n            && packageHash == co_await CodePushPackage::GetCurrentPackageHashAsync();\n\n        promise.Resolve(isFirstRun);\n    }\n\n    /*\n     * This method is the native side of the CodePush.notifyApplicationReady() method.\n     */\n    void CodePushNativeModule::NotifyApplicationReady(ReactPromise<IJsonValue> promise) noexcept\n    {\n        RemovePendingUpdate();\n        promise.Resolve(JsonValue::CreateNullValue());\n    }\n\n    void CodePushNativeModule::Allow(ReactPromise<JSValue> promise) noexcept \n    {\n        CodePushUtils::Log(L\"Re-allowing restarts.\");\n        m_allowed = true;\n\n        if (m_restartQueue.size() > 0)\n        {\n            CodePushUtils::Log(L\"Executing pending restart.\");\n            auto buf{ m_restartQueue[0] };\n            m_restartQueue.erase(m_restartQueue.begin());\n            RestartAppInternal(buf);\n        }\n\n        promise.Resolve(JSValue::Null);\n    }\n\n    void CodePushNativeModule::ClearPendingRestart() noexcept \n    {\n        m_restartQueue.clear();\n    }\n\n    void CodePushNativeModule::Disallow(ReactPromise<JSValue> promise) noexcept\n    {\n        CodePushUtils::Log(L\"Disallowing restarts.\");\n        m_allowed = false;\n        promise.Resolve(JSValue::Null);\n    }\n\n    /*\n     * This method is the native side of the CodePush.restartApp() method.\n     */\n    fire_and_forget CodePushNativeModule::RestartApp(bool onlyIfUpdateIsPending, ReactPromise<JSValue> promise) noexcept \n    {\n        co_await RestartAppInternal(onlyIfUpdateIsPending);\n        promise.Resolve(JSValue::Null);\n    }\n\n    /*\n     * This method clears CodePush's downloaded updates.\n     * It is needed to switch to a different deployment if the current deployment is more recent.\n     * Note: we dont recommend to use this method in scenarios other than that (CodePush will call this method\n     * automatically when needed in other cases) as it could lead to unpredictable behavior.\n     */\n    fire_and_forget CodePushNativeModule::ClearUpdates() noexcept \n    {\n        co_await ClearUpdatesStaticAsync();\n    }\n\n    /*\n     * This method is the native side of the CodePush.downloadAndReplaceCurrentBundle()\n     * method, which replaces the current bundle with the one downloaded from\n     * removeBundleUrl. It is only to be used during tests and no-ops if the test\n     * configuration flag is not set.\n     */\n    fire_and_forget CodePushNativeModule::DownloadAndReplaceCurrentBundle(std::wstring remoteBundleUrl) noexcept \n    {\n        auto errorMessage{ L\"Error: DownloadAndReplaceCurrentBundle is not currently implmented\" };\n        hresult_error error{ E_NOTIMPL, errorMessage };\n        CodePushUtils::Log(error);\n        throw error;\n    }\n\n    /*\n     * This method is checks if a new status update exists (new version was installed,\n     * or an update failed) and return its details (version label, status).\n     */\n    fire_and_forget CodePushNativeModule::GetNewStatusReportAsync(ReactPromise<IJsonValue> promise) noexcept \n    {\n        if (needToReportRollback)\n        {\n            needToReportRollback = false;\n            auto localSettings{ GetLocalSettings() };\n            auto failedUpdatesData{ localSettings.Values().TryLookup(FailedUpdatesKey) };\n            if (failedUpdatesData != nullptr)\n            {\n                auto failedUpdatesString{ unbox_value<hstring>(failedUpdatesData) };\n                JsonArray failedUpdates;\n                auto success{ JsonArray::TryParse(failedUpdatesString, failedUpdates) };\n                if (success)\n                {\n                    auto lastFailedPackage{ failedUpdates.GetObjectAt(failedUpdates.Size() - 1) };\n                    if (lastFailedPackage != nullptr)\n                    {\n                        promise.Resolve(CodePushTelemetryManager::GetRollbackReport(lastFailedPackage));\n                        co_return;\n                    }\n                }\n            }\n        }\n        else if (m_isFirstRunAfterUpdate)\n        {\n            auto currentPackage = co_await CodePushPackage::GetCurrentPackageAsync();\n            if (currentPackage != nullptr)\n            {\n                promise.Resolve(CodePushTelemetryManager::GetUpdateReport(currentPackage));\n                co_return;\n            }\n        }\n        else if (isRunningBinaryVersion)\n        {\n            auto appVersionString{ CodePushConfig::Current().GetAppVersion() };\n            promise.Resolve(CodePushTelemetryManager::GetBinaryUpdateReport(appVersionString));\n            co_return;\n        }\n        else\n        {\n            auto retryStatusReport{ CodePushTelemetryManager::GetRetryStatusReport() };\n            if (retryStatusReport != nullptr)\n            {\n                promise.Resolve(retryStatusReport);\n                co_return;\n            }\n        }\n\n        promise.Resolve(JsonValue::CreateNullValue());\n        co_return;\n    }\n\n    void CodePushNativeModule::RecordStatusReported(JsonObject statusReport) noexcept \n    {\n        CodePushTelemetryManager::RecordStatusReported(statusReport);\n    }\n\n    void CodePushNativeModule::SaveStatusReportForRetry(JsonObject statusReport) noexcept \n    {\n        CodePushTelemetryManager::SaveStatusReportForRetry(statusReport);\n    }\n\n} // namespace CodePush\n\n// Helper functions for reading and sending JsonValues to and from JavaScript\nnamespace winrt::Microsoft::ReactNative\n{\n    using namespace winrt::Windows::Data::Json;\n\n    void WriteValue(IJSValueWriter const& writer, IJsonValue const& value) noexcept\n    {\n        if (value == nullptr)\n        {\n            writer.WriteNull();\n        }\n        else\n        {\n            switch (value.ValueType())\n            {\n            case JsonValueType::Object:\n                writer.WriteObjectBegin();\n                for (const auto& pair : value.GetObject())\n                {\n                    writer.WritePropertyName(pair.Key());\n                    WriteValue(writer, pair.Value());\n                }\n                writer.WriteObjectEnd();\n                break;\n            case JsonValueType::Array:\n                writer.WriteArrayBegin();\n                for (const auto& elem : value.GetArray())\n                {\n                    WriteValue(writer, elem);\n                }\n                writer.WriteArrayEnd();\n                break;\n            case JsonValueType::Boolean:\n                writer.WriteBoolean(value.GetBoolean());\n                break;\n            case JsonValueType::Number:\n                writer.WriteDouble(value.GetNumber());\n                break;\n            case JsonValueType::String:\n                writer.WriteString(value.GetString());\n                break;\n            case JsonValueType::Null:\n                writer.WriteNull();\n                break;\n            }\n        }\n    }\n\n    void ReadValue(IJSValueReader const& reader, /*out*/ JsonObject& value) noexcept\n    {\n        if (reader.ValueType() == JSValueType::Object)\n        {\n            hstring propertyName;\n            while (reader.GetNextObjectProperty(propertyName))\n            {\n                value.Insert(propertyName, ReadValue<IJsonValue>(reader));\n            }\n        }\n    }\n\n    void ReadValue(IJSValueReader const& reader, /*out*/ IJsonValue& value) noexcept\n    {\n        if (reader.ValueType() == JSValueType::Object)\n        {\n            JsonObject valueObject;\n            hstring propertyName;\n            while (reader.GetNextObjectProperty(propertyName))\n            {\n                valueObject.Insert(propertyName, ReadValue<IJsonValue>(reader));\n            }\n            value = valueObject;\n        }\n        else if (reader.ValueType() == JSValueType::Array)\n        {\n            JsonArray valueArray;\n            while (reader.GetNextArrayItem())\n            {\n                valueArray.Append(ReadValue<IJsonValue>(reader));\n            }\n            value = valueArray;\n        }\n        else\n        {\n            switch (reader.ValueType())\n            {\n            case JSValueType::Boolean:\n                value = JsonValue::CreateBooleanValue(reader.GetBoolean());\n                break;\n            case JSValueType::Double:\n                value = JsonValue::CreateNumberValue(reader.GetDouble());\n                break;\n            case JSValueType::Int64:\n                value = JsonValue::CreateNumberValue(static_cast<double>(reader.GetInt64()));\n                break;\n            case JSValueType::String:\n                value = JsonValue::CreateStringValue(reader.GetString());\n                break;\n            case JSValueType::Null:\n                value = JsonValue::CreateNullValue();\n                break;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "windows/CodePush/CodePushNativeModule.h",
    "content": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\n#pragma once\n\n#include \"NativeModules.h\"\n#include \"winrt/Windows.Data.Json.h\"\n#include \"winrt/Windows.Storage.h\"\n\n#include \"CodePushConfig.h\"\n\n// Helper functions for reading and sending JsonValues to and from JavaScript\nnamespace winrt::Microsoft::ReactNative\n{\n\tvoid ReadValue(IJSValueReader const& reader, /*out*/ Windows::Data::Json::JsonObject& value) noexcept;\n\tvoid ReadValue(IJSValueReader const& reader, /*out*/ Windows::Data::Json::IJsonValue& value) noexcept;\n}\n\nnamespace Microsoft::CodePush::ReactNative\n{\n\tREACT_MODULE(CodePushNativeModule, L\"CodePush\");\n\tstruct CodePushNativeModule\n\t{\n\t\tenum class CodePushInstallMode\n\t\t{\n\t\t\tImmediate = 0,\n\t\t\tOnNextRestart = 1,\n\t\t\tOnNextResume = 2,\n\t\t\tOnNextSuspend = 3\n\t\t};\n\n\t\tenum class CodePushUpdateState\n\t\t{\n\t\t\tRunning = 0,\n\t\t\tPending = 1,\n\t\t\tLatest = 2\n\t\t};\n\n\t\tstatic winrt::Windows::Foundation::IAsyncAction LoadBundle();\n\t\tstatic void SetHost(const winrt::Microsoft::ReactNative::ReactNativeHost& host);\n\n\t\tstatic winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Storage::StorageFile> GetBinaryBundleAsync();\n\t\tstatic winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Storage::StorageFile> GetBundleFileAsync();\n\n\t\tstatic winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Storage::StorageFolder> GetBundleAssetsFolderAsync();\n\t\tstatic winrt::Windows::Storage::StorageFolder GetLocalStorageFolder();\n\t\tstatic winrt::Windows::Storage::ApplicationDataContainer GetLocalSettings();\n\n\t\tvoid OverrideAppVersion(std::wstring_view appVersion);\n\t\tvoid SetDeploymentKey(std::wstring_view deploymentKey);\n\n\t\tbool IsFailedHash(std::wstring_view packageHash);\n\n\t\twinrt::Windows::Data::Json::JsonObject GetRollbackInfo();\n\t\tint GetRollbackCountForPackage(\n\t\t\tstd::wstring_view packageHash,\n\t\t\tconst winrt::Windows::Data::Json::JsonObject& latestRollbackInfo);\n\n\t\tstatic bool IsPendingUpdate(std::wstring_view packageHash);\n\n\t\twinrt::Windows::Foundation::IAsyncAction ClearDebugUpdates();\n\n\t\tREACT_INIT(Initialize);\n\t\tvoid Initialize(winrt::Microsoft::ReactNative::ReactContext const& reactContext) noexcept;\n\n\t\tREACT_CONSTANT_PROVIDER(GetConstants);\n\t\tvoid GetConstants(winrt::Microsoft::ReactNative::ReactConstantProvider& constants) noexcept;\n\n\t\t/*\n\t\t * This is native-side of the JavaScript RemotePackage.download method\n\t\t */\n\t\tREACT_METHOD(DownloadUpdateAsync, L\"downloadUpdate\");\n\t\twinrt::fire_and_forget DownloadUpdateAsync(\n\t\t\twinrt::Windows::Data::Json::JsonObject updatePackage,\n\t\t\tbool notifyProgress,\n\t\t\twinrt::Microsoft::ReactNative::ReactPromise<winrt::Windows::Data::Json::IJsonValue> promise) noexcept;\n\n\t\t/*\n\t\t * This is the native side of the CodePush.getConfiguration method. It isn't\n\t\t * currently exposed via the \"react-native-code-push\" module, and is used\n\t\t * internally only by the CodePush.checkForUpdate method in order to get the\n\t\t * app version, as well as the deployment key that was configured in the Info.plist file.\n\t\t */\n\t\tREACT_METHOD(GetConfiguration, L\"getConfiguration\");\n\t\twinrt::fire_and_forget GetConfiguration(winrt::Microsoft::ReactNative::ReactPromise<winrt::Windows::Data::Json::IJsonValue> promise) noexcept;\n\n\t\t/*\n\t\t * This method is the native side of the CodePush.getUpdateMetadata method.\n\t\t */\n\t\tREACT_METHOD(GetUpdateMetadataAsync, L\"getUpdateMetadata\");\n\t\twinrt::fire_and_forget GetUpdateMetadataAsync(\n\t\t\tCodePushUpdateState updateState,\n\t\t\twinrt::Microsoft::ReactNative::ReactPromise<winrt::Windows::Data::Json::IJsonValue> promise) noexcept;\n\n\t\t/*\n\t\t * This method is the native side of the LocalPackage.install method.\n\t\t */\n\t\tREACT_METHOD(InstallUpdateAsync, L\"installUpdate\");\n\t\twinrt::fire_and_forget InstallUpdateAsync(\n\t\t\twinrt::Windows::Data::Json::JsonObject updatePackage,\n\t\t\tCodePushInstallMode installMode,\n\t\t\tint minimumBackgroundDuration,\n\t\t\twinrt::Microsoft::ReactNative::ReactPromise<void> promise) noexcept;\n\n\t\t/*\n\t\t * This method isn't publicly exposed via the \"react-native-code-push\"\n\t\t * module, and is only used internally to populate the RemotePackage.failedInstall property.\n\t\t */\n\t\tREACT_METHOD(IsFailedUpdate, L\"isFailedUpdate\");\n\t\tvoid IsFailedUpdate(\n\t\t\tstd::wstring packageHash,\n\t\t\twinrt::Microsoft::ReactNative::ReactPromise<bool> promise) noexcept;\n\n\t\tREACT_METHOD(SetLatestRollbackInfo, L\"setLatestRollbackInfo\");\n\t\tvoid SetLatestRollbackInfo(std::wstring packageHash) noexcept;\n\n\t\tREACT_METHOD(GetLatestRollbackInfo, L\"getLatestRollbackInfo\");\n\t\tvoid GetLatestRollbackInfo(winrt::Microsoft::ReactNative::ReactPromise<winrt::Windows::Data::Json::IJsonValue> promise) noexcept;\n\n\t\t/*\n\t\t * This method isn't publicly exposed via the \"react-native-code-push\"\n\t\t * module, and is only used internally to populate the LocalPackage.isFirstRun property.\n\t\t */\n\t\tREACT_METHOD(IsFirstRun, L\"isFirstRun\");\n\t\twinrt::fire_and_forget IsFirstRun(\n\t\t\tstd::wstring packageHash,\n\t\t\twinrt::Microsoft::ReactNative::ReactPromise<bool> promise) noexcept;\n\n\t\t/*\n\t\t * This method is the native side of the CodePush.notifyApplicationReady() method.\n\t\t */\n\t\tREACT_METHOD(NotifyApplicationReady, L\"notifyApplicationReady\");\n\t\tvoid NotifyApplicationReady(winrt::Microsoft::ReactNative::ReactPromise<winrt::Windows::Data::Json::IJsonValue> promise) noexcept;\n\n\t\tREACT_METHOD(Allow, L\"allow\");\n\t\tvoid Allow(winrt::Microsoft::ReactNative::ReactPromise<winrt::Microsoft::ReactNative::JSValue> promise) noexcept;\n\n\t\tREACT_METHOD(ClearPendingRestart, L\"clearPendingRestart\");\n\t\tvoid ClearPendingRestart() noexcept;\n\n\t\tREACT_METHOD(Disallow, L\"disallow\");\n\t\tvoid Disallow(winrt::Microsoft::ReactNative::ReactPromise<winrt::Microsoft::ReactNative::JSValue> promise) noexcept;\n\n\t\t/*\n\t\t * This method is the native side of the CodePush.restartApp() method.\n\t\t */\n\t\tREACT_METHOD(RestartApp, L\"restartApp\");\n\t\twinrt::fire_and_forget RestartApp(\n\t\t\tbool onlyIfUpdateIsPending,\n\t\t\twinrt::Microsoft::ReactNative::ReactPromise<winrt::Microsoft::ReactNative::JSValue> promise) noexcept;\n\n\t\t/*\n\t\t * This method clears CodePush's downloaded updates.\n\t\t * It is needed to switch to a different deployment if the current deployment is more recent.\n\t\t * Note: we dont recommend to use this method in scenarios other than that (CodePush will call this method\n\t\t * automatically when needed in other cases) as it could lead to unpredictable behavior.\n\t\t */\n\t\tREACT_METHOD(ClearUpdates, L\"clearUpdates\");\n\t\twinrt::fire_and_forget ClearUpdates() noexcept;\n\n\t\t/*\n\t\t * This method is the native side of the CodePush.downloadAndReplaceCurrentBundle()\n\t\t * method, which replaces the current bundle with the one downloaded from\n\t\t * removeBundleUrl. It is only to be used during tests and no-ops if the test\n\t\t * configuration flag is not set.\n\t\t */\n\t\tREACT_METHOD(DownloadAndReplaceCurrentBundle, L\"downloadAndReplaceCurrentBundle\");\n\t\twinrt::fire_and_forget DownloadAndReplaceCurrentBundle(std::wstring remoteBundleUrl) noexcept;\n\n\t\t/*\n\t\t * This method is checks if a new status update exists (new version was installed,\n\t\t * or an update failed) and return its details (version label, status).\n\t\t */\n\t\tREACT_METHOD(GetNewStatusReportAsync, L\"getNewStatusReport\");\n\t\twinrt::fire_and_forget GetNewStatusReportAsync(winrt::Microsoft::ReactNative::ReactPromise<winrt::Windows::Data::Json::IJsonValue> promise) noexcept;\n\n\t\tREACT_METHOD(RecordStatusReported, L\"recordStatusReported\");\n\t\tvoid RecordStatusReported(winrt::Windows::Data::Json::JsonObject statusReport) noexcept;\n\n\t\tREACT_METHOD(SaveStatusReportForRetry, L\"saveStatusReportForRetry\");\n\t\tvoid SaveStatusReportForRetry(winrt::Windows::Data::Json::JsonObject statusReport) noexcept;\n\n\tprivate:\n\t\tbool m_isFirstRunAfterUpdate{ false };\n\t\tstatic CodePushInstallMode s_installMode;\n\n\t\t// Used to coordinate the dispatching of download progress events to JS.\n\t\tuint64_t m_latestExpectedContentLength{ 0 };\n\t\tuint64_t m_latestReceivedContentLength{ 0 };\n\t\tbool m_didUpdateProgress{ false };\n\n\t\tbool m_allowed{ true };\n\t\tbool m_restartInProgress{ false };\n\t\tstd::vector<uint8_t> m_restartQueue;\n\n\t\tstatic constexpr std::wstring_view BundleExtension{ L\".bundle\" };\n\t\tstatic winrt::hstring s_javaScriptBundleFileName;\n\n\t\t// These constants represent emitted events\n\t\tstatic constexpr std::wstring_view DownloadProgressEvent{ L\"CodePushDownloadProgress\" };\n\n\t\t// These constants represent valid deployment statuses\n\t\tstatic constexpr std::wstring_view DeploymentFailed{ L\"DeploymentFailed\" };\n\t\tstatic constexpr std::wstring_view DeploymentSucceeded{ L\"DeploymentSucceeded\" };\n\n\t\t// These keys represent the names we use to store data in LocalSettings\n\t\tstatic constexpr std::wstring_view FailedUpdatesKey{ L\"CODE_PUSH_FAILED_UPDATES\" };\n\t\tstatic constexpr std::wstring_view PendingUpdateKey{ L\"CODE_PUSH_PENDING_UPDATE\" };\n\n\t\t// These keys are already \"namespaced\" by the PendingUpdateKey, so\n\t\t// their values don't need to be obfuscated to prevent collision with app data\n\t\tstatic constexpr std::wstring_view PendingUpdateHashKey{ L\"hash\" };\n\t\tstatic constexpr std::wstring_view PendingUpdateIsLoadingKey{ L\"isLoading\" };\n\n\t\t// These keys are used to inspect/augment the metadata\n\t\t// that is associated with an update's package.\n\t\tstatic constexpr std::wstring_view AppVersionKey{ L\"appVersion\" };\n\t\tstatic constexpr std::wstring_view BinaryBundleDateKey{ L\"binaryDate\" }; // The date of the BUILD -> the modified date of the executable\n\t\tstatic constexpr std::wstring_view PackageHashKey{ L\"packageHash\" };\n\t\tstatic constexpr std::wstring_view PackageIsPendingKey{ L\"isPending\" };\n\n\t\tstatic bool isRunningBinaryVersion;\n\t\tstatic bool needToReportRollback;\n\n\t\tstatic winrt::Microsoft::ReactNative::ReactNativeHost s_host;\n\t\twinrt::Microsoft::ReactNative::ReactContext m_context;\n\n\t\t// These keys represent the names we use to store information about the latest rollback\n\t\tstatic constexpr std::wstring_view LatestRollbackInfoKey{ L\"LATEST_ROLLBACK_INFO\" };\n\t\tstatic constexpr std::wstring_view LatestRollbackPackageHashKey{ L\"packageHash\" };\n\t\tstatic constexpr std::wstring_view LatestRollbackTimeKey{ L\"time\" };\n\t\tstatic constexpr std::wstring_view LatestRollbackCountKey{ L\"count\" };\n\n\t\t// Bool that keeps track of whether the app has been initialized at least once.\n\t\tstatic bool s_initialized;\n\n\t\tstatic winrt::Windows::Foundation::IAsyncAction ClearUpdatesStaticAsync();\n\t\tvoid DispatchDownloadProgressEvent();\n\t\twinrt::Windows::Foundation::IAsyncAction InitializeUpdateAfterRestart();\n\t\twinrt::Windows::Foundation::IAsyncAction RollbackPackage();\n\t\tstatic void RemoveFailedUpdates();\n\t\tstatic void RemovePendingUpdate();\n\t\twinrt::Windows::Foundation::IAsyncAction RestartAppInternal(bool onlyIfUpdateIsPending);\n\t\tvoid SaveFailedUpdate(winrt::Windows::Data::Json::JsonObject& failedPackage);\n\t\tvoid SavePendingUpdate(std::wstring_view packageHash, bool isLoading);\n\t};\n}\n"
  },
  {
    "path": "windows/CodePush/CodePushPackage.cpp",
    "content": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\n#include \"pch.h\"\n\n#include \"CodePushDownloadHandler.h\"\n#include \"CodePushNativeModule.h\"\n#include \"CodePushPackage.h\"\n#include \"CodePushUtils.h\"\n#include \"CodePushUpdateUtils.h\"\n#include \"FileUtils.h\"\n\n#include <winrt/Windows.Storage.h>\n#include <winrt/Windows.Storage.Streams.h>\n#include <winrt/Windows.Foundation.h>\n\n#include <functional>\n\nnamespace Microsoft::CodePush::ReactNative\n{\n    using namespace winrt;\n    using namespace Windows::Data::Json;\n    using namespace Windows::Foundation;\n    using namespace Windows::Storage;\n    using namespace Windows::Storage::Streams;\n\n    /*static*/ IAsyncAction CodePushPackage::ClearUpdatesAsync()\n    {\n        auto codePushFolder{ co_await GetCodePushFolderAsync() };\n        codePushFolder.DeleteAsync();\n    }\n\n    /*static*/ IAsyncAction CodePushPackage::DownloadPackageAsync(\n        JsonObject& updatePackage,\n        std::wstring_view expectedBundleFileName,\n        std::wstring_view publicKey,\n        std::function<void(int64_t, int64_t)> progressCallback)\n    {\n        auto newUpdateHash{ updatePackage.GetNamedString(L\"packageHash\") };\n        auto codePushFolder{ co_await GetCodePushFolderAsync() };\n\n        auto downloadFile{ co_await codePushFolder.CreateFileAsync(DownloadFileName, CreationCollisionOption::ReplaceExisting) };\n\n        CodePushDownloadHandler downloadHandler{\n            downloadFile,\n            progressCallback };\n\n        auto isZip{ co_await downloadHandler.Download(updatePackage.GetNamedString(L\"downloadUrl\")) };\n\n        StorageFolder newUpdateFolder{ co_await codePushFolder.CreateFolderAsync(newUpdateHash, CreationCollisionOption::ReplaceExisting) };\n        StorageFile newUpdateMetadataFile{ nullptr };\n        auto mutableUpdatePackage{ updatePackage };\n        if (isZip)\n        {\n            auto unzippedFolder{ co_await codePushFolder.CreateFolderAsync(UnzippedFolderName, CreationCollisionOption::ReplaceExisting) };\n            co_await FileUtils::UnzipAsync(downloadFile, unzippedFolder);\n            downloadFile.DeleteAsync();\n\n            auto isDiffUpdate{ false };\n\n            auto diffManifestFile{ (co_await unzippedFolder.TryGetItemAsync(DiffManifestFileName)).try_as<StorageFile>() };\n            if (diffManifestFile != nullptr)\n            {\n                isDiffUpdate = true;\n            }\n\n            if (isDiffUpdate)\n            {\n                // Copy the current package to the new package.\n                auto currentPackageFolder{ co_await GetCurrentPackageFolderAsync() };\n\n                if (currentPackageFolder == nullptr)\n                {\n                    // Currently running the binary version, copy files from the bundled resources\n                    auto newUpdateCodePushFolder{ co_await newUpdateFolder.CreateFolderAsync(CodePushUpdateUtils::ManifestFolderPrefix) };\n\n                    auto binaryAssetsFolder{ co_await CodePushNativeModule::GetBundleAssetsFolderAsync() };\n                    auto newUpdateAssetsFolder{ co_await newUpdateCodePushFolder.CreateFolderAsync(CodePushUpdateUtils::AssetsFolderName) };\n                    CodePushUpdateUtils::CopyEntriesInFolderAsync(binaryAssetsFolder, newUpdateAssetsFolder);\n\n                    auto binaryBundleFile{ co_await CodePushNativeModule::GetBinaryBundleAsync() };\n                    co_await binaryBundleFile.CopyAsync(newUpdateCodePushFolder);\n                }\n                else\n                {\n                    // Copy the contents of the current package to the new package. (how are conflicts resolved?)\n                    co_await CodePushUpdateUtils::CopyEntriesInFolderAsync(currentPackageFolder, newUpdateFolder);\n                }\n\n                auto manifestContent{ co_await FileIO::ReadTextAsync(diffManifestFile, UnicodeEncoding::Utf8) };\n                auto manifestJson{ JsonObject::Parse(manifestContent) };\n                auto deletedFiles{ manifestJson.TryLookup(L\"deletedFiles\") };\n                auto deletedFilesArray{ deletedFiles.try_as<JsonArray>() };\n\n                if (deletedFilesArray != nullptr)\n                {\n                    for (const auto& deletedFileName : deletedFilesArray)\n                    {\n                        auto fileToDelete{ (co_await newUpdateFolder.TryGetItemAsync(deletedFileName.GetString())).try_as<StorageFile>() };\n                        if (fileToDelete != nullptr)\n                        {\n                            co_await fileToDelete.DeleteAsync();\n                        }\n                    }\n                }\n\n                co_await diffManifestFile.DeleteAsync();\n            }\n\n            co_await CodePushUpdateUtils::CopyEntriesInFolderAsync(unzippedFolder, newUpdateFolder);\n            co_await unzippedFolder.DeleteAsync();\n\n            auto relativeBundlePath{ co_await FileUtils::FindFilePathAsync(newUpdateFolder, expectedBundleFileName) };\n            if (!relativeBundlePath.empty())\n            {\n                mutableUpdatePackage.Insert(RelativeBundlePathKey, JsonValue::CreateStringValue(relativeBundlePath));\n            }\n            else\n            {\n                auto errorMessage{ L\"Error: Unable to find JS bundle in downloaded package.\" };\n                hresult_error error{ E_INVALIDARG, errorMessage };\n                CodePushUtils::Log(error);\n                throw error;\n            }\n\n            auto newUpdateMetadata{ co_await newUpdateFolder.TryGetItemAsync(UpdateMetadataFileName) };\n            if (newUpdateMetadata != nullptr)\n            {\n                co_await newUpdateMetadata.DeleteAsync();\n            }\n\n            CodePushUtils::Log((isDiffUpdate) ? L\"Applying diff update.\" : L\"Applying full update.\");\n            auto isSignatureVerificationEnabled{ !publicKey.empty() };\n\n            auto signatureFile{ co_await CodePushUpdateUtils::GetSignatureFileAsync(newUpdateFolder) };\n            auto isSignatureAppearedInBundle{ signatureFile != nullptr };\n\n            if (isSignatureVerificationEnabled)\n            {\n                if (isSignatureAppearedInBundle)\n                {\n                    auto errorMessage{ L\"Error: Signature Verification is not currently supported.\" };\n                    hresult_error error{ E_NOTIMPL, errorMessage };\n                    CodePushUtils::Log(error);\n                    throw error;\n                }\n                else\n                {\n                    auto errorMessage{ L\"Error! Public key was provided but there is no JWT signature within app bundle to verify \" \\\n                                L\"Possible reasons, why that might happen: \\n\" \\\n                                L\"1. You've been released CodePush bundle update using a version of the CodePush CLI that does not support code signing.\\n\" \\\n                                L\"2. You've been released CodePush bundle update without providing --privateKeyPath option.\" };\n                    hresult_error error{ E_FAIL, errorMessage };\n                    CodePushUtils::Log(error);\n                    throw error;\n                }\n            }\n            else\n            {\n                bool needToVerifyHash;\n                if (isSignatureAppearedInBundle)\n                {\n                    CodePushUtils::Log(L\"Warning! JWT signature exists in codepush update but code integrity check couldn't be performed\" \\\n                        L\" because there is no public key configured. \" \\\n                        L\"Please ensure that a public key is properly configured within your application.\");\n                    needToVerifyHash = true;\n                }\n                else\n                {\n                    needToVerifyHash = isDiffUpdate;\n                }\n\n                if (needToVerifyHash)\n                {\n                    auto errorMessage{ L\"Error: package content verification is not currently supported.\" };\n                    hresult_error error{ E_NOTIMPL, errorMessage };\n                    CodePushUtils::Log(error);\n                }\n            }\n        }\n        else\n        {\n            co_await downloadFile.MoveAsync(newUpdateFolder, UpdateBundleFileName, NameCollisionOption::ReplaceExisting);\n        }\n\n        newUpdateMetadataFile = co_await newUpdateFolder.CreateFileAsync(UpdateMetadataFileName, CreationCollisionOption::ReplaceExisting);\n\n        auto packageJsonString{ mutableUpdatePackage.Stringify() };\n        co_await FileIO::WriteTextAsync(newUpdateMetadataFile, packageJsonString);\n\n        co_return;\n    }\n\n    /*static*/ IAsyncOperation<StorageFolder> CodePushPackage::GetCodePushFolderAsync()\n    {\n        auto localStorage{ CodePushNativeModule::GetLocalStorageFolder() };\n        auto codePushFolder{ co_await localStorage.CreateFolderAsync(L\"CodePush\", CreationCollisionOption::OpenIfExists) };\n        co_return codePushFolder;\n    }\n\n    /*static*/ IAsyncOperation<JsonObject> CodePushPackage::GetCurrentPackageAsync()\n    {\n        auto packageHash{ co_await GetCurrentPackageHashAsync() };\n        if (packageHash.empty())\n        {\n            co_return nullptr;\n        }\n        co_return co_await GetPackageAsync(packageHash);\n    }\n\n    /*static*/ IAsyncOperation<StorageFile> CodePushPackage::GetCurrentPackageBundleAsync()\n    {\n        auto packageFolder{ co_await GetCurrentPackageFolderAsync() };\n        if (packageFolder == nullptr)\n        {\n            co_return nullptr;\n        }\n\n        auto currentPackage{ co_await GetCurrentPackageAsync() };\n        if (currentPackage == nullptr)\n        {\n            co_return nullptr;\n        }\n\n        auto relativeBundlePath{ currentPackage.GetNamedString(RelativeBundlePathKey, L\"\") };\n        if (!relativeBundlePath.empty())\n        {\n            auto currentBundle{ (co_await packageFolder.TryGetItemAsync(relativeBundlePath)).try_as<StorageFile>() };\n            co_return currentBundle;\n        }\n\n        co_return nullptr;\n    }\n\n    /*static*/ IAsyncOperation<StorageFolder> CodePushPackage::GetCurrentPackageFolderAsync()\n    {\n        auto info{ co_await GetCurrentPackageInfoAsync() };\n        if (info == nullptr)\n        {\n            return nullptr;\n        }\n\n        auto packageHash{ info.GetNamedString(L\"currentPackage\", L\"\") };\n        if (packageHash.empty())\n        {\n            return nullptr;\n        }\n\n        auto codePushFolder{ co_await GetCodePushFolderAsync() };\n        auto packageFolder{ (co_await codePushFolder.TryGetItemAsync(packageHash)).try_as<StorageFolder>() };\n        co_return packageFolder;\n    }\n\n    /*static*/ IAsyncOperation<hstring> CodePushPackage::GetCurrentPackageHashAsync()\n    {\n        auto info{ co_await GetCurrentPackageInfoAsync() };\n        if (info == nullptr)\n        {\n            co_return L\"\";\n        }\n        auto currentPackage{ info.TryLookup(L\"currentPackage\") };\n        if (currentPackage == nullptr)\n        {\n            co_return L\"\";\n        }\n        co_return currentPackage.GetString();\n    }\n\n    /*static*/ IAsyncOperation<JsonObject> CodePushPackage::GetCurrentPackageInfoAsync()\n    {\n        try\n        {\n            auto statusFile{ co_await GetStatusFileAsync() };\n            if (statusFile == nullptr)\n            {\n                co_return JsonObject{};\n            }\n            auto content{ co_await FileIO::ReadTextAsync(statusFile) };\n            JsonObject json;\n            auto success{ JsonObject::TryParse(content, json) };\n            if (!success)\n            {\n                co_return nullptr;\n            }\n            co_return json;\n        }\n        catch (...)\n        {\n            // Either the file does not exist or does not contain valid JSON\n            co_return nullptr;\n        }\n        co_return nullptr;\n    }\n\n    /*static*/ IAsyncOperation<JsonObject> CodePushPackage::GetPreviousPackageAsync()\n    {\n        auto packageHash{ co_await GetPreviousPackageHashAsync() };\n        if (packageHash.empty())\n        {\n            co_return nullptr;\n        }\n        co_return co_await GetPackageAsync(packageHash);\n    }\n\n    /*static*/ IAsyncOperation<hstring> CodePushPackage::GetPreviousPackageHashAsync()\n    {\n        auto info{ co_await GetCurrentPackageInfoAsync() };\n        if (info == nullptr)\n        {\n            co_return L\"\";\n        }\n        auto previousHash{ info.TryLookup(L\"previousPackage\") };\n        if (previousHash == nullptr)\n        {\n            co_return L\"\";\n        }\n        co_return previousHash.GetString();\n    }\n\n    /*static*/ IAsyncOperation<JsonObject> CodePushPackage::GetPackageAsync(std::wstring_view packageHash)\n    {\n        auto updateDirectory{ co_await GetPackageFolderAsync(packageHash) };\n        if (updateDirectory != nullptr)\n        {\n            auto updateMetadataFile{ (co_await updateDirectory.TryGetItemAsync(UpdateMetadataFileName)).try_as<StorageFile>() };\n            if (updateMetadataFile != nullptr)\n            {\n                auto updateMetadataString{ co_await FileIO::ReadTextAsync(updateMetadataFile) };\n                JsonObject updateMetadata;\n                auto success{ JsonObject::TryParse(updateMetadataString, updateMetadata) };\n                if (success)\n                {\n                    co_return updateMetadata;\n                }\n            }\n        }\n        co_return nullptr;\n    }\n\n    /*static*/ IAsyncOperation<StorageFolder> CodePushPackage::GetPackageFolderAsync(std::wstring_view packageHash)\n    {\n        auto codePushFolder{ co_await GetCodePushFolderAsync() };\n        co_return (co_await codePushFolder.TryGetItemAsync(packageHash)).try_as<StorageFolder>();\n    }\n\n    /*static*/ IAsyncOperation<bool> CodePushPackage::InstallPackageAsync(JsonObject updatePackage, bool removePendingUpdate)\n    {\n        auto packageHash{ updatePackage.GetNamedString(L\"packageHash\") };\n        auto info{ co_await GetCurrentPackageInfoAsync() };\n        if (info == nullptr)\n        {\n            co_return false;\n        }\n\n        if (info.HasKey(L\"currentPackage\") && packageHash == info.GetNamedString(L\"currentPackage\"))\n        {\n            // The current package is already the one being installed, so we should no-op.\n            co_return true;\n        }\n\n        if (removePendingUpdate)\n        {\n            auto currentPackageFolder{ co_await GetCurrentPackageFolderAsync() };\n            if (currentPackageFolder != nullptr)\n            {\n                try\n                {\n                    co_await currentPackageFolder.DeleteAsync();\n                }\n                catch (...)\n                {\n                    CodePushUtils::Log(L\"Error deleting pending package.\");\n                }\n            }\n        }\n        else\n        {\n            auto previousPackageHash{ co_await GetPreviousPackageHashAsync() };\n            if (!previousPackageHash.empty() && previousPackageHash != packageHash)\n            {\n                auto previousPackageFolder{ co_await GetPackageFolderAsync(previousPackageHash) };\n                try\n                {\n                    co_await previousPackageFolder.DeleteAsync();\n                }\n                catch (...)\n                {\n                    CodePushUtils::Log(L\"Error deleting old package.\");\n                }\n            }\n\n            IJsonValue currentPackage;\n            if (info.HasKey(L\"currentPackage\"))\n            {\n                currentPackage = info.Lookup(L\"currentPackage\");\n            }\n            else\n            {\n                currentPackage = JsonValue::CreateStringValue(L\"\");\n            }\n            info.Insert(L\"previousPackage\", currentPackage);\n        }\n\n        info.Insert(L\"currentPackage\", JsonValue::CreateStringValue(packageHash));\n        co_return co_await UpdateCurrentPackageInfoAsync(info);\n    }\n\n    /*static*/ IAsyncAction CodePushPackage::RollbackPackage()\n    {\n        auto info{ co_await GetCurrentPackageInfoAsync() };\n        if (info == nullptr)\n        {\n            CodePushUtils::Log(L\"Error getting current package info.\");\n            co_return;\n        }\n\n        auto currentPackageFolder{ co_await GetCurrentPackageFolderAsync() };\n        if (currentPackageFolder == nullptr)\n        {\n            CodePushUtils::Log(L\"Error getting package folder path.\");\n        }\n\n        try\n        {\n            co_await currentPackageFolder.DeleteAsync();\n        }\n        catch (...)\n        {\n            CodePushUtils::Log(L\"Error deleting current package contents.\");\n        }\n\n        info.Insert(L\"currentPackage\", info.TryLookup(L\"previousPackage\"));\n        info.Remove(L\"previousPackage\");\n\n        co_await UpdateCurrentPackageInfoAsync(info);\n    }\n\n    /*static*/ IAsyncOperation<StorageFile> CodePushPackage::GetStatusFileAsync()\n    {\n        auto codePushFolder{ co_await GetCodePushFolderAsync() };\n        co_return (co_await codePushFolder.TryGetItemAsync(CodePushPackage::StatusFile)).try_as<StorageFile>();\n    }\n\n    /*static*/ IAsyncOperation<bool> CodePushPackage::UpdateCurrentPackageInfoAsync(JsonObject packageInfo)\n    {\n        auto packageInfoString{ packageInfo.Stringify() };\n        auto infoFile{ co_await GetStatusFileAsync() };\n        if (infoFile == nullptr)\n        {\n            auto codePushFolder{ co_await GetCodePushFolderAsync() };\n            infoFile = co_await codePushFolder.CreateFileAsync(CodePushPackage::StatusFile);\n        }\n        co_await FileIO::WriteTextAsync(infoFile, packageInfoString);\n        co_return true;\n    }\n}\n"
  },
  {
    "path": "windows/CodePush/CodePushPackage.h",
    "content": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\n#pragma once\n\n#include <winrt/Windows.Data.Json.h>\n#include <functional>\n\nnamespace Microsoft::CodePush::ReactNative\n{\n\tstruct CodePushPackage\n\t{\n\t\tstatic constexpr std::wstring_view DiffManifestFileName{ L\"hotcodepush.json\" };\n\t\tstatic constexpr std::wstring_view DownloadFileName{ L\"download.zip\" };\n\t\tstatic constexpr std::wstring_view RelativeBundlePathKey{ L\"bundlePath\" };\n\t\tstatic constexpr std::wstring_view StatusFile{ L\"codepush.json\" };\n\t\tstatic constexpr std::wstring_view UpdateBundleFileName{ L\"app.jsbundle\" };\n\t\tstatic constexpr std::wstring_view UpdateMetadataFileName{ L\"app.json\" };\n\t\tstatic constexpr std::wstring_view UnzippedFolderName{ L\"unzipped\" };\n\n\t\tstatic winrt::Windows::Foundation::IAsyncAction ClearUpdatesAsync();\n\n\t\tstatic winrt::Windows::Foundation::IAsyncAction DownloadPackageAsync(\n\t\t\twinrt::Windows::Data::Json::JsonObject& updatePackage,\n\t\t\tstd::wstring_view expectedBundleFileName,\n\t\t\tstd::wstring_view publicKey,\n\t\t\tstd::function<void(int64_t, int64_t)> progressCallback);\n\n\t\tstatic winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Data::Json::JsonObject> GetCurrentPackageAsync();\n\t\tstatic winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Data::Json::JsonObject> GetPreviousPackageAsync();\n\t\tstatic winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Storage::StorageFolder> GetCurrentPackageFolderAsync();\n\t\tstatic winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Storage::StorageFile> GetCurrentPackageBundleAsync();\n\t\tstatic winrt::Windows::Foundation::IAsyncOperation<winrt::hstring> GetCurrentPackageHashAsync();\n\n\t\tstatic winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Data::Json::JsonObject> GetPackageAsync(std::wstring_view packageHash);\n\n\t\tstatic winrt::Windows::Foundation::IAsyncOperation<bool> InstallPackageAsync(winrt::Windows::Data::Json::JsonObject updatePackage, bool removePendingUpdate);\n\n\t\tstatic winrt::Windows::Foundation::IAsyncAction RollbackPackage();\n\n\tprivate:\n\t\tstatic winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Storage::StorageFolder> GetCodePushFolderAsync();\n\t\tstatic winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Data::Json::JsonObject> GetCurrentPackageInfoAsync();\n\t\tstatic winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Storage::StorageFolder> GetPackageFolderAsync(std::wstring_view packageHash);\n\t\tstatic winrt::Windows::Foundation::IAsyncOperation<winrt::hstring> GetPreviousPackageHashAsync();\n\t\tstatic winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Storage::StorageFile> GetStatusFileAsync();\n\t\tstatic winrt::Windows::Foundation::IAsyncOperation<bool> UpdateCurrentPackageInfoAsync(winrt::Windows::Data::Json::JsonObject packageInfo);\n\t};\n}\n"
  },
  {
    "path": "windows/CodePush/CodePushTelemetryManager.cpp",
    "content": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\n#include \"pch.h\"\n\n#include \"CodePushTelemetryManager.h\"\n#include \"CodePushNativeModule.h\"\n\n#include \"winrt/Windows.Storage.h\"\n#include \"winrt/Windows.Data.Json.h\"\n#include <string_view>\n\nnamespace Microsoft::CodePush::ReactNative\n{\n    using namespace winrt;\n    using namespace Windows::Data::Json;\n    using namespace Windows::Storage;\n\n    static const std::wstring_view AppVersionKey{ L\"appVersion\" };\n    static const std::wstring_view DeploymentFailed{ L\"DeploymentFailed\" };\n    static const std::wstring_view DeploymentKeyKey{ L\"deploymentKey\" };\n    static const std::wstring_view DeploymentSucceeded{ L\"DeploymentSucceeded\" };\n    static const std::wstring_view LabelKey{ L\"label\" };\n    static const std::wstring_view LastDeploymentReportKey{ L\"CODE_PUSH_LAST_DEPLOYMENT_REPORT\" };\n    static const std::wstring_view PackageKey{ L\"package\" };\n    static const std::wstring_view PreviousDeploymentKeyKey{ L\"previousDeploymentKey\" };\n    static const std::wstring_view PreviousLabelOrAppVersionKey{ L\"previousLabelOrAppVersion\" };\n    static const std::wstring_view RetryDeploymentReportKey{ L\"CODE_PUSH_RETRY_DEPLOYMENT_REPORT\" };\n    static const std::wstring_view StatusKey{ L\"status\" };\n\n    /*static*/ JsonObject CodePushTelemetryManager::GetBinaryUpdateReport(std::wstring_view appVersion)\n    {\n        auto previousStatusReportIdentifier{ GetPreviousStatusReportIdentifier() };\n        if (previousStatusReportIdentifier.empty())\n        {\n            ClearRetryStatusReport();\n            JsonObject out;\n            out.Insert(AppVersionKey, JsonValue::CreateStringValue(appVersion));\n            return out;\n        }\n        else if (previousStatusReportIdentifier != appVersion)\n        {\n            if (IsStatusReportIdentifierCodePushLabel(previousStatusReportIdentifier))\n            {\n                auto previousDeploymentKey{ GetDeploymentKeyFromStatusReportIdentifier(previousStatusReportIdentifier) };\n                auto previousLabel{ GetVersionLabelFromStatusReportIdentifier(previousStatusReportIdentifier) };\n                ClearRetryStatusReport();\n                JsonObject out;\n                out.Insert(AppVersionKey, JsonValue::CreateStringValue(appVersion));\n                out.Insert(PreviousDeploymentKeyKey, JsonValue::CreateStringValue(previousDeploymentKey));\n                out.Insert(PreviousLabelOrAppVersionKey, JsonValue::CreateStringValue(previousLabel));\n                return out;\n            }\n            else\n            {\n                ClearRetryStatusReport();\n                // Previous status report was with a binary app version.\n                JsonObject out;\n                out.Insert(AppVersionKey, JsonValue::CreateStringValue(appVersion));\n                out.Insert(PreviousLabelOrAppVersionKey, JsonValue::CreateStringValue(previousStatusReportIdentifier));\n                return out;\n            }\n        }\n\n        return nullptr;\n    }\n\n    /*static*/ JsonObject CodePushTelemetryManager::GetRetryStatusReport()\n    {\n        auto localSettings{ CodePushNativeModule::GetLocalSettings() };\n        auto retryStatusReportData{ localSettings.Values().TryLookup(RetryDeploymentReportKey) };\n        if (retryStatusReportData != nullptr)\n        {\n            auto retryStatusReportString{ unbox_value<hstring>(retryStatusReportData) };\n            JsonObject retryStatusReport;\n            auto success{ JsonObject::TryParse(retryStatusReportString, retryStatusReport) };\n            if (success)\n            {\n                return retryStatusReport;\n            }\n        }\n        return nullptr;\n    }\n\n    /*static*/ JsonObject CodePushTelemetryManager::GetRollbackReport(const JsonObject& lastFailedPackage)\n    {\n        JsonObject out;\n        out.Insert(PackageKey, lastFailedPackage);\n        out.Insert(StatusKey, JsonValue::CreateStringValue(DeploymentFailed));\n        return out;\n    }\n\n    /*static*/ JsonObject CodePushTelemetryManager::GetUpdateReport(const JsonObject& currentPackage)\n    {\n        auto currentPackageIdentifier{ GetPackageStatusReportIdentifier(currentPackage) };\n        auto previousStatusReportIdentifier{ GetPreviousStatusReportIdentifier() };\n        if (currentPackageIdentifier.empty())\n        {\n            if (!previousStatusReportIdentifier.empty())\n            {\n                ClearRetryStatusReport();\n                JsonObject out;\n                out.Insert(PackageKey, currentPackage);\n                out.Insert(StatusKey, JsonValue::CreateStringValue(DeploymentSucceeded));\n                return out;\n            }\n            else if (previousStatusReportIdentifier != currentPackageIdentifier)\n            {\n                ClearRetryStatusReport();\n                if (IsStatusReportIdentifierCodePushLabel(previousStatusReportIdentifier))\n                {\n                    auto previousDeploymentKey{ GetDeploymentKeyFromStatusReportIdentifier(previousStatusReportIdentifier) };\n                    auto previousLabel{ GetVersionLabelFromStatusReportIdentifier(previousStatusReportIdentifier) };\n                    JsonObject out;\n                    out.Insert(PackageKey, currentPackage);\n                    out.Insert(StatusKey, JsonValue::CreateStringValue(DeploymentSucceeded));\n                    out.Insert(PreviousDeploymentKeyKey, JsonValue::CreateStringValue(previousDeploymentKey));\n                    out.Insert(PreviousLabelOrAppVersionKey, JsonValue::CreateStringValue(previousLabel));\n                    return out;\n                }\n                else\n                {\n                    // Previous status report was with a binary app version.\n                    JsonObject out;\n                    out.Insert(PackageKey, currentPackage);\n                    out.Insert(StatusKey, JsonValue::CreateStringValue(DeploymentSucceeded));\n                    out.Insert(PreviousLabelOrAppVersionKey, JsonValue::CreateStringValue(previousStatusReportIdentifier));\n                    return out;\n                }\n            }\n        }\n\n        return nullptr;\n    }\n\n    /*static*/ void CodePushTelemetryManager::RecordStatusReported(const JsonObject& statusReport)\n    {\n        // We don't need to record rollback reports, so exit early if that's what was specified.\n        auto status{ statusReport.TryLookup(StatusKey) };\n        if (status != nullptr && status.ValueType() == JsonValueType::String && status.GetString() == DeploymentFailed)\n        {\n            return;\n        }\n\n        if (statusReport.HasKey(AppVersionKey))\n        {\n            SaveStatusReportedForIdentifier(statusReport.GetNamedString(AppVersionKey));\n        }\n        else if (statusReport.HasKey(PackageKey))\n        {\n            auto packageIdentifier{ GetPackageStatusReportIdentifier(statusReport.GetNamedObject(PackageKey)) };\n            SaveStatusReportedForIdentifier(packageIdentifier);\n        }\n    }\n\n    /*static*/ void CodePushTelemetryManager::SaveStatusReportForRetry(const JsonObject& statusReport)\n    {\n        auto localSettings{ CodePushNativeModule::GetLocalSettings() };\n        localSettings.Values().Insert(RetryDeploymentReportKey, box_value(statusReport.Stringify()));\n    }\n\n    /*static*/ void CodePushTelemetryManager::ClearRetryStatusReport()\n    {\n        auto localSettings{ CodePushNativeModule::GetLocalSettings() };\n        localSettings.Values().Remove(RetryDeploymentReportKey);\n    }\n\n    /*static*/ std::wstring_view CodePushTelemetryManager::GetDeploymentKeyFromStatusReportIdentifier(std::wstring_view statusReportIdentifier)\n    {\n        return statusReportIdentifier.substr(0, statusReportIdentifier.find(':'));\n    }\n\n    /*static*/ hstring CodePushTelemetryManager::GetPackageStatusReportIdentifier(const JsonObject& package)\n    {\n        // Because deploymentKeys can be dynamically switched, we use a\n        // combination of the deploymentKey and label as the packageIdentifier.\n        if (package.HasKey(DeploymentKeyKey) && package.HasKey(LabelKey))\n        {\n            return L\"\";\n        }\n        auto deploymentKey{ package.GetNamedString(DeploymentKeyKey) };\n        auto label{ package.GetNamedString(LabelKey) };\n        return deploymentKey + L\":\" + label;\n    }\n\n    /*static*/ hstring CodePushTelemetryManager::GetPreviousStatusReportIdentifier()\n    {\n        auto localSettings{ CodePushNativeModule::GetLocalSettings() };\n        auto sentStatusReportIdentifierData{ localSettings.Values().TryLookup(LastDeploymentReportKey) };\n        if (sentStatusReportIdentifierData != nullptr)\n        {\n            auto sentStatusReportIdentifier{ unbox_value<hstring>(sentStatusReportIdentifierData) };\n            return sentStatusReportIdentifier;\n        }\n        return L\"\";\n    }\n\n    /*static*/ std::wstring_view CodePushTelemetryManager::GetVersionLabelFromStatusReportIdentifier(std::wstring_view statusReportIdentifier)\n    {\n        return statusReportIdentifier.substr(statusReportIdentifier.rfind(':') + 1);\n    }\n\n    /*static*/ bool CodePushTelemetryManager::IsStatusReportIdentifierCodePushLabel(std::wstring_view statusReportIdentifier)\n    {\n        return !statusReportIdentifier.empty() && statusReportIdentifier.find(':') != std::wstring_view::npos;\n    }\n\n    /*static*/ void CodePushTelemetryManager::SaveStatusReportedForIdentifier(std::wstring_view appVersionOrPackageIdentifier)\n    {\n        auto localSettings{ CodePushNativeModule::GetLocalSettings() };\n        localSettings.Values().Insert(LastDeploymentReportKey, box_value(appVersionOrPackageIdentifier));\n    }\n}\n"
  },
  {
    "path": "windows/CodePush/CodePushTelemetryManager.h",
    "content": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\n#pragma once\n\n#include \"winrt/Windows.Data.Json.h\"\n#include <string_view>\n\nnamespace Microsoft::CodePush::ReactNative\n{\n\tstruct CodePushTelemetryManager\n\t{\n\t\tstatic winrt::Windows::Data::Json::JsonObject GetBinaryUpdateReport(std::wstring_view appVersion);\n\t\tstatic winrt::Windows::Data::Json::JsonObject GetRetryStatusReport();\n\t\tstatic winrt::Windows::Data::Json::JsonObject GetRollbackReport(const winrt::Windows::Data::Json::JsonObject& lastFailedPackage);\n\t\tstatic winrt::Windows::Data::Json::JsonObject GetUpdateReport(const winrt::Windows::Data::Json::JsonObject& currentPackage);\n\t\tstatic void RecordStatusReported(const winrt::Windows::Data::Json::JsonObject& statusReport);\n\t\tstatic void SaveStatusReportForRetry(const winrt::Windows::Data::Json::JsonObject& statusReport);\n\n\tprivate:\n\t\tstatic void ClearRetryStatusReport();\n\t\tstatic std::wstring_view GetDeploymentKeyFromStatusReportIdentifier(std::wstring_view statusReportIdentifier);\n\t\tstatic winrt::hstring GetPackageStatusReportIdentifier(const winrt::Windows::Data::Json::JsonObject& package);\n\t\tstatic winrt::hstring GetPreviousStatusReportIdentifier();\n\t\tstatic std::wstring_view GetVersionLabelFromStatusReportIdentifier(std::wstring_view statusReportIdentifier);\n\t\tstatic bool IsStatusReportIdentifierCodePushLabel(std::wstring_view statusReportIdentifier);\n\t\tstatic void SaveStatusReportedForIdentifier(std::wstring_view appVersionOrPackageIdentifier);\n\t};\n}\n"
  },
  {
    "path": "windows/CodePush/CodePushUpdateUtils.cpp",
    "content": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\n#include \"pch.h\"\n\n#include \"winrt/Windows.ApplicationModel.h\"\n#include \"winrt/Windows.Foundation.h\"\n#include \"winrt/Windows.Foundation.Collections.h\"\n#include \"winrt/Windows.Security.Cryptography.h\"\n#include \"winrt/Windows.Security.Cryptography.Core.h\"\n#include \"winrt/Windows.Storage.h\"\n#include \"winrt/Windows.Storage.FileProperties.h\"\n#include \"winrt/Windows.Storage.Streams.h\"\n\n#include <algorithm>\n#include <string_view>\n#include <vector>\n\n#include \"CodePushUpdateUtils.h\"\n#include \"CodePushUtils.h\"\n#include \"CodePushNativeModule.h\"\n\nnamespace Microsoft::CodePush::ReactNative\n{\n    using namespace winrt;\n    using namespace Windows::Foundation;\n    using namespace Windows::Foundation::Collections;\n    using namespace Windows::Storage;\n    using namespace Windows::Security::Cryptography;\n    using namespace Windows::Security::Cryptography::Core;\n\n    /*static*/ IAsyncOperation<bool> CodePushUpdateUtils::CopyEntriesInFolderAsync(StorageFolder& sourceFolder, StorageFolder& destFolder)\n    {\n        auto entries{ co_await sourceFolder.GetItemsAsync() };\n        for (const auto& entry : entries)\n        {\n            if (entry.IsOfType(StorageItemTypes::File))\n            {\n                auto file{ entry.try_as<StorageFile>() };\n                co_await file.CopyAsync(destFolder, file.Name(), NameCollisionOption::ReplaceExisting);\n            }\n            else if (entry.IsOfType(StorageItemTypes::Folder))\n            {\n                auto folder{ entry.try_as<StorageFolder>() };\n                auto folderCopy{ co_await destFolder.CreateFolderAsync(folder.Name(), CreationCollisionOption::ReplaceExisting) };\n                auto result{ co_await CopyEntriesInFolderAsync(folder, folderCopy) };\n                if (!result)\n                {\n                    co_return false;\n                }\n            }\n        }\n\n        co_return true;\n    }\n\n    /*static*/ IAsyncOperation<StorageFile> CodePushUpdateUtils::GetSignatureFileAsync(const StorageFolder& rootFolder)\n    {\n        auto manifestFolder{ (co_await rootFolder.TryGetItemAsync(ManifestFolderPrefix)).try_as<StorageFolder>() };\n        if (manifestFolder != nullptr)\n        {\n            auto bundleJWTFile{ (co_await rootFolder.TryGetItemAsync(BundleJWTFile)).try_as<StorageFile>() };\n            if (bundleJWTFile != nullptr)\n            {\n                co_return bundleJWTFile;\n            }\n        }\n        co_return nullptr;\n    }\n    \n    /*static*/ IAsyncOperation<hstring> CodePushUpdateUtils::ModifiedDateStringOfFileAsync(const StorageFile& file)\n    {\n        if (file != nullptr)\n        {\n            auto basicProperties{ co_await file.GetBasicPropertiesAsync() };\n            auto modifiedDate{ basicProperties.DateModified() };\n            auto mtime{ clock::to_time_t(modifiedDate) };\n            auto modifiedDateString{ to_hstring(mtime) };\n            co_return modifiedDateString;\n        }\n        else\n        {\n            co_return L\"\";\n        }\n    }\n}\n"
  },
  {
    "path": "windows/CodePush/CodePushUpdateUtils.h",
    "content": "#pragma once\n\n#include \"winrt/Windows.Data.Json.h\"\n#include \"winrt/Windows.Foundation.h\"\n#include \"winrt/Windows.Storage.h\"\n\n// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\n#include <string_view>\n\nnamespace Microsoft::CodePush::ReactNative\n{\n    struct CodePushUpdateUtils\n    {\n        static constexpr std::wstring_view AssetsFolderName{ L\"assets\" };\n        static constexpr std::wstring_view BinaryHashKey{ L\"CodePushBinaryHash\" };\n        static constexpr std::wstring_view ManifestFolderPrefix{ L\"CodePush\" };\n        static constexpr std::wstring_view BundleJWTFile{ L\".codepushrelease\" };\n\n        static winrt::Windows::Foundation::IAsyncOperation<bool> CopyEntriesInFolderAsync(\n            winrt::Windows::Storage::StorageFolder& sourceFolder,\n            winrt::Windows::Storage::StorageFolder& destFolder);\n\n        static winrt::Windows::Foundation::IAsyncOperation<winrt::hstring> ModifiedDateStringOfFileAsync(const winrt::Windows::Storage::StorageFile& file);\n\n        static winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Storage::StorageFile> GetSignatureFileAsync(\n            const winrt::Windows::Storage::StorageFolder& rootFolder);\n\n    private:\n        /*\n         Ignore list for hashing\n         */\n        static constexpr std::wstring_view IgnoreMacOSX{ L\"__MACOSX/\" };\n        static constexpr std::wstring_view IgnoreDSStore{ L\".DS_Store\" };\n        static constexpr std::wstring_view IgnoreCodePushMetadata{ L\".codepushrelease\" };\n    };\n}\n"
  },
  {
    "path": "windows/CodePush/CodePushUtils.cpp",
    "content": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\n#include \"pch.h\"\n#include \"CodePushUtils.h\"\n\nnamespace Microsoft::CodePush::ReactNative\n{\n\tusing namespace winrt::Windows::Storage;\n\n\t/*static*/ void CodePushUtils::Log(winrt::hstring message)\n\t{\n\t\tOutputDebugStringW(L\"[CodePush] \");\n\t\tOutputDebugStringW(message.c_str());\n\t\tOutputDebugStringW(L\"\\n\");\n\t}\n\n\t/*static*/ void CodePushUtils::Log(const winrt::hresult_error& ex)\n\t{\n\t\tOutputDebugStringW(L\"[CodePush] Exception \");\n\t\tOutputDebugStringW(ex.message().c_str());\n\t\tOutputDebugStringW(L\"\\n\");\n\t}\n\n\t/*static*/ void CodePushUtils::LogBundleUrl(const IStorageFile& bundle)\n\t{\n\t\tCodePushUtils::Log(L\"Loading JS bundle from \\\"\" + bundle.Path() + L\"\\\"\");\n\t}\n}\n"
  },
  {
    "path": "windows/CodePush/CodePushUtils.h",
    "content": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\n#pragma once\n\n#include \"winrt/base.h\"\n#include \"winrt/Windows.Storage.h\"\n#include <exception>\n\nnamespace Microsoft::CodePush::ReactNative\n{\n\tstruct CodePushUtils\n\t{\n\t\tstatic void Log(winrt::hstring message);\n\t\tstatic void Log(const winrt::hresult_error& ex);\n\t\tstatic void LogBundleUrl(const winrt::Windows::Storage::IStorageFile& bundle);\n\t};\n}\n"
  },
  {
    "path": "windows/CodePush/FileUtils.cpp",
    "content": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\n#include \"pch.h\"\n\n#include \"miniz/miniz.h\"\n#include \"winrt/Windows.Foundation.h\"\n#include \"winrt/Windows.Storage.h\"\n#include \"winrt/Windows.Storage.Search.h\"\n#include \"winrt/Windows.Storage.Streams.h\"\n\n#include <string_view>\n#include <stack>\n\n#include \"CodePushNativeModule.h\"\n#include \"FileUtils.h\"\n\nnamespace Microsoft::CodePush::ReactNative\n{\n    using namespace winrt;\n    using namespace Windows::Foundation;\n    using namespace Windows::Storage;\n    using namespace Windows::Storage::Search;\n    using namespace Windows::Storage::Streams;\n\n    /*static*/ IAsyncOperation<StorageFile> FileUtils::CreateFileFromPathAsync(StorageFolder rootFolder, const std::filesystem::path& relativePath)\n    {\n        auto relPath{ relativePath };\n\n        std::stack<std::string> pathParts;\n        pathParts.push(relPath.filename().string());\n        while (relPath.has_parent_path())\n        {\n            relPath = relPath.parent_path();\n            pathParts.push(relPath.filename().string());\n        }\n\n        while (pathParts.size() > 1)\n        {\n            auto itemName{ pathParts.top() };\n            rootFolder = co_await rootFolder.CreateFolderAsync(to_hstring(itemName), CreationCollisionOption::OpenIfExists);\n            pathParts.pop();\n        }\n        auto fileName{ pathParts.top() };\n        auto file{ co_await rootFolder.CreateFileAsync(to_hstring(fileName), CreationCollisionOption::ReplaceExisting) };\n        co_return file;\n    }\n\n    /*static*/ IAsyncOperation<hstring> FileUtils::FindFilePathAsync(const StorageFolder& rootFolder, std::wstring_view fileName)\n    {\n        try\n        {\n            std::vector<hstring> fileTypeFilter{};\n            fileTypeFilter.push_back(L\".bundle\");\n            QueryOptions queryOptions{ CommonFileQuery::OrderByName, fileTypeFilter };\n            queryOptions.IndexerOption(IndexerOption::DoNotUseIndexer);\n            queryOptions.ApplicationSearchFilter(L\"System.FileName: \" + fileName);\n            auto queryResult{ rootFolder.CreateFileQueryWithOptions(queryOptions) };\n            auto files{ co_await queryResult.GetFilesAsync() };\n\n            if (files.Size() > 0)\n            {\n                auto result{ files.GetAt(0) };\n                std::wstring_view bundlePath{ result.Path() };\n                hstring filePathSub{ bundlePath.substr(rootFolder.Path().size() + 1) };\n                co_return filePathSub;\n            }\n\n            co_return L\"\";\n        }\n        catch (...)\n        {\n            throw;\n        }\n    }\n\n    /*static*/ IAsyncAction FileUtils::UnzipAsync(const StorageFile& zipFile, const StorageFolder& destination)\n    {\n        std::string zipName{ to_string(zipFile.Path()) };\n\n        mz_bool status;\n        mz_zip_archive zip_archive;\n        mz_zip_zero_struct(&zip_archive);\n\n        status = mz_zip_reader_init_file(&zip_archive, zipName.c_str(), 0);\n        assert(status);\n        auto numFiles{ mz_zip_reader_get_num_files(&zip_archive) };\n\n        for (mz_uint i = 0; i < numFiles; i++)\n        {\n            mz_zip_archive_file_stat file_stat;\n            status = mz_zip_reader_file_stat(&zip_archive, i, &file_stat);\n            assert(status);\n            if (!mz_zip_reader_is_file_a_directory(&zip_archive, i))\n            {\n                auto fileName{ file_stat.m_filename };\n                auto filePath{ std::filesystem::path(fileName) };\n                auto filePathName{ filePath.filename() };\n                auto filePathNameString{ filePathName.string() };\n\n                auto entryFile{ co_await CreateFileFromPathAsync(destination, filePath) };\n                \n                auto stream{ co_await entryFile.OpenAsync(FileAccessMode::ReadWrite) };\n                auto os{ stream.GetOutputStreamAt(0) };\n                DataWriter dw{ os };\n\n                const auto arrBufSize = 8 * 1024;\n                std::array<uint8_t, arrBufSize> arrBuf;\n\n                mz_zip_reader_extract_iter_state* pState = mz_zip_reader_extract_iter_new(&zip_archive, i, 0);\n                while (size_t bytesRead{ mz_zip_reader_extract_iter_read(pState, static_cast<void*>(arrBuf.data()), arrBuf.size()) })\n                {\n                    array_view<const uint8_t> view{ arrBuf.data(), arrBuf.data() + bytesRead };\n                    dw.WriteBytes(view);\n                }\n                status = mz_zip_reader_extract_iter_free(pState);\n                assert(status);\n\n                co_await dw.StoreAsync();\n                co_await dw.FlushAsync();\n\n                dw.Close();\n                os.Close();\n                stream.Close();\n            }\n        }\n\n        status = mz_zip_reader_end(&zip_archive);\n        assert(status);\n    }\n}\n"
  },
  {
    "path": "windows/CodePush/FileUtils.h",
    "content": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\n#pragma once\n\n#include \"winrt/Windows.Storage.h\"\n#include \"winrt/Windows.Foundation.h\"\n\n#include <filesystem>\n#include <string_view>\n\nnamespace Microsoft::CodePush::ReactNative\n{\n\tstruct FileUtils\n\t{\n\t\tstatic winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Storage::StorageFile> CreateFileFromPathAsync(\n\t\t\twinrt::Windows::Storage::StorageFolder rootFolder, \n\t\t\tconst std::filesystem::path& relativePath);\n\n\t\tstatic winrt::Windows::Foundation::IAsyncOperation<winrt::hstring> FindFilePathAsync(\n\t\t\tconst winrt::Windows::Storage::StorageFolder& rootFolder, \n\t\t\tstd::wstring_view fileName);\n\n\t\tstatic winrt::Windows::Foundation::IAsyncAction UnzipAsync(\n\t\t\tconst winrt::Windows::Storage::StorageFile& zipFile, \n\t\t\tconst winrt::Windows::Storage::StorageFolder& destination);\n\t};\n}\n"
  },
  {
    "path": "windows/CodePush/PropertySheet.props",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ImportGroup Label=\"PropertySheets\" />\n  <PropertyGroup Label=\"UserMacros\" />\n  <!--\n    To customize common C++/WinRT project properties: \n    * right-click the project node\n    * expand the Common Properties item\n    * select the C++/WinRT property page\n\n    For more advanced scenarios, and complete documentation, please see:\n    https://github.com/Microsoft/cppwinrt/tree/master/nuget \n    -->\n  <PropertyGroup />\n  <ItemDefinitionGroup />\n</Project>\n"
  },
  {
    "path": "windows/CodePush/ReactPackageProvider.cpp",
    "content": "#include \"pch.h\"\n#include \"ReactPackageProvider.h\"\n#include \"ReactPackageProvider.g.cpp\"\n\n#include \"CodePushNativeModule.h\"\n\nusing namespace winrt::Microsoft::ReactNative;\n\nnamespace winrt::Microsoft::CodePush::ReactNative::implementation {\n\nvoid ReactPackageProvider::CreatePackage(IReactPackageBuilder const &packageBuilder) noexcept {\n  AddAttributedModules(packageBuilder);\n}\n\n} // namespace winrt::Microsoft::CodePush::ReactNative::implementation\n"
  },
  {
    "path": "windows/CodePush/ReactPackageProvider.h",
    "content": "#pragma once\n#include \"winrt/Microsoft.CodePush.ReactNative.h\"\n\n#include \"ReactPackageProvider.g.h\"\n\nusing namespace winrt::Microsoft::ReactNative;\n\nnamespace winrt::Microsoft::CodePush::ReactNative::implementation {\n\nstruct ReactPackageProvider : ReactPackageProviderT<ReactPackageProvider> {\n  ReactPackageProvider() = default;\n\n  void CreatePackage(IReactPackageBuilder const &packageBuilder) noexcept;\n};\n\n} // namespace winrt::RNFS::implementation\n\nnamespace winrt::Microsoft::CodePush::ReactNative::factory_implementation {\n\nstruct ReactPackageProvider : ReactPackageProviderT<ReactPackageProvider, implementation::ReactPackageProvider> {};\n\n} // namespace winrt::RNFS::factory_implementation\n"
  },
  {
    "path": "windows/CodePush/ReactPackageProvider.idl",
    "content": "namespace Microsoft.CodePush.ReactNative\n{\n    [webhosthidden]\n    [default_interface]\n    runtimeclass ReactPackageProvider\n        : Microsoft.ReactNative.IReactPackageProvider {\n      ReactPackageProvider();\n    };\n} // namespace CppModule\n"
  },
  {
    "path": "windows/CodePush/miniz/LICENSE",
    "content": "Copyright 2013-2014 RAD Game Tools and Valve Software\nCopyright 2010-2014 Rich Geldreich and Tenacious Software LLC\n\nAll Rights Reserved.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "windows/CodePush/miniz/miniz.c",
    "content": "/**************************************************************************\n *\n * Copyright 2013-2014 RAD Game Tools and Valve Software\n * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC\n * All Rights Reserved.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n *\n **************************************************************************/\n\n#include  \"miniz.h\"\n\ntypedef unsigned char mz_validate_uint16[sizeof(mz_uint16) == 2 ? 1 : -1];\ntypedef unsigned char mz_validate_uint32[sizeof(mz_uint32) == 4 ? 1 : -1];\ntypedef unsigned char mz_validate_uint64[sizeof(mz_uint64) == 8 ? 1 : -1];\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/* ------------------- zlib-style API's */\n\nmz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len)\n{\n    mz_uint32 i, s1 = (mz_uint32)(adler & 0xffff), s2 = (mz_uint32)(adler >> 16);\n    size_t block_len = buf_len % 5552;\n    if (!ptr)\n        return MZ_ADLER32_INIT;\n    while (buf_len)\n    {\n        for (i = 0; i + 7 < block_len; i += 8, ptr += 8)\n        {\n            s1 += ptr[0], s2 += s1;\n            s1 += ptr[1], s2 += s1;\n            s1 += ptr[2], s2 += s1;\n            s1 += ptr[3], s2 += s1;\n            s1 += ptr[4], s2 += s1;\n            s1 += ptr[5], s2 += s1;\n            s1 += ptr[6], s2 += s1;\n            s1 += ptr[7], s2 += s1;\n        }\n        for (; i < block_len; ++i)\n            s1 += *ptr++, s2 += s1;\n        s1 %= 65521U, s2 %= 65521U;\n        buf_len -= block_len;\n        block_len = 5552;\n    }\n    return (s2 << 16) + s1;\n}\n\n/* Karl Malbrain's compact CRC-32. See \"A compact CCITT crc16 and crc32 C implementation that balances processor cache usage against speed\": http://www.geocities.com/malbrain/ */\n#if 0\n    mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len)\n    {\n        static const mz_uint32 s_crc32[16] = { 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,\n                                               0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c };\n        mz_uint32 crcu32 = (mz_uint32)crc;\n        if (!ptr)\n            return MZ_CRC32_INIT;\n        crcu32 = ~crcu32;\n        while (buf_len--)\n        {\n            mz_uint8 b = *ptr++;\n            crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)];\n            crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)];\n        }\n        return ~crcu32;\n    }\n#else\n/* Faster, but larger CPU cache footprint.\n */\nmz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len)\n{\n    static const mz_uint32 s_crc_table[256] =\n        {\n          0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535,\n          0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD,\n          0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D,\n          0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,\n          0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,\n          0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,\n          0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC,\n          0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,\n          0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB,\n          0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F,\n          0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB,\n          0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,\n          0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA,\n          0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE,\n          0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A,\n          0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,\n          0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409,\n          0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,\n          0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739,\n          0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,\n          0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268,\n          0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0,\n          0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8,\n          0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,\n          0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF,\n          0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703,\n          0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7,\n          0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,\n          0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE,\n          0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,\n          0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6,\n          0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,\n          0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D,\n          0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5,\n          0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605,\n          0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,\n          0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D\n        };\n\n    mz_uint32 crc32 = (mz_uint32)crc ^ 0xFFFFFFFF;\n    const mz_uint8 *pByte_buf = (const mz_uint8 *)ptr;\n\n    while (buf_len >= 4)\n    {\n        crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[0]) & 0xFF];\n        crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[1]) & 0xFF];\n        crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[2]) & 0xFF];\n        crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[3]) & 0xFF];\n        pByte_buf += 4;\n        buf_len -= 4;\n    }\n\n    while (buf_len)\n    {\n        crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[0]) & 0xFF];\n        ++pByte_buf;\n        --buf_len;\n    }\n\n    return ~crc32;\n}\n#endif\n\nvoid mz_free(void *p)\n{\n    MZ_FREE(p);\n}\n\nvoid *miniz_def_alloc_func(void *opaque, size_t items, size_t size)\n{\n    (void)opaque, (void)items, (void)size;\n    return MZ_MALLOC(items * size);\n}\nvoid miniz_def_free_func(void *opaque, void *address)\n{\n    (void)opaque, (void)address;\n    MZ_FREE(address);\n}\nvoid *miniz_def_realloc_func(void *opaque, void *address, size_t items, size_t size)\n{\n    (void)opaque, (void)address, (void)items, (void)size;\n    return MZ_REALLOC(address, items * size);\n}\n\nconst char *mz_version(void)\n{\n    return MZ_VERSION;\n}\n\n#ifndef MINIZ_NO_ZLIB_APIS\n\nint mz_deflateInit(mz_streamp pStream, int level)\n{\n    return mz_deflateInit2(pStream, level, MZ_DEFLATED, MZ_DEFAULT_WINDOW_BITS, 9, MZ_DEFAULT_STRATEGY);\n}\n\nint mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy)\n{\n    tdefl_compressor *pComp;\n    mz_uint comp_flags = TDEFL_COMPUTE_ADLER32 | tdefl_create_comp_flags_from_zip_params(level, window_bits, strategy);\n\n    if (!pStream)\n        return MZ_STREAM_ERROR;\n    if ((method != MZ_DEFLATED) || ((mem_level < 1) || (mem_level > 9)) || ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS)))\n        return MZ_PARAM_ERROR;\n\n    pStream->data_type = 0;\n    pStream->adler = MZ_ADLER32_INIT;\n    pStream->msg = NULL;\n    pStream->reserved = 0;\n    pStream->total_in = 0;\n    pStream->total_out = 0;\n    if (!pStream->zalloc)\n        pStream->zalloc = miniz_def_alloc_func;\n    if (!pStream->zfree)\n        pStream->zfree = miniz_def_free_func;\n\n    pComp = (tdefl_compressor *)pStream->zalloc(pStream->opaque, 1, sizeof(tdefl_compressor));\n    if (!pComp)\n        return MZ_MEM_ERROR;\n\n    pStream->state = (struct mz_internal_state *)pComp;\n\n    if (tdefl_init(pComp, NULL, NULL, comp_flags) != TDEFL_STATUS_OKAY)\n    {\n        mz_deflateEnd(pStream);\n        return MZ_PARAM_ERROR;\n    }\n\n    return MZ_OK;\n}\n\nint mz_deflateReset(mz_streamp pStream)\n{\n    if ((!pStream) || (!pStream->state) || (!pStream->zalloc) || (!pStream->zfree))\n        return MZ_STREAM_ERROR;\n    pStream->total_in = pStream->total_out = 0;\n    tdefl_init((tdefl_compressor *)pStream->state, NULL, NULL, ((tdefl_compressor *)pStream->state)->m_flags);\n    return MZ_OK;\n}\n\nint mz_deflate(mz_streamp pStream, int flush)\n{\n    size_t in_bytes, out_bytes;\n    mz_ulong orig_total_in, orig_total_out;\n    int mz_status = MZ_OK;\n\n    if ((!pStream) || (!pStream->state) || (flush < 0) || (flush > MZ_FINISH) || (!pStream->next_out))\n        return MZ_STREAM_ERROR;\n    if (!pStream->avail_out)\n        return MZ_BUF_ERROR;\n\n    if (flush == MZ_PARTIAL_FLUSH)\n        flush = MZ_SYNC_FLUSH;\n\n    if (((tdefl_compressor *)pStream->state)->m_prev_return_status == TDEFL_STATUS_DONE)\n        return (flush == MZ_FINISH) ? MZ_STREAM_END : MZ_BUF_ERROR;\n\n    orig_total_in = pStream->total_in;\n    orig_total_out = pStream->total_out;\n    for (;;)\n    {\n        tdefl_status defl_status;\n        in_bytes = pStream->avail_in;\n        out_bytes = pStream->avail_out;\n\n        defl_status = tdefl_compress((tdefl_compressor *)pStream->state, pStream->next_in, &in_bytes, pStream->next_out, &out_bytes, (tdefl_flush)flush);\n        pStream->next_in += (mz_uint)in_bytes;\n        pStream->avail_in -= (mz_uint)in_bytes;\n        pStream->total_in += (mz_uint)in_bytes;\n        pStream->adler = tdefl_get_adler32((tdefl_compressor *)pStream->state);\n\n        pStream->next_out += (mz_uint)out_bytes;\n        pStream->avail_out -= (mz_uint)out_bytes;\n        pStream->total_out += (mz_uint)out_bytes;\n\n        if (defl_status < 0)\n        {\n            mz_status = MZ_STREAM_ERROR;\n            break;\n        }\n        else if (defl_status == TDEFL_STATUS_DONE)\n        {\n            mz_status = MZ_STREAM_END;\n            break;\n        }\n        else if (!pStream->avail_out)\n            break;\n        else if ((!pStream->avail_in) && (flush != MZ_FINISH))\n        {\n            if ((flush) || (pStream->total_in != orig_total_in) || (pStream->total_out != orig_total_out))\n                break;\n            return MZ_BUF_ERROR; /* Can't make forward progress without some input.\n */\n        }\n    }\n    return mz_status;\n}\n\nint mz_deflateEnd(mz_streamp pStream)\n{\n    if (!pStream)\n        return MZ_STREAM_ERROR;\n    if (pStream->state)\n    {\n        pStream->zfree(pStream->opaque, pStream->state);\n        pStream->state = NULL;\n    }\n    return MZ_OK;\n}\n\nmz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len)\n{\n    (void)pStream;\n    /* This is really over conservative. (And lame, but it's actually pretty tricky to compute a true upper bound given the way tdefl's blocking works.) */\n    return MZ_MAX(128 + (source_len * 110) / 100, 128 + source_len + ((source_len / (31 * 1024)) + 1) * 5);\n}\n\nint mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level)\n{\n    int status;\n    mz_stream stream;\n    memset(&stream, 0, sizeof(stream));\n\n    /* In case mz_ulong is 64-bits (argh I hate longs). */\n    if ((source_len | *pDest_len) > 0xFFFFFFFFU)\n        return MZ_PARAM_ERROR;\n\n    stream.next_in = pSource;\n    stream.avail_in = (mz_uint32)source_len;\n    stream.next_out = pDest;\n    stream.avail_out = (mz_uint32)*pDest_len;\n\n    status = mz_deflateInit(&stream, level);\n    if (status != MZ_OK)\n        return status;\n\n    status = mz_deflate(&stream, MZ_FINISH);\n    if (status != MZ_STREAM_END)\n    {\n        mz_deflateEnd(&stream);\n        return (status == MZ_OK) ? MZ_BUF_ERROR : status;\n    }\n\n    *pDest_len = stream.total_out;\n    return mz_deflateEnd(&stream);\n}\n\nint mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len)\n{\n    return mz_compress2(pDest, pDest_len, pSource, source_len, MZ_DEFAULT_COMPRESSION);\n}\n\nmz_ulong mz_compressBound(mz_ulong source_len)\n{\n    return mz_deflateBound(NULL, source_len);\n}\n\ntypedef struct\n{\n    tinfl_decompressor m_decomp;\n    mz_uint m_dict_ofs, m_dict_avail, m_first_call, m_has_flushed;\n    int m_window_bits;\n    mz_uint8 m_dict[TINFL_LZ_DICT_SIZE];\n    tinfl_status m_last_status;\n} inflate_state;\n\nint mz_inflateInit2(mz_streamp pStream, int window_bits)\n{\n    inflate_state *pDecomp;\n    if (!pStream)\n        return MZ_STREAM_ERROR;\n    if ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS))\n        return MZ_PARAM_ERROR;\n\n    pStream->data_type = 0;\n    pStream->adler = 0;\n    pStream->msg = NULL;\n    pStream->total_in = 0;\n    pStream->total_out = 0;\n    pStream->reserved = 0;\n    if (!pStream->zalloc)\n        pStream->zalloc = miniz_def_alloc_func;\n    if (!pStream->zfree)\n        pStream->zfree = miniz_def_free_func;\n\n    pDecomp = (inflate_state *)pStream->zalloc(pStream->opaque, 1, sizeof(inflate_state));\n    if (!pDecomp)\n        return MZ_MEM_ERROR;\n\n    pStream->state = (struct mz_internal_state *)pDecomp;\n\n    tinfl_init(&pDecomp->m_decomp);\n    pDecomp->m_dict_ofs = 0;\n    pDecomp->m_dict_avail = 0;\n    pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT;\n    pDecomp->m_first_call = 1;\n    pDecomp->m_has_flushed = 0;\n    pDecomp->m_window_bits = window_bits;\n\n    return MZ_OK;\n}\n\nint mz_inflateInit(mz_streamp pStream)\n{\n    return mz_inflateInit2(pStream, MZ_DEFAULT_WINDOW_BITS);\n}\n\nint mz_inflateReset(mz_streamp pStream)\n{\n    inflate_state *pDecomp;\n    if (!pStream)\n        return MZ_STREAM_ERROR;\n\n    pStream->data_type = 0;\n    pStream->adler = 0;\n    pStream->msg = NULL;\n    pStream->total_in = 0;\n    pStream->total_out = 0;\n    pStream->reserved = 0;\n\n    pDecomp = (inflate_state *)pStream->state;\n\n    tinfl_init(&pDecomp->m_decomp);\n    pDecomp->m_dict_ofs = 0;\n    pDecomp->m_dict_avail = 0;\n    pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT;\n    pDecomp->m_first_call = 1;\n    pDecomp->m_has_flushed = 0;\n    /* pDecomp->m_window_bits = window_bits */;\n\n    return MZ_OK;\n}\n\nint mz_inflate(mz_streamp pStream, int flush)\n{\n    inflate_state *pState;\n    mz_uint n, first_call, decomp_flags = TINFL_FLAG_COMPUTE_ADLER32;\n    size_t in_bytes, out_bytes, orig_avail_in;\n    tinfl_status status;\n\n    if ((!pStream) || (!pStream->state))\n        return MZ_STREAM_ERROR;\n    if (flush == MZ_PARTIAL_FLUSH)\n        flush = MZ_SYNC_FLUSH;\n    if ((flush) && (flush != MZ_SYNC_FLUSH) && (flush != MZ_FINISH))\n        return MZ_STREAM_ERROR;\n\n    pState = (inflate_state *)pStream->state;\n    if (pState->m_window_bits > 0)\n        decomp_flags |= TINFL_FLAG_PARSE_ZLIB_HEADER;\n    orig_avail_in = pStream->avail_in;\n\n    first_call = pState->m_first_call;\n    pState->m_first_call = 0;\n    if (pState->m_last_status < 0)\n        return MZ_DATA_ERROR;\n\n    if (pState->m_has_flushed && (flush != MZ_FINISH))\n        return MZ_STREAM_ERROR;\n    pState->m_has_flushed |= (flush == MZ_FINISH);\n\n    if ((flush == MZ_FINISH) && (first_call))\n    {\n        /* MZ_FINISH on the first call implies that the input and output buffers are large enough to hold the entire compressed/decompressed file. */\n        decomp_flags |= TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF;\n        in_bytes = pStream->avail_in;\n        out_bytes = pStream->avail_out;\n        status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pStream->next_out, pStream->next_out, &out_bytes, decomp_flags);\n        pState->m_last_status = status;\n        pStream->next_in += (mz_uint)in_bytes;\n        pStream->avail_in -= (mz_uint)in_bytes;\n        pStream->total_in += (mz_uint)in_bytes;\n        pStream->adler = tinfl_get_adler32(&pState->m_decomp);\n        pStream->next_out += (mz_uint)out_bytes;\n        pStream->avail_out -= (mz_uint)out_bytes;\n        pStream->total_out += (mz_uint)out_bytes;\n\n        if (status < 0)\n            return MZ_DATA_ERROR;\n        else if (status != TINFL_STATUS_DONE)\n        {\n            pState->m_last_status = TINFL_STATUS_FAILED;\n            return MZ_BUF_ERROR;\n        }\n        return MZ_STREAM_END;\n    }\n    /* flush != MZ_FINISH then we must assume there's more input. */\n    if (flush != MZ_FINISH)\n        decomp_flags |= TINFL_FLAG_HAS_MORE_INPUT;\n\n    if (pState->m_dict_avail)\n    {\n        n = MZ_MIN(pState->m_dict_avail, pStream->avail_out);\n        memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n);\n        pStream->next_out += n;\n        pStream->avail_out -= n;\n        pStream->total_out += n;\n        pState->m_dict_avail -= n;\n        pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1);\n        return ((pState->m_last_status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK;\n    }\n\n    for (;;)\n    {\n        in_bytes = pStream->avail_in;\n        out_bytes = TINFL_LZ_DICT_SIZE - pState->m_dict_ofs;\n\n        status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pState->m_dict, pState->m_dict + pState->m_dict_ofs, &out_bytes, decomp_flags);\n        pState->m_last_status = status;\n\n        pStream->next_in += (mz_uint)in_bytes;\n        pStream->avail_in -= (mz_uint)in_bytes;\n        pStream->total_in += (mz_uint)in_bytes;\n        pStream->adler = tinfl_get_adler32(&pState->m_decomp);\n\n        pState->m_dict_avail = (mz_uint)out_bytes;\n\n        n = MZ_MIN(pState->m_dict_avail, pStream->avail_out);\n        memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n);\n        pStream->next_out += n;\n        pStream->avail_out -= n;\n        pStream->total_out += n;\n        pState->m_dict_avail -= n;\n        pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1);\n\n        if (status < 0)\n            return MZ_DATA_ERROR; /* Stream is corrupted (there could be some uncompressed data left in the output dictionary - oh well). */\n        else if ((status == TINFL_STATUS_NEEDS_MORE_INPUT) && (!orig_avail_in))\n            return MZ_BUF_ERROR; /* Signal caller that we can't make forward progress without supplying more input or by setting flush to MZ_FINISH. */\n        else if (flush == MZ_FINISH)\n        {\n            /* The output buffer MUST be large to hold the remaining uncompressed data when flush==MZ_FINISH. */\n            if (status == TINFL_STATUS_DONE)\n                return pState->m_dict_avail ? MZ_BUF_ERROR : MZ_STREAM_END;\n            /* status here must be TINFL_STATUS_HAS_MORE_OUTPUT, which means there's at least 1 more byte on the way. If there's no more room left in the output buffer then something is wrong. */\n            else if (!pStream->avail_out)\n                return MZ_BUF_ERROR;\n        }\n        else if ((status == TINFL_STATUS_DONE) || (!pStream->avail_in) || (!pStream->avail_out) || (pState->m_dict_avail))\n            break;\n    }\n\n    return ((status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK;\n}\n\nint mz_inflateEnd(mz_streamp pStream)\n{\n    if (!pStream)\n        return MZ_STREAM_ERROR;\n    if (pStream->state)\n    {\n        pStream->zfree(pStream->opaque, pStream->state);\n        pStream->state = NULL;\n    }\n    return MZ_OK;\n}\n\nint mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len)\n{\n    mz_stream stream;\n    int status;\n    memset(&stream, 0, sizeof(stream));\n\n    /* In case mz_ulong is 64-bits (argh I hate longs). */\n    if ((source_len | *pDest_len) > 0xFFFFFFFFU)\n        return MZ_PARAM_ERROR;\n\n    stream.next_in = pSource;\n    stream.avail_in = (mz_uint32)source_len;\n    stream.next_out = pDest;\n    stream.avail_out = (mz_uint32)*pDest_len;\n\n    status = mz_inflateInit(&stream);\n    if (status != MZ_OK)\n        return status;\n\n    status = mz_inflate(&stream, MZ_FINISH);\n    if (status != MZ_STREAM_END)\n    {\n        mz_inflateEnd(&stream);\n        return ((status == MZ_BUF_ERROR) && (!stream.avail_in)) ? MZ_DATA_ERROR : status;\n    }\n    *pDest_len = stream.total_out;\n\n    return mz_inflateEnd(&stream);\n}\n\nconst char *mz_error(int err)\n{\n    static struct\n    {\n        int m_err;\n        const char *m_pDesc;\n    } s_error_descs[] =\n        {\n          { MZ_OK, \"\" }, { MZ_STREAM_END, \"stream end\" }, { MZ_NEED_DICT, \"need dictionary\" }, { MZ_ERRNO, \"file error\" }, { MZ_STREAM_ERROR, \"stream error\" }, { MZ_DATA_ERROR, \"data error\" }, { MZ_MEM_ERROR, \"out of memory\" }, { MZ_BUF_ERROR, \"buf error\" }, { MZ_VERSION_ERROR, \"version error\" }, { MZ_PARAM_ERROR, \"parameter error\" }\n        };\n    mz_uint i;\n    for (i = 0; i < sizeof(s_error_descs) / sizeof(s_error_descs[0]); ++i)\n        if (s_error_descs[i].m_err == err)\n            return s_error_descs[i].m_pDesc;\n    return NULL;\n}\n\n#endif /*MINIZ_NO_ZLIB_APIS */\n\n#ifdef __cplusplus\n}\n#endif\n\n/*\n  This is free and unencumbered software released into the public domain.\n\n  Anyone is free to copy, modify, publish, use, compile, sell, or\n  distribute this software, either in source code form or as a compiled\n  binary, for any purpose, commercial or non-commercial, and by any\n  means.\n\n  In jurisdictions that recognize copyright laws, the author or authors\n  of this software dedicate any and all copyright interest in the\n  software to the public domain. We make this dedication for the benefit\n  of the public at large and to the detriment of our heirs and\n  successors. We intend this dedication to be an overt act of\n  relinquishment in perpetuity of all present and future rights to this\n  software under copyright law.\n\n  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR\n  OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,\n  ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\n  OTHER DEALINGS IN THE SOFTWARE.\n\n  For more information, please refer to <http://unlicense.org/>\n*/\n/**************************************************************************\n *\n * Copyright 2013-2014 RAD Game Tools and Valve Software\n * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC\n * All Rights Reserved.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n *\n **************************************************************************/\n\n\n\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/* ------------------- Low-level Compression (independent from all decompression API's) */\n\n/* Purposely making these tables static for faster init and thread safety. */\nstatic const mz_uint16 s_tdefl_len_sym[256] =\n    {\n      257, 258, 259, 260, 261, 262, 263, 264, 265, 265, 266, 266, 267, 267, 268, 268, 269, 269, 269, 269, 270, 270, 270, 270, 271, 271, 271, 271, 272, 272, 272, 272,\n      273, 273, 273, 273, 273, 273, 273, 273, 274, 274, 274, 274, 274, 274, 274, 274, 275, 275, 275, 275, 275, 275, 275, 275, 276, 276, 276, 276, 276, 276, 276, 276,\n      277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278,\n      279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280,\n      281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281,\n      282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282,\n      283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283,\n      284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 285\n    };\n\nstatic const mz_uint8 s_tdefl_len_extra[256] =\n    {\n      0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,\n      4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,\n      5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,\n      5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0\n    };\n\nstatic const mz_uint8 s_tdefl_small_dist_sym[512] =\n    {\n      0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11,\n      11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13,\n      13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,\n      14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,\n      14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,\n      15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,\n      16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,\n      16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,\n      16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,\n      17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,\n      17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,\n      17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17\n    };\n\nstatic const mz_uint8 s_tdefl_small_dist_extra[512] =\n    {\n      0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5,\n      5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,\n      6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,\n      6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,\n      7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,\n      7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,\n      7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,\n      7, 7, 7, 7, 7, 7, 7, 7\n    };\n\nstatic const mz_uint8 s_tdefl_large_dist_sym[128] =\n    {\n      0, 0, 18, 19, 20, 20, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,\n      26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,\n      28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29\n    };\n\nstatic const mz_uint8 s_tdefl_large_dist_extra[128] =\n    {\n      0, 0, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,\n      12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,\n      13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13\n    };\n\n/* Radix sorts tdefl_sym_freq[] array by 16-bit key m_key. Returns ptr to sorted values. */\ntypedef struct\n{\n    mz_uint16 m_key, m_sym_index;\n} tdefl_sym_freq;\nstatic tdefl_sym_freq *tdefl_radix_sort_syms(mz_uint num_syms, tdefl_sym_freq *pSyms0, tdefl_sym_freq *pSyms1)\n{\n    mz_uint32 total_passes = 2, pass_shift, pass, i, hist[256 * 2];\n    tdefl_sym_freq *pCur_syms = pSyms0, *pNew_syms = pSyms1;\n    MZ_CLEAR_OBJ(hist);\n    for (i = 0; i < num_syms; i++)\n    {\n        mz_uint freq = pSyms0[i].m_key;\n        hist[freq & 0xFF]++;\n        hist[256 + ((freq >> 8) & 0xFF)]++;\n    }\n    while ((total_passes > 1) && (num_syms == hist[(total_passes - 1) * 256]))\n        total_passes--;\n    for (pass_shift = 0, pass = 0; pass < total_passes; pass++, pass_shift += 8)\n    {\n        const mz_uint32 *pHist = &hist[pass << 8];\n        mz_uint offsets[256], cur_ofs = 0;\n        for (i = 0; i < 256; i++)\n        {\n            offsets[i] = cur_ofs;\n            cur_ofs += pHist[i];\n        }\n        for (i = 0; i < num_syms; i++)\n            pNew_syms[offsets[(pCur_syms[i].m_key >> pass_shift) & 0xFF]++] = pCur_syms[i];\n        {\n            tdefl_sym_freq *t = pCur_syms;\n            pCur_syms = pNew_syms;\n            pNew_syms = t;\n        }\n    }\n    return pCur_syms;\n}\n\n/* tdefl_calculate_minimum_redundancy() originally written by: Alistair Moffat, alistair@cs.mu.oz.au, Jyrki Katajainen, jyrki@diku.dk, November 1996. */\nstatic void tdefl_calculate_minimum_redundancy(tdefl_sym_freq *A, int n)\n{\n    int root, leaf, next, avbl, used, dpth;\n    if (n == 0)\n        return;\n    else if (n == 1)\n    {\n        A[0].m_key = 1;\n        return;\n    }\n    A[0].m_key += A[1].m_key;\n    root = 0;\n    leaf = 2;\n    for (next = 1; next < n - 1; next++)\n    {\n        if (leaf >= n || A[root].m_key < A[leaf].m_key)\n        {\n            A[next].m_key = A[root].m_key;\n            A[root++].m_key = (mz_uint16)next;\n        }\n        else\n            A[next].m_key = A[leaf++].m_key;\n        if (leaf >= n || (root < next && A[root].m_key < A[leaf].m_key))\n        {\n            A[next].m_key = (mz_uint16)(A[next].m_key + A[root].m_key);\n            A[root++].m_key = (mz_uint16)next;\n        }\n        else\n            A[next].m_key = (mz_uint16)(A[next].m_key + A[leaf++].m_key);\n    }\n    A[n - 2].m_key = 0;\n    for (next = n - 3; next >= 0; next--)\n        A[next].m_key = A[A[next].m_key].m_key + 1;\n    avbl = 1;\n    used = dpth = 0;\n    root = n - 2;\n    next = n - 1;\n    while (avbl > 0)\n    {\n        while (root >= 0 && (int)A[root].m_key == dpth)\n        {\n            used++;\n            root--;\n        }\n        while (avbl > used)\n        {\n            A[next--].m_key = (mz_uint16)(dpth);\n            avbl--;\n        }\n        avbl = 2 * used;\n        dpth++;\n        used = 0;\n    }\n}\n\n/* Limits canonical Huffman code table's max code size. */\nenum\n{\n    TDEFL_MAX_SUPPORTED_HUFF_CODESIZE = 32\n};\nstatic void tdefl_huffman_enforce_max_code_size(int *pNum_codes, int code_list_len, int max_code_size)\n{\n    int i;\n    mz_uint32 total = 0;\n    if (code_list_len <= 1)\n        return;\n    for (i = max_code_size + 1; i <= TDEFL_MAX_SUPPORTED_HUFF_CODESIZE; i++)\n        pNum_codes[max_code_size] += pNum_codes[i];\n    for (i = max_code_size; i > 0; i--)\n        total += (((mz_uint32)pNum_codes[i]) << (max_code_size - i));\n    while (total != (1UL << max_code_size))\n    {\n        pNum_codes[max_code_size]--;\n        for (i = max_code_size - 1; i > 0; i--)\n            if (pNum_codes[i])\n            {\n                pNum_codes[i]--;\n                pNum_codes[i + 1] += 2;\n                break;\n            }\n        total--;\n    }\n}\n\nstatic void tdefl_optimize_huffman_table(tdefl_compressor *d, int table_num, int table_len, int code_size_limit, int static_table)\n{\n    int i, j, l, num_codes[1 + TDEFL_MAX_SUPPORTED_HUFF_CODESIZE];\n    mz_uint next_code[TDEFL_MAX_SUPPORTED_HUFF_CODESIZE + 1];\n    MZ_CLEAR_OBJ(num_codes);\n    if (static_table)\n    {\n        for (i = 0; i < table_len; i++)\n            num_codes[d->m_huff_code_sizes[table_num][i]]++;\n    }\n    else\n    {\n        tdefl_sym_freq syms0[TDEFL_MAX_HUFF_SYMBOLS], syms1[TDEFL_MAX_HUFF_SYMBOLS], *pSyms;\n        int num_used_syms = 0;\n        const mz_uint16 *pSym_count = &d->m_huff_count[table_num][0];\n        for (i = 0; i < table_len; i++)\n            if (pSym_count[i])\n            {\n                syms0[num_used_syms].m_key = (mz_uint16)pSym_count[i];\n                syms0[num_used_syms++].m_sym_index = (mz_uint16)i;\n            }\n\n        pSyms = tdefl_radix_sort_syms(num_used_syms, syms0, syms1);\n        tdefl_calculate_minimum_redundancy(pSyms, num_used_syms);\n\n        for (i = 0; i < num_used_syms; i++)\n            num_codes[pSyms[i].m_key]++;\n\n        tdefl_huffman_enforce_max_code_size(num_codes, num_used_syms, code_size_limit);\n\n        MZ_CLEAR_OBJ(d->m_huff_code_sizes[table_num]);\n        MZ_CLEAR_OBJ(d->m_huff_codes[table_num]);\n        for (i = 1, j = num_used_syms; i <= code_size_limit; i++)\n            for (l = num_codes[i]; l > 0; l--)\n                d->m_huff_code_sizes[table_num][pSyms[--j].m_sym_index] = (mz_uint8)(i);\n    }\n\n    next_code[1] = 0;\n    for (j = 0, i = 2; i <= code_size_limit; i++)\n        next_code[i] = j = ((j + num_codes[i - 1]) << 1);\n\n    for (i = 0; i < table_len; i++)\n    {\n        mz_uint rev_code = 0, code, code_size;\n        if ((code_size = d->m_huff_code_sizes[table_num][i]) == 0)\n            continue;\n        code = next_code[code_size]++;\n        for (l = code_size; l > 0; l--, code >>= 1)\n            rev_code = (rev_code << 1) | (code & 1);\n        d->m_huff_codes[table_num][i] = (mz_uint16)rev_code;\n    }\n}\n\n#define TDEFL_PUT_BITS(b, l)                                       \\\n    do                                                             \\\n    {                                                              \\\n        mz_uint bits = b;                                          \\\n        mz_uint len = l;                                           \\\n        MZ_ASSERT(bits <= ((1U << len) - 1U));                     \\\n        d->m_bit_buffer |= (bits << d->m_bits_in);                 \\\n        d->m_bits_in += len;                                       \\\n        while (d->m_bits_in >= 8)                                  \\\n        {                                                          \\\n            if (d->m_pOutput_buf < d->m_pOutput_buf_end)           \\\n                *d->m_pOutput_buf++ = (mz_uint8)(d->m_bit_buffer); \\\n            d->m_bit_buffer >>= 8;                                 \\\n            d->m_bits_in -= 8;                                     \\\n        }                                                          \\\n    }                                                              \\\n    MZ_MACRO_END\n\n#define TDEFL_RLE_PREV_CODE_SIZE()                                                                                       \\\n    {                                                                                                                    \\\n        if (rle_repeat_count)                                                                                            \\\n        {                                                                                                                \\\n            if (rle_repeat_count < 3)                                                                                    \\\n            {                                                                                                            \\\n                d->m_huff_count[2][prev_code_size] = (mz_uint16)(d->m_huff_count[2][prev_code_size] + rle_repeat_count); \\\n                while (rle_repeat_count--)                                                                               \\\n                    packed_code_sizes[num_packed_code_sizes++] = prev_code_size;                                         \\\n            }                                                                                                            \\\n            else                                                                                                         \\\n            {                                                                                                            \\\n                d->m_huff_count[2][16] = (mz_uint16)(d->m_huff_count[2][16] + 1);                                        \\\n                packed_code_sizes[num_packed_code_sizes++] = 16;                                                         \\\n                packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_repeat_count - 3);                           \\\n            }                                                                                                            \\\n            rle_repeat_count = 0;                                                                                        \\\n        }                                                                                                                \\\n    }\n\n#define TDEFL_RLE_ZERO_CODE_SIZE()                                                         \\\n    {                                                                                      \\\n        if (rle_z_count)                                                                   \\\n        {                                                                                  \\\n            if (rle_z_count < 3)                                                           \\\n            {                                                                              \\\n                d->m_huff_count[2][0] = (mz_uint16)(d->m_huff_count[2][0] + rle_z_count);  \\\n                while (rle_z_count--)                                                      \\\n                    packed_code_sizes[num_packed_code_sizes++] = 0;                        \\\n            }                                                                              \\\n            else if (rle_z_count <= 10)                                                    \\\n            {                                                                              \\\n                d->m_huff_count[2][17] = (mz_uint16)(d->m_huff_count[2][17] + 1);          \\\n                packed_code_sizes[num_packed_code_sizes++] = 17;                           \\\n                packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 3);  \\\n            }                                                                              \\\n            else                                                                           \\\n            {                                                                              \\\n                d->m_huff_count[2][18] = (mz_uint16)(d->m_huff_count[2][18] + 1);          \\\n                packed_code_sizes[num_packed_code_sizes++] = 18;                           \\\n                packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 11); \\\n            }                                                                              \\\n            rle_z_count = 0;                                                               \\\n        }                                                                                  \\\n    }\n\nstatic mz_uint8 s_tdefl_packed_code_size_syms_swizzle[] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };\n\nstatic void tdefl_start_dynamic_block(tdefl_compressor *d)\n{\n    int num_lit_codes, num_dist_codes, num_bit_lengths;\n    mz_uint i, total_code_sizes_to_pack, num_packed_code_sizes, rle_z_count, rle_repeat_count, packed_code_sizes_index;\n    mz_uint8 code_sizes_to_pack[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], packed_code_sizes[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], prev_code_size = 0xFF;\n\n    d->m_huff_count[0][256] = 1;\n\n    tdefl_optimize_huffman_table(d, 0, TDEFL_MAX_HUFF_SYMBOLS_0, 15, MZ_FALSE);\n    tdefl_optimize_huffman_table(d, 1, TDEFL_MAX_HUFF_SYMBOLS_1, 15, MZ_FALSE);\n\n    for (num_lit_codes = 286; num_lit_codes > 257; num_lit_codes--)\n        if (d->m_huff_code_sizes[0][num_lit_codes - 1])\n            break;\n    for (num_dist_codes = 30; num_dist_codes > 1; num_dist_codes--)\n        if (d->m_huff_code_sizes[1][num_dist_codes - 1])\n            break;\n\n    memcpy(code_sizes_to_pack, &d->m_huff_code_sizes[0][0], num_lit_codes);\n    memcpy(code_sizes_to_pack + num_lit_codes, &d->m_huff_code_sizes[1][0], num_dist_codes);\n    total_code_sizes_to_pack = num_lit_codes + num_dist_codes;\n    num_packed_code_sizes = 0;\n    rle_z_count = 0;\n    rle_repeat_count = 0;\n\n    memset(&d->m_huff_count[2][0], 0, sizeof(d->m_huff_count[2][0]) * TDEFL_MAX_HUFF_SYMBOLS_2);\n    for (i = 0; i < total_code_sizes_to_pack; i++)\n    {\n        mz_uint8 code_size = code_sizes_to_pack[i];\n        if (!code_size)\n        {\n            TDEFL_RLE_PREV_CODE_SIZE();\n            if (++rle_z_count == 138)\n            {\n                TDEFL_RLE_ZERO_CODE_SIZE();\n            }\n        }\n        else\n        {\n            TDEFL_RLE_ZERO_CODE_SIZE();\n            if (code_size != prev_code_size)\n            {\n                TDEFL_RLE_PREV_CODE_SIZE();\n                d->m_huff_count[2][code_size] = (mz_uint16)(d->m_huff_count[2][code_size] + 1);\n                packed_code_sizes[num_packed_code_sizes++] = code_size;\n            }\n            else if (++rle_repeat_count == 6)\n            {\n                TDEFL_RLE_PREV_CODE_SIZE();\n            }\n        }\n        prev_code_size = code_size;\n    }\n    if (rle_repeat_count)\n    {\n        TDEFL_RLE_PREV_CODE_SIZE();\n    }\n    else\n    {\n        TDEFL_RLE_ZERO_CODE_SIZE();\n    }\n\n    tdefl_optimize_huffman_table(d, 2, TDEFL_MAX_HUFF_SYMBOLS_2, 7, MZ_FALSE);\n\n    TDEFL_PUT_BITS(2, 2);\n\n    TDEFL_PUT_BITS(num_lit_codes - 257, 5);\n    TDEFL_PUT_BITS(num_dist_codes - 1, 5);\n\n    for (num_bit_lengths = 18; num_bit_lengths >= 0; num_bit_lengths--)\n        if (d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[num_bit_lengths]])\n            break;\n    num_bit_lengths = MZ_MAX(4, (num_bit_lengths + 1));\n    TDEFL_PUT_BITS(num_bit_lengths - 4, 4);\n    for (i = 0; (int)i < num_bit_lengths; i++)\n        TDEFL_PUT_BITS(d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[i]], 3);\n\n    for (packed_code_sizes_index = 0; packed_code_sizes_index < num_packed_code_sizes;)\n    {\n        mz_uint code = packed_code_sizes[packed_code_sizes_index++];\n        MZ_ASSERT(code < TDEFL_MAX_HUFF_SYMBOLS_2);\n        TDEFL_PUT_BITS(d->m_huff_codes[2][code], d->m_huff_code_sizes[2][code]);\n        if (code >= 16)\n            TDEFL_PUT_BITS(packed_code_sizes[packed_code_sizes_index++], \"\\02\\03\\07\"[code - 16]);\n    }\n}\n\nstatic void tdefl_start_static_block(tdefl_compressor *d)\n{\n    mz_uint i;\n    mz_uint8 *p = &d->m_huff_code_sizes[0][0];\n\n    for (i = 0; i <= 143; ++i)\n        *p++ = 8;\n    for (; i <= 255; ++i)\n        *p++ = 9;\n    for (; i <= 279; ++i)\n        *p++ = 7;\n    for (; i <= 287; ++i)\n        *p++ = 8;\n\n    memset(d->m_huff_code_sizes[1], 5, 32);\n\n    tdefl_optimize_huffman_table(d, 0, 288, 15, MZ_TRUE);\n    tdefl_optimize_huffman_table(d, 1, 32, 15, MZ_TRUE);\n\n    TDEFL_PUT_BITS(1, 2);\n}\n\nstatic const mz_uint mz_bitmasks[17] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF };\n\n#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS\nstatic mz_bool tdefl_compress_lz_codes(tdefl_compressor *d)\n{\n    mz_uint flags;\n    mz_uint8 *pLZ_codes;\n    mz_uint8 *pOutput_buf = d->m_pOutput_buf;\n    mz_uint8 *pLZ_code_buf_end = d->m_pLZ_code_buf;\n    mz_uint64 bit_buffer = d->m_bit_buffer;\n    mz_uint bits_in = d->m_bits_in;\n\n#define TDEFL_PUT_BITS_FAST(b, l)                    \\\n    {                                                \\\n        bit_buffer |= (((mz_uint64)(b)) << bits_in); \\\n        bits_in += (l);                              \\\n    }\n\n    flags = 1;\n    for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < pLZ_code_buf_end; flags >>= 1)\n    {\n        if (flags == 1)\n            flags = *pLZ_codes++ | 0x100;\n\n        if (flags & 1)\n        {\n            mz_uint s0, s1, n0, n1, sym, num_extra_bits;\n            mz_uint match_len = pLZ_codes[0], match_dist = *(const mz_uint16 *)(pLZ_codes + 1);\n            pLZ_codes += 3;\n\n            MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]);\n            TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]);\n            TDEFL_PUT_BITS_FAST(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]);\n\n            /* This sequence coaxes MSVC into using cmov's vs. jmp's. */\n            s0 = s_tdefl_small_dist_sym[match_dist & 511];\n            n0 = s_tdefl_small_dist_extra[match_dist & 511];\n            s1 = s_tdefl_large_dist_sym[match_dist >> 8];\n            n1 = s_tdefl_large_dist_extra[match_dist >> 8];\n            sym = (match_dist < 512) ? s0 : s1;\n            num_extra_bits = (match_dist < 512) ? n0 : n1;\n\n            MZ_ASSERT(d->m_huff_code_sizes[1][sym]);\n            TDEFL_PUT_BITS_FAST(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]);\n            TDEFL_PUT_BITS_FAST(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits);\n        }\n        else\n        {\n            mz_uint lit = *pLZ_codes++;\n            MZ_ASSERT(d->m_huff_code_sizes[0][lit]);\n            TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]);\n\n            if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end))\n            {\n                flags >>= 1;\n                lit = *pLZ_codes++;\n                MZ_ASSERT(d->m_huff_code_sizes[0][lit]);\n                TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]);\n\n                if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end))\n                {\n                    flags >>= 1;\n                    lit = *pLZ_codes++;\n                    MZ_ASSERT(d->m_huff_code_sizes[0][lit]);\n                    TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]);\n                }\n            }\n        }\n\n        if (pOutput_buf >= d->m_pOutput_buf_end)\n            return MZ_FALSE;\n\n        *(mz_uint64 *)pOutput_buf = bit_buffer;\n        pOutput_buf += (bits_in >> 3);\n        bit_buffer >>= (bits_in & ~7);\n        bits_in &= 7;\n    }\n\n#undef TDEFL_PUT_BITS_FAST\n\n    d->m_pOutput_buf = pOutput_buf;\n    d->m_bits_in = 0;\n    d->m_bit_buffer = 0;\n\n    while (bits_in)\n    {\n        mz_uint32 n = MZ_MIN(bits_in, 16);\n        TDEFL_PUT_BITS((mz_uint)bit_buffer & mz_bitmasks[n], n);\n        bit_buffer >>= n;\n        bits_in -= n;\n    }\n\n    TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]);\n\n    return (d->m_pOutput_buf < d->m_pOutput_buf_end);\n}\n#else\nstatic mz_bool tdefl_compress_lz_codes(tdefl_compressor *d)\n{\n    mz_uint flags;\n    mz_uint8 *pLZ_codes;\n\n    flags = 1;\n    for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < d->m_pLZ_code_buf; flags >>= 1)\n    {\n        if (flags == 1)\n            flags = *pLZ_codes++ | 0x100;\n        if (flags & 1)\n        {\n            mz_uint sym, num_extra_bits;\n            mz_uint match_len = pLZ_codes[0], match_dist = (pLZ_codes[1] | (pLZ_codes[2] << 8));\n            pLZ_codes += 3;\n\n            MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]);\n            TDEFL_PUT_BITS(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]);\n            TDEFL_PUT_BITS(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]);\n\n            if (match_dist < 512)\n            {\n                sym = s_tdefl_small_dist_sym[match_dist];\n                num_extra_bits = s_tdefl_small_dist_extra[match_dist];\n            }\n            else\n            {\n                sym = s_tdefl_large_dist_sym[match_dist >> 8];\n                num_extra_bits = s_tdefl_large_dist_extra[match_dist >> 8];\n            }\n            MZ_ASSERT(d->m_huff_code_sizes[1][sym]);\n            TDEFL_PUT_BITS(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]);\n            TDEFL_PUT_BITS(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits);\n        }\n        else\n        {\n            mz_uint lit = *pLZ_codes++;\n            MZ_ASSERT(d->m_huff_code_sizes[0][lit]);\n            TDEFL_PUT_BITS(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]);\n        }\n    }\n\n    TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]);\n\n    return (d->m_pOutput_buf < d->m_pOutput_buf_end);\n}\n#endif /* MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS */\n\nstatic mz_bool tdefl_compress_block(tdefl_compressor *d, mz_bool static_block)\n{\n    if (static_block)\n        tdefl_start_static_block(d);\n    else\n        tdefl_start_dynamic_block(d);\n    return tdefl_compress_lz_codes(d);\n}\n\nstatic int tdefl_flush_block(tdefl_compressor *d, int flush)\n{\n    mz_uint saved_bit_buf, saved_bits_in;\n    mz_uint8 *pSaved_output_buf;\n    mz_bool comp_block_succeeded = MZ_FALSE;\n    int n, use_raw_block = ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) && (d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size;\n    mz_uint8 *pOutput_buf_start = ((d->m_pPut_buf_func == NULL) && ((*d->m_pOut_buf_size - d->m_out_buf_ofs) >= TDEFL_OUT_BUF_SIZE)) ? ((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs) : d->m_output_buf;\n\n    d->m_pOutput_buf = pOutput_buf_start;\n    d->m_pOutput_buf_end = d->m_pOutput_buf + TDEFL_OUT_BUF_SIZE - 16;\n\n    MZ_ASSERT(!d->m_output_flush_remaining);\n    d->m_output_flush_ofs = 0;\n    d->m_output_flush_remaining = 0;\n\n    *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> d->m_num_flags_left);\n    d->m_pLZ_code_buf -= (d->m_num_flags_left == 8);\n\n    if ((d->m_flags & TDEFL_WRITE_ZLIB_HEADER) && (!d->m_block_index))\n    {\n        TDEFL_PUT_BITS(0x78, 8);\n        TDEFL_PUT_BITS(0x01, 8);\n    }\n\n    TDEFL_PUT_BITS(flush == TDEFL_FINISH, 1);\n\n    pSaved_output_buf = d->m_pOutput_buf;\n    saved_bit_buf = d->m_bit_buffer;\n    saved_bits_in = d->m_bits_in;\n\n    if (!use_raw_block)\n        comp_block_succeeded = tdefl_compress_block(d, (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) || (d->m_total_lz_bytes < 48));\n\n    /* If the block gets expanded, forget the current contents of the output buffer and send a raw block instead. */\n    if (((use_raw_block) || ((d->m_total_lz_bytes) && ((d->m_pOutput_buf - pSaved_output_buf + 1U) >= d->m_total_lz_bytes))) &&\n        ((d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size))\n    {\n        mz_uint i;\n        d->m_pOutput_buf = pSaved_output_buf;\n        d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in;\n        TDEFL_PUT_BITS(0, 2);\n        if (d->m_bits_in)\n        {\n            TDEFL_PUT_BITS(0, 8 - d->m_bits_in);\n        }\n        for (i = 2; i; --i, d->m_total_lz_bytes ^= 0xFFFF)\n        {\n            TDEFL_PUT_BITS(d->m_total_lz_bytes & 0xFFFF, 16);\n        }\n        for (i = 0; i < d->m_total_lz_bytes; ++i)\n        {\n            TDEFL_PUT_BITS(d->m_dict[(d->m_lz_code_buf_dict_pos + i) & TDEFL_LZ_DICT_SIZE_MASK], 8);\n        }\n    }\n    /* Check for the extremely unlikely (if not impossible) case of the compressed block not fitting into the output buffer when using dynamic codes. */\n    else if (!comp_block_succeeded)\n    {\n        d->m_pOutput_buf = pSaved_output_buf;\n        d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in;\n        tdefl_compress_block(d, MZ_TRUE);\n    }\n\n    if (flush)\n    {\n        if (flush == TDEFL_FINISH)\n        {\n            if (d->m_bits_in)\n            {\n                TDEFL_PUT_BITS(0, 8 - d->m_bits_in);\n            }\n            if (d->m_flags & TDEFL_WRITE_ZLIB_HEADER)\n            {\n                mz_uint i, a = d->m_adler32;\n                for (i = 0; i < 4; i++)\n                {\n                    TDEFL_PUT_BITS((a >> 24) & 0xFF, 8);\n                    a <<= 8;\n                }\n            }\n        }\n        else\n        {\n            mz_uint i, z = 0;\n            TDEFL_PUT_BITS(0, 3);\n            if (d->m_bits_in)\n            {\n                TDEFL_PUT_BITS(0, 8 - d->m_bits_in);\n            }\n            for (i = 2; i; --i, z ^= 0xFFFF)\n            {\n                TDEFL_PUT_BITS(z & 0xFFFF, 16);\n            }\n        }\n    }\n\n    MZ_ASSERT(d->m_pOutput_buf < d->m_pOutput_buf_end);\n\n    memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0);\n    memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1);\n\n    d->m_pLZ_code_buf = d->m_lz_code_buf + 1;\n    d->m_pLZ_flags = d->m_lz_code_buf;\n    d->m_num_flags_left = 8;\n    d->m_lz_code_buf_dict_pos += d->m_total_lz_bytes;\n    d->m_total_lz_bytes = 0;\n    d->m_block_index++;\n\n    if ((n = (int)(d->m_pOutput_buf - pOutput_buf_start)) != 0)\n    {\n        if (d->m_pPut_buf_func)\n        {\n            *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf;\n            if (!(*d->m_pPut_buf_func)(d->m_output_buf, n, d->m_pPut_buf_user))\n                return (d->m_prev_return_status = TDEFL_STATUS_PUT_BUF_FAILED);\n        }\n        else if (pOutput_buf_start == d->m_output_buf)\n        {\n            int bytes_to_copy = (int)MZ_MIN((size_t)n, (size_t)(*d->m_pOut_buf_size - d->m_out_buf_ofs));\n            memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf, bytes_to_copy);\n            d->m_out_buf_ofs += bytes_to_copy;\n            if ((n -= bytes_to_copy) != 0)\n            {\n                d->m_output_flush_ofs = bytes_to_copy;\n                d->m_output_flush_remaining = n;\n            }\n        }\n        else\n        {\n            d->m_out_buf_ofs += n;\n        }\n    }\n\n    return d->m_output_flush_remaining;\n}\n\n#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES\n#ifdef MINIZ_UNALIGNED_USE_MEMCPY\nstatic mz_uint16 TDEFL_READ_UNALIGNED_WORD(const mz_uint8* p)\n{\n\tmz_uint16 ret;\n\tmemcpy(&ret, p, sizeof(mz_uint16));\n\treturn ret;\n}\nstatic mz_uint16 TDEFL_READ_UNALIGNED_WORD2(const mz_uint16* p)\n{\n\tmz_uint16 ret;\n\tmemcpy(&ret, p, sizeof(mz_uint16));\n\treturn ret;\n}\n#else\n#define TDEFL_READ_UNALIGNED_WORD(p) *(const mz_uint16 *)(p)\n#define TDEFL_READ_UNALIGNED_WORD2(p) *(const mz_uint16 *)(p)\n#endif\nstatic MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len)\n{\n    mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len;\n    mz_uint num_probes_left = d->m_max_probes[match_len >= 32];\n    const mz_uint16 *s = (const mz_uint16 *)(d->m_dict + pos), *p, *q;\n    mz_uint16 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]), s01 = TDEFL_READ_UNALIGNED_WORD2(s);\n    MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN);\n    if (max_match_len <= match_len)\n        return;\n    for (;;)\n    {\n        for (;;)\n        {\n            if (--num_probes_left == 0)\n                return;\n#define TDEFL_PROBE                                                                             \\\n    next_probe_pos = d->m_next[probe_pos];                                                      \\\n    if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \\\n        return;                                                                                 \\\n    probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK;                                       \\\n    if (TDEFL_READ_UNALIGNED_WORD(&d->m_dict[probe_pos + match_len - 1]) == c01)                \\\n        break;\n            TDEFL_PROBE;\n            TDEFL_PROBE;\n            TDEFL_PROBE;\n        }\n        if (!dist)\n            break;\n        q = (const mz_uint16 *)(d->m_dict + probe_pos);\n        if (TDEFL_READ_UNALIGNED_WORD2(q) != s01)\n            continue;\n        p = s;\n        probe_len = 32;\n        do\n        {\n        } while ((TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) &&\n                 (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (--probe_len > 0));\n        if (!probe_len)\n        {\n            *pMatch_dist = dist;\n            *pMatch_len = MZ_MIN(max_match_len, (mz_uint)TDEFL_MAX_MATCH_LEN);\n            break;\n        }\n        else if ((probe_len = ((mz_uint)(p - s) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q)) > match_len)\n        {\n            *pMatch_dist = dist;\n            if ((*pMatch_len = match_len = MZ_MIN(max_match_len, probe_len)) == max_match_len)\n                break;\n            c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]);\n        }\n    }\n}\n#else\nstatic MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len)\n{\n    mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len;\n    mz_uint num_probes_left = d->m_max_probes[match_len >= 32];\n    const mz_uint8 *s = d->m_dict + pos, *p, *q;\n    mz_uint8 c0 = d->m_dict[pos + match_len], c1 = d->m_dict[pos + match_len - 1];\n    MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN);\n    if (max_match_len <= match_len)\n        return;\n    for (;;)\n    {\n        for (;;)\n        {\n            if (--num_probes_left == 0)\n                return;\n#define TDEFL_PROBE                                                                               \\\n    next_probe_pos = d->m_next[probe_pos];                                                        \\\n    if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist))   \\\n        return;                                                                                   \\\n    probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK;                                         \\\n    if ((d->m_dict[probe_pos + match_len] == c0) && (d->m_dict[probe_pos + match_len - 1] == c1)) \\\n        break;\n            TDEFL_PROBE;\n            TDEFL_PROBE;\n            TDEFL_PROBE;\n        }\n        if (!dist)\n            break;\n        p = s;\n        q = d->m_dict + probe_pos;\n        for (probe_len = 0; probe_len < max_match_len; probe_len++)\n            if (*p++ != *q++)\n                break;\n        if (probe_len > match_len)\n        {\n            *pMatch_dist = dist;\n            if ((*pMatch_len = match_len = probe_len) == max_match_len)\n                return;\n            c0 = d->m_dict[pos + match_len];\n            c1 = d->m_dict[pos + match_len - 1];\n        }\n    }\n}\n#endif /* #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES */\n\n#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN\n#ifdef MINIZ_UNALIGNED_USE_MEMCPY\nstatic mz_uint32 TDEFL_READ_UNALIGNED_WORD32(const mz_uint8* p)\n{\n\tmz_uint32 ret;\n\tmemcpy(&ret, p, sizeof(mz_uint32));\n\treturn ret;\n}\n#else\n#define TDEFL_READ_UNALIGNED_WORD32(p) *(const mz_uint32 *)(p)\n#endif\nstatic mz_bool tdefl_compress_fast(tdefl_compressor *d)\n{\n    /* Faster, minimally featured LZRW1-style match+parse loop with better register utilization. Intended for applications where raw throughput is valued more highly than ratio. */\n    mz_uint lookahead_pos = d->m_lookahead_pos, lookahead_size = d->m_lookahead_size, dict_size = d->m_dict_size, total_lz_bytes = d->m_total_lz_bytes, num_flags_left = d->m_num_flags_left;\n    mz_uint8 *pLZ_code_buf = d->m_pLZ_code_buf, *pLZ_flags = d->m_pLZ_flags;\n    mz_uint cur_pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK;\n\n    while ((d->m_src_buf_left) || ((d->m_flush) && (lookahead_size)))\n    {\n        const mz_uint TDEFL_COMP_FAST_LOOKAHEAD_SIZE = 4096;\n        mz_uint dst_pos = (lookahead_pos + lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK;\n        mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(d->m_src_buf_left, TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size);\n        d->m_src_buf_left -= num_bytes_to_process;\n        lookahead_size += num_bytes_to_process;\n\n        while (num_bytes_to_process)\n        {\n            mz_uint32 n = MZ_MIN(TDEFL_LZ_DICT_SIZE - dst_pos, num_bytes_to_process);\n            memcpy(d->m_dict + dst_pos, d->m_pSrc, n);\n            if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1))\n                memcpy(d->m_dict + TDEFL_LZ_DICT_SIZE + dst_pos, d->m_pSrc, MZ_MIN(n, (TDEFL_MAX_MATCH_LEN - 1) - dst_pos));\n            d->m_pSrc += n;\n            dst_pos = (dst_pos + n) & TDEFL_LZ_DICT_SIZE_MASK;\n            num_bytes_to_process -= n;\n        }\n\n        dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - lookahead_size, dict_size);\n        if ((!d->m_flush) && (lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE))\n            break;\n\n        while (lookahead_size >= 4)\n        {\n            mz_uint cur_match_dist, cur_match_len = 1;\n            mz_uint8 *pCur_dict = d->m_dict + cur_pos;\n            mz_uint first_trigram = TDEFL_READ_UNALIGNED_WORD32(pCur_dict) & 0xFFFFFF;\n            mz_uint hash = (first_trigram ^ (first_trigram >> (24 - (TDEFL_LZ_HASH_BITS - 8)))) & TDEFL_LEVEL1_HASH_SIZE_MASK;\n            mz_uint probe_pos = d->m_hash[hash];\n            d->m_hash[hash] = (mz_uint16)lookahead_pos;\n\n            if (((cur_match_dist = (mz_uint16)(lookahead_pos - probe_pos)) <= dict_size) && ((TDEFL_READ_UNALIGNED_WORD32(d->m_dict + (probe_pos &= TDEFL_LZ_DICT_SIZE_MASK)) & 0xFFFFFF) == first_trigram))\n            {\n                const mz_uint16 *p = (const mz_uint16 *)pCur_dict;\n                const mz_uint16 *q = (const mz_uint16 *)(d->m_dict + probe_pos);\n                mz_uint32 probe_len = 32;\n                do\n                {\n                } while ((TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) &&\n                         (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (--probe_len > 0));\n                cur_match_len = ((mz_uint)(p - (const mz_uint16 *)pCur_dict) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q);\n                if (!probe_len)\n                    cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0;\n\n                if ((cur_match_len < TDEFL_MIN_MATCH_LEN) || ((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U * 1024U)))\n                {\n                    cur_match_len = 1;\n                    *pLZ_code_buf++ = (mz_uint8)first_trigram;\n                    *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1);\n                    d->m_huff_count[0][(mz_uint8)first_trigram]++;\n                }\n                else\n                {\n                    mz_uint32 s0, s1;\n                    cur_match_len = MZ_MIN(cur_match_len, lookahead_size);\n\n                    MZ_ASSERT((cur_match_len >= TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 1) && (cur_match_dist <= TDEFL_LZ_DICT_SIZE));\n\n                    cur_match_dist--;\n\n                    pLZ_code_buf[0] = (mz_uint8)(cur_match_len - TDEFL_MIN_MATCH_LEN);\n#ifdef MINIZ_UNALIGNED_USE_MEMCPY\n\t\t\t\t\tmemcpy(&pLZ_code_buf[1], &cur_match_dist, sizeof(cur_match_dist));\n#else\n                    *(mz_uint16 *)(&pLZ_code_buf[1]) = (mz_uint16)cur_match_dist;\n#endif\n                    pLZ_code_buf += 3;\n                    *pLZ_flags = (mz_uint8)((*pLZ_flags >> 1) | 0x80);\n\n                    s0 = s_tdefl_small_dist_sym[cur_match_dist & 511];\n                    s1 = s_tdefl_large_dist_sym[cur_match_dist >> 8];\n                    d->m_huff_count[1][(cur_match_dist < 512) ? s0 : s1]++;\n\n                    d->m_huff_count[0][s_tdefl_len_sym[cur_match_len - TDEFL_MIN_MATCH_LEN]]++;\n                }\n            }\n            else\n            {\n                *pLZ_code_buf++ = (mz_uint8)first_trigram;\n                *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1);\n                d->m_huff_count[0][(mz_uint8)first_trigram]++;\n            }\n\n            if (--num_flags_left == 0)\n            {\n                num_flags_left = 8;\n                pLZ_flags = pLZ_code_buf++;\n            }\n\n            total_lz_bytes += cur_match_len;\n            lookahead_pos += cur_match_len;\n            dict_size = MZ_MIN(dict_size + cur_match_len, (mz_uint)TDEFL_LZ_DICT_SIZE);\n            cur_pos = (cur_pos + cur_match_len) & TDEFL_LZ_DICT_SIZE_MASK;\n            MZ_ASSERT(lookahead_size >= cur_match_len);\n            lookahead_size -= cur_match_len;\n\n            if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8])\n            {\n                int n;\n                d->m_lookahead_pos = lookahead_pos;\n                d->m_lookahead_size = lookahead_size;\n                d->m_dict_size = dict_size;\n                d->m_total_lz_bytes = total_lz_bytes;\n                d->m_pLZ_code_buf = pLZ_code_buf;\n                d->m_pLZ_flags = pLZ_flags;\n                d->m_num_flags_left = num_flags_left;\n                if ((n = tdefl_flush_block(d, 0)) != 0)\n                    return (n < 0) ? MZ_FALSE : MZ_TRUE;\n                total_lz_bytes = d->m_total_lz_bytes;\n                pLZ_code_buf = d->m_pLZ_code_buf;\n                pLZ_flags = d->m_pLZ_flags;\n                num_flags_left = d->m_num_flags_left;\n            }\n        }\n\n        while (lookahead_size)\n        {\n            mz_uint8 lit = d->m_dict[cur_pos];\n\n            total_lz_bytes++;\n            *pLZ_code_buf++ = lit;\n            *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1);\n            if (--num_flags_left == 0)\n            {\n                num_flags_left = 8;\n                pLZ_flags = pLZ_code_buf++;\n            }\n\n            d->m_huff_count[0][lit]++;\n\n            lookahead_pos++;\n            dict_size = MZ_MIN(dict_size + 1, (mz_uint)TDEFL_LZ_DICT_SIZE);\n            cur_pos = (cur_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK;\n            lookahead_size--;\n\n            if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8])\n            {\n                int n;\n                d->m_lookahead_pos = lookahead_pos;\n                d->m_lookahead_size = lookahead_size;\n                d->m_dict_size = dict_size;\n                d->m_total_lz_bytes = total_lz_bytes;\n                d->m_pLZ_code_buf = pLZ_code_buf;\n                d->m_pLZ_flags = pLZ_flags;\n                d->m_num_flags_left = num_flags_left;\n                if ((n = tdefl_flush_block(d, 0)) != 0)\n                    return (n < 0) ? MZ_FALSE : MZ_TRUE;\n                total_lz_bytes = d->m_total_lz_bytes;\n                pLZ_code_buf = d->m_pLZ_code_buf;\n                pLZ_flags = d->m_pLZ_flags;\n                num_flags_left = d->m_num_flags_left;\n            }\n        }\n    }\n\n    d->m_lookahead_pos = lookahead_pos;\n    d->m_lookahead_size = lookahead_size;\n    d->m_dict_size = dict_size;\n    d->m_total_lz_bytes = total_lz_bytes;\n    d->m_pLZ_code_buf = pLZ_code_buf;\n    d->m_pLZ_flags = pLZ_flags;\n    d->m_num_flags_left = num_flags_left;\n    return MZ_TRUE;\n}\n#endif /* MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN */\n\nstatic MZ_FORCEINLINE void tdefl_record_literal(tdefl_compressor *d, mz_uint8 lit)\n{\n    d->m_total_lz_bytes++;\n    *d->m_pLZ_code_buf++ = lit;\n    *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> 1);\n    if (--d->m_num_flags_left == 0)\n    {\n        d->m_num_flags_left = 8;\n        d->m_pLZ_flags = d->m_pLZ_code_buf++;\n    }\n    d->m_huff_count[0][lit]++;\n}\n\nstatic MZ_FORCEINLINE void tdefl_record_match(tdefl_compressor *d, mz_uint match_len, mz_uint match_dist)\n{\n    mz_uint32 s0, s1;\n\n    MZ_ASSERT((match_len >= TDEFL_MIN_MATCH_LEN) && (match_dist >= 1) && (match_dist <= TDEFL_LZ_DICT_SIZE));\n\n    d->m_total_lz_bytes += match_len;\n\n    d->m_pLZ_code_buf[0] = (mz_uint8)(match_len - TDEFL_MIN_MATCH_LEN);\n\n    match_dist -= 1;\n    d->m_pLZ_code_buf[1] = (mz_uint8)(match_dist & 0xFF);\n    d->m_pLZ_code_buf[2] = (mz_uint8)(match_dist >> 8);\n    d->m_pLZ_code_buf += 3;\n\n    *d->m_pLZ_flags = (mz_uint8)((*d->m_pLZ_flags >> 1) | 0x80);\n    if (--d->m_num_flags_left == 0)\n    {\n        d->m_num_flags_left = 8;\n        d->m_pLZ_flags = d->m_pLZ_code_buf++;\n    }\n\n    s0 = s_tdefl_small_dist_sym[match_dist & 511];\n    s1 = s_tdefl_large_dist_sym[(match_dist >> 8) & 127];\n    d->m_huff_count[1][(match_dist < 512) ? s0 : s1]++;\n\n    if (match_len >= TDEFL_MIN_MATCH_LEN)\n        d->m_huff_count[0][s_tdefl_len_sym[match_len - TDEFL_MIN_MATCH_LEN]]++;\n}\n\nstatic mz_bool tdefl_compress_normal(tdefl_compressor *d)\n{\n    const mz_uint8 *pSrc = d->m_pSrc;\n    size_t src_buf_left = d->m_src_buf_left;\n    tdefl_flush flush = d->m_flush;\n\n    while ((src_buf_left) || ((flush) && (d->m_lookahead_size)))\n    {\n        mz_uint len_to_move, cur_match_dist, cur_match_len, cur_pos;\n        /* Update dictionary and hash chains. Keeps the lookahead size equal to TDEFL_MAX_MATCH_LEN. */\n        if ((d->m_lookahead_size + d->m_dict_size) >= (TDEFL_MIN_MATCH_LEN - 1))\n        {\n            mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK, ins_pos = d->m_lookahead_pos + d->m_lookahead_size - 2;\n            mz_uint hash = (d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK];\n            mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(src_buf_left, TDEFL_MAX_MATCH_LEN - d->m_lookahead_size);\n            const mz_uint8 *pSrc_end = pSrc + num_bytes_to_process;\n            src_buf_left -= num_bytes_to_process;\n            d->m_lookahead_size += num_bytes_to_process;\n            while (pSrc != pSrc_end)\n            {\n                mz_uint8 c = *pSrc++;\n                d->m_dict[dst_pos] = c;\n                if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1))\n                    d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c;\n                hash = ((hash << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1);\n                d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash];\n                d->m_hash[hash] = (mz_uint16)(ins_pos);\n                dst_pos = (dst_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK;\n                ins_pos++;\n            }\n        }\n        else\n        {\n            while ((src_buf_left) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN))\n            {\n                mz_uint8 c = *pSrc++;\n                mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK;\n                src_buf_left--;\n                d->m_dict[dst_pos] = c;\n                if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1))\n                    d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c;\n                if ((++d->m_lookahead_size + d->m_dict_size) >= TDEFL_MIN_MATCH_LEN)\n                {\n                    mz_uint ins_pos = d->m_lookahead_pos + (d->m_lookahead_size - 1) - 2;\n                    mz_uint hash = ((d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << (TDEFL_LZ_HASH_SHIFT * 2)) ^ (d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1);\n                    d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash];\n                    d->m_hash[hash] = (mz_uint16)(ins_pos);\n                }\n            }\n        }\n        d->m_dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - d->m_lookahead_size, d->m_dict_size);\n        if ((!flush) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN))\n            break;\n\n        /* Simple lazy/greedy parsing state machine. */\n        len_to_move = 1;\n        cur_match_dist = 0;\n        cur_match_len = d->m_saved_match_len ? d->m_saved_match_len : (TDEFL_MIN_MATCH_LEN - 1);\n        cur_pos = d->m_lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK;\n        if (d->m_flags & (TDEFL_RLE_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS))\n        {\n            if ((d->m_dict_size) && (!(d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS)))\n            {\n                mz_uint8 c = d->m_dict[(cur_pos - 1) & TDEFL_LZ_DICT_SIZE_MASK];\n                cur_match_len = 0;\n                while (cur_match_len < d->m_lookahead_size)\n                {\n                    if (d->m_dict[cur_pos + cur_match_len] != c)\n                        break;\n                    cur_match_len++;\n                }\n                if (cur_match_len < TDEFL_MIN_MATCH_LEN)\n                    cur_match_len = 0;\n                else\n                    cur_match_dist = 1;\n            }\n        }\n        else\n        {\n            tdefl_find_match(d, d->m_lookahead_pos, d->m_dict_size, d->m_lookahead_size, &cur_match_dist, &cur_match_len);\n        }\n        if (((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U * 1024U)) || (cur_pos == cur_match_dist) || ((d->m_flags & TDEFL_FILTER_MATCHES) && (cur_match_len <= 5)))\n        {\n            cur_match_dist = cur_match_len = 0;\n        }\n        if (d->m_saved_match_len)\n        {\n            if (cur_match_len > d->m_saved_match_len)\n            {\n                tdefl_record_literal(d, (mz_uint8)d->m_saved_lit);\n                if (cur_match_len >= 128)\n                {\n                    tdefl_record_match(d, cur_match_len, cur_match_dist);\n                    d->m_saved_match_len = 0;\n                    len_to_move = cur_match_len;\n                }\n                else\n                {\n                    d->m_saved_lit = d->m_dict[cur_pos];\n                    d->m_saved_match_dist = cur_match_dist;\n                    d->m_saved_match_len = cur_match_len;\n                }\n            }\n            else\n            {\n                tdefl_record_match(d, d->m_saved_match_len, d->m_saved_match_dist);\n                len_to_move = d->m_saved_match_len - 1;\n                d->m_saved_match_len = 0;\n            }\n        }\n        else if (!cur_match_dist)\n            tdefl_record_literal(d, d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]);\n        else if ((d->m_greedy_parsing) || (d->m_flags & TDEFL_RLE_MATCHES) || (cur_match_len >= 128))\n        {\n            tdefl_record_match(d, cur_match_len, cur_match_dist);\n            len_to_move = cur_match_len;\n        }\n        else\n        {\n            d->m_saved_lit = d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)];\n            d->m_saved_match_dist = cur_match_dist;\n            d->m_saved_match_len = cur_match_len;\n        }\n        /* Move the lookahead forward by len_to_move bytes. */\n        d->m_lookahead_pos += len_to_move;\n        MZ_ASSERT(d->m_lookahead_size >= len_to_move);\n        d->m_lookahead_size -= len_to_move;\n        d->m_dict_size = MZ_MIN(d->m_dict_size + len_to_move, (mz_uint)TDEFL_LZ_DICT_SIZE);\n        /* Check if it's time to flush the current LZ codes to the internal output buffer. */\n        if ((d->m_pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) ||\n            ((d->m_total_lz_bytes > 31 * 1024) && (((((mz_uint)(d->m_pLZ_code_buf - d->m_lz_code_buf) * 115) >> 7) >= d->m_total_lz_bytes) || (d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))))\n        {\n            int n;\n            d->m_pSrc = pSrc;\n            d->m_src_buf_left = src_buf_left;\n            if ((n = tdefl_flush_block(d, 0)) != 0)\n                return (n < 0) ? MZ_FALSE : MZ_TRUE;\n        }\n    }\n\n    d->m_pSrc = pSrc;\n    d->m_src_buf_left = src_buf_left;\n    return MZ_TRUE;\n}\n\nstatic tdefl_status tdefl_flush_output_buffer(tdefl_compressor *d)\n{\n    if (d->m_pIn_buf_size)\n    {\n        *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf;\n    }\n\n    if (d->m_pOut_buf_size)\n    {\n        size_t n = MZ_MIN(*d->m_pOut_buf_size - d->m_out_buf_ofs, d->m_output_flush_remaining);\n        memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf + d->m_output_flush_ofs, n);\n        d->m_output_flush_ofs += (mz_uint)n;\n        d->m_output_flush_remaining -= (mz_uint)n;\n        d->m_out_buf_ofs += n;\n\n        *d->m_pOut_buf_size = d->m_out_buf_ofs;\n    }\n\n    return (d->m_finished && !d->m_output_flush_remaining) ? TDEFL_STATUS_DONE : TDEFL_STATUS_OKAY;\n}\n\ntdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush)\n{\n    if (!d)\n    {\n        if (pIn_buf_size)\n            *pIn_buf_size = 0;\n        if (pOut_buf_size)\n            *pOut_buf_size = 0;\n        return TDEFL_STATUS_BAD_PARAM;\n    }\n\n    d->m_pIn_buf = pIn_buf;\n    d->m_pIn_buf_size = pIn_buf_size;\n    d->m_pOut_buf = pOut_buf;\n    d->m_pOut_buf_size = pOut_buf_size;\n    d->m_pSrc = (const mz_uint8 *)(pIn_buf);\n    d->m_src_buf_left = pIn_buf_size ? *pIn_buf_size : 0;\n    d->m_out_buf_ofs = 0;\n    d->m_flush = flush;\n\n    if (((d->m_pPut_buf_func != NULL) == ((pOut_buf != NULL) || (pOut_buf_size != NULL))) || (d->m_prev_return_status != TDEFL_STATUS_OKAY) ||\n        (d->m_wants_to_finish && (flush != TDEFL_FINISH)) || (pIn_buf_size && *pIn_buf_size && !pIn_buf) || (pOut_buf_size && *pOut_buf_size && !pOut_buf))\n    {\n        if (pIn_buf_size)\n            *pIn_buf_size = 0;\n        if (pOut_buf_size)\n            *pOut_buf_size = 0;\n        return (d->m_prev_return_status = TDEFL_STATUS_BAD_PARAM);\n    }\n    d->m_wants_to_finish |= (flush == TDEFL_FINISH);\n\n    if ((d->m_output_flush_remaining) || (d->m_finished))\n        return (d->m_prev_return_status = tdefl_flush_output_buffer(d));\n\n#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN\n    if (((d->m_flags & TDEFL_MAX_PROBES_MASK) == 1) &&\n        ((d->m_flags & TDEFL_GREEDY_PARSING_FLAG) != 0) &&\n        ((d->m_flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS | TDEFL_RLE_MATCHES)) == 0))\n    {\n        if (!tdefl_compress_fast(d))\n            return d->m_prev_return_status;\n    }\n    else\n#endif /* #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN */\n    {\n        if (!tdefl_compress_normal(d))\n            return d->m_prev_return_status;\n    }\n\n    if ((d->m_flags & (TDEFL_WRITE_ZLIB_HEADER | TDEFL_COMPUTE_ADLER32)) && (pIn_buf))\n        d->m_adler32 = (mz_uint32)mz_adler32(d->m_adler32, (const mz_uint8 *)pIn_buf, d->m_pSrc - (const mz_uint8 *)pIn_buf);\n\n    if ((flush) && (!d->m_lookahead_size) && (!d->m_src_buf_left) && (!d->m_output_flush_remaining))\n    {\n        if (tdefl_flush_block(d, flush) < 0)\n            return d->m_prev_return_status;\n        d->m_finished = (flush == TDEFL_FINISH);\n        if (flush == TDEFL_FULL_FLUSH)\n        {\n            MZ_CLEAR_OBJ(d->m_hash);\n            MZ_CLEAR_OBJ(d->m_next);\n            d->m_dict_size = 0;\n        }\n    }\n\n    return (d->m_prev_return_status = tdefl_flush_output_buffer(d));\n}\n\ntdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush)\n{\n    MZ_ASSERT(d->m_pPut_buf_func);\n    return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush);\n}\n\ntdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags)\n{\n    d->m_pPut_buf_func = pPut_buf_func;\n    d->m_pPut_buf_user = pPut_buf_user;\n    d->m_flags = (mz_uint)(flags);\n    d->m_max_probes[0] = 1 + ((flags & 0xFFF) + 2) / 3;\n    d->m_greedy_parsing = (flags & TDEFL_GREEDY_PARSING_FLAG) != 0;\n    d->m_max_probes[1] = 1 + (((flags & 0xFFF) >> 2) + 2) / 3;\n    if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG))\n        MZ_CLEAR_OBJ(d->m_hash);\n    d->m_lookahead_pos = d->m_lookahead_size = d->m_dict_size = d->m_total_lz_bytes = d->m_lz_code_buf_dict_pos = d->m_bits_in = 0;\n    d->m_output_flush_ofs = d->m_output_flush_remaining = d->m_finished = d->m_block_index = d->m_bit_buffer = d->m_wants_to_finish = 0;\n    d->m_pLZ_code_buf = d->m_lz_code_buf + 1;\n    d->m_pLZ_flags = d->m_lz_code_buf;\n    d->m_num_flags_left = 8;\n    d->m_pOutput_buf = d->m_output_buf;\n    d->m_pOutput_buf_end = d->m_output_buf;\n    d->m_prev_return_status = TDEFL_STATUS_OKAY;\n    d->m_saved_match_dist = d->m_saved_match_len = d->m_saved_lit = 0;\n    d->m_adler32 = 1;\n    d->m_pIn_buf = NULL;\n    d->m_pOut_buf = NULL;\n    d->m_pIn_buf_size = NULL;\n    d->m_pOut_buf_size = NULL;\n    d->m_flush = TDEFL_NO_FLUSH;\n    d->m_pSrc = NULL;\n    d->m_src_buf_left = 0;\n    d->m_out_buf_ofs = 0;\n    if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG))\n        MZ_CLEAR_OBJ(d->m_dict);\n    memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0);\n    memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1);\n    return TDEFL_STATUS_OKAY;\n}\n\ntdefl_status tdefl_get_prev_return_status(tdefl_compressor *d)\n{\n    return d->m_prev_return_status;\n}\n\nmz_uint32 tdefl_get_adler32(tdefl_compressor *d)\n{\n    return d->m_adler32;\n}\n\nmz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags)\n{\n    tdefl_compressor *pComp;\n    mz_bool succeeded;\n    if (((buf_len) && (!pBuf)) || (!pPut_buf_func))\n        return MZ_FALSE;\n    pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor));\n    if (!pComp)\n        return MZ_FALSE;\n    succeeded = (tdefl_init(pComp, pPut_buf_func, pPut_buf_user, flags) == TDEFL_STATUS_OKAY);\n    succeeded = succeeded && (tdefl_compress_buffer(pComp, pBuf, buf_len, TDEFL_FINISH) == TDEFL_STATUS_DONE);\n    MZ_FREE(pComp);\n    return succeeded;\n}\n\ntypedef struct\n{\n    size_t m_size, m_capacity;\n    mz_uint8 *m_pBuf;\n    mz_bool m_expandable;\n} tdefl_output_buffer;\n\nstatic mz_bool tdefl_output_buffer_putter(const void *pBuf, int len, void *pUser)\n{\n    tdefl_output_buffer *p = (tdefl_output_buffer *)pUser;\n    size_t new_size = p->m_size + len;\n    if (new_size > p->m_capacity)\n    {\n        size_t new_capacity = p->m_capacity;\n        mz_uint8 *pNew_buf;\n        if (!p->m_expandable)\n            return MZ_FALSE;\n        do\n        {\n            new_capacity = MZ_MAX(128U, new_capacity << 1U);\n        } while (new_size > new_capacity);\n        pNew_buf = (mz_uint8 *)MZ_REALLOC(p->m_pBuf, new_capacity);\n        if (!pNew_buf)\n            return MZ_FALSE;\n        p->m_pBuf = pNew_buf;\n        p->m_capacity = new_capacity;\n    }\n    memcpy((mz_uint8 *)p->m_pBuf + p->m_size, pBuf, len);\n    p->m_size = new_size;\n    return MZ_TRUE;\n}\n\nvoid *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags)\n{\n    tdefl_output_buffer out_buf;\n    MZ_CLEAR_OBJ(out_buf);\n    if (!pOut_len)\n        return MZ_FALSE;\n    else\n        *pOut_len = 0;\n    out_buf.m_expandable = MZ_TRUE;\n    if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags))\n        return NULL;\n    *pOut_len = out_buf.m_size;\n    return out_buf.m_pBuf;\n}\n\nsize_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags)\n{\n    tdefl_output_buffer out_buf;\n    MZ_CLEAR_OBJ(out_buf);\n    if (!pOut_buf)\n        return 0;\n    out_buf.m_pBuf = (mz_uint8 *)pOut_buf;\n    out_buf.m_capacity = out_buf_len;\n    if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags))\n        return 0;\n    return out_buf.m_size;\n}\n\nstatic const mz_uint s_tdefl_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 };\n\n/* level may actually range from [0,10] (10 is a \"hidden\" max level, where we want a bit more compression and it's fine if throughput to fall off a cliff on some files). */\nmz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy)\n{\n    mz_uint comp_flags = s_tdefl_num_probes[(level >= 0) ? MZ_MIN(10, level) : MZ_DEFAULT_LEVEL] | ((level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0);\n    if (window_bits > 0)\n        comp_flags |= TDEFL_WRITE_ZLIB_HEADER;\n\n    if (!level)\n        comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS;\n    else if (strategy == MZ_FILTERED)\n        comp_flags |= TDEFL_FILTER_MATCHES;\n    else if (strategy == MZ_HUFFMAN_ONLY)\n        comp_flags &= ~TDEFL_MAX_PROBES_MASK;\n    else if (strategy == MZ_FIXED)\n        comp_flags |= TDEFL_FORCE_ALL_STATIC_BLOCKS;\n    else if (strategy == MZ_RLE)\n        comp_flags |= TDEFL_RLE_MATCHES;\n\n    return comp_flags;\n}\n\n#ifdef _MSC_VER\n#pragma warning(push)\n#pragma warning(disable : 4204) /* nonstandard extension used : non-constant aggregate initializer (also supported by GNU C and C99, so no big deal) */\n#endif\n\n/* Simple PNG writer function by Alex Evans, 2011. Released into the public domain: https://gist.github.com/908299, more context at\n http://altdevblogaday.org/2011/04/06/a-smaller-jpg-encoder/.\n This is actually a modification of Alex's original code so PNG files generated by this function pass pngcheck. */\nvoid *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip)\n{\n    /* Using a local copy of this array here in case MINIZ_NO_ZLIB_APIS was defined. */\n    static const mz_uint s_tdefl_png_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 };\n    tdefl_compressor *pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor));\n    tdefl_output_buffer out_buf;\n    int i, bpl = w * num_chans, y, z;\n    mz_uint32 c;\n    *pLen_out = 0;\n    if (!pComp)\n        return NULL;\n    MZ_CLEAR_OBJ(out_buf);\n    out_buf.m_expandable = MZ_TRUE;\n    out_buf.m_capacity = 57 + MZ_MAX(64, (1 + bpl) * h);\n    if (NULL == (out_buf.m_pBuf = (mz_uint8 *)MZ_MALLOC(out_buf.m_capacity)))\n    {\n        MZ_FREE(pComp);\n        return NULL;\n    }\n    /* write dummy header */\n    for (z = 41; z; --z)\n        tdefl_output_buffer_putter(&z, 1, &out_buf);\n    /* compress image data */\n    tdefl_init(pComp, tdefl_output_buffer_putter, &out_buf, s_tdefl_png_num_probes[MZ_MIN(10, level)] | TDEFL_WRITE_ZLIB_HEADER);\n    for (y = 0; y < h; ++y)\n    {\n        tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH);\n        tdefl_compress_buffer(pComp, (mz_uint8 *)pImage + (flip ? (h - 1 - y) : y) * bpl, bpl, TDEFL_NO_FLUSH);\n    }\n    if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) != TDEFL_STATUS_DONE)\n    {\n        MZ_FREE(pComp);\n        MZ_FREE(out_buf.m_pBuf);\n        return NULL;\n    }\n    /* write real header */\n    *pLen_out = out_buf.m_size - 41;\n    {\n        static const mz_uint8 chans[] = { 0x00, 0x00, 0x04, 0x02, 0x06 };\n        mz_uint8 pnghdr[41] = { 0x89, 0x50, 0x4e, 0x47, 0x0d,\n                                0x0a, 0x1a, 0x0a, 0x00, 0x00,\n                                0x00, 0x0d, 0x49, 0x48, 0x44,\n                                0x52, 0x00, 0x00, 0x00, 0x00,\n                                0x00, 0x00, 0x00, 0x00, 0x08,\n                                0x00, 0x00, 0x00, 0x00, 0x00,\n                                0x00, 0x00, 0x00, 0x00, 0x00,\n                                0x00, 0x00, 0x49, 0x44, 0x41,\n                                0x54 };\n        pnghdr[18] = (mz_uint8)(w >> 8);\n        pnghdr[19] = (mz_uint8)w;\n        pnghdr[22] = (mz_uint8)(h >> 8);\n        pnghdr[23] = (mz_uint8)h;\n        pnghdr[25] = chans[num_chans];\n        pnghdr[33] = (mz_uint8)(*pLen_out >> 24);\n        pnghdr[34] = (mz_uint8)(*pLen_out >> 16);\n        pnghdr[35] = (mz_uint8)(*pLen_out >> 8);\n        pnghdr[36] = (mz_uint8)*pLen_out;\n        c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, pnghdr + 12, 17);\n        for (i = 0; i < 4; ++i, c <<= 8)\n            ((mz_uint8 *)(pnghdr + 29))[i] = (mz_uint8)(c >> 24);\n        memcpy(out_buf.m_pBuf, pnghdr, 41);\n    }\n    /* write footer (IDAT CRC-32, followed by IEND chunk) */\n    if (!tdefl_output_buffer_putter(\"\\0\\0\\0\\0\\0\\0\\0\\0\\x49\\x45\\x4e\\x44\\xae\\x42\\x60\\x82\", 16, &out_buf))\n    {\n        *pLen_out = 0;\n        MZ_FREE(pComp);\n        MZ_FREE(out_buf.m_pBuf);\n        return NULL;\n    }\n    c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, out_buf.m_pBuf + 41 - 4, *pLen_out + 4);\n    for (i = 0; i < 4; ++i, c <<= 8)\n        (out_buf.m_pBuf + out_buf.m_size - 16)[i] = (mz_uint8)(c >> 24);\n    /* compute final size of file, grab compressed data buffer and return */\n    *pLen_out += 57;\n    MZ_FREE(pComp);\n    return out_buf.m_pBuf;\n}\nvoid *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out)\n{\n    /* Level 6 corresponds to TDEFL_DEFAULT_MAX_PROBES or MZ_DEFAULT_LEVEL (but we can't depend on MZ_DEFAULT_LEVEL being available in case the zlib API's where #defined out) */\n    return tdefl_write_image_to_png_file_in_memory_ex(pImage, w, h, num_chans, pLen_out, 6, MZ_FALSE);\n}\n\n#ifndef MINIZ_NO_MALLOC\n/* Allocate the tdefl_compressor and tinfl_decompressor structures in C so that */\n/* non-C language bindings to tdefL_ and tinfl_ API don't need to worry about */\n/* structure size and allocation mechanism. */\ntdefl_compressor *tdefl_compressor_alloc()\n{\n    return (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor));\n}\n\nvoid tdefl_compressor_free(tdefl_compressor *pComp)\n{\n    MZ_FREE(pComp);\n}\n#endif\n\n#ifdef _MSC_VER\n#pragma warning(pop)\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n/**************************************************************************\n *\n * Copyright 2013-2014 RAD Game Tools and Valve Software\n * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC\n * All Rights Reserved.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n *\n **************************************************************************/\n\n\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/* ------------------- Low-level Decompression (completely independent from all compression API's) */\n\n#define TINFL_MEMCPY(d, s, l) memcpy(d, s, l)\n#define TINFL_MEMSET(p, c, l) memset(p, c, l)\n\n#define TINFL_CR_BEGIN  \\\n    switch (r->m_state) \\\n    {                   \\\n        case 0:\n#define TINFL_CR_RETURN(state_index, result) \\\n    do                                       \\\n    {                                        \\\n        status = result;                     \\\n        r->m_state = state_index;            \\\n        goto common_exit;                    \\\n        case state_index:;                   \\\n    }                                        \\\n    MZ_MACRO_END\n#define TINFL_CR_RETURN_FOREVER(state_index, result) \\\n    do                                               \\\n    {                                                \\\n        for (;;)                                     \\\n        {                                            \\\n            TINFL_CR_RETURN(state_index, result);    \\\n        }                                            \\\n    }                                                \\\n    MZ_MACRO_END\n#define TINFL_CR_FINISH }\n\n#define TINFL_GET_BYTE(state_index, c)                                                                                                                           \\\n    do                                                                                                                                                           \\\n    {                                                                                                                                                            \\\n        while (pIn_buf_cur >= pIn_buf_end)                                                                                                                       \\\n        {                                                                                                                                                        \\\n            TINFL_CR_RETURN(state_index, (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) ? TINFL_STATUS_NEEDS_MORE_INPUT : TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS); \\\n        }                                                                                                                                                        \\\n        c = *pIn_buf_cur++;                                                                                                                                      \\\n    }                                                                                                                                                            \\\n    MZ_MACRO_END\n\n#define TINFL_NEED_BITS(state_index, n)                \\\n    do                                                 \\\n    {                                                  \\\n        mz_uint c;                                     \\\n        TINFL_GET_BYTE(state_index, c);                \\\n        bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); \\\n        num_bits += 8;                                 \\\n    } while (num_bits < (mz_uint)(n))\n#define TINFL_SKIP_BITS(state_index, n)      \\\n    do                                       \\\n    {                                        \\\n        if (num_bits < (mz_uint)(n))         \\\n        {                                    \\\n            TINFL_NEED_BITS(state_index, n); \\\n        }                                    \\\n        bit_buf >>= (n);                     \\\n        num_bits -= (n);                     \\\n    }                                        \\\n    MZ_MACRO_END\n#define TINFL_GET_BITS(state_index, b, n)    \\\n    do                                       \\\n    {                                        \\\n        if (num_bits < (mz_uint)(n))         \\\n        {                                    \\\n            TINFL_NEED_BITS(state_index, n); \\\n        }                                    \\\n        b = bit_buf & ((1 << (n)) - 1);      \\\n        bit_buf >>= (n);                     \\\n        num_bits -= (n);                     \\\n    }                                        \\\n    MZ_MACRO_END\n\n/* TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes remaining in the input buffer falls below 2. */\n/* It reads just enough bytes from the input stream that are needed to decode the next Huffman code (and absolutely no more). It works by trying to fully decode a */\n/* Huffman code by using whatever bits are currently present in the bit buffer. If this fails, it reads another byte, and tries again until it succeeds or until the */\n/* bit buffer contains >=15 bits (deflate's max. Huffman code size). */\n#define TINFL_HUFF_BITBUF_FILL(state_index, pHuff)                             \\\n    do                                                                         \\\n    {                                                                          \\\n        temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)];     \\\n        if (temp >= 0)                                                         \\\n        {                                                                      \\\n            code_len = temp >> 9;                                              \\\n            if ((code_len) && (num_bits >= code_len))                          \\\n                break;                                                         \\\n        }                                                                      \\\n        else if (num_bits > TINFL_FAST_LOOKUP_BITS)                            \\\n        {                                                                      \\\n            code_len = TINFL_FAST_LOOKUP_BITS;                                 \\\n            do                                                                 \\\n            {                                                                  \\\n                temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \\\n            } while ((temp < 0) && (num_bits >= (code_len + 1)));              \\\n            if (temp >= 0)                                                     \\\n                break;                                                         \\\n        }                                                                      \\\n        TINFL_GET_BYTE(state_index, c);                                        \\\n        bit_buf |= (((tinfl_bit_buf_t)c) << num_bits);                         \\\n        num_bits += 8;                                                         \\\n    } while (num_bits < 15);\n\n/* TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex than you would initially expect because the zlib API expects the decompressor to never read */\n/* beyond the final byte of the deflate stream. (In other words, when this macro wants to read another byte from the input, it REALLY needs another byte in order to fully */\n/* decode the next Huffman code.) Handling this properly is particularly important on raw deflate (non-zlib) streams, which aren't followed by a byte aligned adler-32. */\n/* The slow path is only executed at the very end of the input buffer. */\n/* v1.16: The original macro handled the case at the very end of the passed-in input buffer, but we also need to handle the case where the user passes in 1+zillion bytes */\n/* following the deflate data and our non-conservative read-ahead path won't kick in here on this code. This is much trickier. */\n#define TINFL_HUFF_DECODE(state_index, sym, pHuff)                                                                                  \\\n    do                                                                                                                              \\\n    {                                                                                                                               \\\n        int temp;                                                                                                                   \\\n        mz_uint code_len, c;                                                                                                        \\\n        if (num_bits < 15)                                                                                                          \\\n        {                                                                                                                           \\\n            if ((pIn_buf_end - pIn_buf_cur) < 2)                                                                                    \\\n            {                                                                                                                       \\\n                TINFL_HUFF_BITBUF_FILL(state_index, pHuff);                                                                         \\\n            }                                                                                                                       \\\n            else                                                                                                                    \\\n            {                                                                                                                       \\\n                bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); \\\n                pIn_buf_cur += 2;                                                                                                   \\\n                num_bits += 16;                                                                                                     \\\n            }                                                                                                                       \\\n        }                                                                                                                           \\\n        if ((temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0)                                               \\\n            code_len = temp >> 9, temp &= 511;                                                                                      \\\n        else                                                                                                                        \\\n        {                                                                                                                           \\\n            code_len = TINFL_FAST_LOOKUP_BITS;                                                                                      \\\n            do                                                                                                                      \\\n            {                                                                                                                       \\\n                temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)];                                                      \\\n            } while (temp < 0);                                                                                                     \\\n        }                                                                                                                           \\\n        sym = temp;                                                                                                                 \\\n        bit_buf >>= code_len;                                                                                                       \\\n        num_bits -= code_len;                                                                                                       \\\n    }                                                                                                                               \\\n    MZ_MACRO_END\n\ntinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags)\n{\n    static const int s_length_base[31] = { 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 };\n    static const int s_length_extra[31] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 0, 0 };\n    static const int s_dist_base[32] = { 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0 };\n    static const int s_dist_extra[32] = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13 };\n    static const mz_uint8 s_length_dezigzag[19] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };\n    static const int s_min_table_sizes[3] = { 257, 1, 4 };\n\n    tinfl_status status = TINFL_STATUS_FAILED;\n    mz_uint32 num_bits, dist, counter, num_extra;\n    tinfl_bit_buf_t bit_buf;\n    const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = pIn_buf_next + *pIn_buf_size;\n    mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = pOut_buf_next + *pOut_buf_size;\n    size_t out_buf_size_mask = (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) ? (size_t)-1 : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1, dist_from_out_buf_start;\n\n    /* Ensure the output buffer's size is a power of 2, unless the output buffer is large enough to hold the entire output file (in which case it doesn't matter). */\n    if (((out_buf_size_mask + 1) & out_buf_size_mask) || (pOut_buf_next < pOut_buf_start))\n    {\n        *pIn_buf_size = *pOut_buf_size = 0;\n        return TINFL_STATUS_BAD_PARAM;\n    }\n\n    num_bits = r->m_num_bits;\n    bit_buf = r->m_bit_buf;\n    dist = r->m_dist;\n    counter = r->m_counter;\n    num_extra = r->m_num_extra;\n    dist_from_out_buf_start = r->m_dist_from_out_buf_start;\n    TINFL_CR_BEGIN\n\n    bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0;\n    r->m_z_adler32 = r->m_check_adler32 = 1;\n    if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER)\n    {\n        TINFL_GET_BYTE(1, r->m_zhdr0);\n        TINFL_GET_BYTE(2, r->m_zhdr1);\n        counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8));\n        if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))\n            counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) || ((out_buf_size_mask + 1) < (size_t)(1U << (8U + (r->m_zhdr0 >> 4)))));\n        if (counter)\n        {\n            TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED);\n        }\n    }\n\n    do\n    {\n        TINFL_GET_BITS(3, r->m_final, 3);\n        r->m_type = r->m_final >> 1;\n        if (r->m_type == 0)\n        {\n            TINFL_SKIP_BITS(5, num_bits & 7);\n            for (counter = 0; counter < 4; ++counter)\n            {\n                if (num_bits)\n                    TINFL_GET_BITS(6, r->m_raw_header[counter], 8);\n                else\n                    TINFL_GET_BYTE(7, r->m_raw_header[counter]);\n            }\n            if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) != (mz_uint)(0xFFFF ^ (r->m_raw_header[2] | (r->m_raw_header[3] << 8))))\n            {\n                TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED);\n            }\n            while ((counter) && (num_bits))\n            {\n                TINFL_GET_BITS(51, dist, 8);\n                while (pOut_buf_cur >= pOut_buf_end)\n                {\n                    TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT);\n                }\n                *pOut_buf_cur++ = (mz_uint8)dist;\n                counter--;\n            }\n            while (counter)\n            {\n                size_t n;\n                while (pOut_buf_cur >= pOut_buf_end)\n                {\n                    TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT);\n                }\n                while (pIn_buf_cur >= pIn_buf_end)\n                {\n                    TINFL_CR_RETURN(38, (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) ? TINFL_STATUS_NEEDS_MORE_INPUT : TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS);\n                }\n                n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur), (size_t)(pIn_buf_end - pIn_buf_cur)), counter);\n                TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n);\n                pIn_buf_cur += n;\n                pOut_buf_cur += n;\n                counter -= (mz_uint)n;\n            }\n        }\n        else if (r->m_type == 3)\n        {\n            TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED);\n        }\n        else\n        {\n            if (r->m_type == 1)\n            {\n                mz_uint8 *p = r->m_tables[0].m_code_size;\n                mz_uint i;\n                r->m_table_sizes[0] = 288;\n                r->m_table_sizes[1] = 32;\n                TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32);\n                for (i = 0; i <= 143; ++i)\n                    *p++ = 8;\n                for (; i <= 255; ++i)\n                    *p++ = 9;\n                for (; i <= 279; ++i)\n                    *p++ = 7;\n                for (; i <= 287; ++i)\n                    *p++ = 8;\n            }\n            else\n            {\n                for (counter = 0; counter < 3; counter++)\n                {\n                    TINFL_GET_BITS(11, r->m_table_sizes[counter], \"\\05\\05\\04\"[counter]);\n                    r->m_table_sizes[counter] += s_min_table_sizes[counter];\n                }\n                MZ_CLEAR_OBJ(r->m_tables[2].m_code_size);\n                for (counter = 0; counter < r->m_table_sizes[2]; counter++)\n                {\n                    mz_uint s;\n                    TINFL_GET_BITS(14, s, 3);\n                    r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s;\n                }\n                r->m_table_sizes[2] = 19;\n            }\n            for (; (int)r->m_type >= 0; r->m_type--)\n            {\n                int tree_next, tree_cur;\n                tinfl_huff_table *pTable;\n                mz_uint i, j, used_syms, total, sym_index, next_code[17], total_syms[16];\n                pTable = &r->m_tables[r->m_type];\n                MZ_CLEAR_OBJ(total_syms);\n                MZ_CLEAR_OBJ(pTable->m_look_up);\n                MZ_CLEAR_OBJ(pTable->m_tree);\n                for (i = 0; i < r->m_table_sizes[r->m_type]; ++i)\n                    total_syms[pTable->m_code_size[i]]++;\n                used_syms = 0, total = 0;\n                next_code[0] = next_code[1] = 0;\n                for (i = 1; i <= 15; ++i)\n                {\n                    used_syms += total_syms[i];\n                    next_code[i + 1] = (total = ((total + total_syms[i]) << 1));\n                }\n                if ((65536 != total) && (used_syms > 1))\n                {\n                    TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED);\n                }\n                for (tree_next = -1, sym_index = 0; sym_index < r->m_table_sizes[r->m_type]; ++sym_index)\n                {\n                    mz_uint rev_code = 0, l, cur_code, code_size = pTable->m_code_size[sym_index];\n                    if (!code_size)\n                        continue;\n                    cur_code = next_code[code_size]++;\n                    for (l = code_size; l > 0; l--, cur_code >>= 1)\n                        rev_code = (rev_code << 1) | (cur_code & 1);\n                    if (code_size <= TINFL_FAST_LOOKUP_BITS)\n                    {\n                        mz_int16 k = (mz_int16)((code_size << 9) | sym_index);\n                        while (rev_code < TINFL_FAST_LOOKUP_SIZE)\n                        {\n                            pTable->m_look_up[rev_code] = k;\n                            rev_code += (1 << code_size);\n                        }\n                        continue;\n                    }\n                    if (0 == (tree_cur = pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)]))\n                    {\n                        pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] = (mz_int16)tree_next;\n                        tree_cur = tree_next;\n                        tree_next -= 2;\n                    }\n                    rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1);\n                    for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--)\n                    {\n                        tree_cur -= ((rev_code >>= 1) & 1);\n                        if (!pTable->m_tree[-tree_cur - 1])\n                        {\n                            pTable->m_tree[-tree_cur - 1] = (mz_int16)tree_next;\n                            tree_cur = tree_next;\n                            tree_next -= 2;\n                        }\n                        else\n                            tree_cur = pTable->m_tree[-tree_cur - 1];\n                    }\n                    tree_cur -= ((rev_code >>= 1) & 1);\n                    pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index;\n                }\n                if (r->m_type == 2)\n                {\n                    for (counter = 0; counter < (r->m_table_sizes[0] + r->m_table_sizes[1]);)\n                    {\n                        mz_uint s;\n                        TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]);\n                        if (dist < 16)\n                        {\n                            r->m_len_codes[counter++] = (mz_uint8)dist;\n                            continue;\n                        }\n                        if ((dist == 16) && (!counter))\n                        {\n                            TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED);\n                        }\n                        num_extra = \"\\02\\03\\07\"[dist - 16];\n                        TINFL_GET_BITS(18, s, num_extra);\n                        s += \"\\03\\03\\013\"[dist - 16];\n                        TINFL_MEMSET(r->m_len_codes + counter, (dist == 16) ? r->m_len_codes[counter - 1] : 0, s);\n                        counter += s;\n                    }\n                    if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter)\n                    {\n                        TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED);\n                    }\n                    TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes, r->m_table_sizes[0]);\n                    TINFL_MEMCPY(r->m_tables[1].m_code_size, r->m_len_codes + r->m_table_sizes[0], r->m_table_sizes[1]);\n                }\n            }\n            for (;;)\n            {\n                mz_uint8 *pSrc;\n                for (;;)\n                {\n                    if (((pIn_buf_end - pIn_buf_cur) < 4) || ((pOut_buf_end - pOut_buf_cur) < 2))\n                    {\n                        TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]);\n                        if (counter >= 256)\n                            break;\n                        while (pOut_buf_cur >= pOut_buf_end)\n                        {\n                            TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT);\n                        }\n                        *pOut_buf_cur++ = (mz_uint8)counter;\n                    }\n                    else\n                    {\n                        int sym2;\n                        mz_uint code_len;\n#if TINFL_USE_64BIT_BITBUF\n                        if (num_bits < 30)\n                        {\n                            bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits);\n                            pIn_buf_cur += 4;\n                            num_bits += 32;\n                        }\n#else\n                        if (num_bits < 15)\n                        {\n                            bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits);\n                            pIn_buf_cur += 2;\n                            num_bits += 16;\n                        }\n#endif\n                        if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0)\n                            code_len = sym2 >> 9;\n                        else\n                        {\n                            code_len = TINFL_FAST_LOOKUP_BITS;\n                            do\n                            {\n                                sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)];\n                            } while (sym2 < 0);\n                        }\n                        counter = sym2;\n                        bit_buf >>= code_len;\n                        num_bits -= code_len;\n                        if (counter & 256)\n                            break;\n\n#if !TINFL_USE_64BIT_BITBUF\n                        if (num_bits < 15)\n                        {\n                            bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits);\n                            pIn_buf_cur += 2;\n                            num_bits += 16;\n                        }\n#endif\n                        if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0)\n                            code_len = sym2 >> 9;\n                        else\n                        {\n                            code_len = TINFL_FAST_LOOKUP_BITS;\n                            do\n                            {\n                                sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)];\n                            } while (sym2 < 0);\n                        }\n                        bit_buf >>= code_len;\n                        num_bits -= code_len;\n\n                        pOut_buf_cur[0] = (mz_uint8)counter;\n                        if (sym2 & 256)\n                        {\n                            pOut_buf_cur++;\n                            counter = sym2;\n                            break;\n                        }\n                        pOut_buf_cur[1] = (mz_uint8)sym2;\n                        pOut_buf_cur += 2;\n                    }\n                }\n                if ((counter &= 511) == 256)\n                    break;\n\n                num_extra = s_length_extra[counter - 257];\n                counter = s_length_base[counter - 257];\n                if (num_extra)\n                {\n                    mz_uint extra_bits;\n                    TINFL_GET_BITS(25, extra_bits, num_extra);\n                    counter += extra_bits;\n                }\n\n                TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]);\n                num_extra = s_dist_extra[dist];\n                dist = s_dist_base[dist];\n                if (num_extra)\n                {\n                    mz_uint extra_bits;\n                    TINFL_GET_BITS(27, extra_bits, num_extra);\n                    dist += extra_bits;\n                }\n\n                dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start;\n                if ((dist > dist_from_out_buf_start) && (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))\n                {\n                    TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED);\n                }\n\n                pSrc = pOut_buf_start + ((dist_from_out_buf_start - dist) & out_buf_size_mask);\n\n                if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end)\n                {\n                    while (counter--)\n                    {\n                        while (pOut_buf_cur >= pOut_buf_end)\n                        {\n                            TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT);\n                        }\n                        *pOut_buf_cur++ = pOut_buf_start[(dist_from_out_buf_start++ - dist) & out_buf_size_mask];\n                    }\n                    continue;\n                }\n#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES\n                else if ((counter >= 9) && (counter <= dist))\n                {\n                    const mz_uint8 *pSrc_end = pSrc + (counter & ~7);\n                    do\n                    {\n#ifdef MINIZ_UNALIGNED_USE_MEMCPY\n\t\t\t\t\t\tmemcpy(pOut_buf_cur, pSrc, sizeof(mz_uint32)*2);\n#else\n                        ((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0];\n                        ((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1];\n#endif\n                        pOut_buf_cur += 8;\n                    } while ((pSrc += 8) < pSrc_end);\n                    if ((counter &= 7) < 3)\n                    {\n                        if (counter)\n                        {\n                            pOut_buf_cur[0] = pSrc[0];\n                            if (counter > 1)\n                                pOut_buf_cur[1] = pSrc[1];\n                            pOut_buf_cur += counter;\n                        }\n                        continue;\n                    }\n                }\n#endif\n                while(counter>2)\n                {\n                    pOut_buf_cur[0] = pSrc[0];\n                    pOut_buf_cur[1] = pSrc[1];\n                    pOut_buf_cur[2] = pSrc[2];\n                    pOut_buf_cur += 3;\n                    pSrc += 3;\n\t\t\t\t\tcounter -= 3;\n                }\n                if (counter > 0)\n                {\n                    pOut_buf_cur[0] = pSrc[0];\n                    if (counter > 1)\n                        pOut_buf_cur[1] = pSrc[1];\n                    pOut_buf_cur += counter;\n                }\n            }\n        }\n    } while (!(r->m_final & 1));\n\n    /* Ensure byte alignment and put back any bytes from the bitbuf if we've looked ahead too far on gzip, or other Deflate streams followed by arbitrary data. */\n    /* I'm being super conservative here. A number of simplifications can be made to the byte alignment part, and the Adler32 check shouldn't ever need to worry about reading from the bitbuf now. */\n    TINFL_SKIP_BITS(32, num_bits & 7);\n    while ((pIn_buf_cur > pIn_buf_next) && (num_bits >= 8))\n    {\n        --pIn_buf_cur;\n        num_bits -= 8;\n    }\n    bit_buf &= (tinfl_bit_buf_t)((((mz_uint64)1) << num_bits) - (mz_uint64)1);\n    MZ_ASSERT(!num_bits); /* if this assert fires then we've read beyond the end of non-deflate/zlib streams with following data (such as gzip streams). */\n\n    if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER)\n    {\n        for (counter = 0; counter < 4; ++counter)\n        {\n            mz_uint s;\n            if (num_bits)\n                TINFL_GET_BITS(41, s, 8);\n            else\n                TINFL_GET_BYTE(42, s);\n            r->m_z_adler32 = (r->m_z_adler32 << 8) | s;\n        }\n    }\n    TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE);\n\n    TINFL_CR_FINISH\n\ncommon_exit:\n    /* As long as we aren't telling the caller that we NEED more input to make forward progress: */\n    /* Put back any bytes from the bitbuf in case we've looked ahead too far on gzip, or other Deflate streams followed by arbitrary data. */\n    /* We need to be very careful here to NOT push back any bytes we definitely know we need to make forward progress, though, or we'll lock the caller up into an inf loop. */\n    if ((status != TINFL_STATUS_NEEDS_MORE_INPUT) && (status != TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS))\n    {\n        while ((pIn_buf_cur > pIn_buf_next) && (num_bits >= 8))\n        {\n            --pIn_buf_cur;\n            num_bits -= 8;\n        }\n    }\n    r->m_num_bits = num_bits;\n    r->m_bit_buf = bit_buf & (tinfl_bit_buf_t)((((mz_uint64)1) << num_bits) - (mz_uint64)1);\n    r->m_dist = dist;\n    r->m_counter = counter;\n    r->m_num_extra = num_extra;\n    r->m_dist_from_out_buf_start = dist_from_out_buf_start;\n    *pIn_buf_size = pIn_buf_cur - pIn_buf_next;\n    *pOut_buf_size = pOut_buf_cur - pOut_buf_next;\n    if ((decomp_flags & (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) && (status >= 0))\n    {\n        const mz_uint8 *ptr = pOut_buf_next;\n        size_t buf_len = *pOut_buf_size;\n        mz_uint32 i, s1 = r->m_check_adler32 & 0xffff, s2 = r->m_check_adler32 >> 16;\n        size_t block_len = buf_len % 5552;\n        while (buf_len)\n        {\n            for (i = 0; i + 7 < block_len; i += 8, ptr += 8)\n            {\n                s1 += ptr[0], s2 += s1;\n                s1 += ptr[1], s2 += s1;\n                s1 += ptr[2], s2 += s1;\n                s1 += ptr[3], s2 += s1;\n                s1 += ptr[4], s2 += s1;\n                s1 += ptr[5], s2 += s1;\n                s1 += ptr[6], s2 += s1;\n                s1 += ptr[7], s2 += s1;\n            }\n            for (; i < block_len; ++i)\n                s1 += *ptr++, s2 += s1;\n            s1 %= 65521U, s2 %= 65521U;\n            buf_len -= block_len;\n            block_len = 5552;\n        }\n        r->m_check_adler32 = (s2 << 16) + s1;\n        if ((status == TINFL_STATUS_DONE) && (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) && (r->m_check_adler32 != r->m_z_adler32))\n            status = TINFL_STATUS_ADLER32_MISMATCH;\n    }\n    return status;\n}\n\n/* Higher level helper functions. */\nvoid *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags)\n{\n    tinfl_decompressor decomp;\n    void *pBuf = NULL, *pNew_buf;\n    size_t src_buf_ofs = 0, out_buf_capacity = 0;\n    *pOut_len = 0;\n    tinfl_init(&decomp);\n    for (;;)\n    {\n        size_t src_buf_size = src_buf_len - src_buf_ofs, dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity;\n        tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf + src_buf_ofs, &src_buf_size, (mz_uint8 *)pBuf, pBuf ? (mz_uint8 *)pBuf + *pOut_len : NULL, &dst_buf_size,\n                                               (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);\n        if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT))\n        {\n            MZ_FREE(pBuf);\n            *pOut_len = 0;\n            return NULL;\n        }\n        src_buf_ofs += src_buf_size;\n        *pOut_len += dst_buf_size;\n        if (status == TINFL_STATUS_DONE)\n            break;\n        new_out_buf_capacity = out_buf_capacity * 2;\n        if (new_out_buf_capacity < 128)\n            new_out_buf_capacity = 128;\n        pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity);\n        if (!pNew_buf)\n        {\n            MZ_FREE(pBuf);\n            *pOut_len = 0;\n            return NULL;\n        }\n        pBuf = pNew_buf;\n        out_buf_capacity = new_out_buf_capacity;\n    }\n    return pBuf;\n}\n\nsize_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags)\n{\n    tinfl_decompressor decomp;\n    tinfl_status status;\n    tinfl_init(&decomp);\n    status = tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf, &src_buf_len, (mz_uint8 *)pOut_buf, (mz_uint8 *)pOut_buf, &out_buf_len, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);\n    return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED : out_buf_len;\n}\n\nint tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags)\n{\n    int result = 0;\n    tinfl_decompressor decomp;\n    mz_uint8 *pDict = (mz_uint8 *)MZ_MALLOC(TINFL_LZ_DICT_SIZE);\n    size_t in_buf_ofs = 0, dict_ofs = 0;\n    if (!pDict)\n        return TINFL_STATUS_FAILED;\n    tinfl_init(&decomp);\n    for (;;)\n    {\n        size_t in_buf_size = *pIn_buf_size - in_buf_ofs, dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs;\n        tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8 *)pIn_buf + in_buf_ofs, &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size,\n                                               (flags & ~(TINFL_FLAG_HAS_MORE_INPUT | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)));\n        in_buf_ofs += in_buf_size;\n        if ((dst_buf_size) && (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user)))\n            break;\n        if (status != TINFL_STATUS_HAS_MORE_OUTPUT)\n        {\n            result = (status == TINFL_STATUS_DONE);\n            break;\n        }\n        dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1);\n    }\n    MZ_FREE(pDict);\n    *pIn_buf_size = in_buf_ofs;\n    return result;\n}\n\n#ifndef MINIZ_NO_MALLOC\ntinfl_decompressor *tinfl_decompressor_alloc()\n{\n    tinfl_decompressor *pDecomp = (tinfl_decompressor *)MZ_MALLOC(sizeof(tinfl_decompressor));\n    if (pDecomp)\n        tinfl_init(pDecomp);\n    return pDecomp;\n}\n\nvoid tinfl_decompressor_free(tinfl_decompressor *pDecomp)\n{\n    MZ_FREE(pDecomp);\n}\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n/**************************************************************************\n *\n * Copyright 2013-2014 RAD Game Tools and Valve Software\n * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC\n * Copyright 2016 Martin Raiber\n * All Rights Reserved.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n *\n **************************************************************************/\n\n\n#ifndef MINIZ_NO_ARCHIVE_APIS\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/* ------------------- .ZIP archive reading */\n\n#ifdef MINIZ_NO_STDIO\n#define MZ_FILE void *\n#else\n#include <sys/stat.h>\n\n#if defined(_MSC_VER) || defined(__MINGW64__)\nstatic FILE *mz_fopen(const char *pFilename, const char *pMode)\n{\n    FILE *pFile = NULL;\n    fopen_s(&pFile, pFilename, pMode);\n    return pFile;\n}\nstatic FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream)\n{\n    FILE *pFile = NULL;\n    if (freopen_s(&pFile, pPath, pMode, pStream))\n        return NULL;\n    return pFile;\n}\n#ifndef MINIZ_NO_TIME\n#include <sys/utime.h>\n#endif\n#define MZ_FOPEN mz_fopen\n#define MZ_FCLOSE fclose\n#define MZ_FREAD fread\n#define MZ_FWRITE fwrite\n#define MZ_FTELL64 _ftelli64\n#define MZ_FSEEK64 _fseeki64\n#define MZ_FILE_STAT_STRUCT _stat64\n#define MZ_FILE_STAT _stat64\n#define MZ_FFLUSH fflush\n#define MZ_FREOPEN mz_freopen\n#define MZ_DELETE_FILE remove\n#elif defined(__MINGW32__)\n#ifndef MINIZ_NO_TIME\n#include <sys/utime.h>\n#endif\n#define MZ_FOPEN(f, m) fopen(f, m)\n#define MZ_FCLOSE fclose\n#define MZ_FREAD fread\n#define MZ_FWRITE fwrite\n#define MZ_FTELL64 ftello64\n#define MZ_FSEEK64 fseeko64\n#define MZ_FILE_STAT_STRUCT _stat\n#define MZ_FILE_STAT _stat\n#define MZ_FFLUSH fflush\n#define MZ_FREOPEN(f, m, s) freopen(f, m, s)\n#define MZ_DELETE_FILE remove\n#elif defined(__TINYC__)\n#ifndef MINIZ_NO_TIME\n#include <sys/utime.h>\n#endif\n#define MZ_FOPEN(f, m) fopen(f, m)\n#define MZ_FCLOSE fclose\n#define MZ_FREAD fread\n#define MZ_FWRITE fwrite\n#define MZ_FTELL64 ftell\n#define MZ_FSEEK64 fseek\n#define MZ_FILE_STAT_STRUCT stat\n#define MZ_FILE_STAT stat\n#define MZ_FFLUSH fflush\n#define MZ_FREOPEN(f, m, s) freopen(f, m, s)\n#define MZ_DELETE_FILE remove\n#elif defined(__GNUC__) && defined(_LARGEFILE64_SOURCE)\n#ifndef MINIZ_NO_TIME\n#include <utime.h>\n#endif\n#define MZ_FOPEN(f, m) fopen64(f, m)\n#define MZ_FCLOSE fclose\n#define MZ_FREAD fread\n#define MZ_FWRITE fwrite\n#define MZ_FTELL64 ftello64\n#define MZ_FSEEK64 fseeko64\n#define MZ_FILE_STAT_STRUCT stat64\n#define MZ_FILE_STAT stat64\n#define MZ_FFLUSH fflush\n#define MZ_FREOPEN(p, m, s) freopen64(p, m, s)\n#define MZ_DELETE_FILE remove\n#elif defined(__APPLE__)\n#ifndef MINIZ_NO_TIME\n#include <utime.h>\n#endif\n#define MZ_FOPEN(f, m) fopen(f, m)\n#define MZ_FCLOSE fclose\n#define MZ_FREAD fread\n#define MZ_FWRITE fwrite\n#define MZ_FTELL64 ftello\n#define MZ_FSEEK64 fseeko\n#define MZ_FILE_STAT_STRUCT stat\n#define MZ_FILE_STAT stat\n#define MZ_FFLUSH fflush\n#define MZ_FREOPEN(p, m, s) freopen(p, m, s)\n#define MZ_DELETE_FILE remove\n\n#else\n#pragma message(\"Using fopen, ftello, fseeko, stat() etc. path for file I/O - this path may not support large files.\")\n#ifndef MINIZ_NO_TIME\n#include <utime.h>\n#endif\n#define MZ_FOPEN(f, m) fopen(f, m)\n#define MZ_FCLOSE fclose\n#define MZ_FREAD fread\n#define MZ_FWRITE fwrite\n#ifdef __STRICT_ANSI__\n#define MZ_FTELL64 ftell\n#define MZ_FSEEK64 fseek\n#else\n#define MZ_FTELL64 ftello\n#define MZ_FSEEK64 fseeko\n#endif\n#define MZ_FILE_STAT_STRUCT stat\n#define MZ_FILE_STAT stat\n#define MZ_FFLUSH fflush\n#define MZ_FREOPEN(f, m, s) freopen(f, m, s)\n#define MZ_DELETE_FILE remove\n#endif /* #ifdef _MSC_VER */\n#endif /* #ifdef MINIZ_NO_STDIO */\n\n#define MZ_TOLOWER(c) ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c))\n\n/* Various ZIP archive enums. To completely avoid cross platform compiler alignment and platform endian issues, miniz.c doesn't use structs for any of this stuff. */\nenum\n{\n    /* ZIP archive identifiers and record sizes */\n    MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06054b50,\n    MZ_ZIP_CENTRAL_DIR_HEADER_SIG = 0x02014b50,\n    MZ_ZIP_LOCAL_DIR_HEADER_SIG = 0x04034b50,\n    MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30,\n    MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46,\n    MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22,\n\n    /* ZIP64 archive identifier and record sizes */\n    MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06064b50,\n    MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG = 0x07064b50,\n    MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE = 56,\n    MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE = 20,\n    MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID = 0x0001,\n    MZ_ZIP_DATA_DESCRIPTOR_ID = 0x08074b50,\n    MZ_ZIP_DATA_DESCRIPTER_SIZE64 = 24,\n    MZ_ZIP_DATA_DESCRIPTER_SIZE32 = 16,\n\n    /* Central directory header record offsets */\n    MZ_ZIP_CDH_SIG_OFS = 0,\n    MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4,\n    MZ_ZIP_CDH_VERSION_NEEDED_OFS = 6,\n    MZ_ZIP_CDH_BIT_FLAG_OFS = 8,\n    MZ_ZIP_CDH_METHOD_OFS = 10,\n    MZ_ZIP_CDH_FILE_TIME_OFS = 12,\n    MZ_ZIP_CDH_FILE_DATE_OFS = 14,\n    MZ_ZIP_CDH_CRC32_OFS = 16,\n    MZ_ZIP_CDH_COMPRESSED_SIZE_OFS = 20,\n    MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS = 24,\n    MZ_ZIP_CDH_FILENAME_LEN_OFS = 28,\n    MZ_ZIP_CDH_EXTRA_LEN_OFS = 30,\n    MZ_ZIP_CDH_COMMENT_LEN_OFS = 32,\n    MZ_ZIP_CDH_DISK_START_OFS = 34,\n    MZ_ZIP_CDH_INTERNAL_ATTR_OFS = 36,\n    MZ_ZIP_CDH_EXTERNAL_ATTR_OFS = 38,\n    MZ_ZIP_CDH_LOCAL_HEADER_OFS = 42,\n\n    /* Local directory header offsets */\n    MZ_ZIP_LDH_SIG_OFS = 0,\n    MZ_ZIP_LDH_VERSION_NEEDED_OFS = 4,\n    MZ_ZIP_LDH_BIT_FLAG_OFS = 6,\n    MZ_ZIP_LDH_METHOD_OFS = 8,\n    MZ_ZIP_LDH_FILE_TIME_OFS = 10,\n    MZ_ZIP_LDH_FILE_DATE_OFS = 12,\n    MZ_ZIP_LDH_CRC32_OFS = 14,\n    MZ_ZIP_LDH_COMPRESSED_SIZE_OFS = 18,\n    MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS = 22,\n    MZ_ZIP_LDH_FILENAME_LEN_OFS = 26,\n    MZ_ZIP_LDH_EXTRA_LEN_OFS = 28,\n    MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR = 1 << 3,\n\n    /* End of central directory offsets */\n    MZ_ZIP_ECDH_SIG_OFS = 0,\n    MZ_ZIP_ECDH_NUM_THIS_DISK_OFS = 4,\n    MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS = 6,\n    MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 8,\n    MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS = 10,\n    MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12,\n    MZ_ZIP_ECDH_CDIR_OFS_OFS = 16,\n    MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20,\n\n    /* ZIP64 End of central directory locator offsets */\n    MZ_ZIP64_ECDL_SIG_OFS = 0,                    /* 4 bytes */\n    MZ_ZIP64_ECDL_NUM_DISK_CDIR_OFS = 4,          /* 4 bytes */\n    MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS = 8,  /* 8 bytes */\n    MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS = 16, /* 4 bytes */\n\n    /* ZIP64 End of central directory header offsets */\n    MZ_ZIP64_ECDH_SIG_OFS = 0,                       /* 4 bytes */\n    MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS = 4,            /* 8 bytes */\n    MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS = 12,          /* 2 bytes */\n    MZ_ZIP64_ECDH_VERSION_NEEDED_OFS = 14,           /* 2 bytes */\n    MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS = 16,            /* 4 bytes */\n    MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS = 20,            /* 4 bytes */\n    MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 24, /* 8 bytes */\n    MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS = 32,       /* 8 bytes */\n    MZ_ZIP64_ECDH_CDIR_SIZE_OFS = 40,                /* 8 bytes */\n    MZ_ZIP64_ECDH_CDIR_OFS_OFS = 48,                 /* 8 bytes */\n    MZ_ZIP_VERSION_MADE_BY_DOS_FILESYSTEM_ID = 0,\n    MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG = 0x10,\n    MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED = 1,\n    MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG = 32,\n    MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION = 64,\n    MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED = 8192,\n    MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8 = 1 << 11\n};\n\ntypedef struct\n{\n    void *m_p;\n    size_t m_size, m_capacity;\n    mz_uint m_element_size;\n} mz_zip_array;\n\nstruct mz_zip_internal_state_tag\n{\n    mz_zip_array m_central_dir;\n    mz_zip_array m_central_dir_offsets;\n    mz_zip_array m_sorted_central_dir_offsets;\n\n    /* The flags passed in when the archive is initially opened. */\n    uint32_t m_init_flags;\n\n    /* MZ_TRUE if the archive has a zip64 end of central directory headers, etc. */\n    mz_bool m_zip64;\n\n    /* MZ_TRUE if we found zip64 extended info in the central directory (m_zip64 will also be slammed to true too, even if we didn't find a zip64 end of central dir header, etc.) */\n    mz_bool m_zip64_has_extended_info_fields;\n\n    /* These fields are used by the file, FILE, memory, and memory/heap read/write helpers. */\n    MZ_FILE *m_pFile;\n    mz_uint64 m_file_archive_start_ofs;\n\n    void *m_pMem;\n    size_t m_mem_size;\n    size_t m_mem_capacity;\n};\n\n#define MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(array_ptr, element_size) (array_ptr)->m_element_size = element_size\n\n#if defined(DEBUG) || defined(_DEBUG) || defined(NDEBUG)\nstatic MZ_FORCEINLINE mz_uint mz_zip_array_range_check(const mz_zip_array *pArray, mz_uint index)\n{\n    MZ_ASSERT(index < pArray->m_size);\n    return index;\n}\n#define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[mz_zip_array_range_check(array_ptr, index)]\n#else\n#define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[index]\n#endif\n\nstatic MZ_FORCEINLINE void mz_zip_array_init(mz_zip_array *pArray, mz_uint32 element_size)\n{\n    memset(pArray, 0, sizeof(mz_zip_array));\n    pArray->m_element_size = element_size;\n}\n\nstatic MZ_FORCEINLINE void mz_zip_array_clear(mz_zip_archive *pZip, mz_zip_array *pArray)\n{\n    pZip->m_pFree(pZip->m_pAlloc_opaque, pArray->m_p);\n    memset(pArray, 0, sizeof(mz_zip_array));\n}\n\nstatic mz_bool mz_zip_array_ensure_capacity(mz_zip_archive *pZip, mz_zip_array *pArray, size_t min_new_capacity, mz_uint growing)\n{\n    void *pNew_p;\n    size_t new_capacity = min_new_capacity;\n    MZ_ASSERT(pArray->m_element_size);\n    if (pArray->m_capacity >= min_new_capacity)\n        return MZ_TRUE;\n    if (growing)\n    {\n        new_capacity = MZ_MAX(1, pArray->m_capacity);\n        while (new_capacity < min_new_capacity)\n            new_capacity *= 2;\n    }\n    if (NULL == (pNew_p = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pArray->m_p, pArray->m_element_size, new_capacity)))\n        return MZ_FALSE;\n    pArray->m_p = pNew_p;\n    pArray->m_capacity = new_capacity;\n    return MZ_TRUE;\n}\n\nstatic MZ_FORCEINLINE mz_bool mz_zip_array_reserve(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_capacity, mz_uint growing)\n{\n    if (new_capacity > pArray->m_capacity)\n    {\n        if (!mz_zip_array_ensure_capacity(pZip, pArray, new_capacity, growing))\n            return MZ_FALSE;\n    }\n    return MZ_TRUE;\n}\n\nstatic MZ_FORCEINLINE mz_bool mz_zip_array_resize(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_size, mz_uint growing)\n{\n    if (new_size > pArray->m_capacity)\n    {\n        if (!mz_zip_array_ensure_capacity(pZip, pArray, new_size, growing))\n            return MZ_FALSE;\n    }\n    pArray->m_size = new_size;\n    return MZ_TRUE;\n}\n\nstatic MZ_FORCEINLINE mz_bool mz_zip_array_ensure_room(mz_zip_archive *pZip, mz_zip_array *pArray, size_t n)\n{\n    return mz_zip_array_reserve(pZip, pArray, pArray->m_size + n, MZ_TRUE);\n}\n\nstatic MZ_FORCEINLINE mz_bool mz_zip_array_push_back(mz_zip_archive *pZip, mz_zip_array *pArray, const void *pElements, size_t n)\n{\n    size_t orig_size = pArray->m_size;\n    if (!mz_zip_array_resize(pZip, pArray, orig_size + n, MZ_TRUE))\n        return MZ_FALSE;\n    if (n > 0)\n        memcpy((mz_uint8 *)pArray->m_p + orig_size * pArray->m_element_size, pElements, n * pArray->m_element_size);\n    return MZ_TRUE;\n}\n\n#ifndef MINIZ_NO_TIME\nstatic MZ_TIME_T mz_zip_dos_to_time_t(int dos_time, int dos_date)\n{\n    struct tm tm;\n    memset(&tm, 0, sizeof(tm));\n    tm.tm_isdst = -1;\n    tm.tm_year = ((dos_date >> 9) & 127) + 1980 - 1900;\n    tm.tm_mon = ((dos_date >> 5) & 15) - 1;\n    tm.tm_mday = dos_date & 31;\n    tm.tm_hour = (dos_time >> 11) & 31;\n    tm.tm_min = (dos_time >> 5) & 63;\n    tm.tm_sec = (dos_time << 1) & 62;\n    return mktime(&tm);\n}\n\n#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS\nstatic void mz_zip_time_t_to_dos_time(MZ_TIME_T time, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date)\n{\n#ifdef _MSC_VER\n    struct tm tm_struct;\n    struct tm *tm = &tm_struct;\n    errno_t err = localtime_s(tm, &time);\n    if (err)\n    {\n        *pDOS_date = 0;\n        *pDOS_time = 0;\n        return;\n    }\n#else\n    struct tm *tm = localtime(&time);\n#endif /* #ifdef _MSC_VER */\n\n    *pDOS_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) + ((tm->tm_sec) >> 1));\n    *pDOS_date = (mz_uint16)(((tm->tm_year + 1900 - 1980) << 9) + ((tm->tm_mon + 1) << 5) + tm->tm_mday);\n}\n#endif /* MINIZ_NO_ARCHIVE_WRITING_APIS */\n\n#ifndef MINIZ_NO_STDIO\n#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS\nstatic mz_bool mz_zip_get_file_modified_time(const char *pFilename, MZ_TIME_T *pTime)\n{\n    struct MZ_FILE_STAT_STRUCT file_stat;\n\n    /* On Linux with x86 glibc, this call will fail on large files (I think >= 0x80000000 bytes) unless you compiled with _LARGEFILE64_SOURCE. Argh. */\n    if (MZ_FILE_STAT(pFilename, &file_stat) != 0)\n        return MZ_FALSE;\n\n    *pTime = file_stat.st_mtime;\n\n    return MZ_TRUE;\n}\n#endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS*/\n\nstatic mz_bool mz_zip_set_file_times(const char *pFilename, MZ_TIME_T access_time, MZ_TIME_T modified_time)\n{\n    struct utimbuf t;\n\n    memset(&t, 0, sizeof(t));\n    t.actime = access_time;\n    t.modtime = modified_time;\n\n    return !utime(pFilename, &t);\n}\n#endif /* #ifndef MINIZ_NO_STDIO */\n#endif /* #ifndef MINIZ_NO_TIME */\n\nstatic MZ_FORCEINLINE mz_bool mz_zip_set_error(mz_zip_archive *pZip, mz_zip_error err_num)\n{\n    if (pZip)\n        pZip->m_last_error = err_num;\n    return MZ_FALSE;\n}\n\nstatic mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip, mz_uint flags)\n{\n    (void)flags;\n    if ((!pZip) || (pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID))\n        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);\n\n    if (!pZip->m_pAlloc)\n        pZip->m_pAlloc = miniz_def_alloc_func;\n    if (!pZip->m_pFree)\n        pZip->m_pFree = miniz_def_free_func;\n    if (!pZip->m_pRealloc)\n        pZip->m_pRealloc = miniz_def_realloc_func;\n\n    pZip->m_archive_size = 0;\n    pZip->m_central_directory_file_ofs = 0;\n    pZip->m_total_files = 0;\n    pZip->m_last_error = MZ_ZIP_NO_ERROR;\n\n    if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state))))\n        return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);\n\n    memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state));\n    MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8));\n    MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32));\n    MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32));\n    pZip->m_pState->m_init_flags = flags;\n    pZip->m_pState->m_zip64 = MZ_FALSE;\n    pZip->m_pState->m_zip64_has_extended_info_fields = MZ_FALSE;\n\n    pZip->m_zip_mode = MZ_ZIP_MODE_READING;\n\n    return MZ_TRUE;\n}\n\nstatic MZ_FORCEINLINE mz_bool mz_zip_reader_filename_less(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, mz_uint r_index)\n{\n    const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE;\n    const mz_uint8 *pR = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, r_index));\n    mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS), r_len = MZ_READ_LE16(pR + MZ_ZIP_CDH_FILENAME_LEN_OFS);\n    mz_uint8 l = 0, r = 0;\n    pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;\n    pR += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;\n    pE = pL + MZ_MIN(l_len, r_len);\n    while (pL < pE)\n    {\n        if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR)))\n            break;\n        pL++;\n        pR++;\n    }\n    return (pL == pE) ? (l_len < r_len) : (l < r);\n}\n\n#define MZ_SWAP_UINT32(a, b) \\\n    do                       \\\n    {                        \\\n        mz_uint32 t = a;     \\\n        a = b;               \\\n        b = t;               \\\n    }                        \\\n    MZ_MACRO_END\n\n/* Heap sort of lowercased filenames, used to help accelerate plain central directory searches by mz_zip_reader_locate_file(). (Could also use qsort(), but it could allocate memory.) */\nstatic void mz_zip_reader_sort_central_dir_offsets_by_filename(mz_zip_archive *pZip)\n{\n    mz_zip_internal_state *pState = pZip->m_pState;\n    const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets;\n    const mz_zip_array *pCentral_dir = &pState->m_central_dir;\n    mz_uint32 *pIndices;\n    mz_uint32 start, end;\n    const mz_uint32 size = pZip->m_total_files;\n\n    if (size <= 1U)\n        return;\n\n    pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0);\n\n    start = (size - 2U) >> 1U;\n    for (;;)\n    {\n        mz_uint64 child, root = start;\n        for (;;)\n        {\n            if ((child = (root << 1U) + 1U) >= size)\n                break;\n            child += (((child + 1U) < size) && (mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1U])));\n            if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child]))\n                break;\n            MZ_SWAP_UINT32(pIndices[root], pIndices[child]);\n            root = child;\n        }\n        if (!start)\n            break;\n        start--;\n    }\n\n    end = size - 1;\n    while (end > 0)\n    {\n        mz_uint64 child, root = 0;\n        MZ_SWAP_UINT32(pIndices[end], pIndices[0]);\n        for (;;)\n        {\n            if ((child = (root << 1U) + 1U) >= end)\n                break;\n            child += (((child + 1U) < end) && mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1U]));\n            if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child]))\n                break;\n            MZ_SWAP_UINT32(pIndices[root], pIndices[child]);\n            root = child;\n        }\n        end--;\n    }\n}\n\nstatic mz_bool mz_zip_reader_locate_header_sig(mz_zip_archive *pZip, mz_uint32 record_sig, mz_uint32 record_size, mz_int64 *pOfs)\n{\n    mz_int64 cur_file_ofs;\n    mz_uint32 buf_u32[4096 / sizeof(mz_uint32)];\n    mz_uint8 *pBuf = (mz_uint8 *)buf_u32;\n\n    /* Basic sanity checks - reject files which are too small */\n    if (pZip->m_archive_size < record_size)\n        return MZ_FALSE;\n\n    /* Find the record by scanning the file from the end towards the beginning. */\n    cur_file_ofs = MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0);\n    for (;;)\n    {\n        int i, n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs);\n\n        if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n)\n            return MZ_FALSE;\n\n        for (i = n - 4; i >= 0; --i)\n        {\n            mz_uint s = MZ_READ_LE32(pBuf + i);\n            if (s == record_sig)\n            {\n                if ((pZip->m_archive_size - (cur_file_ofs + i)) >= record_size)\n                    break;\n            }\n        }\n\n        if (i >= 0)\n        {\n            cur_file_ofs += i;\n            break;\n        }\n\n        /* Give up if we've searched the entire file, or we've gone back \"too far\" (~64kb) */\n        if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >= (MZ_UINT16_MAX + record_size)))\n            return MZ_FALSE;\n\n        cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0);\n    }\n\n    *pOfs = cur_file_ofs;\n    return MZ_TRUE;\n}\n\nstatic mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, mz_uint flags)\n{\n    mz_uint cdir_size = 0, cdir_entries_on_this_disk = 0, num_this_disk = 0, cdir_disk_index = 0;\n    mz_uint64 cdir_ofs = 0;\n    mz_int64 cur_file_ofs = 0;\n    const mz_uint8 *p;\n\n    mz_uint32 buf_u32[4096 / sizeof(mz_uint32)];\n    mz_uint8 *pBuf = (mz_uint8 *)buf_u32;\n    mz_bool sort_central_dir = ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0);\n    mz_uint32 zip64_end_of_central_dir_locator_u32[(MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)];\n    mz_uint8 *pZip64_locator = (mz_uint8 *)zip64_end_of_central_dir_locator_u32;\n\n    mz_uint32 zip64_end_of_central_dir_header_u32[(MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)];\n    mz_uint8 *pZip64_end_of_central_dir = (mz_uint8 *)zip64_end_of_central_dir_header_u32;\n\n    mz_uint64 zip64_end_of_central_dir_ofs = 0;\n\n    /* Basic sanity checks - reject files which are too small, and check the first 4 bytes of the file to make sure a local header is there. */\n    if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)\n        return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);\n\n    if (!mz_zip_reader_locate_header_sig(pZip, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE, &cur_file_ofs))\n        return mz_zip_set_error(pZip, MZ_ZIP_FAILED_FINDING_CENTRAL_DIR);\n\n    /* Read and verify the end of central directory record. */\n    if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)\n        return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);\n\n    if (MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG)\n        return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);\n\n    if (cur_file_ofs >= (MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE))\n    {\n        if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs - MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE, pZip64_locator, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) == MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE)\n        {\n            if (MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_SIG_OFS) == MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG)\n            {\n                zip64_end_of_central_dir_ofs = MZ_READ_LE64(pZip64_locator + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS);\n                if (zip64_end_of_central_dir_ofs > (pZip->m_archive_size - MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE))\n                    return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);\n\n                if (pZip->m_pRead(pZip->m_pIO_opaque, zip64_end_of_central_dir_ofs, pZip64_end_of_central_dir, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) == MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)\n                {\n                    if (MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIG_OFS) == MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG)\n                    {\n                        pZip->m_pState->m_zip64 = MZ_TRUE;\n                    }\n                }\n            }\n        }\n    }\n\n    pZip->m_total_files = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS);\n    cdir_entries_on_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS);\n    num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS);\n    cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS);\n    cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS);\n    cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS);\n\n    if (pZip->m_pState->m_zip64)\n    {\n        mz_uint32 zip64_total_num_of_disks = MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS);\n        mz_uint64 zip64_cdir_total_entries = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS);\n        mz_uint64 zip64_cdir_total_entries_on_this_disk = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS);\n        mz_uint64 zip64_size_of_end_of_central_dir_record = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS);\n        mz_uint64 zip64_size_of_central_directory = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_SIZE_OFS);\n\n        if (zip64_size_of_end_of_central_dir_record < (MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - 12))\n            return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);\n\n        if (zip64_total_num_of_disks != 1U)\n            return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK);\n\n        /* Check for miniz's practical limits */\n        if (zip64_cdir_total_entries > MZ_UINT32_MAX)\n            return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);\n\n        pZip->m_total_files = (mz_uint32)zip64_cdir_total_entries;\n\n        if (zip64_cdir_total_entries_on_this_disk > MZ_UINT32_MAX)\n            return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);\n\n        cdir_entries_on_this_disk = (mz_uint32)zip64_cdir_total_entries_on_this_disk;\n\n        /* Check for miniz's current practical limits (sorry, this should be enough for millions of files) */\n        if (zip64_size_of_central_directory > MZ_UINT32_MAX)\n            return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE);\n\n        cdir_size = (mz_uint32)zip64_size_of_central_directory;\n\n        num_this_disk = MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS);\n\n        cdir_disk_index = MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS);\n\n        cdir_ofs = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_OFS_OFS);\n    }\n\n    if (pZip->m_total_files != cdir_entries_on_this_disk)\n        return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK);\n\n    if (((num_this_disk | cdir_disk_index) != 0) && ((num_this_disk != 1) || (cdir_disk_index != 1)))\n        return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK);\n\n    if (cdir_size < pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)\n        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);\n\n    if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size)\n        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);\n\n    pZip->m_central_directory_file_ofs = cdir_ofs;\n\n    if (pZip->m_total_files)\n    {\n        mz_uint i, n;\n        /* Read the entire central directory into a heap block, and allocate another heap block to hold the unsorted central dir file record offsets, and possibly another to hold the sorted indices. */\n        if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size, MZ_FALSE)) ||\n            (!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets, pZip->m_total_files, MZ_FALSE)))\n            return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);\n\n        if (sort_central_dir)\n        {\n            if (!mz_zip_array_resize(pZip, &pZip->m_pState->m_sorted_central_dir_offsets, pZip->m_total_files, MZ_FALSE))\n                return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);\n        }\n\n        if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs, pZip->m_pState->m_central_dir.m_p, cdir_size) != cdir_size)\n            return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);\n\n        /* Now create an index into the central directory file records, do some basic sanity checking on each record */\n        p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p;\n        for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i)\n        {\n            mz_uint total_header_size, disk_index, bit_flags, filename_size, ext_data_size;\n            mz_uint64 comp_size, decomp_size, local_header_ofs;\n\n            if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) || (MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG))\n                return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);\n\n            MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, i) = (mz_uint32)(p - (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p);\n\n            if (sort_central_dir)\n                MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets, mz_uint32, i) = i;\n\n            comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);\n            decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS);\n            local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS);\n            filename_size = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);\n            ext_data_size = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS);\n\n            if ((!pZip->m_pState->m_zip64_has_extended_info_fields) &&\n                (ext_data_size) &&\n                (MZ_MAX(MZ_MAX(comp_size, decomp_size), local_header_ofs) == MZ_UINT32_MAX))\n            {\n                /* Attempt to find zip64 extended information field in the entry's extra data */\n                mz_uint32 extra_size_remaining = ext_data_size;\n\n                if (extra_size_remaining)\n                {\n\t\t\t\t\tconst mz_uint8 *pExtra_data;\n\t\t\t\t\tvoid* buf = NULL;\n\n\t\t\t\t\tif (MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + ext_data_size > n)\n\t\t\t\t\t{\n\t\t\t\t\t\tbuf = MZ_MALLOC(ext_data_size);\n\t\t\t\t\t\tif(buf==NULL)\n\t\t\t\t\t\t\treturn mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);\n\n\t\t\t\t\t\tif (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size, buf, ext_data_size) != ext_data_size)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tMZ_FREE(buf);\n\t\t\t\t\t\t\treturn mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tpExtra_data = (mz_uint8*)buf;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tpExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size;\n\t\t\t\t\t}\n\n                    do\n                    {\n                        mz_uint32 field_id;\n                        mz_uint32 field_data_size;\n\n\t\t\t\t\t\tif (extra_size_remaining < (sizeof(mz_uint16) * 2))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tMZ_FREE(buf);\n\t\t\t\t\t\t\treturn mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);\n\t\t\t\t\t\t}\n\n                        field_id = MZ_READ_LE16(pExtra_data);\n                        field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16));\n\n\t\t\t\t\t\tif ((field_data_size + sizeof(mz_uint16) * 2) > extra_size_remaining)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tMZ_FREE(buf);\n\t\t\t\t\t\t\treturn mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);\n\t\t\t\t\t\t}\n\n                        if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID)\n                        {\n                            /* Ok, the archive didn't have any zip64 headers but it uses a zip64 extended information field so mark it as zip64 anyway (this can occur with infozip's zip util when it reads compresses files from stdin). */\n                            pZip->m_pState->m_zip64 = MZ_TRUE;\n                            pZip->m_pState->m_zip64_has_extended_info_fields = MZ_TRUE;\n                            break;\n                        }\n\n                        pExtra_data += sizeof(mz_uint16) * 2 + field_data_size;\n                        extra_size_remaining = extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size;\n                    } while (extra_size_remaining);\n\n\t\t\t\t\tMZ_FREE(buf);\n                }\n            }\n\n            /* I've seen archives that aren't marked as zip64 that uses zip64 ext data, argh */\n            if ((comp_size != MZ_UINT32_MAX) && (decomp_size != MZ_UINT32_MAX))\n            {\n                if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) && (decomp_size != comp_size)) || (decomp_size && !comp_size))\n                    return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);\n            }\n\n            disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS);\n            if ((disk_index == MZ_UINT16_MAX) || ((disk_index != num_this_disk) && (disk_index != 1)))\n                return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK);\n\n            if (comp_size != MZ_UINT32_MAX)\n            {\n                if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size)\n                    return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);\n            }\n\n            bit_flags = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS);\n            if (bit_flags & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED)\n                return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION);\n\n            if ((total_header_size = MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS)) > n)\n                return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);\n\n            n -= total_header_size;\n            p += total_header_size;\n        }\n    }\n\n    if (sort_central_dir)\n        mz_zip_reader_sort_central_dir_offsets_by_filename(pZip);\n\n    return MZ_TRUE;\n}\n\nvoid mz_zip_zero_struct(mz_zip_archive *pZip)\n{\n    if (pZip)\n        MZ_CLEAR_OBJ(*pZip);\n}\n\nstatic mz_bool mz_zip_reader_end_internal(mz_zip_archive *pZip, mz_bool set_last_error)\n{\n    mz_bool status = MZ_TRUE;\n\n    if (!pZip)\n        return MZ_FALSE;\n\n    if ((!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING))\n    {\n        if (set_last_error)\n            pZip->m_last_error = MZ_ZIP_INVALID_PARAMETER;\n\n        return MZ_FALSE;\n    }\n\n    if (pZip->m_pState)\n    {\n        mz_zip_internal_state *pState = pZip->m_pState;\n        pZip->m_pState = NULL;\n\n        mz_zip_array_clear(pZip, &pState->m_central_dir);\n        mz_zip_array_clear(pZip, &pState->m_central_dir_offsets);\n        mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets);\n\n#ifndef MINIZ_NO_STDIO\n        if (pState->m_pFile)\n        {\n            if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE)\n            {\n                if (MZ_FCLOSE(pState->m_pFile) == EOF)\n                {\n                    if (set_last_error)\n                        pZip->m_last_error = MZ_ZIP_FILE_CLOSE_FAILED;\n                    status = MZ_FALSE;\n                }\n            }\n            pState->m_pFile = NULL;\n        }\n#endif /* #ifndef MINIZ_NO_STDIO */\n\n        pZip->m_pFree(pZip->m_pAlloc_opaque, pState);\n    }\n    pZip->m_zip_mode = MZ_ZIP_MODE_INVALID;\n\n    return status;\n}\n\nmz_bool mz_zip_reader_end(mz_zip_archive *pZip)\n{\n    return mz_zip_reader_end_internal(pZip, MZ_TRUE);\n}\nmz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint flags)\n{\n    if ((!pZip) || (!pZip->m_pRead))\n        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);\n\n    if (!mz_zip_reader_init_internal(pZip, flags))\n        return MZ_FALSE;\n\n    pZip->m_zip_type = MZ_ZIP_TYPE_USER;\n    pZip->m_archive_size = size;\n\n    if (!mz_zip_reader_read_central_dir(pZip, flags))\n    {\n        mz_zip_reader_end_internal(pZip, MZ_FALSE);\n        return MZ_FALSE;\n    }\n\n    return MZ_TRUE;\n}\n\nstatic size_t mz_zip_mem_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n)\n{\n    mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;\n    size_t s = (file_ofs >= pZip->m_archive_size) ? 0 : (size_t)MZ_MIN(pZip->m_archive_size - file_ofs, n);\n    memcpy(pBuf, (const mz_uint8 *)pZip->m_pState->m_pMem + file_ofs, s);\n    return s;\n}\n\nmz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint flags)\n{\n    if (!pMem)\n        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);\n\n    if (size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)\n        return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);\n\n    if (!mz_zip_reader_init_internal(pZip, flags))\n        return MZ_FALSE;\n\n    pZip->m_zip_type = MZ_ZIP_TYPE_MEMORY;\n    pZip->m_archive_size = size;\n    pZip->m_pRead = mz_zip_mem_read_func;\n    pZip->m_pIO_opaque = pZip;\n    pZip->m_pNeeds_keepalive = NULL;\n\n#ifdef __cplusplus\n    pZip->m_pState->m_pMem = const_cast<void *>(pMem);\n#else\n    pZip->m_pState->m_pMem = (void *)pMem;\n#endif\n\n    pZip->m_pState->m_mem_size = size;\n\n    if (!mz_zip_reader_read_central_dir(pZip, flags))\n    {\n        mz_zip_reader_end_internal(pZip, MZ_FALSE);\n        return MZ_FALSE;\n    }\n\n    return MZ_TRUE;\n}\n\n#ifndef MINIZ_NO_STDIO\nstatic size_t mz_zip_file_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n)\n{\n    mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;\n    mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile);\n\n    file_ofs += pZip->m_pState->m_file_archive_start_ofs;\n\n    if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET))))\n        return 0;\n\n    return MZ_FREAD(pBuf, 1, n, pZip->m_pState->m_pFile);\n}\n\nmz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags)\n{\n    return mz_zip_reader_init_file_v2(pZip, pFilename, flags, 0, 0);\n}\n\nmz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags, mz_uint64 file_start_ofs, mz_uint64 archive_size)\n{\n    mz_uint64 file_size;\n    MZ_FILE *pFile;\n\n    if ((!pZip) || (!pFilename) || ((archive_size) && (archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)))\n        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);\n\n    pFile = MZ_FOPEN(pFilename, \"rb\");\n    if (!pFile)\n        return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED);\n\n    file_size = archive_size;\n    if (!file_size)\n    {\n        if (MZ_FSEEK64(pFile, 0, SEEK_END))\n        {\n            MZ_FCLOSE(pFile);\n            return mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED);\n        }\n\n        file_size = MZ_FTELL64(pFile);\n    }\n\n    /* TODO: Better sanity check archive_size and the # of actual remaining bytes */\n\n    if (file_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)\n    {\n\tMZ_FCLOSE(pFile);\n        return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);\n    }\n\n    if (!mz_zip_reader_init_internal(pZip, flags))\n    {\n        MZ_FCLOSE(pFile);\n        return MZ_FALSE;\n    }\n\n    pZip->m_zip_type = MZ_ZIP_TYPE_FILE;\n    pZip->m_pRead = mz_zip_file_read_func;\n    pZip->m_pIO_opaque = pZip;\n    pZip->m_pState->m_pFile = pFile;\n    pZip->m_archive_size = file_size;\n    pZip->m_pState->m_file_archive_start_ofs = file_start_ofs;\n\n    if (!mz_zip_reader_read_central_dir(pZip, flags))\n    {\n        mz_zip_reader_end_internal(pZip, MZ_FALSE);\n        return MZ_FALSE;\n    }\n\n    return MZ_TRUE;\n}\n\nmz_bool mz_zip_reader_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint64 archive_size, mz_uint flags)\n{\n    mz_uint64 cur_file_ofs;\n\n    if ((!pZip) || (!pFile))\n        return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED);\n\n    cur_file_ofs = MZ_FTELL64(pFile);\n\n    if (!archive_size)\n    {\n        if (MZ_FSEEK64(pFile, 0, SEEK_END))\n            return mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED);\n\n        archive_size = MZ_FTELL64(pFile) - cur_file_ofs;\n\n        if (archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)\n            return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);\n    }\n\n    if (!mz_zip_reader_init_internal(pZip, flags))\n        return MZ_FALSE;\n\n    pZip->m_zip_type = MZ_ZIP_TYPE_CFILE;\n    pZip->m_pRead = mz_zip_file_read_func;\n\n    pZip->m_pIO_opaque = pZip;\n    pZip->m_pState->m_pFile = pFile;\n    pZip->m_archive_size = archive_size;\n    pZip->m_pState->m_file_archive_start_ofs = cur_file_ofs;\n\n    if (!mz_zip_reader_read_central_dir(pZip, flags))\n    {\n        mz_zip_reader_end_internal(pZip, MZ_FALSE);\n        return MZ_FALSE;\n    }\n\n    return MZ_TRUE;\n}\n\n#endif /* #ifndef MINIZ_NO_STDIO */\n\nstatic MZ_FORCEINLINE const mz_uint8 *mz_zip_get_cdh(mz_zip_archive *pZip, mz_uint file_index)\n{\n    if ((!pZip) || (!pZip->m_pState) || (file_index >= pZip->m_total_files))\n        return NULL;\n    return &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index));\n}\n\nmz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index)\n{\n    mz_uint m_bit_flag;\n    const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index);\n    if (!p)\n    {\n        mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);\n        return MZ_FALSE;\n    }\n\n    m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS);\n    return (m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION)) != 0;\n}\n\nmz_bool mz_zip_reader_is_file_supported(mz_zip_archive *pZip, mz_uint file_index)\n{\n    mz_uint bit_flag;\n    mz_uint method;\n\n    const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index);\n    if (!p)\n    {\n        mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);\n        return MZ_FALSE;\n    }\n\n    method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS);\n    bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS);\n\n    if ((method != 0) && (method != MZ_DEFLATED))\n    {\n        mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD);\n        return MZ_FALSE;\n    }\n\n    if (bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION))\n    {\n        mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION);\n        return MZ_FALSE;\n    }\n\n    if (bit_flag & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)\n    {\n        mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE);\n        return MZ_FALSE;\n    }\n\n    return MZ_TRUE;\n}\n\nmz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index)\n{\n    mz_uint filename_len, attribute_mapping_id, external_attr;\n    const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index);\n    if (!p)\n    {\n        mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);\n        return MZ_FALSE;\n    }\n\n    filename_len = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);\n    if (filename_len)\n    {\n        if (*(p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_len - 1) == '/')\n            return MZ_TRUE;\n    }\n\n    /* Bugfix: This code was also checking if the internal attribute was non-zero, which wasn't correct. */\n    /* Most/all zip writers (hopefully) set DOS file/directory attributes in the low 16-bits, so check for the DOS directory flag and ignore the source OS ID in the created by field. */\n    /* FIXME: Remove this check? Is it necessary - we already check the filename. */\n    attribute_mapping_id = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS) >> 8;\n    (void)attribute_mapping_id;\n\n    external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS);\n    if ((external_attr & MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG) != 0)\n    {\n        return MZ_TRUE;\n    }\n\n    return MZ_FALSE;\n}\n\nstatic mz_bool mz_zip_file_stat_internal(mz_zip_archive *pZip, mz_uint file_index, const mz_uint8 *pCentral_dir_header, mz_zip_archive_file_stat *pStat, mz_bool *pFound_zip64_extra_data)\n{\n    mz_uint n;\n    const mz_uint8 *p = pCentral_dir_header;\n\n    if (pFound_zip64_extra_data)\n        *pFound_zip64_extra_data = MZ_FALSE;\n\n    if ((!p) || (!pStat))\n        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);\n\n    /* Extract fields from the central directory record. */\n    pStat->m_file_index = file_index;\n    pStat->m_central_dir_ofs = MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index);\n    pStat->m_version_made_by = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS);\n    pStat->m_version_needed = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_NEEDED_OFS);\n    pStat->m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS);\n    pStat->m_method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS);\n#ifndef MINIZ_NO_TIME\n    pStat->m_time = mz_zip_dos_to_time_t(MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_TIME_OFS), MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_DATE_OFS));\n#endif\n    pStat->m_crc32 = MZ_READ_LE32(p + MZ_ZIP_CDH_CRC32_OFS);\n    pStat->m_comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);\n    pStat->m_uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS);\n    pStat->m_internal_attr = MZ_READ_LE16(p + MZ_ZIP_CDH_INTERNAL_ATTR_OFS);\n    pStat->m_external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS);\n    pStat->m_local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS);\n\n    /* Copy as much of the filename and comment as possible. */\n    n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);\n    n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - 1);\n    memcpy(pStat->m_filename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n);\n    pStat->m_filename[n] = '\\0';\n\n    n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS);\n    n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1);\n    pStat->m_comment_size = n;\n    memcpy(pStat->m_comment, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS), n);\n    pStat->m_comment[n] = '\\0';\n\n    /* Set some flags for convienance */\n    pStat->m_is_directory = mz_zip_reader_is_file_a_directory(pZip, file_index);\n    pStat->m_is_encrypted = mz_zip_reader_is_file_encrypted(pZip, file_index);\n    pStat->m_is_supported = mz_zip_reader_is_file_supported(pZip, file_index);\n\n    /* See if we need to read any zip64 extended information fields. */\n    /* Confusingly, these zip64 fields can be present even on non-zip64 archives (Debian zip on a huge files from stdin piped to stdout creates them). */\n    if (MZ_MAX(MZ_MAX(pStat->m_comp_size, pStat->m_uncomp_size), pStat->m_local_header_ofs) == MZ_UINT32_MAX)\n    {\n        /* Attempt to find zip64 extended information field in the entry's extra data */\n        mz_uint32 extra_size_remaining = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS);\n\n        if (extra_size_remaining)\n        {\n            const mz_uint8 *pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);\n\n            do\n            {\n                mz_uint32 field_id;\n                mz_uint32 field_data_size;\n\n                if (extra_size_remaining < (sizeof(mz_uint16) * 2))\n                    return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);\n\n                field_id = MZ_READ_LE16(pExtra_data);\n                field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16));\n\n                if ((field_data_size + sizeof(mz_uint16) * 2) > extra_size_remaining)\n                    return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);\n\n                if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID)\n                {\n                    const mz_uint8 *pField_data = pExtra_data + sizeof(mz_uint16) * 2;\n                    mz_uint32 field_data_remaining = field_data_size;\n\n                    if (pFound_zip64_extra_data)\n                        *pFound_zip64_extra_data = MZ_TRUE;\n\n                    if (pStat->m_uncomp_size == MZ_UINT32_MAX)\n                    {\n                        if (field_data_remaining < sizeof(mz_uint64))\n                            return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);\n\n                        pStat->m_uncomp_size = MZ_READ_LE64(pField_data);\n                        pField_data += sizeof(mz_uint64);\n                        field_data_remaining -= sizeof(mz_uint64);\n                    }\n\n                    if (pStat->m_comp_size == MZ_UINT32_MAX)\n                    {\n                        if (field_data_remaining < sizeof(mz_uint64))\n                            return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);\n\n                        pStat->m_comp_size = MZ_READ_LE64(pField_data);\n                        pField_data += sizeof(mz_uint64);\n                        field_data_remaining -= sizeof(mz_uint64);\n                    }\n\n                    if (pStat->m_local_header_ofs == MZ_UINT32_MAX)\n                    {\n                        if (field_data_remaining < sizeof(mz_uint64))\n                            return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);\n\n                        pStat->m_local_header_ofs = MZ_READ_LE64(pField_data);\n                        pField_data += sizeof(mz_uint64);\n                        field_data_remaining -= sizeof(mz_uint64);\n                    }\n\n                    break;\n                }\n\n                pExtra_data += sizeof(mz_uint16) * 2 + field_data_size;\n                extra_size_remaining = extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size;\n            } while (extra_size_remaining);\n        }\n    }\n\n    return MZ_TRUE;\n}\n\nstatic MZ_FORCEINLINE mz_bool mz_zip_string_equal(const char *pA, const char *pB, mz_uint len, mz_uint flags)\n{\n    mz_uint i;\n    if (flags & MZ_ZIP_FLAG_CASE_SENSITIVE)\n        return 0 == memcmp(pA, pB, len);\n    for (i = 0; i < len; ++i)\n        if (MZ_TOLOWER(pA[i]) != MZ_TOLOWER(pB[i]))\n            return MZ_FALSE;\n    return MZ_TRUE;\n}\n\nstatic MZ_FORCEINLINE int mz_zip_filename_compare(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, const char *pR, mz_uint r_len)\n{\n    const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE;\n    mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS);\n    mz_uint8 l = 0, r = 0;\n    pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;\n    pE = pL + MZ_MIN(l_len, r_len);\n    while (pL < pE)\n    {\n        if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR)))\n            break;\n        pL++;\n        pR++;\n    }\n    return (pL == pE) ? (int)(l_len - r_len) : (l - r);\n}\n\nstatic mz_bool mz_zip_locate_file_binary_search(mz_zip_archive *pZip, const char *pFilename, mz_uint32 *pIndex)\n{\n    mz_zip_internal_state *pState = pZip->m_pState;\n    const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets;\n    const mz_zip_array *pCentral_dir = &pState->m_central_dir;\n    mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0);\n    const uint32_t size = pZip->m_total_files;\n    const mz_uint filename_len = (mz_uint)strlen(pFilename);\n\n    if (pIndex)\n        *pIndex = 0;\n\n    if (size)\n    {\n        /* yes I could use uint32_t's, but then we would have to add some special case checks in the loop, argh, and */\n        /* honestly the major expense here on 32-bit CPU's will still be the filename compare */\n        mz_int64 l = 0, h = (mz_int64)size - 1;\n\n        while (l <= h)\n        {\n            mz_int64 m = l + ((h - l) >> 1);\n            uint32_t file_index = pIndices[(uint32_t)m];\n\n            int comp = mz_zip_filename_compare(pCentral_dir, pCentral_dir_offsets, file_index, pFilename, filename_len);\n            if (!comp)\n            {\n                if (pIndex)\n                    *pIndex = file_index;\n                return MZ_TRUE;\n            }\n            else if (comp < 0)\n                l = m + 1;\n            else\n                h = m - 1;\n        }\n    }\n\n    return mz_zip_set_error(pZip, MZ_ZIP_FILE_NOT_FOUND);\n}\n\nint mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags)\n{\n    mz_uint32 index;\n    if (!mz_zip_reader_locate_file_v2(pZip, pName, pComment, flags, &index))\n        return -1;\n    else\n        return (int)index;\n}\n\nmz_bool mz_zip_reader_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *pIndex)\n{\n    mz_uint file_index;\n    size_t name_len, comment_len;\n\n    if (pIndex)\n        *pIndex = 0;\n\n    if ((!pZip) || (!pZip->m_pState) || (!pName))\n        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);\n\n    /* See if we can use a binary search */\n    if (((pZip->m_pState->m_init_flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0) &&\n        (pZip->m_zip_mode == MZ_ZIP_MODE_READING) &&\n        ((flags & (MZ_ZIP_FLAG_IGNORE_PATH | MZ_ZIP_FLAG_CASE_SENSITIVE)) == 0) && (!pComment) && (pZip->m_pState->m_sorted_central_dir_offsets.m_size))\n    {\n        return mz_zip_locate_file_binary_search(pZip, pName, pIndex);\n    }\n\n    /* Locate the entry by scanning the entire central directory */\n    name_len = strlen(pName);\n    if (name_len > MZ_UINT16_MAX)\n        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);\n\n    comment_len = pComment ? strlen(pComment) : 0;\n    if (comment_len > MZ_UINT16_MAX)\n        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);\n\n    for (file_index = 0; file_index < pZip->m_total_files; file_index++)\n    {\n        const mz_uint8 *pHeader = &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index));\n        mz_uint filename_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS);\n        const char *pFilename = (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;\n        if (filename_len < name_len)\n            continue;\n        if (comment_len)\n        {\n            mz_uint file_extra_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_EXTRA_LEN_OFS), file_comment_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_COMMENT_LEN_OFS);\n            const char *pFile_comment = pFilename + filename_len + file_extra_len;\n            if ((file_comment_len != comment_len) || (!mz_zip_string_equal(pComment, pFile_comment, file_comment_len, flags)))\n                continue;\n        }\n        if ((flags & MZ_ZIP_FLAG_IGNORE_PATH) && (filename_len))\n        {\n            int ofs = filename_len - 1;\n            do\n            {\n                if ((pFilename[ofs] == '/') || (pFilename[ofs] == '\\\\') || (pFilename[ofs] == ':'))\n                    break;\n            } while (--ofs >= 0);\n            ofs++;\n            pFilename += ofs;\n            filename_len -= ofs;\n        }\n        if ((filename_len == name_len) && (mz_zip_string_equal(pName, pFilename, filename_len, flags)))\n        {\n            if (pIndex)\n                *pIndex = file_index;\n            return MZ_TRUE;\n        }\n    }\n\n    return mz_zip_set_error(pZip, MZ_ZIP_FILE_NOT_FOUND);\n}\n\nmz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size)\n{\n    int status = TINFL_STATUS_DONE;\n    mz_uint64 needed_size, cur_file_ofs, comp_remaining, out_buf_ofs = 0, read_buf_size, read_buf_ofs = 0, read_buf_avail;\n    mz_zip_archive_file_stat file_stat;\n    void *pRead_buf;\n    mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)];\n    mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32;\n    tinfl_decompressor inflator;\n\n    if ((!pZip) || (!pZip->m_pState) || ((buf_size) && (!pBuf)) || ((user_read_buf_size) && (!pUser_read_buf)) || (!pZip->m_pRead))\n        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);\n\n    if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat))\n        return MZ_FALSE;\n\n    /* A directory or zero length file */\n    if ((file_stat.m_is_directory) || (!file_stat.m_comp_size))\n        return MZ_TRUE;\n\n    /* Encryption and patch files are not supported. */\n    if (file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG))\n        return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION);\n\n    /* This function only supports decompressing stored and deflate. */\n    if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED))\n        return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD);\n\n    /* Ensure supplied output buffer is large enough. */\n    needed_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size : file_stat.m_uncomp_size;\n    if (buf_size < needed_size)\n        return mz_zip_set_error(pZip, MZ_ZIP_BUF_TOO_SMALL);\n\n    /* Read and parse the local directory entry. */\n    cur_file_ofs = file_stat.m_local_header_ofs;\n    if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE)\n        return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);\n\n    if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG)\n        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);\n\n    cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS);\n    if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size)\n        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);\n\n    if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method))\n    {\n        /* The file is stored or the caller has requested the compressed data. */\n        if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, (size_t)needed_size) != needed_size)\n            return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);\n\n#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS\n        if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) == 0)\n        {\n            if (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32)\n                return mz_zip_set_error(pZip, MZ_ZIP_CRC_CHECK_FAILED);\n        }\n#endif\n\n        return MZ_TRUE;\n    }\n\n    /* Decompress the file either directly from memory or from a file input buffer. */\n    tinfl_init(&inflator);\n\n    if (pZip->m_pState->m_pMem)\n    {\n        /* Read directly from the archive in memory. */\n        pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs;\n        read_buf_size = read_buf_avail = file_stat.m_comp_size;\n        comp_remaining = 0;\n    }\n    else if (pUser_read_buf)\n    {\n        /* Use a user provided read buffer. */\n        if (!user_read_buf_size)\n            return MZ_FALSE;\n        pRead_buf = (mz_uint8 *)pUser_read_buf;\n        read_buf_size = user_read_buf_size;\n        read_buf_avail = 0;\n        comp_remaining = file_stat.m_comp_size;\n    }\n    else\n    {\n        /* Temporarily allocate a read buffer. */\n        read_buf_size = MZ_MIN(file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE);\n        if (((sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF))\n            return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);\n\n        if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size)))\n            return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);\n\n        read_buf_avail = 0;\n        comp_remaining = file_stat.m_comp_size;\n    }\n\n    do\n    {\n        /* The size_t cast here should be OK because we've verified that the output buffer is >= file_stat.m_uncomp_size above */\n        size_t in_buf_size, out_buf_size = (size_t)(file_stat.m_uncomp_size - out_buf_ofs);\n        if ((!read_buf_avail) && (!pZip->m_pState->m_pMem))\n        {\n            read_buf_avail = MZ_MIN(read_buf_size, comp_remaining);\n            if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail)\n            {\n                status = TINFL_STATUS_FAILED;\n                mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED);\n                break;\n            }\n            cur_file_ofs += read_buf_avail;\n            comp_remaining -= read_buf_avail;\n            read_buf_ofs = 0;\n        }\n        in_buf_size = (size_t)read_buf_avail;\n        status = tinfl_decompress(&inflator, (mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pBuf, (mz_uint8 *)pBuf + out_buf_ofs, &out_buf_size, TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF | (comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0));\n        read_buf_avail -= in_buf_size;\n        read_buf_ofs += in_buf_size;\n        out_buf_ofs += out_buf_size;\n    } while (status == TINFL_STATUS_NEEDS_MORE_INPUT);\n\n    if (status == TINFL_STATUS_DONE)\n    {\n        /* Make sure the entire file was decompressed, and check its CRC. */\n        if (out_buf_ofs != file_stat.m_uncomp_size)\n        {\n            mz_zip_set_error(pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE);\n            status = TINFL_STATUS_FAILED;\n        }\n#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS\n        else if (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32)\n        {\n            mz_zip_set_error(pZip, MZ_ZIP_CRC_CHECK_FAILED);\n            status = TINFL_STATUS_FAILED;\n        }\n#endif\n    }\n\n    if ((!pZip->m_pState->m_pMem) && (!pUser_read_buf))\n        pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);\n\n    return status == TINFL_STATUS_DONE;\n}\n\nmz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size)\n{\n    mz_uint32 file_index;\n    if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index))\n        return MZ_FALSE;\n    return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, pUser_read_buf, user_read_buf_size);\n}\n\nmz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags)\n{\n    return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, NULL, 0);\n}\n\nmz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags)\n{\n    return mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf, buf_size, flags, NULL, 0);\n}\n\nvoid *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags)\n{\n    mz_uint64 comp_size, uncomp_size, alloc_size;\n    const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index);\n    void *pBuf;\n\n    if (pSize)\n        *pSize = 0;\n\n    if (!p)\n    {\n        mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);\n        return NULL;\n    }\n\n    comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);\n    uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS);\n\n    alloc_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? comp_size : uncomp_size;\n    if (((sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF))\n    {\n        mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);\n        return NULL;\n    }\n\n    if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)alloc_size)))\n    {\n        mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);\n        return NULL;\n    }\n\n    if (!mz_zip_reader_extract_to_mem(pZip, file_index, pBuf, (size_t)alloc_size, flags))\n    {\n        pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);\n        return NULL;\n    }\n\n    if (pSize)\n        *pSize = (size_t)alloc_size;\n    return pBuf;\n}\n\nvoid *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags)\n{\n    mz_uint32 file_index;\n    if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index))\n    {\n        if (pSize)\n            *pSize = 0;\n        return MZ_FALSE;\n    }\n    return mz_zip_reader_extract_to_heap(pZip, file_index, pSize, flags);\n}\n\nmz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags)\n{\n    int status = TINFL_STATUS_DONE;\n    mz_uint file_crc32 = MZ_CRC32_INIT;\n    mz_uint64 read_buf_size, read_buf_ofs = 0, read_buf_avail, comp_remaining, out_buf_ofs = 0, cur_file_ofs;\n    mz_zip_archive_file_stat file_stat;\n    void *pRead_buf = NULL;\n    void *pWrite_buf = NULL;\n    mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)];\n    mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32;\n\n    if ((!pZip) || (!pZip->m_pState) || (!pCallback) || (!pZip->m_pRead))\n        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);\n\n    if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat))\n        return MZ_FALSE;\n\n    /* A directory or zero length file */\n    if ((file_stat.m_is_directory) || (!file_stat.m_comp_size))\n        return MZ_TRUE;\n\n    /* Encryption and patch files are not supported. */\n    if (file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG))\n        return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION);\n\n    /* This function only supports decompressing stored and deflate. */\n    if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED))\n        return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD);\n\n    /* Read and do some minimal validation of the local directory entry (this doesn't crack the zip64 stuff, which we already have from the central dir) */\n    cur_file_ofs = file_stat.m_local_header_ofs;\n    if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE)\n        return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);\n\n    if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG)\n        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);\n\n    cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS);\n    if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size)\n        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);\n\n    /* Decompress the file either directly from memory or from a file input buffer. */\n    if (pZip->m_pState->m_pMem)\n    {\n        pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs;\n        read_buf_size = read_buf_avail = file_stat.m_comp_size;\n        comp_remaining = 0;\n    }\n    else\n    {\n        read_buf_size = MZ_MIN(file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE);\n        if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size)))\n            return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);\n\n        read_buf_avail = 0;\n        comp_remaining = file_stat.m_comp_size;\n    }\n\n    if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method))\n    {\n        /* The file is stored or the caller has requested the compressed data. */\n        if (pZip->m_pState->m_pMem)\n        {\n            if (((sizeof(size_t) == sizeof(mz_uint32))) && (file_stat.m_comp_size > MZ_UINT32_MAX))\n                return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);\n\n            if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)file_stat.m_comp_size) != file_stat.m_comp_size)\n            {\n                mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED);\n                status = TINFL_STATUS_FAILED;\n            }\n            else if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))\n            {\n#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS\n                file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)file_stat.m_comp_size);\n#endif\n            }\n\n            cur_file_ofs += file_stat.m_comp_size;\n            out_buf_ofs += file_stat.m_comp_size;\n            comp_remaining = 0;\n        }\n        else\n        {\n            while (comp_remaining)\n            {\n                read_buf_avail = MZ_MIN(read_buf_size, comp_remaining);\n                if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail)\n                {\n                    mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);\n                    status = TINFL_STATUS_FAILED;\n                    break;\n                }\n\n#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS\n                if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))\n                {\n                    file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)read_buf_avail);\n                }\n#endif\n\n                if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail)\n                {\n                    mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED);\n                    status = TINFL_STATUS_FAILED;\n                    break;\n                }\n\n                cur_file_ofs += read_buf_avail;\n                out_buf_ofs += read_buf_avail;\n                comp_remaining -= read_buf_avail;\n            }\n        }\n    }\n    else\n    {\n        tinfl_decompressor inflator;\n        tinfl_init(&inflator);\n\n        if (NULL == (pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE)))\n        {\n            mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);\n            status = TINFL_STATUS_FAILED;\n        }\n        else\n        {\n            do\n            {\n                mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pWrite_buf + (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1));\n                size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1));\n                if ((!read_buf_avail) && (!pZip->m_pState->m_pMem))\n                {\n                    read_buf_avail = MZ_MIN(read_buf_size, comp_remaining);\n                    if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail)\n                    {\n                        mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);\n                        status = TINFL_STATUS_FAILED;\n                        break;\n                    }\n                    cur_file_ofs += read_buf_avail;\n                    comp_remaining -= read_buf_avail;\n                    read_buf_ofs = 0;\n                }\n\n                in_buf_size = (size_t)read_buf_avail;\n                status = tinfl_decompress(&inflator, (const mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pWrite_buf, pWrite_buf_cur, &out_buf_size, comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0);\n                read_buf_avail -= in_buf_size;\n                read_buf_ofs += in_buf_size;\n\n                if (out_buf_size)\n                {\n                    if (pCallback(pOpaque, out_buf_ofs, pWrite_buf_cur, out_buf_size) != out_buf_size)\n                    {\n                        mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED);\n                        status = TINFL_STATUS_FAILED;\n                        break;\n                    }\n\n#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS\n                    file_crc32 = (mz_uint32)mz_crc32(file_crc32, pWrite_buf_cur, out_buf_size);\n#endif\n                    if ((out_buf_ofs += out_buf_size) > file_stat.m_uncomp_size)\n                    {\n                        mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED);\n                        status = TINFL_STATUS_FAILED;\n                        break;\n                    }\n                }\n            } while ((status == TINFL_STATUS_NEEDS_MORE_INPUT) || (status == TINFL_STATUS_HAS_MORE_OUTPUT));\n        }\n    }\n\n    if ((status == TINFL_STATUS_DONE) && (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)))\n    {\n        /* Make sure the entire file was decompressed, and check its CRC. */\n        if (out_buf_ofs != file_stat.m_uncomp_size)\n        {\n            mz_zip_set_error(pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE);\n            status = TINFL_STATUS_FAILED;\n        }\n#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS\n        else if (file_crc32 != file_stat.m_crc32)\n        {\n            mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED);\n            status = TINFL_STATUS_FAILED;\n        }\n#endif\n    }\n\n    if (!pZip->m_pState->m_pMem)\n        pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);\n\n    if (pWrite_buf)\n        pZip->m_pFree(pZip->m_pAlloc_opaque, pWrite_buf);\n\n    return status == TINFL_STATUS_DONE;\n}\n\nmz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags)\n{\n    mz_uint32 file_index;\n    if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index))\n        return MZ_FALSE;\n\n    return mz_zip_reader_extract_to_callback(pZip, file_index, pCallback, pOpaque, flags);\n}\n\nmz_zip_reader_extract_iter_state* mz_zip_reader_extract_iter_new(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags)\n{\n    mz_zip_reader_extract_iter_state *pState;\n    mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)];\n    mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32;\n\n    /* Argument sanity check */\n    if ((!pZip) || (!pZip->m_pState))\n        return NULL;\n\n    /* Allocate an iterator status structure */\n    pState = (mz_zip_reader_extract_iter_state*)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_reader_extract_iter_state));\n    if (!pState)\n    {\n        mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);\n        return NULL;\n    }\n\n    /* Fetch file details */\n    if (!mz_zip_reader_file_stat(pZip, file_index, &pState->file_stat))\n    {\n        pZip->m_pFree(pZip->m_pAlloc_opaque, pState);\n        return NULL;\n    }\n\n    /* Encryption and patch files are not supported. */\n    if (pState->file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG))\n    {\n        mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION);\n        pZip->m_pFree(pZip->m_pAlloc_opaque, pState);\n        return NULL;\n    }\n\n    /* This function only supports decompressing stored and deflate. */\n    if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (pState->file_stat.m_method != 0) && (pState->file_stat.m_method != MZ_DEFLATED))\n    {\n        mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD);\n        pZip->m_pFree(pZip->m_pAlloc_opaque, pState);\n        return NULL;\n    }\n\n    /* Init state - save args */\n    pState->pZip = pZip;\n    pState->flags = flags;\n\n    /* Init state - reset variables to defaults */\n    pState->status = TINFL_STATUS_DONE;\n#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS\n    pState->file_crc32 = MZ_CRC32_INIT;\n#endif\n    pState->read_buf_ofs = 0;\n    pState->out_buf_ofs = 0;\n    pState->pRead_buf = NULL;\n    pState->pWrite_buf = NULL;\n    pState->out_blk_remain = 0;\n\n    /* Read and parse the local directory entry. */\n    pState->cur_file_ofs = pState->file_stat.m_local_header_ofs;\n    if (pZip->m_pRead(pZip->m_pIO_opaque, pState->cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE)\n    {\n        mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);\n        pZip->m_pFree(pZip->m_pAlloc_opaque, pState);\n        return NULL;\n    }\n\n    if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG)\n    {\n        mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);\n        pZip->m_pFree(pZip->m_pAlloc_opaque, pState);\n        return NULL;\n    }\n\n    pState->cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS);\n    if ((pState->cur_file_ofs + pState->file_stat.m_comp_size) > pZip->m_archive_size)\n    {\n        mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);\n        pZip->m_pFree(pZip->m_pAlloc_opaque, pState);\n        return NULL;\n    }\n\n    /* Decompress the file either directly from memory or from a file input buffer. */\n    if (pZip->m_pState->m_pMem)\n    {\n        pState->pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + pState->cur_file_ofs;\n        pState->read_buf_size = pState->read_buf_avail = pState->file_stat.m_comp_size;\n        pState->comp_remaining = pState->file_stat.m_comp_size;\n    }\n    else\n    {\n        if (!((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method)))\n        {\n            /* Decompression required, therefore intermediate read buffer required */\n            pState->read_buf_size = MZ_MIN(pState->file_stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE);\n            if (NULL == (pState->pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)pState->read_buf_size)))\n            {\n                mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);\n                pZip->m_pFree(pZip->m_pAlloc_opaque, pState);\n                return NULL;\n            }\n        }\n        else\n        {\n            /* Decompression not required - we will be reading directly into user buffer, no temp buf required */\n            pState->read_buf_size = 0;\n        }\n        pState->read_buf_avail = 0;\n        pState->comp_remaining = pState->file_stat.m_comp_size;\n    }\n\n    if (!((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method)))\n    {\n        /* Decompression required, init decompressor */\n        tinfl_init( &pState->inflator );\n\n        /* Allocate write buffer */\n        if (NULL == (pState->pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE)))\n        {\n            mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);\n            if (pState->pRead_buf)\n                pZip->m_pFree(pZip->m_pAlloc_opaque, pState->pRead_buf);\n            pZip->m_pFree(pZip->m_pAlloc_opaque, pState);\n            return NULL;\n        }\n    }\n\n    return pState;\n}\n\nmz_zip_reader_extract_iter_state* mz_zip_reader_extract_file_iter_new(mz_zip_archive *pZip, const char *pFilename, mz_uint flags)\n{\n    mz_uint32 file_index;\n\n    /* Locate file index by name */\n    if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index))\n        return NULL;\n\n    /* Construct iterator */\n    return mz_zip_reader_extract_iter_new(pZip, file_index, flags);\n}\n\nsize_t mz_zip_reader_extract_iter_read(mz_zip_reader_extract_iter_state* pState, void* pvBuf, size_t buf_size)\n{\n    size_t copied_to_caller = 0;\n\n    /* Argument sanity check */\n    if ((!pState) || (!pState->pZip) || (!pState->pZip->m_pState) || (!pvBuf))\n        return 0;\n\n    if ((pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method))\n    {\n        /* The file is stored or the caller has requested the compressed data, calc amount to return. */\n        copied_to_caller = (size_t)MZ_MIN( buf_size, pState->comp_remaining );\n\n        /* Zip is in memory....or requires reading from a file? */\n        if (pState->pZip->m_pState->m_pMem)\n        {\n            /* Copy data to caller's buffer */\n            memcpy( pvBuf, pState->pRead_buf, copied_to_caller );\n            pState->pRead_buf = ((mz_uint8*)pState->pRead_buf) + copied_to_caller;\n        }\n        else\n        {\n            /* Read directly into caller's buffer */\n            if (pState->pZip->m_pRead(pState->pZip->m_pIO_opaque, pState->cur_file_ofs, pvBuf, copied_to_caller) != copied_to_caller)\n            {\n                /* Failed to read all that was asked for, flag failure and alert user */\n                mz_zip_set_error(pState->pZip, MZ_ZIP_FILE_READ_FAILED);\n                pState->status = TINFL_STATUS_FAILED;\n                copied_to_caller = 0;\n            }\n        }\n\n#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS\n        /* Compute CRC if not returning compressed data only */\n        if (!(pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA))\n            pState->file_crc32 = (mz_uint32)mz_crc32(pState->file_crc32, (const mz_uint8 *)pvBuf, copied_to_caller);\n#endif\n\n        /* Advance offsets, dec counters */\n        pState->cur_file_ofs += copied_to_caller;\n        pState->out_buf_ofs += copied_to_caller;\n        pState->comp_remaining -= copied_to_caller;\n    }\n    else\n    {\n        do\n        {\n            /* Calc ptr to write buffer - given current output pos and block size */\n            mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pState->pWrite_buf + (pState->out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1));\n\n            /* Calc max output size - given current output pos and block size */\n            size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (pState->out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1));\n\n            if (!pState->out_blk_remain)\n            {\n                /* Read more data from file if none available (and reading from file) */\n                if ((!pState->read_buf_avail) && (!pState->pZip->m_pState->m_pMem))\n                {\n                    /* Calc read size */\n                    pState->read_buf_avail = MZ_MIN(pState->read_buf_size, pState->comp_remaining);\n                    if (pState->pZip->m_pRead(pState->pZip->m_pIO_opaque, pState->cur_file_ofs, pState->pRead_buf, (size_t)pState->read_buf_avail) != pState->read_buf_avail)\n                    {\n                        mz_zip_set_error(pState->pZip, MZ_ZIP_FILE_READ_FAILED);\n                        pState->status = TINFL_STATUS_FAILED;\n                        break;\n                    }\n\n                    /* Advance offsets, dec counters */\n                    pState->cur_file_ofs += pState->read_buf_avail;\n                    pState->comp_remaining -= pState->read_buf_avail;\n                    pState->read_buf_ofs = 0;\n                }\n\n                /* Perform decompression */\n                in_buf_size = (size_t)pState->read_buf_avail;\n                pState->status = tinfl_decompress(&pState->inflator, (const mz_uint8 *)pState->pRead_buf + pState->read_buf_ofs, &in_buf_size, (mz_uint8 *)pState->pWrite_buf, pWrite_buf_cur, &out_buf_size, pState->comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0);\n                pState->read_buf_avail -= in_buf_size;\n                pState->read_buf_ofs += in_buf_size;\n\n                /* Update current output block size remaining */\n                pState->out_blk_remain = out_buf_size;\n            }\n\n            if (pState->out_blk_remain)\n            {\n                /* Calc amount to return. */\n                size_t to_copy = MZ_MIN( (buf_size - copied_to_caller), pState->out_blk_remain );\n\n                /* Copy data to caller's buffer */\n                memcpy( (uint8_t*)pvBuf + copied_to_caller, pWrite_buf_cur, to_copy );\n\n#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS\n                /* Perform CRC */\n                pState->file_crc32 = (mz_uint32)mz_crc32(pState->file_crc32, pWrite_buf_cur, to_copy);\n#endif\n\n                /* Decrement data consumed from block */\n                pState->out_blk_remain -= to_copy;\n\n                /* Inc output offset, while performing sanity check */\n                if ((pState->out_buf_ofs += to_copy) > pState->file_stat.m_uncomp_size)\n                {\n                    mz_zip_set_error(pState->pZip, MZ_ZIP_DECOMPRESSION_FAILED);\n                    pState->status = TINFL_STATUS_FAILED;\n                    break;\n                }\n\n                /* Increment counter of data copied to caller */\n                copied_to_caller += to_copy;\n            }\n        } while ( (copied_to_caller < buf_size) && ((pState->status == TINFL_STATUS_NEEDS_MORE_INPUT) || (pState->status == TINFL_STATUS_HAS_MORE_OUTPUT)) );\n    }\n\n    /* Return how many bytes were copied into user buffer */\n    return copied_to_caller;\n}\n\nmz_bool mz_zip_reader_extract_iter_free(mz_zip_reader_extract_iter_state* pState)\n{\n    int status;\n\n    /* Argument sanity check */\n    if ((!pState) || (!pState->pZip) || (!pState->pZip->m_pState))\n        return MZ_FALSE;\n\n    /* Was decompression completed and requested? */\n    if ((pState->status == TINFL_STATUS_DONE) && (!(pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA)))\n    {\n        /* Make sure the entire file was decompressed, and check its CRC. */\n        if (pState->out_buf_ofs != pState->file_stat.m_uncomp_size)\n        {\n            mz_zip_set_error(pState->pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE);\n            pState->status = TINFL_STATUS_FAILED;\n        }\n#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS\n        else if (pState->file_crc32 != pState->file_stat.m_crc32)\n        {\n            mz_zip_set_error(pState->pZip, MZ_ZIP_DECOMPRESSION_FAILED);\n            pState->status = TINFL_STATUS_FAILED;\n        }\n#endif\n    }\n\n    /* Free buffers */\n    if (!pState->pZip->m_pState->m_pMem)\n        pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState->pRead_buf);\n    if (pState->pWrite_buf)\n        pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState->pWrite_buf);\n\n    /* Save status */\n    status = pState->status;\n\n    /* Free context */\n    pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState);\n\n    return status == TINFL_STATUS_DONE;\n}\n\n#ifndef MINIZ_NO_STDIO\nstatic size_t mz_zip_file_write_callback(void *pOpaque, mz_uint64 ofs, const void *pBuf, size_t n)\n{\n    (void)ofs;\n\n    return MZ_FWRITE(pBuf, 1, n, (MZ_FILE *)pOpaque);\n}\n\nmz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags)\n{\n    mz_bool status;\n    mz_zip_archive_file_stat file_stat;\n    MZ_FILE *pFile;\n\n    if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat))\n        return MZ_FALSE;\n\n    if ((file_stat.m_is_directory) || (!file_stat.m_is_supported))\n        return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE);\n\n    pFile = MZ_FOPEN(pDst_filename, \"wb\");\n    if (!pFile)\n        return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED);\n\n    status = mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags);\n\n    if (MZ_FCLOSE(pFile) == EOF)\n    {\n        if (status)\n            mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED);\n\n        status = MZ_FALSE;\n    }\n\n#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_STDIO)\n    if (status)\n        mz_zip_set_file_times(pDst_filename, file_stat.m_time, file_stat.m_time);\n#endif\n\n    return status;\n}\n\nmz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags)\n{\n    mz_uint32 file_index;\n    if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, NULL, flags, &file_index))\n        return MZ_FALSE;\n\n    return mz_zip_reader_extract_to_file(pZip, file_index, pDst_filename, flags);\n}\n\nmz_bool mz_zip_reader_extract_to_cfile(mz_zip_archive *pZip, mz_uint file_index, MZ_FILE *pFile, mz_uint flags)\n{\n    mz_zip_archive_file_stat file_stat;\n\n    if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat))\n        return MZ_FALSE;\n\n    if ((file_stat.m_is_directory) || (!file_stat.m_is_supported))\n        return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE);\n\n    return mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags);\n}\n\nmz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pArchive_filename, MZ_FILE *pFile, mz_uint flags)\n{\n    mz_uint32 file_index;\n    if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, NULL, flags, &file_index))\n        return MZ_FALSE;\n\n    return mz_zip_reader_extract_to_cfile(pZip, file_index, pFile, flags);\n}\n#endif /* #ifndef MINIZ_NO_STDIO */\n\nstatic size_t mz_zip_compute_crc32_callback(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n)\n{\n    mz_uint32 *p = (mz_uint32 *)pOpaque;\n    (void)file_ofs;\n    *p = (mz_uint32)mz_crc32(*p, (const mz_uint8 *)pBuf, n);\n    return n;\n}\n\nmz_bool mz_zip_validate_file(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags)\n{\n    mz_zip_archive_file_stat file_stat;\n    mz_zip_internal_state *pState;\n    const mz_uint8 *pCentral_dir_header;\n    mz_bool found_zip64_ext_data_in_cdir = MZ_FALSE;\n    mz_bool found_zip64_ext_data_in_ldir = MZ_FALSE;\n    mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)];\n    mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32;\n    mz_uint64 local_header_ofs = 0;\n    mz_uint32 local_header_filename_len, local_header_extra_len, local_header_crc32;\n    mz_uint64 local_header_comp_size, local_header_uncomp_size;\n    mz_uint32 uncomp_crc32 = MZ_CRC32_INIT;\n    mz_bool has_data_descriptor;\n    mz_uint32 local_header_bit_flags;\n\n    mz_zip_array file_data_array;\n    mz_zip_array_init(&file_data_array, 1);\n\n    if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (!pZip->m_pRead))\n        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);\n\n    if (file_index > pZip->m_total_files)\n        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);\n\n    pState = pZip->m_pState;\n\n    pCentral_dir_header = mz_zip_get_cdh(pZip, file_index);\n\n    if (!mz_zip_file_stat_internal(pZip, file_index, pCentral_dir_header, &file_stat, &found_zip64_ext_data_in_cdir))\n        return MZ_FALSE;\n\n    /* A directory or zero length file */\n    if ((file_stat.m_is_directory) || (!file_stat.m_uncomp_size))\n        return MZ_TRUE;\n\n    /* Encryption and patch files are not supported. */\n    if (file_stat.m_is_encrypted)\n        return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION);\n\n    /* This function only supports stored and deflate. */\n    if ((file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED))\n        return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD);\n\n    if (!file_stat.m_is_supported)\n        return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE);\n\n    /* Read and parse the local directory entry. */\n    local_header_ofs = file_stat.m_local_header_ofs;\n    if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE)\n        return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);\n\n    if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG)\n        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);\n\n    local_header_filename_len = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS);\n    local_header_extra_len = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS);\n    local_header_comp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS);\n    local_header_uncomp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS);\n    local_header_crc32 = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_CRC32_OFS);\n    local_header_bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS);\n    has_data_descriptor = (local_header_bit_flags & 8) != 0;\n\n    if (local_header_filename_len != strlen(file_stat.m_filename))\n        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);\n\n    if ((local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_len + local_header_extra_len + file_stat.m_comp_size) > pZip->m_archive_size)\n        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);\n\n    if (!mz_zip_array_resize(pZip, &file_data_array, MZ_MAX(local_header_filename_len, local_header_extra_len), MZ_FALSE))\n        return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);\n\n    if (local_header_filename_len)\n    {\n        if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE, file_data_array.m_p, local_header_filename_len) != local_header_filename_len)\n        {\n            mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);\n            goto handle_failure;\n        }\n\n        /* I've seen 1 archive that had the same pathname, but used backslashes in the local dir and forward slashes in the central dir. Do we care about this? For now, this case will fail validation. */\n        if (memcmp(file_stat.m_filename, file_data_array.m_p, local_header_filename_len) != 0)\n        {\n            mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED);\n            goto handle_failure;\n        }\n    }\n\n    if ((local_header_extra_len) && ((local_header_comp_size == MZ_UINT32_MAX) || (local_header_uncomp_size == MZ_UINT32_MAX)))\n    {\n        mz_uint32 extra_size_remaining = local_header_extra_len;\n        const mz_uint8 *pExtra_data = (const mz_uint8 *)file_data_array.m_p;\n\n        if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_len, file_data_array.m_p, local_header_extra_len) != local_header_extra_len)\n        {\n            mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);\n            goto handle_failure;\n        }\n\n        do\n        {\n            mz_uint32 field_id, field_data_size, field_total_size;\n\n            if (extra_size_remaining < (sizeof(mz_uint16) * 2))\n                return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);\n\n            field_id = MZ_READ_LE16(pExtra_data);\n            field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16));\n            field_total_size = field_data_size + sizeof(mz_uint16) * 2;\n\n            if (field_total_size > extra_size_remaining)\n                return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);\n\n            if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID)\n            {\n                const mz_uint8 *pSrc_field_data = pExtra_data + sizeof(mz_uint32);\n\n                if (field_data_size < sizeof(mz_uint64) * 2)\n                {\n                    mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);\n                    goto handle_failure;\n                }\n\n                local_header_uncomp_size = MZ_READ_LE64(pSrc_field_data);\n                local_header_comp_size = MZ_READ_LE64(pSrc_field_data + sizeof(mz_uint64));\n\n                found_zip64_ext_data_in_ldir = MZ_TRUE;\n                break;\n            }\n\n            pExtra_data += field_total_size;\n            extra_size_remaining -= field_total_size;\n        } while (extra_size_remaining);\n    }\n\n    /* TODO: parse local header extra data when local_header_comp_size is 0xFFFFFFFF! (big_descriptor.zip) */\n    /* I've seen zips in the wild with the data descriptor bit set, but proper local header values and bogus data descriptors */\n    if ((has_data_descriptor) && (!local_header_comp_size) && (!local_header_crc32))\n    {\n        mz_uint8 descriptor_buf[32];\n        mz_bool has_id;\n        const mz_uint8 *pSrc;\n        mz_uint32 file_crc32;\n        mz_uint64 comp_size = 0, uncomp_size = 0;\n\n        mz_uint32 num_descriptor_uint32s = ((pState->m_zip64) || (found_zip64_ext_data_in_ldir)) ? 6 : 4;\n\n        if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_len + local_header_extra_len + file_stat.m_comp_size, descriptor_buf, sizeof(mz_uint32) * num_descriptor_uint32s) != (sizeof(mz_uint32) * num_descriptor_uint32s))\n        {\n            mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);\n            goto handle_failure;\n        }\n\n        has_id = (MZ_READ_LE32(descriptor_buf) == MZ_ZIP_DATA_DESCRIPTOR_ID);\n        pSrc = has_id ? (descriptor_buf + sizeof(mz_uint32)) : descriptor_buf;\n\n        file_crc32 = MZ_READ_LE32(pSrc);\n\n        if ((pState->m_zip64) || (found_zip64_ext_data_in_ldir))\n        {\n            comp_size = MZ_READ_LE64(pSrc + sizeof(mz_uint32));\n            uncomp_size = MZ_READ_LE64(pSrc + sizeof(mz_uint32) + sizeof(mz_uint64));\n        }\n        else\n        {\n            comp_size = MZ_READ_LE32(pSrc + sizeof(mz_uint32));\n            uncomp_size = MZ_READ_LE32(pSrc + sizeof(mz_uint32) + sizeof(mz_uint32));\n        }\n\n        if ((file_crc32 != file_stat.m_crc32) || (comp_size != file_stat.m_comp_size) || (uncomp_size != file_stat.m_uncomp_size))\n        {\n            mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED);\n            goto handle_failure;\n        }\n    }\n    else\n    {\n        if ((local_header_crc32 != file_stat.m_crc32) || (local_header_comp_size != file_stat.m_comp_size) || (local_header_uncomp_size != file_stat.m_uncomp_size))\n        {\n            mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED);\n            goto handle_failure;\n        }\n    }\n\n    mz_zip_array_clear(pZip, &file_data_array);\n\n    if ((flags & MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY) == 0)\n    {\n        if (!mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_compute_crc32_callback, &uncomp_crc32, 0))\n            return MZ_FALSE;\n\n        /* 1 more check to be sure, although the extract checks too. */\n        if (uncomp_crc32 != file_stat.m_crc32)\n        {\n            mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED);\n            return MZ_FALSE;\n        }\n    }\n\n    return MZ_TRUE;\n\nhandle_failure:\n    mz_zip_array_clear(pZip, &file_data_array);\n    return MZ_FALSE;\n}\n\nmz_bool mz_zip_validate_archive(mz_zip_archive *pZip, mz_uint flags)\n{\n    mz_zip_internal_state *pState;\n    uint32_t i;\n\n    if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (!pZip->m_pRead))\n        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);\n\n    pState = pZip->m_pState;\n\n    /* Basic sanity checks */\n    if (!pState->m_zip64)\n    {\n        if (pZip->m_total_files > MZ_UINT16_MAX)\n            return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);\n\n        if (pZip->m_archive_size > MZ_UINT32_MAX)\n            return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);\n    }\n    else\n    {\n        if (pZip->m_total_files >= MZ_UINT32_MAX)\n            return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);\n\n        if (pState->m_central_dir.m_size >= MZ_UINT32_MAX)\n            return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);\n    }\n\n    for (i = 0; i < pZip->m_total_files; i++)\n    {\n        if (MZ_ZIP_FLAG_VALIDATE_LOCATE_FILE_FLAG & flags)\n        {\n            mz_uint32 found_index;\n            mz_zip_archive_file_stat stat;\n\n            if (!mz_zip_reader_file_stat(pZip, i, &stat))\n                return MZ_FALSE;\n\n            if (!mz_zip_reader_locate_file_v2(pZip, stat.m_filename, NULL, 0, &found_index))\n                return MZ_FALSE;\n\n            /* This check can fail if there are duplicate filenames in the archive (which we don't check for when writing - that's up to the user) */\n            if (found_index != i)\n                return mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED);\n        }\n\n        if (!mz_zip_validate_file(pZip, i, flags))\n            return MZ_FALSE;\n    }\n\n    return MZ_TRUE;\n}\n\nmz_bool mz_zip_validate_mem_archive(const void *pMem, size_t size, mz_uint flags, mz_zip_error *pErr)\n{\n    mz_bool success = MZ_TRUE;\n    mz_zip_archive zip;\n    mz_zip_error actual_err = MZ_ZIP_NO_ERROR;\n\n    if ((!pMem) || (!size))\n    {\n        if (pErr)\n            *pErr = MZ_ZIP_INVALID_PARAMETER;\n        return MZ_FALSE;\n    }\n\n    mz_zip_zero_struct(&zip);\n\n    if (!mz_zip_reader_init_mem(&zip, pMem, size, flags))\n    {\n        if (pErr)\n            *pErr = zip.m_last_error;\n        return MZ_FALSE;\n    }\n\n    if (!mz_zip_validate_archive(&zip, flags))\n    {\n        actual_err = zip.m_last_error;\n        success = MZ_FALSE;\n    }\n\n    if (!mz_zip_reader_end_internal(&zip, success))\n    {\n        if (!actual_err)\n            actual_err = zip.m_last_error;\n        success = MZ_FALSE;\n    }\n\n    if (pErr)\n        *pErr = actual_err;\n\n    return success;\n}\n\n#ifndef MINIZ_NO_STDIO\nmz_bool mz_zip_validate_file_archive(const char *pFilename, mz_uint flags, mz_zip_error *pErr)\n{\n    mz_bool success = MZ_TRUE;\n    mz_zip_archive zip;\n    mz_zip_error actual_err = MZ_ZIP_NO_ERROR;\n\n    if (!pFilename)\n    {\n        if (pErr)\n            *pErr = MZ_ZIP_INVALID_PARAMETER;\n        return MZ_FALSE;\n    }\n\n    mz_zip_zero_struct(&zip);\n\n    if (!mz_zip_reader_init_file_v2(&zip, pFilename, flags, 0, 0))\n    {\n        if (pErr)\n            *pErr = zip.m_last_error;\n        return MZ_FALSE;\n    }\n\n    if (!mz_zip_validate_archive(&zip, flags))\n    {\n        actual_err = zip.m_last_error;\n        success = MZ_FALSE;\n    }\n\n    if (!mz_zip_reader_end_internal(&zip, success))\n    {\n        if (!actual_err)\n            actual_err = zip.m_last_error;\n        success = MZ_FALSE;\n    }\n\n    if (pErr)\n        *pErr = actual_err;\n\n    return success;\n}\n#endif /* #ifndef MINIZ_NO_STDIO */\n\n/* ------------------- .ZIP archive writing */\n\n#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS\n\nstatic MZ_FORCEINLINE void mz_write_le16(mz_uint8 *p, mz_uint16 v)\n{\n    p[0] = (mz_uint8)v;\n    p[1] = (mz_uint8)(v >> 8);\n}\nstatic MZ_FORCEINLINE void mz_write_le32(mz_uint8 *p, mz_uint32 v)\n{\n    p[0] = (mz_uint8)v;\n    p[1] = (mz_uint8)(v >> 8);\n    p[2] = (mz_uint8)(v >> 16);\n    p[3] = (mz_uint8)(v >> 24);\n}\nstatic MZ_FORCEINLINE void mz_write_le64(mz_uint8 *p, mz_uint64 v)\n{\n    mz_write_le32(p, (mz_uint32)v);\n    mz_write_le32(p + sizeof(mz_uint32), (mz_uint32)(v >> 32));\n}\n\n#define MZ_WRITE_LE16(p, v) mz_write_le16((mz_uint8 *)(p), (mz_uint16)(v))\n#define MZ_WRITE_LE32(p, v) mz_write_le32((mz_uint8 *)(p), (mz_uint32)(v))\n#define MZ_WRITE_LE64(p, v) mz_write_le64((mz_uint8 *)(p), (mz_uint64)(v))\n\nstatic size_t mz_zip_heap_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n)\n{\n    mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;\n    mz_zip_internal_state *pState = pZip->m_pState;\n    mz_uint64 new_size = MZ_MAX(file_ofs + n, pState->m_mem_size);\n\n    if (!n)\n        return 0;\n\n    /* An allocation this big is likely to just fail on 32-bit systems, so don't even go there. */\n    if ((sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF))\n    {\n        mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE);\n        return 0;\n    }\n\n    if (new_size > pState->m_mem_capacity)\n    {\n        void *pNew_block;\n        size_t new_capacity = MZ_MAX(64, pState->m_mem_capacity);\n\n        while (new_capacity < new_size)\n            new_capacity *= 2;\n\n        if (NULL == (pNew_block = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pState->m_pMem, 1, new_capacity)))\n        {\n            mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);\n            return 0;\n        }\n\n        pState->m_pMem = pNew_block;\n        pState->m_mem_capacity = new_capacity;\n    }\n    memcpy((mz_uint8 *)pState->m_pMem + file_ofs, pBuf, n);\n    pState->m_mem_size = (size_t)new_size;\n    return n;\n}\n\nstatic mz_bool mz_zip_writer_end_internal(mz_zip_archive *pZip, mz_bool set_last_error)\n{\n    mz_zip_internal_state *pState;\n    mz_bool status = MZ_TRUE;\n\n    if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || ((pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) && (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED)))\n    {\n        if (set_last_error)\n            mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);\n        return MZ_FALSE;\n    }\n\n    pState = pZip->m_pState;\n    pZip->m_pState = NULL;\n    mz_zip_array_clear(pZip, &pState->m_central_dir);\n    mz_zip_array_clear(pZip, &pState->m_central_dir_offsets);\n    mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets);\n\n#ifndef MINIZ_NO_STDIO\n    if (pState->m_pFile)\n    {\n        if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE)\n        {\n            if (MZ_FCLOSE(pState->m_pFile) == EOF)\n            {\n                if (set_last_error)\n                    mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED);\n                status = MZ_FALSE;\n            }\n        }\n\n        pState->m_pFile = NULL;\n    }\n#endif /* #ifndef MINIZ_NO_STDIO */\n\n    if ((pZip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem))\n    {\n        pZip->m_pFree(pZip->m_pAlloc_opaque, pState->m_pMem);\n        pState->m_pMem = NULL;\n    }\n\n    pZip->m_pFree(pZip->m_pAlloc_opaque, pState);\n    pZip->m_zip_mode = MZ_ZIP_MODE_INVALID;\n    return status;\n}\n\nmz_bool mz_zip_writer_init_v2(mz_zip_archive *pZip, mz_uint64 existing_size, mz_uint flags)\n{\n    mz_bool zip64 = (flags & MZ_ZIP_FLAG_WRITE_ZIP64) != 0;\n\n    if ((!pZip) || (pZip->m_pState) || (!pZip->m_pWrite) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID))\n        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);\n\n    if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING)\n    {\n        if (!pZip->m_pRead)\n            return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);\n    }\n\n    if (pZip->m_file_offset_alignment)\n    {\n        /* Ensure user specified file offset alignment is a power of 2. */\n        if (pZip->m_file_offset_alignment & (pZip->m_file_offset_alignment - 1))\n            return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);\n    }\n\n    if (!pZip->m_pAlloc)\n        pZip->m_pAlloc = miniz_def_alloc_func;\n    if (!pZip->m_pFree)\n        pZip->m_pFree = miniz_def_free_func;\n    if (!pZip->m_pRealloc)\n        pZip->m_pRealloc = miniz_def_realloc_func;\n\n    pZip->m_archive_size = existing_size;\n    pZip->m_central_directory_file_ofs = 0;\n    pZip->m_total_files = 0;\n\n    if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state))))\n        return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);\n\n    memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state));\n\n    MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8));\n    MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32));\n    MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32));\n\n    pZip->m_pState->m_zip64 = zip64;\n    pZip->m_pState->m_zip64_has_extended_info_fields = zip64;\n\n    pZip->m_zip_type = MZ_ZIP_TYPE_USER;\n    pZip->m_zip_mode = MZ_ZIP_MODE_WRITING;\n\n    return MZ_TRUE;\n}\n\nmz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size)\n{\n    return mz_zip_writer_init_v2(pZip, existing_size, 0);\n}\n\nmz_bool mz_zip_writer_init_heap_v2(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size, mz_uint flags)\n{\n    pZip->m_pWrite = mz_zip_heap_write_func;\n    pZip->m_pNeeds_keepalive = NULL;\n\n    if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING)\n        pZip->m_pRead = mz_zip_mem_read_func;\n\n    pZip->m_pIO_opaque = pZip;\n\n    if (!mz_zip_writer_init_v2(pZip, size_to_reserve_at_beginning, flags))\n        return MZ_FALSE;\n\n    pZip->m_zip_type = MZ_ZIP_TYPE_HEAP;\n\n    if (0 != (initial_allocation_size = MZ_MAX(initial_allocation_size, size_to_reserve_at_beginning)))\n    {\n        if (NULL == (pZip->m_pState->m_pMem = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, initial_allocation_size)))\n        {\n            mz_zip_writer_end_internal(pZip, MZ_FALSE);\n            return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);\n        }\n        pZip->m_pState->m_mem_capacity = initial_allocation_size;\n    }\n\n    return MZ_TRUE;\n}\n\nmz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size)\n{\n    return mz_zip_writer_init_heap_v2(pZip, size_to_reserve_at_beginning, initial_allocation_size, 0);\n}\n\n#ifndef MINIZ_NO_STDIO\nstatic size_t mz_zip_file_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n)\n{\n    mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;\n    mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile);\n\n    file_ofs += pZip->m_pState->m_file_archive_start_ofs;\n\n    if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET))))\n    {\n        mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED);\n        return 0;\n    }\n\n    return MZ_FWRITE(pBuf, 1, n, pZip->m_pState->m_pFile);\n}\n\nmz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning)\n{\n    return mz_zip_writer_init_file_v2(pZip, pFilename, size_to_reserve_at_beginning, 0);\n}\n\nmz_bool mz_zip_writer_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning, mz_uint flags)\n{\n    MZ_FILE *pFile;\n\n    pZip->m_pWrite = mz_zip_file_write_func;\n    pZip->m_pNeeds_keepalive = NULL;\n\n    if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING)\n        pZip->m_pRead = mz_zip_file_read_func;\n\n    pZip->m_pIO_opaque = pZip;\n\n    if (!mz_zip_writer_init_v2(pZip, size_to_reserve_at_beginning, flags))\n        return MZ_FALSE;\n\n    if (NULL == (pFile = MZ_FOPEN(pFilename, (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) ? \"w+b\" : \"wb\")))\n    {\n        mz_zip_writer_end(pZip);\n        return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED);\n    }\n\n    pZip->m_pState->m_pFile = pFile;\n    pZip->m_zip_type = MZ_ZIP_TYPE_FILE;\n\n    if (size_to_reserve_at_beginning)\n    {\n        mz_uint64 cur_ofs = 0;\n        char buf[4096];\n\n        MZ_CLEAR_OBJ(buf);\n\n        do\n        {\n            size_t n = (size_t)MZ_MIN(sizeof(buf), size_to_reserve_at_beginning);\n            if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_ofs, buf, n) != n)\n            {\n                mz_zip_writer_end(pZip);\n                return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);\n            }\n            cur_ofs += n;\n            size_to_reserve_at_beginning -= n;\n        } while (size_to_reserve_at_beginning);\n    }\n\n    return MZ_TRUE;\n}\n\nmz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint flags)\n{\n    pZip->m_pWrite = mz_zip_file_write_func;\n    pZip->m_pNeeds_keepalive = NULL;\n\n    if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING)\n        pZip->m_pRead = mz_zip_file_read_func;\n\n    pZip->m_pIO_opaque = pZip;\n\n    if (!mz_zip_writer_init_v2(pZip, 0, flags))\n        return MZ_FALSE;\n\n    pZip->m_pState->m_pFile = pFile;\n    pZip->m_pState->m_file_archive_start_ofs = MZ_FTELL64(pZip->m_pState->m_pFile);\n    pZip->m_zip_type = MZ_ZIP_TYPE_CFILE;\n\n    return MZ_TRUE;\n}\n#endif /* #ifndef MINIZ_NO_STDIO */\n\nmz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags)\n{\n    mz_zip_internal_state *pState;\n\n    if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING))\n        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);\n\n    if (flags & MZ_ZIP_FLAG_WRITE_ZIP64)\n    {\n        /* We don't support converting a non-zip64 file to zip64 - this seems like more trouble than it's worth. (What about the existing 32-bit data descriptors that could follow the compressed data?) */\n        if (!pZip->m_pState->m_zip64)\n            return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);\n    }\n\n    /* No sense in trying to write to an archive that's already at the support max size */\n    if (pZip->m_pState->m_zip64)\n    {\n        if (pZip->m_total_files == MZ_UINT32_MAX)\n            return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);\n    }\n    else\n    {\n        if (pZip->m_total_files == MZ_UINT16_MAX)\n            return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);\n\n        if ((pZip->m_archive_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) > MZ_UINT32_MAX)\n            return mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE);\n    }\n\n    pState = pZip->m_pState;\n\n    if (pState->m_pFile)\n    {\n#ifdef MINIZ_NO_STDIO\n        (void)pFilename;\n        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);\n#else\n        if (pZip->m_pIO_opaque != pZip)\n            return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);\n\n        if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE)\n        {\n            if (!pFilename)\n                return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);\n\n            /* Archive is being read from stdio and was originally opened only for reading. Try to reopen as writable. */\n            if (NULL == (pState->m_pFile = MZ_FREOPEN(pFilename, \"r+b\", pState->m_pFile)))\n            {\n                /* The mz_zip_archive is now in a bogus state because pState->m_pFile is NULL, so just close it. */\n                mz_zip_reader_end_internal(pZip, MZ_FALSE);\n                return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED);\n            }\n        }\n\n        pZip->m_pWrite = mz_zip_file_write_func;\n        pZip->m_pNeeds_keepalive = NULL;\n#endif /* #ifdef MINIZ_NO_STDIO */\n    }\n    else if (pState->m_pMem)\n    {\n        /* Archive lives in a memory block. Assume it's from the heap that we can resize using the realloc callback. */\n        if (pZip->m_pIO_opaque != pZip)\n            return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);\n\n        pState->m_mem_capacity = pState->m_mem_size;\n        pZip->m_pWrite = mz_zip_heap_write_func;\n        pZip->m_pNeeds_keepalive = NULL;\n    }\n    /* Archive is being read via a user provided read function - make sure the user has specified a write function too. */\n    else if (!pZip->m_pWrite)\n        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);\n\n    /* Start writing new files at the archive's current central directory location. */\n    /* TODO: We could add a flag that lets the user start writing immediately AFTER the existing central dir - this would be safer. */\n    pZip->m_archive_size = pZip->m_central_directory_file_ofs;\n    pZip->m_central_directory_file_ofs = 0;\n\n    /* Clear the sorted central dir offsets, they aren't useful or maintained now. */\n    /* Even though we're now in write mode, files can still be extracted and verified, but file locates will be slow. */\n    /* TODO: We could easily maintain the sorted central directory offsets. */\n    mz_zip_array_clear(pZip, &pZip->m_pState->m_sorted_central_dir_offsets);\n\n    pZip->m_zip_mode = MZ_ZIP_MODE_WRITING;\n\n    return MZ_TRUE;\n}\n\nmz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename)\n{\n    return mz_zip_writer_init_from_reader_v2(pZip, pFilename, 0);\n}\n\n/* TODO: pArchive_name is a terrible name here! */\nmz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags)\n{\n    return mz_zip_writer_add_mem_ex(pZip, pArchive_name, pBuf, buf_size, NULL, 0, level_and_flags, 0, 0);\n}\n\ntypedef struct\n{\n    mz_zip_archive *m_pZip;\n    mz_uint64 m_cur_archive_file_ofs;\n    mz_uint64 m_comp_size;\n} mz_zip_writer_add_state;\n\nstatic mz_bool mz_zip_writer_add_put_buf_callback(const void *pBuf, int len, void *pUser)\n{\n    mz_zip_writer_add_state *pState = (mz_zip_writer_add_state *)pUser;\n    if ((int)pState->m_pZip->m_pWrite(pState->m_pZip->m_pIO_opaque, pState->m_cur_archive_file_ofs, pBuf, len) != len)\n        return MZ_FALSE;\n\n    pState->m_cur_archive_file_ofs += len;\n    pState->m_comp_size += len;\n    return MZ_TRUE;\n}\n\n#define MZ_ZIP64_MAX_LOCAL_EXTRA_FIELD_SIZE (sizeof(mz_uint16) * 2 + sizeof(mz_uint64) * 2)\n#define MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE (sizeof(mz_uint16) * 2 + sizeof(mz_uint64) * 3)\nstatic mz_uint32 mz_zip_writer_create_zip64_extra_data(mz_uint8 *pBuf, mz_uint64 *pUncomp_size, mz_uint64 *pComp_size, mz_uint64 *pLocal_header_ofs)\n{\n    mz_uint8 *pDst = pBuf;\n    mz_uint32 field_size = 0;\n\n    MZ_WRITE_LE16(pDst + 0, MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID);\n    MZ_WRITE_LE16(pDst + 2, 0);\n    pDst += sizeof(mz_uint16) * 2;\n\n    if (pUncomp_size)\n    {\n        MZ_WRITE_LE64(pDst, *pUncomp_size);\n        pDst += sizeof(mz_uint64);\n        field_size += sizeof(mz_uint64);\n    }\n\n    if (pComp_size)\n    {\n        MZ_WRITE_LE64(pDst, *pComp_size);\n        pDst += sizeof(mz_uint64);\n        field_size += sizeof(mz_uint64);\n    }\n\n    if (pLocal_header_ofs)\n    {\n        MZ_WRITE_LE64(pDst, *pLocal_header_ofs);\n        pDst += sizeof(mz_uint64);\n        field_size += sizeof(mz_uint64);\n    }\n\n    MZ_WRITE_LE16(pBuf + 2, field_size);\n\n    return (mz_uint32)(pDst - pBuf);\n}\n\nstatic mz_bool mz_zip_writer_create_local_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, mz_uint16 extra_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date)\n{\n    (void)pZip;\n    memset(pDst, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE);\n    MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_SIG_OFS, MZ_ZIP_LOCAL_DIR_HEADER_SIG);\n    MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_VERSION_NEEDED_OFS, method ? 20 : 0);\n    MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_BIT_FLAG_OFS, bit_flags);\n    MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_METHOD_OFS, method);\n    MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_TIME_OFS, dos_time);\n    MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_DATE_OFS, dos_date);\n    MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_CRC32_OFS, uncomp_crc32);\n    MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS, MZ_MIN(comp_size, MZ_UINT32_MAX));\n    MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS, MZ_MIN(uncomp_size, MZ_UINT32_MAX));\n    MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILENAME_LEN_OFS, filename_size);\n    MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_EXTRA_LEN_OFS, extra_size);\n    return MZ_TRUE;\n}\n\nstatic mz_bool mz_zip_writer_create_central_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst,\n                                                       mz_uint16 filename_size, mz_uint16 extra_size, mz_uint16 comment_size,\n                                                       mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32,\n                                                       mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date,\n                                                       mz_uint64 local_header_ofs, mz_uint32 ext_attributes)\n{\n    (void)pZip;\n    memset(pDst, 0, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE);\n    MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_SIG_OFS, MZ_ZIP_CENTRAL_DIR_HEADER_SIG);\n    MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_NEEDED_OFS, method ? 20 : 0);\n    MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_BIT_FLAG_OFS, bit_flags);\n    MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_METHOD_OFS, method);\n    MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_TIME_OFS, dos_time);\n    MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_DATE_OFS, dos_date);\n    MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_CRC32_OFS, uncomp_crc32);\n    MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, MZ_MIN(comp_size, MZ_UINT32_MAX));\n    MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, MZ_MIN(uncomp_size, MZ_UINT32_MAX));\n    MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILENAME_LEN_OFS, filename_size);\n    MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_EXTRA_LEN_OFS, extra_size);\n    MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_COMMENT_LEN_OFS, comment_size);\n    MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS, ext_attributes);\n    MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_LOCAL_HEADER_OFS, MZ_MIN(local_header_ofs, MZ_UINT32_MAX));\n    return MZ_TRUE;\n}\n\nstatic mz_bool mz_zip_writer_add_to_central_dir(mz_zip_archive *pZip, const char *pFilename, mz_uint16 filename_size,\n                                                const void *pExtra, mz_uint16 extra_size, const void *pComment, mz_uint16 comment_size,\n                                                mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32,\n                                                mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date,\n                                                mz_uint64 local_header_ofs, mz_uint32 ext_attributes,\n                                                const char *user_extra_data, mz_uint user_extra_data_len)\n{\n    mz_zip_internal_state *pState = pZip->m_pState;\n    mz_uint32 central_dir_ofs = (mz_uint32)pState->m_central_dir.m_size;\n    size_t orig_central_dir_size = pState->m_central_dir.m_size;\n    mz_uint8 central_dir_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE];\n\n    if (!pZip->m_pState->m_zip64)\n    {\n        if (local_header_ofs > 0xFFFFFFFF)\n            return mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE);\n    }\n\n    /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */\n    if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + extra_size + user_extra_data_len + comment_size) >= MZ_UINT32_MAX)\n        return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE);\n\n    if (!mz_zip_writer_create_central_dir_header(pZip, central_dir_header, filename_size, (mz_uint16)(extra_size + user_extra_data_len), comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_header_ofs, ext_attributes))\n        return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);\n\n    if ((!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_dir_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) ||\n        (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pFilename, filename_size)) ||\n        (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pExtra, extra_size)) ||\n        (!mz_zip_array_push_back(pZip, &pState->m_central_dir, user_extra_data, user_extra_data_len)) ||\n        (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pComment, comment_size)) ||\n        (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, &central_dir_ofs, 1)))\n    {\n        /* Try to resize the central directory array back into its original state. */\n        mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE);\n        return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);\n    }\n\n    return MZ_TRUE;\n}\n\nstatic mz_bool mz_zip_writer_validate_archive_name(const char *pArchive_name)\n{\n    /* Basic ZIP archive filename validity checks: Valid filenames cannot start with a forward slash, cannot contain a drive letter, and cannot use DOS-style backward slashes. */\n    if (*pArchive_name == '/')\n        return MZ_FALSE;\n\n    /* Making sure the name does not contain drive letters or DOS style backward slashes is the responsibility of the program using miniz*/\n\n    return MZ_TRUE;\n}\n\nstatic mz_uint mz_zip_writer_compute_padding_needed_for_file_alignment(mz_zip_archive *pZip)\n{\n    mz_uint32 n;\n    if (!pZip->m_file_offset_alignment)\n        return 0;\n    n = (mz_uint32)(pZip->m_archive_size & (pZip->m_file_offset_alignment - 1));\n    return (mz_uint)((pZip->m_file_offset_alignment - n) & (pZip->m_file_offset_alignment - 1));\n}\n\nstatic mz_bool mz_zip_writer_write_zeros(mz_zip_archive *pZip, mz_uint64 cur_file_ofs, mz_uint32 n)\n{\n    char buf[4096];\n    memset(buf, 0, MZ_MIN(sizeof(buf), n));\n    while (n)\n    {\n        mz_uint32 s = MZ_MIN(sizeof(buf), n);\n        if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_file_ofs, buf, s) != s)\n            return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);\n\n        cur_file_ofs += s;\n        n -= s;\n    }\n    return MZ_TRUE;\n}\n\nmz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags,\n                                 mz_uint64 uncomp_size, mz_uint32 uncomp_crc32)\n{\n    return mz_zip_writer_add_mem_ex_v2(pZip, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, uncomp_size, uncomp_crc32, NULL, NULL, 0, NULL, 0);\n}\n\nmz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size,\n                                    mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32, MZ_TIME_T *last_modified,\n                                    const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len)\n{\n    mz_uint16 method = 0, dos_time = 0, dos_date = 0;\n    mz_uint level, ext_attributes = 0, num_alignment_padding_bytes;\n    mz_uint64 local_dir_header_ofs = pZip->m_archive_size, cur_archive_file_ofs = pZip->m_archive_size, comp_size = 0;\n    size_t archive_name_size;\n    mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE];\n    tdefl_compressor *pComp = NULL;\n    mz_bool store_data_uncompressed;\n    mz_zip_internal_state *pState;\n    mz_uint8 *pExtra_data = NULL;\n    mz_uint32 extra_size = 0;\n    mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE];\n    mz_uint16 bit_flags = 0;\n\n    if ((int)level_and_flags < 0)\n        level_and_flags = MZ_DEFAULT_LEVEL;\n\n    if (uncomp_size || (buf_size && !(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)))\n        bit_flags |= MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR;\n\n    if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME))\n        bit_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8;\n\n    level = level_and_flags & 0xF;\n    store_data_uncompressed = ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA));\n\n    if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION))\n        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);\n\n    pState = pZip->m_pState;\n\n    if (pState->m_zip64)\n    {\n        if (pZip->m_total_files == MZ_UINT32_MAX)\n            return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);\n    }\n    else\n    {\n        if (pZip->m_total_files == MZ_UINT16_MAX)\n        {\n            pState->m_zip64 = MZ_TRUE;\n            /*return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); */\n        }\n        if ((buf_size > 0xFFFFFFFF) || (uncomp_size > 0xFFFFFFFF))\n        {\n            pState->m_zip64 = MZ_TRUE;\n            /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */\n        }\n    }\n\n    if ((!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (uncomp_size))\n        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);\n\n    if (!mz_zip_writer_validate_archive_name(pArchive_name))\n        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME);\n\n#ifndef MINIZ_NO_TIME\n    if (last_modified != NULL)\n    {\n        mz_zip_time_t_to_dos_time(*last_modified, &dos_time, &dos_date);\n    }\n    else\n    {\n        MZ_TIME_T cur_time;\n        time(&cur_time);\n        mz_zip_time_t_to_dos_time(cur_time, &dos_time, &dos_date);\n    }\n#endif /* #ifndef MINIZ_NO_TIME */\n\n\tif (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA))\n\t{\n\t\tuncomp_crc32 = (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, buf_size);\n\t\tuncomp_size = buf_size;\n\t\tif (uncomp_size <= 3)\n\t\t{\n\t\t\tlevel = 0;\n\t\t\tstore_data_uncompressed = MZ_TRUE;\n\t\t}\n\t}\n\n    archive_name_size = strlen(pArchive_name);\n    if (archive_name_size > MZ_UINT16_MAX)\n        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME);\n\n    num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip);\n\n    /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */\n    if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE + comment_size) >= MZ_UINT32_MAX)\n        return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE);\n\n    if (!pState->m_zip64)\n    {\n        /* Bail early if the archive would obviously become too large */\n        if ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size \n\t\t\t+ MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + user_extra_data_len + \n\t\t\tpState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + user_extra_data_central_len\n\t\t\t+ MZ_ZIP_DATA_DESCRIPTER_SIZE32) > 0xFFFFFFFF)\n        {\n            pState->m_zip64 = MZ_TRUE;\n            /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */\n        }\n    }\n\n    if ((archive_name_size) && (pArchive_name[archive_name_size - 1] == '/'))\n    {\n        /* Set DOS Subdirectory attribute bit. */\n        ext_attributes |= MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG;\n\n        /* Subdirectories cannot contain data. */\n        if ((buf_size) || (uncomp_size))\n            return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);\n    }\n\n    /* Try to do any allocations before writing to the archive, so if an allocation fails the file remains unmodified. (A good idea if we're doing an in-place modification.) */\n    if ((!mz_zip_array_ensure_room(pZip, &pState->m_central_dir, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + (pState->m_zip64 ? MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE : 0))) || (!mz_zip_array_ensure_room(pZip, &pState->m_central_dir_offsets, 1)))\n        return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);\n\n    if ((!store_data_uncompressed) && (buf_size))\n    {\n        if (NULL == (pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor))))\n            return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);\n    }\n\n    if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes))\n    {\n        pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);\n        return MZ_FALSE;\n    }\n\n    local_dir_header_ofs += num_alignment_padding_bytes;\n    if (pZip->m_file_offset_alignment)\n    {\n        MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0);\n    }\n    cur_archive_file_ofs += num_alignment_padding_bytes;\n\n    MZ_CLEAR_OBJ(local_dir_header);\n\n    if (!store_data_uncompressed || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA))\n    {\n        method = MZ_DEFLATED;\n    }\n\n    if (pState->m_zip64)\n    {\n        if (uncomp_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX)\n        {\n            pExtra_data = extra_data;\n            extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL,\n                                                               (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL);\n        }\n\n        if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, (mz_uint16)(extra_size + user_extra_data_len), 0, 0, 0, method, bit_flags, dos_time, dos_date))\n            return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);\n\n        if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header))\n            return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);\n\n        cur_archive_file_ofs += sizeof(local_dir_header);\n\n        if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size)\n        {\n            pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);\n            return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);\n        }\n        cur_archive_file_ofs += archive_name_size;\n\n        if (pExtra_data != NULL)\n        {\n            if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, extra_data, extra_size) != extra_size)\n                return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);\n\n            cur_archive_file_ofs += extra_size;\n        }\n    }\n    else\n    {\n        if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX))\n            return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);\n        if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, (mz_uint16)user_extra_data_len, 0, 0, 0, method, bit_flags, dos_time, dos_date))\n            return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);\n\n        if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header))\n            return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);\n\n        cur_archive_file_ofs += sizeof(local_dir_header);\n\n        if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size)\n        {\n            pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);\n            return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);\n        }\n        cur_archive_file_ofs += archive_name_size;\n    }\n\n\tif (user_extra_data_len > 0)\n\t{\n\t\tif (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len)\n\t\t\treturn mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);\n\n\t\tcur_archive_file_ofs += user_extra_data_len;\n\t}\n\n    if (store_data_uncompressed)\n    {\n        if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pBuf, buf_size) != buf_size)\n        {\n            pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);\n            return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);\n        }\n\n        cur_archive_file_ofs += buf_size;\n        comp_size = buf_size;\n    }\n    else if (buf_size)\n    {\n        mz_zip_writer_add_state state;\n\n        state.m_pZip = pZip;\n        state.m_cur_archive_file_ofs = cur_archive_file_ofs;\n        state.m_comp_size = 0;\n\n        if ((tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) ||\n            (tdefl_compress_buffer(pComp, pBuf, buf_size, TDEFL_FINISH) != TDEFL_STATUS_DONE))\n        {\n            pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);\n            return mz_zip_set_error(pZip, MZ_ZIP_COMPRESSION_FAILED);\n        }\n\n        comp_size = state.m_comp_size;\n        cur_archive_file_ofs = state.m_cur_archive_file_ofs;\n    }\n\n    pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);\n    pComp = NULL;\n\n    if (uncomp_size)\n    {\n        mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64];\n        mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE32;\n\n        MZ_ASSERT(bit_flags & MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR);\n\n        MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID);\n        MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32);\n        if (pExtra_data == NULL)\n        {\n            if (comp_size > MZ_UINT32_MAX)\n                return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);\n\n            MZ_WRITE_LE32(local_dir_footer + 8, comp_size);\n            MZ_WRITE_LE32(local_dir_footer + 12, uncomp_size);\n        }\n        else\n        {\n            MZ_WRITE_LE64(local_dir_footer + 8, comp_size);\n            MZ_WRITE_LE64(local_dir_footer + 16, uncomp_size);\n            local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64;\n        }\n\n        if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_footer, local_dir_footer_size) != local_dir_footer_size)\n            return MZ_FALSE;\n\n        cur_archive_file_ofs += local_dir_footer_size;\n    }\n\n    if (pExtra_data != NULL)\n    {\n        extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL,\n                                                           (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL);\n    }\n\n    if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, pExtra_data, (mz_uint16)extra_size, pComment,\n                                          comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_dir_header_ofs, ext_attributes,\n                                          user_extra_data_central, user_extra_data_central_len))\n        return MZ_FALSE;\n\n    pZip->m_total_files++;\n    pZip->m_archive_size = cur_archive_file_ofs;\n\n    return MZ_TRUE;\n}\n\nmz_bool mz_zip_writer_add_read_buf_callback(mz_zip_archive *pZip, const char *pArchive_name, mz_file_read_func read_callback, void* callback_opaque, mz_uint64 size_to_add, const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags,\n                                const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len)\n{\n    mz_uint16 gen_flags = MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR;\n    mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes;\n    mz_uint16 method = 0, dos_time = 0, dos_date = 0, ext_attributes = 0;\n    mz_uint64 local_dir_header_ofs, cur_archive_file_ofs = pZip->m_archive_size, uncomp_size = size_to_add, comp_size = 0;\n    size_t archive_name_size;\n    mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE];\n    mz_uint8 *pExtra_data = NULL;\n    mz_uint32 extra_size = 0;\n    mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE];\n    mz_zip_internal_state *pState;\n\tmz_uint64 file_ofs = 0;\n\n    if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME))\n        gen_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8;\n\n    if ((int)level_and_flags < 0)\n        level_and_flags = MZ_DEFAULT_LEVEL;\n    level = level_and_flags & 0xF;\n\n    /* Sanity checks */\n    if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION))\n        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);\n\n    pState = pZip->m_pState;\n\n    if ((!pState->m_zip64) && (uncomp_size > MZ_UINT32_MAX))\n    {\n        /* Source file is too large for non-zip64 */\n        /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */\n        pState->m_zip64 = MZ_TRUE;\n    }\n\n    /* We could support this, but why? */\n    if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)\n        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);\n\n    if (!mz_zip_writer_validate_archive_name(pArchive_name))\n        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME);\n\n    if (pState->m_zip64)\n    {\n        if (pZip->m_total_files == MZ_UINT32_MAX)\n            return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);\n    }\n    else\n    {\n        if (pZip->m_total_files == MZ_UINT16_MAX)\n        {\n            pState->m_zip64 = MZ_TRUE;\n            /*return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); */\n        }\n    }\n\n    archive_name_size = strlen(pArchive_name);\n    if (archive_name_size > MZ_UINT16_MAX)\n        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME);\n\n    num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip);\n\n    /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */\n    if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE + comment_size) >= MZ_UINT32_MAX)\n        return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE);\n\n    if (!pState->m_zip64)\n    {\n        /* Bail early if the archive would obviously become too large */\n        if ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE\n\t\t\t+ archive_name_size + comment_size + user_extra_data_len + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + 1024\n\t\t\t+ MZ_ZIP_DATA_DESCRIPTER_SIZE32 + user_extra_data_central_len) > 0xFFFFFFFF)\n        {\n            pState->m_zip64 = MZ_TRUE;\n            /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */\n        }\n    }\n\n#ifndef MINIZ_NO_TIME\n    if (pFile_time)\n    {\n        mz_zip_time_t_to_dos_time(*pFile_time, &dos_time, &dos_date);\n    }\n#endif\n\n    if (uncomp_size <= 3)\n        level = 0;\n\n    if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes))\n    {\n        return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);\n    }\n\n    cur_archive_file_ofs += num_alignment_padding_bytes;\n    local_dir_header_ofs = cur_archive_file_ofs;\n\n    if (pZip->m_file_offset_alignment)\n    {\n        MZ_ASSERT((cur_archive_file_ofs & (pZip->m_file_offset_alignment - 1)) == 0);\n    }\n\n    if (uncomp_size && level)\n    {\n        method = MZ_DEFLATED;\n    }\n\n    MZ_CLEAR_OBJ(local_dir_header);\n    if (pState->m_zip64)\n    {\n        if (uncomp_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX)\n        {\n            pExtra_data = extra_data;\n            extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL,\n                                                               (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL);\n        }\n\n        if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, (mz_uint16)(extra_size + user_extra_data_len), 0, 0, 0, method, gen_flags, dos_time, dos_date))\n            return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);\n\n        if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header))\n            return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);\n\n        cur_archive_file_ofs += sizeof(local_dir_header);\n\n        if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size)\n        {\n            return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);\n        }\n\n        cur_archive_file_ofs += archive_name_size;\n\n        if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, extra_data, extra_size) != extra_size)\n            return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);\n\n        cur_archive_file_ofs += extra_size;\n    }\n    else\n    {\n        if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX))\n            return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);\n        if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, (mz_uint16)user_extra_data_len, 0, 0, 0, method, gen_flags, dos_time, dos_date))\n            return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);\n\n        if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header))\n            return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);\n\n        cur_archive_file_ofs += sizeof(local_dir_header);\n\n        if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size)\n        {\n            return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);\n        }\n\n        cur_archive_file_ofs += archive_name_size;\n    }\n\n    if (user_extra_data_len > 0)\n    {\n        if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len)\n            return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);\n\n        cur_archive_file_ofs += user_extra_data_len;\n    }\n\n    if (uncomp_size)\n    {\n        mz_uint64 uncomp_remaining = uncomp_size;\n        void *pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, MZ_ZIP_MAX_IO_BUF_SIZE);\n        if (!pRead_buf)\n        {\n            return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);\n        }\n\n        if (!level)\n        {\n            while (uncomp_remaining)\n            {\n                mz_uint n = (mz_uint)MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, uncomp_remaining);\n                if ((read_callback(callback_opaque, file_ofs, pRead_buf, n) != n) || (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pRead_buf, n) != n))\n                {\n                    pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);\n                    return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);\n                }\n\t\t\t\tfile_ofs += n;\n                uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n);\n                uncomp_remaining -= n;\n                cur_archive_file_ofs += n;\n            }\n            comp_size = uncomp_size;\n        }\n        else\n        {\n            mz_bool result = MZ_FALSE;\n            mz_zip_writer_add_state state;\n            tdefl_compressor *pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor));\n            if (!pComp)\n            {\n                pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);\n                return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);\n            }\n\n            state.m_pZip = pZip;\n            state.m_cur_archive_file_ofs = cur_archive_file_ofs;\n            state.m_comp_size = 0;\n\n            if (tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY)\n            {\n                pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);\n                pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);\n                return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);\n            }\n\n            for (;;)\n            {\n                size_t in_buf_size = (mz_uint32)MZ_MIN(uncomp_remaining, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE);\n                tdefl_status status;\n                tdefl_flush flush = TDEFL_NO_FLUSH;\n\n                if (read_callback(callback_opaque, file_ofs, pRead_buf, in_buf_size)!= in_buf_size)\n                {\n                    mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);\n                    break;\n                }\n\n\t\t\t\tfile_ofs += in_buf_size;\n                uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, in_buf_size);\n                uncomp_remaining -= in_buf_size;\n\n                if (pZip->m_pNeeds_keepalive != NULL && pZip->m_pNeeds_keepalive(pZip->m_pIO_opaque))\n                    flush = TDEFL_FULL_FLUSH;\n\n                status = tdefl_compress_buffer(pComp, pRead_buf, in_buf_size, uncomp_remaining ? flush : TDEFL_FINISH);\n                if (status == TDEFL_STATUS_DONE)\n                {\n                    result = MZ_TRUE;\n                    break;\n                }\n                else if (status != TDEFL_STATUS_OKAY)\n                {\n                    mz_zip_set_error(pZip, MZ_ZIP_COMPRESSION_FAILED);\n                    break;\n                }\n            }\n\n            pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);\n\n            if (!result)\n            {\n                pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);\n                return MZ_FALSE;\n            }\n\n            comp_size = state.m_comp_size;\n            cur_archive_file_ofs = state.m_cur_archive_file_ofs;\n        }\n\n        pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);\n    }\n\n    {\n        mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64];\n        mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE32;\n\n        MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID);\n        MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32);\n        if (pExtra_data == NULL)\n        {\n            if (comp_size > MZ_UINT32_MAX)\n                return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);\n\n            MZ_WRITE_LE32(local_dir_footer + 8, comp_size);\n            MZ_WRITE_LE32(local_dir_footer + 12, uncomp_size);\n        }\n        else\n        {\n            MZ_WRITE_LE64(local_dir_footer + 8, comp_size);\n            MZ_WRITE_LE64(local_dir_footer + 16, uncomp_size);\n            local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64;\n        }\n\n        if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_footer, local_dir_footer_size) != local_dir_footer_size)\n            return MZ_FALSE;\n\n        cur_archive_file_ofs += local_dir_footer_size;\n    }\n\n    if (pExtra_data != NULL)\n    {\n        extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL,\n                                                           (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL);\n    }\n\n    if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, pExtra_data, (mz_uint16)extra_size, pComment, comment_size,\n                                          uncomp_size, comp_size, uncomp_crc32, method, gen_flags, dos_time, dos_date, local_dir_header_ofs, ext_attributes,\n                                          user_extra_data_central, user_extra_data_central_len))\n        return MZ_FALSE;\n\n    pZip->m_total_files++;\n    pZip->m_archive_size = cur_archive_file_ofs;\n\n    return MZ_TRUE;\n}\n\n#ifndef MINIZ_NO_STDIO\n\nstatic size_t mz_file_read_func_stdio(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n)\n{\n\tMZ_FILE *pSrc_file = (MZ_FILE *)pOpaque;\n\tmz_int64 cur_ofs = MZ_FTELL64(pSrc_file);\n\n\tif (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pSrc_file, (mz_int64)file_ofs, SEEK_SET))))\n\t\treturn 0;\n\n\treturn MZ_FREAD(pBuf, 1, n, pSrc_file);\n}\n\nmz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 size_to_add, const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags,\n\tconst char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len)\n{\n\treturn mz_zip_writer_add_read_buf_callback(pZip, pArchive_name, mz_file_read_func_stdio, pSrc_file, size_to_add, pFile_time, pComment, comment_size, level_and_flags,\n\t\tuser_extra_data, user_extra_data_len, user_extra_data_central, user_extra_data_central_len);\n}\n\nmz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags)\n{\n    MZ_FILE *pSrc_file = NULL;\n    mz_uint64 uncomp_size = 0;\n    MZ_TIME_T file_modified_time;\n    MZ_TIME_T *pFile_time = NULL;\n    mz_bool status;\n\n    memset(&file_modified_time, 0, sizeof(file_modified_time));\n\n#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_STDIO)\n    pFile_time = &file_modified_time;\n    if (!mz_zip_get_file_modified_time(pSrc_filename, &file_modified_time))\n        return mz_zip_set_error(pZip, MZ_ZIP_FILE_STAT_FAILED);\n#endif\n\n    pSrc_file = MZ_FOPEN(pSrc_filename, \"rb\");\n    if (!pSrc_file)\n        return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED);\n\n    MZ_FSEEK64(pSrc_file, 0, SEEK_END);\n    uncomp_size = MZ_FTELL64(pSrc_file);\n    MZ_FSEEK64(pSrc_file, 0, SEEK_SET);\n\n    status = mz_zip_writer_add_cfile(pZip, pArchive_name, pSrc_file, uncomp_size, pFile_time, pComment, comment_size, level_and_flags, NULL, 0, NULL, 0);\n\n    MZ_FCLOSE(pSrc_file);\n\n    return status;\n}\n#endif /* #ifndef MINIZ_NO_STDIO */\n\nstatic mz_bool mz_zip_writer_update_zip64_extension_block(mz_zip_array *pNew_ext, mz_zip_archive *pZip, const mz_uint8 *pExt, uint32_t ext_len, mz_uint64 *pComp_size, mz_uint64 *pUncomp_size, mz_uint64 *pLocal_header_ofs, mz_uint32 *pDisk_start)\n{\n    /* + 64 should be enough for any new zip64 data */\n    if (!mz_zip_array_reserve(pZip, pNew_ext, ext_len + 64, MZ_FALSE))\n        return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);\n\n    mz_zip_array_resize(pZip, pNew_ext, 0, MZ_FALSE);\n\n    if ((pUncomp_size) || (pComp_size) || (pLocal_header_ofs) || (pDisk_start))\n    {\n        mz_uint8 new_ext_block[64];\n        mz_uint8 *pDst = new_ext_block;\n        mz_write_le16(pDst, MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID);\n        mz_write_le16(pDst + sizeof(mz_uint16), 0);\n        pDst += sizeof(mz_uint16) * 2;\n\n        if (pUncomp_size)\n        {\n            mz_write_le64(pDst, *pUncomp_size);\n            pDst += sizeof(mz_uint64);\n        }\n\n        if (pComp_size)\n        {\n            mz_write_le64(pDst, *pComp_size);\n            pDst += sizeof(mz_uint64);\n        }\n\n        if (pLocal_header_ofs)\n        {\n            mz_write_le64(pDst, *pLocal_header_ofs);\n            pDst += sizeof(mz_uint64);\n        }\n\n        if (pDisk_start)\n        {\n            mz_write_le32(pDst, *pDisk_start);\n            pDst += sizeof(mz_uint32);\n        }\n\n        mz_write_le16(new_ext_block + sizeof(mz_uint16), (mz_uint16)((pDst - new_ext_block) - sizeof(mz_uint16) * 2));\n\n        if (!mz_zip_array_push_back(pZip, pNew_ext, new_ext_block, pDst - new_ext_block))\n            return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);\n    }\n\n    if ((pExt) && (ext_len))\n    {\n        mz_uint32 extra_size_remaining = ext_len;\n        const mz_uint8 *pExtra_data = pExt;\n\n        do\n        {\n            mz_uint32 field_id, field_data_size, field_total_size;\n\n            if (extra_size_remaining < (sizeof(mz_uint16) * 2))\n                return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);\n\n            field_id = MZ_READ_LE16(pExtra_data);\n            field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16));\n            field_total_size = field_data_size + sizeof(mz_uint16) * 2;\n\n            if (field_total_size > extra_size_remaining)\n                return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);\n\n            if (field_id != MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID)\n            {\n                if (!mz_zip_array_push_back(pZip, pNew_ext, pExtra_data, field_total_size))\n                    return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);\n            }\n\n            pExtra_data += field_total_size;\n            extra_size_remaining -= field_total_size;\n        } while (extra_size_remaining);\n    }\n\n    return MZ_TRUE;\n}\n\n/* TODO: This func is now pretty freakin complex due to zip64, split it up? */\nmz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint src_file_index)\n{\n    mz_uint n, bit_flags, num_alignment_padding_bytes, src_central_dir_following_data_size;\n    mz_uint64 src_archive_bytes_remaining, local_dir_header_ofs;\n    mz_uint64 cur_src_file_ofs, cur_dst_file_ofs;\n    mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)];\n    mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32;\n    mz_uint8 new_central_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE];\n    size_t orig_central_dir_size;\n    mz_zip_internal_state *pState;\n    void *pBuf;\n    const mz_uint8 *pSrc_central_header;\n    mz_zip_archive_file_stat src_file_stat;\n    mz_uint32 src_filename_len, src_comment_len, src_ext_len;\n    mz_uint32 local_header_filename_size, local_header_extra_len;\n    mz_uint64 local_header_comp_size, local_header_uncomp_size;\n    mz_bool found_zip64_ext_data_in_ldir = MZ_FALSE;\n\n    /* Sanity checks */\n    if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pSource_zip->m_pRead))\n        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);\n\n    pState = pZip->m_pState;\n\n    /* Don't support copying files from zip64 archives to non-zip64, even though in some cases this is possible */\n    if ((pSource_zip->m_pState->m_zip64) && (!pZip->m_pState->m_zip64))\n        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);\n\n    /* Get pointer to the source central dir header and crack it */\n    if (NULL == (pSrc_central_header = mz_zip_get_cdh(pSource_zip, src_file_index)))\n        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);\n\n    if (MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_SIG_OFS) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG)\n        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);\n\n    src_filename_len = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_FILENAME_LEN_OFS);\n    src_comment_len = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_COMMENT_LEN_OFS);\n    src_ext_len = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS);\n    src_central_dir_following_data_size = src_filename_len + src_ext_len + src_comment_len;\n\n    /* TODO: We don't support central dir's >= MZ_UINT32_MAX bytes right now (+32 fudge factor in case we need to add more extra data) */\n    if ((pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_central_dir_following_data_size + 32) >= MZ_UINT32_MAX)\n        return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE);\n\n    num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip);\n\n    if (!pState->m_zip64)\n    {\n        if (pZip->m_total_files == MZ_UINT16_MAX)\n            return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);\n    }\n    else\n    {\n        /* TODO: Our zip64 support still has some 32-bit limits that may not be worth fixing. */\n        if (pZip->m_total_files == MZ_UINT32_MAX)\n            return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);\n    }\n\n    if (!mz_zip_file_stat_internal(pSource_zip, src_file_index, pSrc_central_header, &src_file_stat, NULL))\n        return MZ_FALSE;\n\n    cur_src_file_ofs = src_file_stat.m_local_header_ofs;\n    cur_dst_file_ofs = pZip->m_archive_size;\n\n    /* Read the source archive's local dir header */\n    if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE)\n        return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);\n\n    if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG)\n        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);\n\n    cur_src_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE;\n\n    /* Compute the total size we need to copy (filename+extra data+compressed data) */\n    local_header_filename_size = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS);\n    local_header_extra_len = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS);\n    local_header_comp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS);\n    local_header_uncomp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS);\n    src_archive_bytes_remaining = local_header_filename_size + local_header_extra_len + src_file_stat.m_comp_size;\n\n    /* Try to find a zip64 extended information field */\n    if ((local_header_extra_len) && ((local_header_comp_size == MZ_UINT32_MAX) || (local_header_uncomp_size == MZ_UINT32_MAX)))\n    {\n        mz_zip_array file_data_array;\n        const mz_uint8 *pExtra_data;\n        mz_uint32 extra_size_remaining = local_header_extra_len;\n\n        mz_zip_array_init(&file_data_array, 1);\n        if (!mz_zip_array_resize(pZip, &file_data_array, local_header_extra_len, MZ_FALSE))\n        {\n            return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);\n        }\n\n        if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, src_file_stat.m_local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_size, file_data_array.m_p, local_header_extra_len) != local_header_extra_len)\n        {\n            mz_zip_array_clear(pZip, &file_data_array);\n            return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);\n        }\n\n        pExtra_data = (const mz_uint8 *)file_data_array.m_p;\n\n        do\n        {\n            mz_uint32 field_id, field_data_size, field_total_size;\n\n            if (extra_size_remaining < (sizeof(mz_uint16) * 2))\n            {\n                mz_zip_array_clear(pZip, &file_data_array);\n                return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);\n            }\n\n            field_id = MZ_READ_LE16(pExtra_data);\n            field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16));\n            field_total_size = field_data_size + sizeof(mz_uint16) * 2;\n\n            if (field_total_size > extra_size_remaining)\n            {\n                mz_zip_array_clear(pZip, &file_data_array);\n                return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);\n            }\n\n            if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID)\n            {\n                const mz_uint8 *pSrc_field_data = pExtra_data + sizeof(mz_uint32);\n\n                if (field_data_size < sizeof(mz_uint64) * 2)\n                {\n                    mz_zip_array_clear(pZip, &file_data_array);\n                    return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);\n                }\n\n                local_header_uncomp_size = MZ_READ_LE64(pSrc_field_data);\n                local_header_comp_size = MZ_READ_LE64(pSrc_field_data + sizeof(mz_uint64)); /* may be 0 if there's a descriptor */\n\n                found_zip64_ext_data_in_ldir = MZ_TRUE;\n                break;\n            }\n\n            pExtra_data += field_total_size;\n            extra_size_remaining -= field_total_size;\n        } while (extra_size_remaining);\n\n        mz_zip_array_clear(pZip, &file_data_array);\n    }\n\n    if (!pState->m_zip64)\n    {\n        /* Try to detect if the new archive will most likely wind up too big and bail early (+(sizeof(mz_uint32) * 4) is for the optional descriptor which could be present, +64 is a fudge factor). */\n        /* We also check when the archive is finalized so this doesn't need to be perfect. */\n        mz_uint64 approx_new_archive_size = cur_dst_file_ofs + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + src_archive_bytes_remaining + (sizeof(mz_uint32) * 4) +\n                                            pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_central_dir_following_data_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + 64;\n\n        if (approx_new_archive_size >= MZ_UINT32_MAX)\n            return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);\n    }\n\n    /* Write dest archive padding */\n    if (!mz_zip_writer_write_zeros(pZip, cur_dst_file_ofs, num_alignment_padding_bytes))\n        return MZ_FALSE;\n\n    cur_dst_file_ofs += num_alignment_padding_bytes;\n\n    local_dir_header_ofs = cur_dst_file_ofs;\n    if (pZip->m_file_offset_alignment)\n    {\n        MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0);\n    }\n\n    /* The original zip's local header+ext block doesn't change, even with zip64, so we can just copy it over to the dest zip */\n    if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE)\n        return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);\n\n    cur_dst_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE;\n\n    /* Copy over the source archive bytes to the dest archive, also ensure we have enough buf space to handle optional data descriptor */\n    if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)MZ_MAX(32U, MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, src_archive_bytes_remaining)))))\n        return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);\n\n    while (src_archive_bytes_remaining)\n    {\n        n = (mz_uint)MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, src_archive_bytes_remaining);\n        if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, n) != n)\n        {\n            pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);\n            return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);\n        }\n        cur_src_file_ofs += n;\n\n        if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n)\n        {\n            pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);\n            return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);\n        }\n        cur_dst_file_ofs += n;\n\n        src_archive_bytes_remaining -= n;\n    }\n\n    /* Now deal with the optional data descriptor */\n    bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS);\n    if (bit_flags & 8)\n    {\n        /* Copy data descriptor */\n        if ((pSource_zip->m_pState->m_zip64) || (found_zip64_ext_data_in_ldir))\n        {\n            /* src is zip64, dest must be zip64 */\n\n            /* name\t\t\tuint32_t's */\n            /* id\t\t\t\t1 (optional in zip64?) */\n            /* crc\t\t\t1 */\n            /* comp_size\t2 */\n            /* uncomp_size 2 */\n            if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, (sizeof(mz_uint32) * 6)) != (sizeof(mz_uint32) * 6))\n            {\n                pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);\n                return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);\n            }\n\n            n = sizeof(mz_uint32) * ((MZ_READ_LE32(pBuf) == MZ_ZIP_DATA_DESCRIPTOR_ID) ? 6 : 5);\n        }\n        else\n        {\n            /* src is NOT zip64 */\n            mz_bool has_id;\n\n            if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, sizeof(mz_uint32) * 4) != sizeof(mz_uint32) * 4)\n            {\n                pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);\n                return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);\n            }\n\n            has_id = (MZ_READ_LE32(pBuf) == MZ_ZIP_DATA_DESCRIPTOR_ID);\n\n            if (pZip->m_pState->m_zip64)\n            {\n                /* dest is zip64, so upgrade the data descriptor */\n                const mz_uint32 *pSrc_descriptor = (const mz_uint32 *)((const mz_uint8 *)pBuf + (has_id ? sizeof(mz_uint32) : 0));\n                const mz_uint32 src_crc32 = pSrc_descriptor[0];\n                const mz_uint64 src_comp_size = pSrc_descriptor[1];\n                const mz_uint64 src_uncomp_size = pSrc_descriptor[2];\n\n                mz_write_le32((mz_uint8 *)pBuf, MZ_ZIP_DATA_DESCRIPTOR_ID);\n                mz_write_le32((mz_uint8 *)pBuf + sizeof(mz_uint32) * 1, src_crc32);\n                mz_write_le64((mz_uint8 *)pBuf + sizeof(mz_uint32) * 2, src_comp_size);\n                mz_write_le64((mz_uint8 *)pBuf + sizeof(mz_uint32) * 4, src_uncomp_size);\n\n                n = sizeof(mz_uint32) * 6;\n            }\n            else\n            {\n                /* dest is NOT zip64, just copy it as-is */\n                n = sizeof(mz_uint32) * (has_id ? 4 : 3);\n            }\n        }\n\n        if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n)\n        {\n            pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);\n            return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);\n        }\n\n        cur_src_file_ofs += n;\n        cur_dst_file_ofs += n;\n    }\n    pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);\n\n    /* Finally, add the new central dir header */\n    orig_central_dir_size = pState->m_central_dir.m_size;\n\n    memcpy(new_central_header, pSrc_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE);\n\n    if (pState->m_zip64)\n    {\n        /* This is the painful part: We need to write a new central dir header + ext block with updated zip64 fields, and ensure the old fields (if any) are not included. */\n        const mz_uint8 *pSrc_ext = pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_filename_len;\n        mz_zip_array new_ext_block;\n\n        mz_zip_array_init(&new_ext_block, sizeof(mz_uint8));\n\n        MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, MZ_UINT32_MAX);\n        MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, MZ_UINT32_MAX);\n        MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS, MZ_UINT32_MAX);\n\n        if (!mz_zip_writer_update_zip64_extension_block(&new_ext_block, pZip, pSrc_ext, src_ext_len, &src_file_stat.m_comp_size, &src_file_stat.m_uncomp_size, &local_dir_header_ofs, NULL))\n        {\n            mz_zip_array_clear(pZip, &new_ext_block);\n            return MZ_FALSE;\n        }\n\n        MZ_WRITE_LE16(new_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS, new_ext_block.m_size);\n\n        if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, new_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE))\n        {\n            mz_zip_array_clear(pZip, &new_ext_block);\n            return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);\n        }\n\n        if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, src_filename_len))\n        {\n            mz_zip_array_clear(pZip, &new_ext_block);\n            mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE);\n            return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);\n        }\n\n        if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, new_ext_block.m_p, new_ext_block.m_size))\n        {\n            mz_zip_array_clear(pZip, &new_ext_block);\n            mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE);\n            return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);\n        }\n\n        if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_filename_len + src_ext_len, src_comment_len))\n        {\n            mz_zip_array_clear(pZip, &new_ext_block);\n            mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE);\n            return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);\n        }\n\n        mz_zip_array_clear(pZip, &new_ext_block);\n    }\n    else\n    {\n        /* sanity checks */\n        if (cur_dst_file_ofs > MZ_UINT32_MAX)\n            return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);\n\n        if (local_dir_header_ofs >= MZ_UINT32_MAX)\n            return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);\n\n        MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS, local_dir_header_ofs);\n\n        if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, new_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE))\n            return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);\n\n        if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, src_central_dir_following_data_size))\n        {\n            mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE);\n            return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);\n        }\n    }\n\n    /* This shouldn't trigger unless we screwed up during the initial sanity checks */\n    if (pState->m_central_dir.m_size >= MZ_UINT32_MAX)\n    {\n        /* TODO: Support central dirs >= 32-bits in size */\n        mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE);\n        return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE);\n    }\n\n    n = (mz_uint32)orig_central_dir_size;\n    if (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, &n, 1))\n    {\n        mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE);\n        return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);\n    }\n\n    pZip->m_total_files++;\n    pZip->m_archive_size = cur_dst_file_ofs;\n\n    return MZ_TRUE;\n}\n\nmz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip)\n{\n    mz_zip_internal_state *pState;\n    mz_uint64 central_dir_ofs, central_dir_size;\n    mz_uint8 hdr[256];\n\n    if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING))\n        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);\n\n    pState = pZip->m_pState;\n\n    if (pState->m_zip64)\n    {\n        if ((pZip->m_total_files > MZ_UINT32_MAX) || (pState->m_central_dir.m_size >= MZ_UINT32_MAX))\n            return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);\n    }\n    else\n    {\n        if ((pZip->m_total_files > MZ_UINT16_MAX) || ((pZip->m_archive_size + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) > MZ_UINT32_MAX))\n            return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);\n    }\n\n    central_dir_ofs = 0;\n    central_dir_size = 0;\n    if (pZip->m_total_files)\n    {\n        /* Write central directory */\n        central_dir_ofs = pZip->m_archive_size;\n        central_dir_size = pState->m_central_dir.m_size;\n        pZip->m_central_directory_file_ofs = central_dir_ofs;\n        if (pZip->m_pWrite(pZip->m_pIO_opaque, central_dir_ofs, pState->m_central_dir.m_p, (size_t)central_dir_size) != central_dir_size)\n            return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);\n\n        pZip->m_archive_size += central_dir_size;\n    }\n\n    if (pState->m_zip64)\n    {\n        /* Write zip64 end of central directory header */\n        mz_uint64 rel_ofs_to_zip64_ecdr = pZip->m_archive_size;\n\n        MZ_CLEAR_OBJ(hdr);\n        MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDH_SIG_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG);\n        MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - sizeof(mz_uint32) - sizeof(mz_uint64));\n        MZ_WRITE_LE16(hdr + MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS, 0x031E); /* TODO: always Unix */\n        MZ_WRITE_LE16(hdr + MZ_ZIP64_ECDH_VERSION_NEEDED_OFS, 0x002D);\n        MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, pZip->m_total_files);\n        MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS, pZip->m_total_files);\n        MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_SIZE_OFS, central_dir_size);\n        MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_OFS_OFS, central_dir_ofs);\n        if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)\n            return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);\n\n        pZip->m_archive_size += MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE;\n\n        /* Write zip64 end of central directory locator */\n        MZ_CLEAR_OBJ(hdr);\n        MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_SIG_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG);\n        MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS, rel_ofs_to_zip64_ecdr);\n        MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS, 1);\n        if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) != MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE)\n            return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);\n\n        pZip->m_archive_size += MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE;\n    }\n\n    /* Write end of central directory record */\n    MZ_CLEAR_OBJ(hdr);\n    MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_SIG_OFS, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG);\n    MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files));\n    MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS, MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files));\n    MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_SIZE_OFS, MZ_MIN(MZ_UINT32_MAX, central_dir_size));\n    MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_OFS_OFS, MZ_MIN(MZ_UINT32_MAX, central_dir_ofs));\n\n    if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)\n        return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);\n\n#ifndef MINIZ_NO_STDIO\n    if ((pState->m_pFile) && (MZ_FFLUSH(pState->m_pFile) == EOF))\n        return mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED);\n#endif /* #ifndef MINIZ_NO_STDIO */\n\n    pZip->m_archive_size += MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE;\n\n    pZip->m_zip_mode = MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED;\n    return MZ_TRUE;\n}\n\nmz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **ppBuf, size_t *pSize)\n{\n    if ((!ppBuf) || (!pSize))\n        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);\n\n    *ppBuf = NULL;\n    *pSize = 0;\n\n    if ((!pZip) || (!pZip->m_pState))\n        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);\n\n    if (pZip->m_pWrite != mz_zip_heap_write_func)\n        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);\n\n    if (!mz_zip_writer_finalize_archive(pZip))\n        return MZ_FALSE;\n\n    *ppBuf = pZip->m_pState->m_pMem;\n    *pSize = pZip->m_pState->m_mem_size;\n    pZip->m_pState->m_pMem = NULL;\n    pZip->m_pState->m_mem_size = pZip->m_pState->m_mem_capacity = 0;\n\n    return MZ_TRUE;\n}\n\nmz_bool mz_zip_writer_end(mz_zip_archive *pZip)\n{\n    return mz_zip_writer_end_internal(pZip, MZ_TRUE);\n}\n\n#ifndef MINIZ_NO_STDIO\nmz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags)\n{\n    return mz_zip_add_mem_to_archive_file_in_place_v2(pZip_filename, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, NULL);\n}\n\nmz_bool mz_zip_add_mem_to_archive_file_in_place_v2(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_zip_error *pErr)\n{\n    mz_bool status, created_new_archive = MZ_FALSE;\n    mz_zip_archive zip_archive;\n    struct MZ_FILE_STAT_STRUCT file_stat;\n    mz_zip_error actual_err = MZ_ZIP_NO_ERROR;\n\n    mz_zip_zero_struct(&zip_archive);\n    if ((int)level_and_flags < 0)\n        level_and_flags = MZ_DEFAULT_LEVEL;\n\n    if ((!pZip_filename) || (!pArchive_name) || ((buf_size) && (!pBuf)) || ((comment_size) && (!pComment)) || ((level_and_flags & 0xF) > MZ_UBER_COMPRESSION))\n    {\n        if (pErr)\n            *pErr = MZ_ZIP_INVALID_PARAMETER;\n        return MZ_FALSE;\n    }\n\n    if (!mz_zip_writer_validate_archive_name(pArchive_name))\n    {\n        if (pErr)\n            *pErr = MZ_ZIP_INVALID_FILENAME;\n        return MZ_FALSE;\n    }\n\n    /* Important: The regular non-64 bit version of stat() can fail here if the file is very large, which could cause the archive to be overwritten. */\n    /* So be sure to compile with _LARGEFILE64_SOURCE 1 */\n    if (MZ_FILE_STAT(pZip_filename, &file_stat) != 0)\n    {\n        /* Create a new archive. */\n        if (!mz_zip_writer_init_file_v2(&zip_archive, pZip_filename, 0, level_and_flags))\n        {\n            if (pErr)\n                *pErr = zip_archive.m_last_error;\n            return MZ_FALSE;\n        }\n\n        created_new_archive = MZ_TRUE;\n    }\n    else\n    {\n        /* Append to an existing archive. */\n        if (!mz_zip_reader_init_file_v2(&zip_archive, pZip_filename, level_and_flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0))\n        {\n            if (pErr)\n                *pErr = zip_archive.m_last_error;\n            return MZ_FALSE;\n        }\n\n        if (!mz_zip_writer_init_from_reader_v2(&zip_archive, pZip_filename, level_and_flags))\n        {\n            if (pErr)\n                *pErr = zip_archive.m_last_error;\n\n            mz_zip_reader_end_internal(&zip_archive, MZ_FALSE);\n\n            return MZ_FALSE;\n        }\n    }\n\n    status = mz_zip_writer_add_mem_ex(&zip_archive, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, 0, 0);\n    actual_err = zip_archive.m_last_error;\n\n    /* Always finalize, even if adding failed for some reason, so we have a valid central directory. (This may not always succeed, but we can try.) */\n    if (!mz_zip_writer_finalize_archive(&zip_archive))\n    {\n        if (!actual_err)\n            actual_err = zip_archive.m_last_error;\n\n        status = MZ_FALSE;\n    }\n\n    if (!mz_zip_writer_end_internal(&zip_archive, status))\n    {\n        if (!actual_err)\n            actual_err = zip_archive.m_last_error;\n\n        status = MZ_FALSE;\n    }\n\n    if ((!status) && (created_new_archive))\n    {\n        /* It's a new archive and something went wrong, so just delete it. */\n        int ignoredStatus = MZ_DELETE_FILE(pZip_filename);\n        (void)ignoredStatus;\n    }\n\n    if (pErr)\n        *pErr = actual_err;\n\n    return status;\n}\n\nvoid *mz_zip_extract_archive_file_to_heap_v2(const char *pZip_filename, const char *pArchive_name, const char *pComment, size_t *pSize, mz_uint flags, mz_zip_error *pErr)\n{\n    mz_uint32 file_index;\n    mz_zip_archive zip_archive;\n    void *p = NULL;\n\n    if (pSize)\n        *pSize = 0;\n\n    if ((!pZip_filename) || (!pArchive_name))\n    {\n        if (pErr)\n            *pErr = MZ_ZIP_INVALID_PARAMETER;\n\n        return NULL;\n    }\n\n    mz_zip_zero_struct(&zip_archive);\n    if (!mz_zip_reader_init_file_v2(&zip_archive, pZip_filename, flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0))\n    {\n        if (pErr)\n            *pErr = zip_archive.m_last_error;\n\n        return NULL;\n    }\n\n    if (mz_zip_reader_locate_file_v2(&zip_archive, pArchive_name, pComment, flags, &file_index))\n    {\n        p = mz_zip_reader_extract_to_heap(&zip_archive, file_index, pSize, flags);\n    }\n\n    mz_zip_reader_end_internal(&zip_archive, p != NULL);\n\n    if (pErr)\n        *pErr = zip_archive.m_last_error;\n\n    return p;\n}\n\nvoid *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags)\n{\n    return mz_zip_extract_archive_file_to_heap_v2(pZip_filename, pArchive_name, NULL, pSize, flags, NULL);\n}\n\n#endif /* #ifndef MINIZ_NO_STDIO */\n\n#endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS */\n\n/* ------------------- Misc utils */\n\nmz_zip_mode mz_zip_get_mode(mz_zip_archive *pZip)\n{\n    return pZip ? pZip->m_zip_mode : MZ_ZIP_MODE_INVALID;\n}\n\nmz_zip_type mz_zip_get_type(mz_zip_archive *pZip)\n{\n    return pZip ? pZip->m_zip_type : MZ_ZIP_TYPE_INVALID;\n}\n\nmz_zip_error mz_zip_set_last_error(mz_zip_archive *pZip, mz_zip_error err_num)\n{\n    mz_zip_error prev_err;\n\n    if (!pZip)\n        return MZ_ZIP_INVALID_PARAMETER;\n\n    prev_err = pZip->m_last_error;\n\n    pZip->m_last_error = err_num;\n    return prev_err;\n}\n\nmz_zip_error mz_zip_peek_last_error(mz_zip_archive *pZip)\n{\n    if (!pZip)\n        return MZ_ZIP_INVALID_PARAMETER;\n\n    return pZip->m_last_error;\n}\n\nmz_zip_error mz_zip_clear_last_error(mz_zip_archive *pZip)\n{\n    return mz_zip_set_last_error(pZip, MZ_ZIP_NO_ERROR);\n}\n\nmz_zip_error mz_zip_get_last_error(mz_zip_archive *pZip)\n{\n    mz_zip_error prev_err;\n\n    if (!pZip)\n        return MZ_ZIP_INVALID_PARAMETER;\n\n    prev_err = pZip->m_last_error;\n\n    pZip->m_last_error = MZ_ZIP_NO_ERROR;\n    return prev_err;\n}\n\nconst char *mz_zip_get_error_string(mz_zip_error mz_err)\n{\n    switch (mz_err)\n    {\n        case MZ_ZIP_NO_ERROR:\n            return \"no error\";\n        case MZ_ZIP_UNDEFINED_ERROR:\n            return \"undefined error\";\n        case MZ_ZIP_TOO_MANY_FILES:\n            return \"too many files\";\n        case MZ_ZIP_FILE_TOO_LARGE:\n            return \"file too large\";\n        case MZ_ZIP_UNSUPPORTED_METHOD:\n            return \"unsupported method\";\n        case MZ_ZIP_UNSUPPORTED_ENCRYPTION:\n            return \"unsupported encryption\";\n        case MZ_ZIP_UNSUPPORTED_FEATURE:\n            return \"unsupported feature\";\n        case MZ_ZIP_FAILED_FINDING_CENTRAL_DIR:\n            return \"failed finding central directory\";\n        case MZ_ZIP_NOT_AN_ARCHIVE:\n            return \"not a ZIP archive\";\n        case MZ_ZIP_INVALID_HEADER_OR_CORRUPTED:\n            return \"invalid header or archive is corrupted\";\n        case MZ_ZIP_UNSUPPORTED_MULTIDISK:\n            return \"unsupported multidisk archive\";\n        case MZ_ZIP_DECOMPRESSION_FAILED:\n            return \"decompression failed or archive is corrupted\";\n        case MZ_ZIP_COMPRESSION_FAILED:\n            return \"compression failed\";\n        case MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE:\n            return \"unexpected decompressed size\";\n        case MZ_ZIP_CRC_CHECK_FAILED:\n            return \"CRC-32 check failed\";\n        case MZ_ZIP_UNSUPPORTED_CDIR_SIZE:\n            return \"unsupported central directory size\";\n        case MZ_ZIP_ALLOC_FAILED:\n            return \"allocation failed\";\n        case MZ_ZIP_FILE_OPEN_FAILED:\n            return \"file open failed\";\n        case MZ_ZIP_FILE_CREATE_FAILED:\n            return \"file create failed\";\n        case MZ_ZIP_FILE_WRITE_FAILED:\n            return \"file write failed\";\n        case MZ_ZIP_FILE_READ_FAILED:\n            return \"file read failed\";\n        case MZ_ZIP_FILE_CLOSE_FAILED:\n            return \"file close failed\";\n        case MZ_ZIP_FILE_SEEK_FAILED:\n            return \"file seek failed\";\n        case MZ_ZIP_FILE_STAT_FAILED:\n            return \"file stat failed\";\n        case MZ_ZIP_INVALID_PARAMETER:\n            return \"invalid parameter\";\n        case MZ_ZIP_INVALID_FILENAME:\n            return \"invalid filename\";\n        case MZ_ZIP_BUF_TOO_SMALL:\n            return \"buffer too small\";\n        case MZ_ZIP_INTERNAL_ERROR:\n            return \"internal error\";\n        case MZ_ZIP_FILE_NOT_FOUND:\n            return \"file not found\";\n        case MZ_ZIP_ARCHIVE_TOO_LARGE:\n            return \"archive is too large\";\n        case MZ_ZIP_VALIDATION_FAILED:\n            return \"validation failed\";\n        case MZ_ZIP_WRITE_CALLBACK_FAILED:\n            return \"write calledback failed\";\n        default:\n            break;\n    }\n\n    return \"unknown error\";\n}\n\n/* Note: Just because the archive is not zip64 doesn't necessarily mean it doesn't have Zip64 extended information extra field, argh. */\nmz_bool mz_zip_is_zip64(mz_zip_archive *pZip)\n{\n    if ((!pZip) || (!pZip->m_pState))\n        return MZ_FALSE;\n\n    return pZip->m_pState->m_zip64;\n}\n\nsize_t mz_zip_get_central_dir_size(mz_zip_archive *pZip)\n{\n    if ((!pZip) || (!pZip->m_pState))\n        return 0;\n\n    return pZip->m_pState->m_central_dir.m_size;\n}\n\nmz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip)\n{\n    return pZip ? pZip->m_total_files : 0;\n}\n\nmz_uint64 mz_zip_get_archive_size(mz_zip_archive *pZip)\n{\n    if (!pZip)\n        return 0;\n    return pZip->m_archive_size;\n}\n\nmz_uint64 mz_zip_get_archive_file_start_offset(mz_zip_archive *pZip)\n{\n    if ((!pZip) || (!pZip->m_pState))\n        return 0;\n    return pZip->m_pState->m_file_archive_start_ofs;\n}\n\nMZ_FILE *mz_zip_get_cfile(mz_zip_archive *pZip)\n{\n    if ((!pZip) || (!pZip->m_pState))\n        return 0;\n    return pZip->m_pState->m_pFile;\n}\n\nsize_t mz_zip_read_archive_data(mz_zip_archive *pZip, mz_uint64 file_ofs, void *pBuf, size_t n)\n{\n    if ((!pZip) || (!pZip->m_pState) || (!pBuf) || (!pZip->m_pRead))\n        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);\n\n    return pZip->m_pRead(pZip->m_pIO_opaque, file_ofs, pBuf, n);\n}\n\nmz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size)\n{\n    mz_uint n;\n    const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index);\n    if (!p)\n    {\n        if (filename_buf_size)\n            pFilename[0] = '\\0';\n        mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);\n        return 0;\n    }\n    n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);\n    if (filename_buf_size)\n    {\n        n = MZ_MIN(n, filename_buf_size - 1);\n        memcpy(pFilename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n);\n        pFilename[n] = '\\0';\n    }\n    return n + 1;\n}\n\nmz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat)\n{\n    return mz_zip_file_stat_internal(pZip, file_index, mz_zip_get_cdh(pZip, file_index), pStat, NULL);\n}\n\nmz_bool mz_zip_end(mz_zip_archive *pZip)\n{\n    if (!pZip)\n        return MZ_FALSE;\n\n    if (pZip->m_zip_mode == MZ_ZIP_MODE_READING)\n        return mz_zip_reader_end(pZip);\n#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS\n    else if ((pZip->m_zip_mode == MZ_ZIP_MODE_WRITING) || (pZip->m_zip_mode == MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED))\n        return mz_zip_writer_end(pZip);\n#endif\n\n    return MZ_FALSE;\n}\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /*#ifndef MINIZ_NO_ARCHIVE_APIS*/\n"
  },
  {
    "path": "windows/CodePush/miniz/miniz.h",
    "content": "/* miniz.c 2.1.0 - public domain deflate/inflate, zlib-subset, ZIP reading/writing/appending, PNG writing\n   See \"unlicense\" statement at the end of this file.\n   Rich Geldreich <richgel99@gmail.com>, last updated Oct. 13, 2013\n   Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: http://www.ietf.org/rfc/rfc1951.txt\n\n   Most API's defined in miniz.c are optional. For example, to disable the archive related functions just define\n   MINIZ_NO_ARCHIVE_APIS, or to get rid of all stdio usage define MINIZ_NO_STDIO (see the list below for more macros).\n\n   * Low-level Deflate/Inflate implementation notes:\n\n     Compression: Use the \"tdefl\" API's. The compressor supports raw, static, and dynamic blocks, lazy or\n     greedy parsing, match length filtering, RLE-only, and Huffman-only streams. It performs and compresses\n     approximately as well as zlib.\n\n     Decompression: Use the \"tinfl\" API's. The entire decompressor is implemented as a single function\n     coroutine: see tinfl_decompress(). It supports decompression into a 32KB (or larger power of 2) wrapping buffer, or into a memory\n     block large enough to hold the entire file.\n\n     The low-level tdefl/tinfl API's do not make any use of dynamic memory allocation.\n\n   * zlib-style API notes:\n\n     miniz.c implements a fairly large subset of zlib. There's enough functionality present for it to be a drop-in\n     zlib replacement in many apps:\n        The z_stream struct, optional memory allocation callbacks\n        deflateInit/deflateInit2/deflate/deflateReset/deflateEnd/deflateBound\n        inflateInit/inflateInit2/inflate/inflateReset/inflateEnd\n        compress, compress2, compressBound, uncompress\n        CRC-32, Adler-32 - Using modern, minimal code size, CPU cache friendly routines.\n        Supports raw deflate streams or standard zlib streams with adler-32 checking.\n\n     Limitations:\n      The callback API's are not implemented yet. No support for gzip headers or zlib static dictionaries.\n      I've tried to closely emulate zlib's various flavors of stream flushing and return status codes, but\n      there are no guarantees that miniz.c pulls this off perfectly.\n\n   * PNG writing: See the tdefl_write_image_to_png_file_in_memory() function, originally written by\n     Alex Evans. Supports 1-4 bytes/pixel images.\n\n   * ZIP archive API notes:\n\n     The ZIP archive API's where designed with simplicity and efficiency in mind, with just enough abstraction to\n     get the job done with minimal fuss. There are simple API's to retrieve file information, read files from\n     existing archives, create new archives, append new files to existing archives, or clone archive data from\n     one archive to another. It supports archives located in memory or the heap, on disk (using stdio.h),\n     or you can specify custom file read/write callbacks.\n\n     - Archive reading: Just call this function to read a single file from a disk archive:\n\n      void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name,\n        size_t *pSize, mz_uint zip_flags);\n\n     For more complex cases, use the \"mz_zip_reader\" functions. Upon opening an archive, the entire central\n     directory is located and read as-is into memory, and subsequent file access only occurs when reading individual files.\n\n     - Archives file scanning: The simple way is to use this function to scan a loaded archive for a specific file:\n\n     int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags);\n\n     The locate operation can optionally check file comments too, which (as one example) can be used to identify\n     multiple versions of the same file in an archive. This function uses a simple linear search through the central\n     directory, so it's not very fast.\n\n     Alternately, you can iterate through all the files in an archive (using mz_zip_reader_get_num_files()) and\n     retrieve detailed info on each file by calling mz_zip_reader_file_stat().\n\n     - Archive creation: Use the \"mz_zip_writer\" functions. The ZIP writer immediately writes compressed file data\n     to disk and builds an exact image of the central directory in memory. The central directory image is written\n     all at once at the end of the archive file when the archive is finalized.\n\n     The archive writer can optionally align each file's local header and file data to any power of 2 alignment,\n     which can be useful when the archive will be read from optical media. Also, the writer supports placing\n     arbitrary data blobs at the very beginning of ZIP archives. Archives written using either feature are still\n     readable by any ZIP tool.\n\n     - Archive appending: The simple way to add a single file to an archive is to call this function:\n\n      mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name,\n        const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags);\n\n     The archive will be created if it doesn't already exist, otherwise it'll be appended to.\n     Note the appending is done in-place and is not an atomic operation, so if something goes wrong\n     during the operation it's possible the archive could be left without a central directory (although the local\n     file headers and file data will be fine, so the archive will be recoverable).\n\n     For more complex archive modification scenarios:\n     1. The safest way is to use a mz_zip_reader to read the existing archive, cloning only those bits you want to\n     preserve into a new archive using using the mz_zip_writer_add_from_zip_reader() function (which compiles the\n     compressed file data as-is). When you're done, delete the old archive and rename the newly written archive, and\n     you're done. This is safe but requires a bunch of temporary disk space or heap memory.\n\n     2. Or, you can convert an mz_zip_reader in-place to an mz_zip_writer using mz_zip_writer_init_from_reader(),\n     append new files as needed, then finalize the archive which will write an updated central directory to the\n     original archive. (This is basically what mz_zip_add_mem_to_archive_file_in_place() does.) There's a\n     possibility that the archive's central directory could be lost with this method if anything goes wrong, though.\n\n     - ZIP archive support limitations:\n     No zip64 or spanning support. Extraction functions can only handle unencrypted, stored or deflated files.\n     Requires streams capable of seeking.\n\n   * This is a header file library, like stb_image.c. To get only a header file, either cut and paste the\n     below header, or create miniz.h, #define MINIZ_HEADER_FILE_ONLY, and then include miniz.c from it.\n\n   * Important: For best perf. be sure to customize the below macros for your target platform:\n     #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1\n     #define MINIZ_LITTLE_ENDIAN 1\n     #define MINIZ_HAS_64BIT_REGISTERS 1\n\n   * On platforms using glibc, Be sure to \"#define _LARGEFILE64_SOURCE 1\" before including miniz.c to ensure miniz\n     uses the 64-bit variants: fopen64(), stat64(), etc. Otherwise you won't be able to process large files\n     (i.e. 32-bit stat() fails for me on files > 0x7FFFFFFF bytes).\n*/\n#pragma once\n\n\n\n\n\n/* Defines to completely disable specific portions of miniz.c: \n   If all macros here are defined the only functionality remaining will be CRC-32, adler-32, tinfl, and tdefl. */\n\n/* Define MINIZ_NO_STDIO to disable all usage and any functions which rely on stdio for file I/O. */\n/*#define MINIZ_NO_STDIO */\n\n/* If MINIZ_NO_TIME is specified then the ZIP archive functions will not be able to get the current time, or */\n/* get/set file times, and the C run-time funcs that get/set times won't be called. */\n/* The current downside is the times written to your archives will be from 1979. */\n/*#define MINIZ_NO_TIME */\n\n/* Define MINIZ_NO_ARCHIVE_APIS to disable all ZIP archive API's. */\n/*#define MINIZ_NO_ARCHIVE_APIS */\n\n/* Define MINIZ_NO_ARCHIVE_WRITING_APIS to disable all writing related ZIP archive API's. */\n/*#define MINIZ_NO_ARCHIVE_WRITING_APIS */\n\n/* Define MINIZ_NO_ZLIB_APIS to remove all ZLIB-style compression/decompression API's. */\n/*#define MINIZ_NO_ZLIB_APIS */\n\n/* Define MINIZ_NO_ZLIB_COMPATIBLE_NAME to disable zlib names, to prevent conflicts against stock zlib. */\n/*#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES */\n\n/* Define MINIZ_NO_MALLOC to disable all calls to malloc, free, and realloc. \n   Note if MINIZ_NO_MALLOC is defined then the user must always provide custom user alloc/free/realloc\n   callbacks to the zlib and archive API's, and a few stand-alone helper API's which don't provide custom user\n   functions (such as tdefl_compress_mem_to_heap() and tinfl_decompress_mem_to_heap()) won't work. */\n/*#define MINIZ_NO_MALLOC */\n\n#if defined(__TINYC__) && (defined(__linux) || defined(__linux__))\n/* TODO: Work around \"error: include file 'sys\\utime.h' when compiling with tcc on Linux */\n#define MINIZ_NO_TIME\n#endif\n\n#include <stddef.h>\n\n#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_ARCHIVE_APIS)\n#include <time.h>\n#endif\n\n#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__i386) || defined(__i486__) || defined(__i486) || defined(i386) || defined(__ia64__) || defined(__x86_64__)\n/* MINIZ_X86_OR_X64_CPU is only used to help set the below macros. */\n#define MINIZ_X86_OR_X64_CPU 1\n#else\n#define MINIZ_X86_OR_X64_CPU 0\n#endif\n\n#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU\n/* Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian. */\n#define MINIZ_LITTLE_ENDIAN 1\n#else\n#define MINIZ_LITTLE_ENDIAN 0\n#endif\n\n/* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES only if not set */\n#if !defined(MINIZ_USE_UNALIGNED_LOADS_AND_STORES)\n#if MINIZ_X86_OR_X64_CPU\n/* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient integer loads and stores from unaligned addresses. */\n#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1\n#define MINIZ_UNALIGNED_USE_MEMCPY\n#else\n#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 0\n#endif\n#endif\n\n#if defined(_M_X64) || defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__) || defined(__ia64__) || defined(__x86_64__)\n/* Set MINIZ_HAS_64BIT_REGISTERS to 1 if operations on 64-bit integers are reasonably fast (and don't involve compiler generated calls to helper functions). */\n#define MINIZ_HAS_64BIT_REGISTERS 1\n#else\n#define MINIZ_HAS_64BIT_REGISTERS 0\n#endif\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/* ------------------- zlib-style API Definitions. */\n\n/* For more compatibility with zlib, miniz.c uses unsigned long for some parameters/struct members. Beware: mz_ulong can be either 32 or 64-bits! */\ntypedef unsigned long mz_ulong;\n\n/* mz_free() internally uses the MZ_FREE() macro (which by default calls free() unless you've modified the MZ_MALLOC macro) to release a block allocated from the heap. */\nvoid mz_free(void *p);\n\n#define MZ_ADLER32_INIT (1)\n/* mz_adler32() returns the initial adler-32 value to use when called with ptr==NULL. */\nmz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len);\n\n#define MZ_CRC32_INIT (0)\n/* mz_crc32() returns the initial CRC-32 value to use when called with ptr==NULL. */\nmz_ulong mz_crc32(mz_ulong crc, const unsigned char *ptr, size_t buf_len);\n\n/* Compression strategies. */\nenum\n{\n    MZ_DEFAULT_STRATEGY = 0,\n    MZ_FILTERED = 1,\n    MZ_HUFFMAN_ONLY = 2,\n    MZ_RLE = 3,\n    MZ_FIXED = 4\n};\n\n/* Method */\n#define MZ_DEFLATED 8\n\n/* Heap allocation callbacks.\nNote that mz_alloc_func parameter types purpsosely differ from zlib's: items/size is size_t, not unsigned long. */\ntypedef void *(*mz_alloc_func)(void *opaque, size_t items, size_t size);\ntypedef void (*mz_free_func)(void *opaque, void *address);\ntypedef void *(*mz_realloc_func)(void *opaque, void *address, size_t items, size_t size);\n\n/* Compression levels: 0-9 are the standard zlib-style levels, 10 is best possible compression (not zlib compatible, and may be very slow), MZ_DEFAULT_COMPRESSION=MZ_DEFAULT_LEVEL. */\nenum\n{\n    MZ_NO_COMPRESSION = 0,\n    MZ_BEST_SPEED = 1,\n    MZ_BEST_COMPRESSION = 9,\n    MZ_UBER_COMPRESSION = 10,\n    MZ_DEFAULT_LEVEL = 6,\n    MZ_DEFAULT_COMPRESSION = -1\n};\n\n#define MZ_VERSION \"10.1.0\"\n#define MZ_VERNUM 0xA100\n#define MZ_VER_MAJOR 10\n#define MZ_VER_MINOR 1\n#define MZ_VER_REVISION 0\n#define MZ_VER_SUBREVISION 0\n\n#ifndef MINIZ_NO_ZLIB_APIS\n\n/* Flush values. For typical usage you only need MZ_NO_FLUSH and MZ_FINISH. The other values are for advanced use (refer to the zlib docs). */\nenum\n{\n    MZ_NO_FLUSH = 0,\n    MZ_PARTIAL_FLUSH = 1,\n    MZ_SYNC_FLUSH = 2,\n    MZ_FULL_FLUSH = 3,\n    MZ_FINISH = 4,\n    MZ_BLOCK = 5\n};\n\n/* Return status codes. MZ_PARAM_ERROR is non-standard. */\nenum\n{\n    MZ_OK = 0,\n    MZ_STREAM_END = 1,\n    MZ_NEED_DICT = 2,\n    MZ_ERRNO = -1,\n    MZ_STREAM_ERROR = -2,\n    MZ_DATA_ERROR = -3,\n    MZ_MEM_ERROR = -4,\n    MZ_BUF_ERROR = -5,\n    MZ_VERSION_ERROR = -6,\n    MZ_PARAM_ERROR = -10000\n};\n\n/* Window bits */\n#define MZ_DEFAULT_WINDOW_BITS 15\n\nstruct mz_internal_state;\n\n/* Compression/decompression stream struct. */\ntypedef struct mz_stream_s\n{\n    const unsigned char *next_in; /* pointer to next byte to read */\n    unsigned int avail_in;        /* number of bytes available at next_in */\n    mz_ulong total_in;            /* total number of bytes consumed so far */\n\n    unsigned char *next_out; /* pointer to next byte to write */\n    unsigned int avail_out;  /* number of bytes that can be written to next_out */\n    mz_ulong total_out;      /* total number of bytes produced so far */\n\n    char *msg;                       /* error msg (unused) */\n    struct mz_internal_state *state; /* internal state, allocated by zalloc/zfree */\n\n    mz_alloc_func zalloc; /* optional heap allocation function (defaults to malloc) */\n    mz_free_func zfree;   /* optional heap free function (defaults to free) */\n    void *opaque;         /* heap alloc function user pointer */\n\n    int data_type;     /* data_type (unused) */\n    mz_ulong adler;    /* adler32 of the source or uncompressed data */\n    mz_ulong reserved; /* not used */\n} mz_stream;\n\ntypedef mz_stream *mz_streamp;\n\n/* Returns the version string of miniz.c. */\nconst char *mz_version(void);\n\n/* mz_deflateInit() initializes a compressor with default options: */\n/* Parameters: */\n/*  pStream must point to an initialized mz_stream struct. */\n/*  level must be between [MZ_NO_COMPRESSION, MZ_BEST_COMPRESSION]. */\n/*  level 1 enables a specially optimized compression function that's been optimized purely for performance, not ratio. */\n/*  (This special func. is currently only enabled when MINIZ_USE_UNALIGNED_LOADS_AND_STORES and MINIZ_LITTLE_ENDIAN are defined.) */\n/* Return values: */\n/*  MZ_OK on success. */\n/*  MZ_STREAM_ERROR if the stream is bogus. */\n/*  MZ_PARAM_ERROR if the input parameters are bogus. */\n/*  MZ_MEM_ERROR on out of memory. */\nint mz_deflateInit(mz_streamp pStream, int level);\n\n/* mz_deflateInit2() is like mz_deflate(), except with more control: */\n/* Additional parameters: */\n/*   method must be MZ_DEFLATED */\n/*   window_bits must be MZ_DEFAULT_WINDOW_BITS (to wrap the deflate stream with zlib header/adler-32 footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate/no header or footer) */\n/*   mem_level must be between [1, 9] (it's checked but ignored by miniz.c) */\nint mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy);\n\n/* Quickly resets a compressor without having to reallocate anything. Same as calling mz_deflateEnd() followed by mz_deflateInit()/mz_deflateInit2(). */\nint mz_deflateReset(mz_streamp pStream);\n\n/* mz_deflate() compresses the input to output, consuming as much of the input and producing as much output as possible. */\n/* Parameters: */\n/*   pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members. */\n/*   flush may be MZ_NO_FLUSH, MZ_PARTIAL_FLUSH/MZ_SYNC_FLUSH, MZ_FULL_FLUSH, or MZ_FINISH. */\n/* Return values: */\n/*   MZ_OK on success (when flushing, or if more input is needed but not available, and/or there's more output to be written but the output buffer is full). */\n/*   MZ_STREAM_END if all input has been consumed and all output bytes have been written. Don't call mz_deflate() on the stream anymore. */\n/*   MZ_STREAM_ERROR if the stream is bogus. */\n/*   MZ_PARAM_ERROR if one of the parameters is invalid. */\n/*   MZ_BUF_ERROR if no forward progress is possible because the input and/or output buffers are empty. (Fill up the input buffer or free up some output space and try again.) */\nint mz_deflate(mz_streamp pStream, int flush);\n\n/* mz_deflateEnd() deinitializes a compressor: */\n/* Return values: */\n/*  MZ_OK on success. */\n/*  MZ_STREAM_ERROR if the stream is bogus. */\nint mz_deflateEnd(mz_streamp pStream);\n\n/* mz_deflateBound() returns a (very) conservative upper bound on the amount of data that could be generated by deflate(), assuming flush is set to only MZ_NO_FLUSH or MZ_FINISH. */\nmz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len);\n\n/* Single-call compression functions mz_compress() and mz_compress2(): */\n/* Returns MZ_OK on success, or one of the error codes from mz_deflate() on failure. */\nint mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len);\nint mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level);\n\n/* mz_compressBound() returns a (very) conservative upper bound on the amount of data that could be generated by calling mz_compress(). */\nmz_ulong mz_compressBound(mz_ulong source_len);\n\n/* Initializes a decompressor. */\nint mz_inflateInit(mz_streamp pStream);\n\n/* mz_inflateInit2() is like mz_inflateInit() with an additional option that controls the window size and whether or not the stream has been wrapped with a zlib header/footer: */\n/* window_bits must be MZ_DEFAULT_WINDOW_BITS (to parse zlib header/footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate). */\nint mz_inflateInit2(mz_streamp pStream, int window_bits);\n\n/* Quickly resets a compressor without having to reallocate anything. Same as calling mz_inflateEnd() followed by mz_inflateInit()/mz_inflateInit2(). */\nint mz_inflateReset(mz_streamp pStream);\n\n/* Decompresses the input stream to the output, consuming only as much of the input as needed, and writing as much to the output as possible. */\n/* Parameters: */\n/*   pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members. */\n/*   flush may be MZ_NO_FLUSH, MZ_SYNC_FLUSH, or MZ_FINISH. */\n/*   On the first call, if flush is MZ_FINISH it's assumed the input and output buffers are both sized large enough to decompress the entire stream in a single call (this is slightly faster). */\n/*   MZ_FINISH implies that there are no more source bytes available beside what's already in the input buffer, and that the output buffer is large enough to hold the rest of the decompressed data. */\n/* Return values: */\n/*   MZ_OK on success. Either more input is needed but not available, and/or there's more output to be written but the output buffer is full. */\n/*   MZ_STREAM_END if all needed input has been consumed and all output bytes have been written. For zlib streams, the adler-32 of the decompressed data has also been verified. */\n/*   MZ_STREAM_ERROR if the stream is bogus. */\n/*   MZ_DATA_ERROR if the deflate stream is invalid. */\n/*   MZ_PARAM_ERROR if one of the parameters is invalid. */\n/*   MZ_BUF_ERROR if no forward progress is possible because the input buffer is empty but the inflater needs more input to continue, or if the output buffer is not large enough. Call mz_inflate() again */\n/*   with more input data, or with more room in the output buffer (except when using single call decompression, described above). */\nint mz_inflate(mz_streamp pStream, int flush);\n\n/* Deinitializes a decompressor. */\nint mz_inflateEnd(mz_streamp pStream);\n\n/* Single-call decompression. */\n/* Returns MZ_OK on success, or one of the error codes from mz_inflate() on failure. */\nint mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len);\n\n/* Returns a string description of the specified error code, or NULL if the error code is invalid. */\nconst char *mz_error(int err);\n\n/* Redefine zlib-compatible names to miniz equivalents, so miniz.c can be used as a drop-in replacement for the subset of zlib that miniz.c supports. */\n/* Define MINIZ_NO_ZLIB_COMPATIBLE_NAMES to disable zlib-compatibility if you use zlib in the same project. */\n#ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES\ntypedef unsigned char Byte;\ntypedef unsigned int uInt;\ntypedef mz_ulong uLong;\ntypedef Byte Bytef;\ntypedef uInt uIntf;\ntypedef char charf;\ntypedef int intf;\ntypedef void *voidpf;\ntypedef uLong uLongf;\ntypedef void *voidp;\ntypedef void *const voidpc;\n#define Z_NULL 0\n#define Z_NO_FLUSH MZ_NO_FLUSH\n#define Z_PARTIAL_FLUSH MZ_PARTIAL_FLUSH\n#define Z_SYNC_FLUSH MZ_SYNC_FLUSH\n#define Z_FULL_FLUSH MZ_FULL_FLUSH\n#define Z_FINISH MZ_FINISH\n#define Z_BLOCK MZ_BLOCK\n#define Z_OK MZ_OK\n#define Z_STREAM_END MZ_STREAM_END\n#define Z_NEED_DICT MZ_NEED_DICT\n#define Z_ERRNO MZ_ERRNO\n#define Z_STREAM_ERROR MZ_STREAM_ERROR\n#define Z_DATA_ERROR MZ_DATA_ERROR\n#define Z_MEM_ERROR MZ_MEM_ERROR\n#define Z_BUF_ERROR MZ_BUF_ERROR\n#define Z_VERSION_ERROR MZ_VERSION_ERROR\n#define Z_PARAM_ERROR MZ_PARAM_ERROR\n#define Z_NO_COMPRESSION MZ_NO_COMPRESSION\n#define Z_BEST_SPEED MZ_BEST_SPEED\n#define Z_BEST_COMPRESSION MZ_BEST_COMPRESSION\n#define Z_DEFAULT_COMPRESSION MZ_DEFAULT_COMPRESSION\n#define Z_DEFAULT_STRATEGY MZ_DEFAULT_STRATEGY\n#define Z_FILTERED MZ_FILTERED\n#define Z_HUFFMAN_ONLY MZ_HUFFMAN_ONLY\n#define Z_RLE MZ_RLE\n#define Z_FIXED MZ_FIXED\n#define Z_DEFLATED MZ_DEFLATED\n#define Z_DEFAULT_WINDOW_BITS MZ_DEFAULT_WINDOW_BITS\n#define alloc_func mz_alloc_func\n#define free_func mz_free_func\n#define internal_state mz_internal_state\n#define z_stream mz_stream\n#define deflateInit mz_deflateInit\n#define deflateInit2 mz_deflateInit2\n#define deflateReset mz_deflateReset\n#define deflate mz_deflate\n#define deflateEnd mz_deflateEnd\n#define deflateBound mz_deflateBound\n#define compress mz_compress\n#define compress2 mz_compress2\n#define compressBound mz_compressBound\n#define inflateInit mz_inflateInit\n#define inflateInit2 mz_inflateInit2\n#define inflateReset mz_inflateReset\n#define inflate mz_inflate\n#define inflateEnd mz_inflateEnd\n#define uncompress mz_uncompress\n#define crc32 mz_crc32\n#define adler32 mz_adler32\n#define MAX_WBITS 15\n#define MAX_MEM_LEVEL 9\n#define zError mz_error\n#define ZLIB_VERSION MZ_VERSION\n#define ZLIB_VERNUM MZ_VERNUM\n#define ZLIB_VER_MAJOR MZ_VER_MAJOR\n#define ZLIB_VER_MINOR MZ_VER_MINOR\n#define ZLIB_VER_REVISION MZ_VER_REVISION\n#define ZLIB_VER_SUBREVISION MZ_VER_SUBREVISION\n#define zlibVersion mz_version\n#define zlib_version mz_version()\n#endif /* #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES */\n\n#endif /* MINIZ_NO_ZLIB_APIS */\n\n#ifdef __cplusplus\n}\n#endif\n#pragma once\n#include <assert.h>\n#include <stdint.h>\n#include <stdlib.h>\n#include <string.h>\n\n/* ------------------- Types and macros */\ntypedef unsigned char mz_uint8;\ntypedef signed short mz_int16;\ntypedef unsigned short mz_uint16;\ntypedef unsigned int mz_uint32;\ntypedef unsigned int mz_uint;\ntypedef int64_t mz_int64;\ntypedef uint64_t mz_uint64;\ntypedef int mz_bool;\n\n#define MZ_FALSE (0)\n#define MZ_TRUE (1)\n\n/* Works around MSVC's spammy \"warning C4127: conditional expression is constant\" message. */\n#ifdef _MSC_VER\n#define MZ_MACRO_END while (0, 0)\n#else\n#define MZ_MACRO_END while (0)\n#endif\n\n#ifdef MINIZ_NO_STDIO\n#define MZ_FILE void *\n#else\n#include <stdio.h>\n#define MZ_FILE FILE\n#endif /* #ifdef MINIZ_NO_STDIO */\n\n#ifdef MINIZ_NO_TIME\ntypedef struct mz_dummy_time_t_tag\n{\n    int m_dummy;\n} mz_dummy_time_t;\n#define MZ_TIME_T mz_dummy_time_t\n#else\n#define MZ_TIME_T time_t\n#endif\n\n#define MZ_ASSERT(x) assert(x)\n\n#ifdef MINIZ_NO_MALLOC\n#define MZ_MALLOC(x) NULL\n#define MZ_FREE(x) (void)x, ((void)0)\n#define MZ_REALLOC(p, x) NULL\n#else\n#define MZ_MALLOC(x) malloc(x)\n#define MZ_FREE(x) free(x)\n#define MZ_REALLOC(p, x) realloc(p, x)\n#endif\n\n#define MZ_MAX(a, b) (((a) > (b)) ? (a) : (b))\n#define MZ_MIN(a, b) (((a) < (b)) ? (a) : (b))\n#define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj))\n\n#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN\n#define MZ_READ_LE16(p) *((const mz_uint16 *)(p))\n#define MZ_READ_LE32(p) *((const mz_uint32 *)(p))\n#else\n#define MZ_READ_LE16(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U))\n#define MZ_READ_LE32(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U))\n#endif\n\n#define MZ_READ_LE64(p) (((mz_uint64)MZ_READ_LE32(p)) | (((mz_uint64)MZ_READ_LE32((const mz_uint8 *)(p) + sizeof(mz_uint32))) << 32U))\n\n#ifdef _MSC_VER\n#define MZ_FORCEINLINE __forceinline\n#elif defined(__GNUC__)\n#define MZ_FORCEINLINE __inline__ __attribute__((__always_inline__))\n#else\n#define MZ_FORCEINLINE inline\n#endif\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nextern void *miniz_def_alloc_func(void *opaque, size_t items, size_t size);\nextern void miniz_def_free_func(void *opaque, void *address);\nextern void *miniz_def_realloc_func(void *opaque, void *address, size_t items, size_t size);\n\n#define MZ_UINT16_MAX (0xFFFFU)\n#define MZ_UINT32_MAX (0xFFFFFFFFU)\n\n#ifdef __cplusplus\n}\n#endif\n#pragma once\n\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n/* ------------------- Low-level Compression API Definitions */\n\n/* Set TDEFL_LESS_MEMORY to 1 to use less memory (compression will be slightly slower, and raw/dynamic blocks will be output more frequently). */\n#define TDEFL_LESS_MEMORY 0\n\n/* tdefl_init() compression flags logically OR'd together (low 12 bits contain the max. number of probes per dictionary search): */\n/* TDEFL_DEFAULT_MAX_PROBES: The compressor defaults to 128 dictionary probes per dictionary search. 0=Huffman only, 1=Huffman+LZ (fastest/crap compression), 4095=Huffman+LZ (slowest/best compression). */\nenum\n{\n    TDEFL_HUFFMAN_ONLY = 0,\n    TDEFL_DEFAULT_MAX_PROBES = 128,\n    TDEFL_MAX_PROBES_MASK = 0xFFF\n};\n\n/* TDEFL_WRITE_ZLIB_HEADER: If set, the compressor outputs a zlib header before the deflate data, and the Adler-32 of the source data at the end. Otherwise, you'll get raw deflate data. */\n/* TDEFL_COMPUTE_ADLER32: Always compute the adler-32 of the input data (even when not writing zlib headers). */\n/* TDEFL_GREEDY_PARSING_FLAG: Set to use faster greedy parsing, instead of more efficient lazy parsing. */\n/* TDEFL_NONDETERMINISTIC_PARSING_FLAG: Enable to decrease the compressor's initialization time to the minimum, but the output may vary from run to run given the same input (depending on the contents of memory). */\n/* TDEFL_RLE_MATCHES: Only look for RLE matches (matches with a distance of 1) */\n/* TDEFL_FILTER_MATCHES: Discards matches <= 5 chars if enabled. */\n/* TDEFL_FORCE_ALL_STATIC_BLOCKS: Disable usage of optimized Huffman tables. */\n/* TDEFL_FORCE_ALL_RAW_BLOCKS: Only use raw (uncompressed) deflate blocks. */\n/* The low 12 bits are reserved to control the max # of hash probes per dictionary lookup (see TDEFL_MAX_PROBES_MASK). */\nenum\n{\n    TDEFL_WRITE_ZLIB_HEADER = 0x01000,\n    TDEFL_COMPUTE_ADLER32 = 0x02000,\n    TDEFL_GREEDY_PARSING_FLAG = 0x04000,\n    TDEFL_NONDETERMINISTIC_PARSING_FLAG = 0x08000,\n    TDEFL_RLE_MATCHES = 0x10000,\n    TDEFL_FILTER_MATCHES = 0x20000,\n    TDEFL_FORCE_ALL_STATIC_BLOCKS = 0x40000,\n    TDEFL_FORCE_ALL_RAW_BLOCKS = 0x80000\n};\n\n/* High level compression functions: */\n/* tdefl_compress_mem_to_heap() compresses a block in memory to a heap block allocated via malloc(). */\n/* On entry: */\n/*  pSrc_buf, src_buf_len: Pointer and size of source block to compress. */\n/*  flags: The max match finder probes (default is 128) logically OR'd against the above flags. Higher probes are slower but improve compression. */\n/* On return: */\n/*  Function returns a pointer to the compressed data, or NULL on failure. */\n/*  *pOut_len will be set to the compressed data's size, which could be larger than src_buf_len on uncompressible data. */\n/*  The caller must free() the returned block when it's no longer needed. */\nvoid *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags);\n\n/* tdefl_compress_mem_to_mem() compresses a block in memory to another block in memory. */\n/* Returns 0 on failure. */\nsize_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags);\n\n/* Compresses an image to a compressed PNG file in memory. */\n/* On entry: */\n/*  pImage, w, h, and num_chans describe the image to compress. num_chans may be 1, 2, 3, or 4. */\n/*  The image pitch in bytes per scanline will be w*num_chans. The leftmost pixel on the top scanline is stored first in memory. */\n/*  level may range from [0,10], use MZ_NO_COMPRESSION, MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc. or a decent default is MZ_DEFAULT_LEVEL */\n/*  If flip is true, the image will be flipped on the Y axis (useful for OpenGL apps). */\n/* On return: */\n/*  Function returns a pointer to the compressed data, or NULL on failure. */\n/*  *pLen_out will be set to the size of the PNG image file. */\n/*  The caller must mz_free() the returned heap block (which will typically be larger than *pLen_out) when it's no longer needed. */\nvoid *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip);\nvoid *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out);\n\n/* Output stream interface. The compressor uses this interface to write compressed data. It'll typically be called TDEFL_OUT_BUF_SIZE at a time. */\ntypedef mz_bool (*tdefl_put_buf_func_ptr)(const void *pBuf, int len, void *pUser);\n\n/* tdefl_compress_mem_to_output() compresses a block to an output stream. The above helpers use this function internally. */\nmz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags);\n\nenum\n{\n    TDEFL_MAX_HUFF_TABLES = 3,\n    TDEFL_MAX_HUFF_SYMBOLS_0 = 288,\n    TDEFL_MAX_HUFF_SYMBOLS_1 = 32,\n    TDEFL_MAX_HUFF_SYMBOLS_2 = 19,\n    TDEFL_LZ_DICT_SIZE = 32768,\n    TDEFL_LZ_DICT_SIZE_MASK = TDEFL_LZ_DICT_SIZE - 1,\n    TDEFL_MIN_MATCH_LEN = 3,\n    TDEFL_MAX_MATCH_LEN = 258\n};\n\n/* TDEFL_OUT_BUF_SIZE MUST be large enough to hold a single entire compressed output block (using static/fixed Huffman codes). */\n#if TDEFL_LESS_MEMORY\nenum\n{\n    TDEFL_LZ_CODE_BUF_SIZE = 24 * 1024,\n    TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10,\n    TDEFL_MAX_HUFF_SYMBOLS = 288,\n    TDEFL_LZ_HASH_BITS = 12,\n    TDEFL_LEVEL1_HASH_SIZE_MASK = 4095,\n    TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3,\n    TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS\n};\n#else\nenum\n{\n    TDEFL_LZ_CODE_BUF_SIZE = 64 * 1024,\n    TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10,\n    TDEFL_MAX_HUFF_SYMBOLS = 288,\n    TDEFL_LZ_HASH_BITS = 15,\n    TDEFL_LEVEL1_HASH_SIZE_MASK = 4095,\n    TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3,\n    TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS\n};\n#endif\n\n/* The low-level tdefl functions below may be used directly if the above helper functions aren't flexible enough. The low-level functions don't make any heap allocations, unlike the above helper functions. */\ntypedef enum {\n    TDEFL_STATUS_BAD_PARAM = -2,\n    TDEFL_STATUS_PUT_BUF_FAILED = -1,\n    TDEFL_STATUS_OKAY = 0,\n    TDEFL_STATUS_DONE = 1\n} tdefl_status;\n\n/* Must map to MZ_NO_FLUSH, MZ_SYNC_FLUSH, etc. enums */\ntypedef enum {\n    TDEFL_NO_FLUSH = 0,\n    TDEFL_SYNC_FLUSH = 2,\n    TDEFL_FULL_FLUSH = 3,\n    TDEFL_FINISH = 4\n} tdefl_flush;\n\n/* tdefl's compression state structure. */\ntypedef struct\n{\n    tdefl_put_buf_func_ptr m_pPut_buf_func;\n    void *m_pPut_buf_user;\n    mz_uint m_flags, m_max_probes[2];\n    int m_greedy_parsing;\n    mz_uint m_adler32, m_lookahead_pos, m_lookahead_size, m_dict_size;\n    mz_uint8 *m_pLZ_code_buf, *m_pLZ_flags, *m_pOutput_buf, *m_pOutput_buf_end;\n    mz_uint m_num_flags_left, m_total_lz_bytes, m_lz_code_buf_dict_pos, m_bits_in, m_bit_buffer;\n    mz_uint m_saved_match_dist, m_saved_match_len, m_saved_lit, m_output_flush_ofs, m_output_flush_remaining, m_finished, m_block_index, m_wants_to_finish;\n    tdefl_status m_prev_return_status;\n    const void *m_pIn_buf;\n    void *m_pOut_buf;\n    size_t *m_pIn_buf_size, *m_pOut_buf_size;\n    tdefl_flush m_flush;\n    const mz_uint8 *m_pSrc;\n    size_t m_src_buf_left, m_out_buf_ofs;\n    mz_uint8 m_dict[TDEFL_LZ_DICT_SIZE + TDEFL_MAX_MATCH_LEN - 1];\n    mz_uint16 m_huff_count[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS];\n    mz_uint16 m_huff_codes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS];\n    mz_uint8 m_huff_code_sizes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS];\n    mz_uint8 m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE];\n    mz_uint16 m_next[TDEFL_LZ_DICT_SIZE];\n    mz_uint16 m_hash[TDEFL_LZ_HASH_SIZE];\n    mz_uint8 m_output_buf[TDEFL_OUT_BUF_SIZE];\n} tdefl_compressor;\n\n/* Initializes the compressor. */\n/* There is no corresponding deinit() function because the tdefl API's do not dynamically allocate memory. */\n/* pBut_buf_func: If NULL, output data will be supplied to the specified callback. In this case, the user should call the tdefl_compress_buffer() API for compression. */\n/* If pBut_buf_func is NULL the user should always call the tdefl_compress() API. */\n/* flags: See the above enums (TDEFL_HUFFMAN_ONLY, TDEFL_WRITE_ZLIB_HEADER, etc.) */\ntdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags);\n\n/* Compresses a block of data, consuming as much of the specified input buffer as possible, and writing as much compressed data to the specified output buffer as possible. */\ntdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush);\n\n/* tdefl_compress_buffer() is only usable when the tdefl_init() is called with a non-NULL tdefl_put_buf_func_ptr. */\n/* tdefl_compress_buffer() always consumes the entire input buffer. */\ntdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush);\n\ntdefl_status tdefl_get_prev_return_status(tdefl_compressor *d);\nmz_uint32 tdefl_get_adler32(tdefl_compressor *d);\n\n/* Create tdefl_compress() flags given zlib-style compression parameters. */\n/* level may range from [0,10] (where 10 is absolute max compression, but may be much slower on some files) */\n/* window_bits may be -15 (raw deflate) or 15 (zlib) */\n/* strategy may be either MZ_DEFAULT_STRATEGY, MZ_FILTERED, MZ_HUFFMAN_ONLY, MZ_RLE, or MZ_FIXED */\nmz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy);\n\n#ifndef MINIZ_NO_MALLOC\n/* Allocate the tdefl_compressor structure in C so that */\n/* non-C language bindings to tdefl_ API don't need to worry about */\n/* structure size and allocation mechanism. */\ntdefl_compressor *tdefl_compressor_alloc(void);\nvoid tdefl_compressor_free(tdefl_compressor *pComp);\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n#pragma once\n\n/* ------------------- Low-level Decompression API Definitions */\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n/* Decompression flags used by tinfl_decompress(). */\n/* TINFL_FLAG_PARSE_ZLIB_HEADER: If set, the input has a valid zlib header and ends with an adler32 checksum (it's a valid zlib stream). Otherwise, the input is a raw deflate stream. */\n/* TINFL_FLAG_HAS_MORE_INPUT: If set, there are more input bytes available beyond the end of the supplied input buffer. If clear, the input buffer contains all remaining input. */\n/* TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large enough to hold the entire decompressed stream. If clear, the output buffer is at least the size of the dictionary (typically 32KB). */\n/* TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the decompressed bytes. */\nenum\n{\n    TINFL_FLAG_PARSE_ZLIB_HEADER = 1,\n    TINFL_FLAG_HAS_MORE_INPUT = 2,\n    TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4,\n    TINFL_FLAG_COMPUTE_ADLER32 = 8\n};\n\n/* High level decompression functions: */\n/* tinfl_decompress_mem_to_heap() decompresses a block in memory to a heap block allocated via malloc(). */\n/* On entry: */\n/*  pSrc_buf, src_buf_len: Pointer and size of the Deflate or zlib source data to decompress. */\n/* On return: */\n/*  Function returns a pointer to the decompressed data, or NULL on failure. */\n/*  *pOut_len will be set to the decompressed data's size, which could be larger than src_buf_len on uncompressible data. */\n/*  The caller must call mz_free() on the returned block when it's no longer needed. */\nvoid *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags);\n\n/* tinfl_decompress_mem_to_mem() decompresses a block in memory to another block in memory. */\n/* Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes written on success. */\n#define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1))\nsize_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags);\n\n/* tinfl_decompress_mem_to_callback() decompresses a block in memory to an internal 32KB buffer, and a user provided callback function will be called to flush the buffer. */\n/* Returns 1 on success or 0 on failure. */\ntypedef int (*tinfl_put_buf_func_ptr)(const void *pBuf, int len, void *pUser);\nint tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags);\n\nstruct tinfl_decompressor_tag;\ntypedef struct tinfl_decompressor_tag tinfl_decompressor;\n\n#ifndef MINIZ_NO_MALLOC\n/* Allocate the tinfl_decompressor structure in C so that */\n/* non-C language bindings to tinfl_ API don't need to worry about */\n/* structure size and allocation mechanism. */\ntinfl_decompressor *tinfl_decompressor_alloc(void);\nvoid tinfl_decompressor_free(tinfl_decompressor *pDecomp);\n#endif\n\n/* Max size of LZ dictionary. */\n#define TINFL_LZ_DICT_SIZE 32768\n\n/* Return status. */\ntypedef enum {\n    /* This flags indicates the inflator needs 1 or more input bytes to make forward progress, but the caller is indicating that no more are available. The compressed data */\n    /* is probably corrupted. If you call the inflator again with more bytes it'll try to continue processing the input but this is a BAD sign (either the data is corrupted or you called it incorrectly). */\n    /* If you call it again with no input you'll just get TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS again. */\n    TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS = -4,\n\n    /* This flag indicates that one or more of the input parameters was obviously bogus. (You can try calling it again, but if you get this error the calling code is wrong.) */\n    TINFL_STATUS_BAD_PARAM = -3,\n\n    /* This flags indicate the inflator is finished but the adler32 check of the uncompressed data didn't match. If you call it again it'll return TINFL_STATUS_DONE. */\n    TINFL_STATUS_ADLER32_MISMATCH = -2,\n\n    /* This flags indicate the inflator has somehow failed (bad code, corrupted input, etc.). If you call it again without resetting via tinfl_init() it it'll just keep on returning the same status failure code. */\n    TINFL_STATUS_FAILED = -1,\n\n    /* Any status code less than TINFL_STATUS_DONE must indicate a failure. */\n\n    /* This flag indicates the inflator has returned every byte of uncompressed data that it can, has consumed every byte that it needed, has successfully reached the end of the deflate stream, and */\n    /* if zlib headers and adler32 checking enabled that it has successfully checked the uncompressed data's adler32. If you call it again you'll just get TINFL_STATUS_DONE over and over again. */\n    TINFL_STATUS_DONE = 0,\n\n    /* This flag indicates the inflator MUST have more input data (even 1 byte) before it can make any more forward progress, or you need to clear the TINFL_FLAG_HAS_MORE_INPUT */\n    /* flag on the next call if you don't have any more source data. If the source data was somehow corrupted it's also possible (but unlikely) for the inflator to keep on demanding input to */\n    /* proceed, so be sure to properly set the TINFL_FLAG_HAS_MORE_INPUT flag. */\n    TINFL_STATUS_NEEDS_MORE_INPUT = 1,\n\n    /* This flag indicates the inflator definitely has 1 or more bytes of uncompressed data available, but it cannot write this data into the output buffer. */\n    /* Note if the source compressed data was corrupted it's possible for the inflator to return a lot of uncompressed data to the caller. I've been assuming you know how much uncompressed data to expect */\n    /* (either exact or worst case) and will stop calling the inflator and fail after receiving too much. In pure streaming scenarios where you have no idea how many bytes to expect this may not be possible */\n    /* so I may need to add some code to address this. */\n    TINFL_STATUS_HAS_MORE_OUTPUT = 2\n} tinfl_status;\n\n/* Initializes the decompressor to its initial state. */\n#define tinfl_init(r)     \\\n    do                    \\\n    {                     \\\n        (r)->m_state = 0; \\\n    }                     \\\n    MZ_MACRO_END\n#define tinfl_get_adler32(r) (r)->m_check_adler32\n\n/* Main low-level decompressor coroutine function. This is the only function actually needed for decompression. All the other functions are just high-level helpers for improved usability. */\n/* This is a universal API, i.e. it can be used as a building block to build any desired higher level decompression API. In the limit case, it can be called once per every byte input or output. */\ntinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags);\n\n/* Internal/private bits follow. */\nenum\n{\n    TINFL_MAX_HUFF_TABLES = 3,\n    TINFL_MAX_HUFF_SYMBOLS_0 = 288,\n    TINFL_MAX_HUFF_SYMBOLS_1 = 32,\n    TINFL_MAX_HUFF_SYMBOLS_2 = 19,\n    TINFL_FAST_LOOKUP_BITS = 10,\n    TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS\n};\n\ntypedef struct\n{\n    mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0];\n    mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE], m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2];\n} tinfl_huff_table;\n\n#if MINIZ_HAS_64BIT_REGISTERS\n#define TINFL_USE_64BIT_BITBUF 1\n#else\n#define TINFL_USE_64BIT_BITBUF 0\n#endif\n\n#if TINFL_USE_64BIT_BITBUF\ntypedef mz_uint64 tinfl_bit_buf_t;\n#define TINFL_BITBUF_SIZE (64)\n#else\ntypedef mz_uint32 tinfl_bit_buf_t;\n#define TINFL_BITBUF_SIZE (32)\n#endif\n\nstruct tinfl_decompressor_tag\n{\n    mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, m_check_adler32, m_dist, m_counter, m_num_extra, m_table_sizes[TINFL_MAX_HUFF_TABLES];\n    tinfl_bit_buf_t m_bit_buf;\n    size_t m_dist_from_out_buf_start;\n    tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES];\n    mz_uint8 m_raw_header[4], m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137];\n};\n\n#ifdef __cplusplus\n}\n#endif\n\n#pragma once\n\n\n/* ------------------- ZIP archive reading/writing */\n\n#ifndef MINIZ_NO_ARCHIVE_APIS\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nenum\n{\n    /* Note: These enums can be reduced as needed to save memory or stack space - they are pretty conservative. */\n    MZ_ZIP_MAX_IO_BUF_SIZE = 64 * 1024,\n    MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 512,\n    MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 512\n};\n\ntypedef struct\n{\n    /* Central directory file index. */\n    mz_uint32 m_file_index;\n\n    /* Byte offset of this entry in the archive's central directory. Note we currently only support up to UINT_MAX or less bytes in the central dir. */\n    mz_uint64 m_central_dir_ofs;\n\n    /* These fields are copied directly from the zip's central dir. */\n    mz_uint16 m_version_made_by;\n    mz_uint16 m_version_needed;\n    mz_uint16 m_bit_flag;\n    mz_uint16 m_method;\n\n#ifndef MINIZ_NO_TIME\n    MZ_TIME_T m_time;\n#endif\n\n    /* CRC-32 of uncompressed data. */\n    mz_uint32 m_crc32;\n\n    /* File's compressed size. */\n    mz_uint64 m_comp_size;\n\n    /* File's uncompressed size. Note, I've seen some old archives where directory entries had 512 bytes for their uncompressed sizes, but when you try to unpack them you actually get 0 bytes. */\n    mz_uint64 m_uncomp_size;\n\n    /* Zip internal and external file attributes. */\n    mz_uint16 m_internal_attr;\n    mz_uint32 m_external_attr;\n\n    /* Entry's local header file offset in bytes. */\n    mz_uint64 m_local_header_ofs;\n\n    /* Size of comment in bytes. */\n    mz_uint32 m_comment_size;\n\n    /* MZ_TRUE if the entry appears to be a directory. */\n    mz_bool m_is_directory;\n\n    /* MZ_TRUE if the entry uses encryption/strong encryption (which miniz_zip doesn't support) */\n    mz_bool m_is_encrypted;\n\n    /* MZ_TRUE if the file is not encrypted, a patch file, and if it uses a compression method we support. */\n    mz_bool m_is_supported;\n\n    /* Filename. If string ends in '/' it's a subdirectory entry. */\n    /* Guaranteed to be zero terminated, may be truncated to fit. */\n    char m_filename[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE];\n\n    /* Comment field. */\n    /* Guaranteed to be zero terminated, may be truncated to fit. */\n    char m_comment[MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE];\n\n} mz_zip_archive_file_stat;\n\ntypedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n);\ntypedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n);\ntypedef mz_bool (*mz_file_needs_keepalive)(void *pOpaque);\n\nstruct mz_zip_internal_state_tag;\ntypedef struct mz_zip_internal_state_tag mz_zip_internal_state;\n\ntypedef enum {\n    MZ_ZIP_MODE_INVALID = 0,\n    MZ_ZIP_MODE_READING = 1,\n    MZ_ZIP_MODE_WRITING = 2,\n    MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3\n} mz_zip_mode;\n\ntypedef enum {\n    MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100,\n    MZ_ZIP_FLAG_IGNORE_PATH = 0x0200,\n    MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400,\n    MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY = 0x0800,\n    MZ_ZIP_FLAG_VALIDATE_LOCATE_FILE_FLAG = 0x1000, /* if enabled, mz_zip_reader_locate_file() will be called on each file as its validated to ensure the func finds the file in the central dir (intended for testing) */\n    MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY = 0x2000,     /* validate the local headers, but don't decompress the entire file and check the crc32 */\n    MZ_ZIP_FLAG_WRITE_ZIP64 = 0x4000,               /* always use the zip64 file format, instead of the original zip file format with automatic switch to zip64. Use as flags parameter with mz_zip_writer_init*_v2 */\n    MZ_ZIP_FLAG_WRITE_ALLOW_READING = 0x8000,\n    MZ_ZIP_FLAG_ASCII_FILENAME = 0x10000\n} mz_zip_flags;\n\ntypedef enum {\n    MZ_ZIP_TYPE_INVALID = 0,\n    MZ_ZIP_TYPE_USER,\n    MZ_ZIP_TYPE_MEMORY,\n    MZ_ZIP_TYPE_HEAP,\n    MZ_ZIP_TYPE_FILE,\n    MZ_ZIP_TYPE_CFILE,\n    MZ_ZIP_TOTAL_TYPES\n} mz_zip_type;\n\n/* miniz error codes. Be sure to update mz_zip_get_error_string() if you add or modify this enum. */\ntypedef enum {\n    MZ_ZIP_NO_ERROR = 0,\n    MZ_ZIP_UNDEFINED_ERROR,\n    MZ_ZIP_TOO_MANY_FILES,\n    MZ_ZIP_FILE_TOO_LARGE,\n    MZ_ZIP_UNSUPPORTED_METHOD,\n    MZ_ZIP_UNSUPPORTED_ENCRYPTION,\n    MZ_ZIP_UNSUPPORTED_FEATURE,\n    MZ_ZIP_FAILED_FINDING_CENTRAL_DIR,\n    MZ_ZIP_NOT_AN_ARCHIVE,\n    MZ_ZIP_INVALID_HEADER_OR_CORRUPTED,\n    MZ_ZIP_UNSUPPORTED_MULTIDISK,\n    MZ_ZIP_DECOMPRESSION_FAILED,\n    MZ_ZIP_COMPRESSION_FAILED,\n    MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE,\n    MZ_ZIP_CRC_CHECK_FAILED,\n    MZ_ZIP_UNSUPPORTED_CDIR_SIZE,\n    MZ_ZIP_ALLOC_FAILED,\n    MZ_ZIP_FILE_OPEN_FAILED,\n    MZ_ZIP_FILE_CREATE_FAILED,\n    MZ_ZIP_FILE_WRITE_FAILED,\n    MZ_ZIP_FILE_READ_FAILED,\n    MZ_ZIP_FILE_CLOSE_FAILED,\n    MZ_ZIP_FILE_SEEK_FAILED,\n    MZ_ZIP_FILE_STAT_FAILED,\n    MZ_ZIP_INVALID_PARAMETER,\n    MZ_ZIP_INVALID_FILENAME,\n    MZ_ZIP_BUF_TOO_SMALL,\n    MZ_ZIP_INTERNAL_ERROR,\n    MZ_ZIP_FILE_NOT_FOUND,\n    MZ_ZIP_ARCHIVE_TOO_LARGE,\n    MZ_ZIP_VALIDATION_FAILED,\n    MZ_ZIP_WRITE_CALLBACK_FAILED,\n    MZ_ZIP_TOTAL_ERRORS\n} mz_zip_error;\n\ntypedef struct\n{\n    mz_uint64 m_archive_size;\n    mz_uint64 m_central_directory_file_ofs;\n\n    /* We only support up to UINT32_MAX files in zip64 mode. */\n    mz_uint32 m_total_files;\n    mz_zip_mode m_zip_mode;\n    mz_zip_type m_zip_type;\n    mz_zip_error m_last_error;\n\n    mz_uint64 m_file_offset_alignment;\n\n    mz_alloc_func m_pAlloc;\n    mz_free_func m_pFree;\n    mz_realloc_func m_pRealloc;\n    void *m_pAlloc_opaque;\n\n    mz_file_read_func m_pRead;\n    mz_file_write_func m_pWrite;\n    mz_file_needs_keepalive m_pNeeds_keepalive;\n    void *m_pIO_opaque;\n\n    mz_zip_internal_state *m_pState;\n\n} mz_zip_archive;\n\ntypedef struct\n{\n    mz_zip_archive *pZip;\n    mz_uint flags;\n\n    int status;\n#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS\n    mz_uint file_crc32;\n#endif\n    mz_uint64 read_buf_size, read_buf_ofs, read_buf_avail, comp_remaining, out_buf_ofs, cur_file_ofs;\n    mz_zip_archive_file_stat file_stat;\n    void *pRead_buf;\n    void *pWrite_buf;\n\n    size_t out_blk_remain;\n\n    tinfl_decompressor inflator;\n\n} mz_zip_reader_extract_iter_state;\n\n/* -------- ZIP reading */\n\n/* Inits a ZIP archive reader. */\n/* These functions read and validate the archive's central directory. */\nmz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint flags);\n\nmz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint flags);\n\n#ifndef MINIZ_NO_STDIO\n/* Read a archive from a disk file. */\n/* file_start_ofs is the file offset where the archive actually begins, or 0. */\n/* actual_archive_size is the true total size of the archive, which may be smaller than the file's actual size on disk. If zero the entire file is treated as the archive. */\nmz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags);\nmz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags, mz_uint64 file_start_ofs, mz_uint64 archive_size);\n\n/* Read an archive from an already opened FILE, beginning at the current file position. */\n/* The archive is assumed to be archive_size bytes long. If archive_size is < 0, then the entire rest of the file is assumed to contain the archive. */\n/* The FILE will NOT be closed when mz_zip_reader_end() is called. */\nmz_bool mz_zip_reader_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint64 archive_size, mz_uint flags);\n#endif\n\n/* Ends archive reading, freeing all allocations, and closing the input archive file if mz_zip_reader_init_file() was used. */\nmz_bool mz_zip_reader_end(mz_zip_archive *pZip);\n\n/* -------- ZIP reading or writing */\n\n/* Clears a mz_zip_archive struct to all zeros. */\n/* Important: This must be done before passing the struct to any mz_zip functions. */\nvoid mz_zip_zero_struct(mz_zip_archive *pZip);\n\nmz_zip_mode mz_zip_get_mode(mz_zip_archive *pZip);\nmz_zip_type mz_zip_get_type(mz_zip_archive *pZip);\n\n/* Returns the total number of files in the archive. */\nmz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip);\n\nmz_uint64 mz_zip_get_archive_size(mz_zip_archive *pZip);\nmz_uint64 mz_zip_get_archive_file_start_offset(mz_zip_archive *pZip);\nMZ_FILE *mz_zip_get_cfile(mz_zip_archive *pZip);\n\n/* Reads n bytes of raw archive data, starting at file offset file_ofs, to pBuf. */\nsize_t mz_zip_read_archive_data(mz_zip_archive *pZip, mz_uint64 file_ofs, void *pBuf, size_t n);\n\n/* All mz_zip funcs set the m_last_error field in the mz_zip_archive struct. These functions retrieve/manipulate this field. */\n/* Note that the m_last_error functionality is not thread safe. */\nmz_zip_error mz_zip_set_last_error(mz_zip_archive *pZip, mz_zip_error err_num);\nmz_zip_error mz_zip_peek_last_error(mz_zip_archive *pZip);\nmz_zip_error mz_zip_clear_last_error(mz_zip_archive *pZip);\nmz_zip_error mz_zip_get_last_error(mz_zip_archive *pZip);\nconst char *mz_zip_get_error_string(mz_zip_error mz_err);\n\n/* MZ_TRUE if the archive file entry is a directory entry. */\nmz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index);\n\n/* MZ_TRUE if the file is encrypted/strong encrypted. */\nmz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index);\n\n/* MZ_TRUE if the compression method is supported, and the file is not encrypted, and the file is not a compressed patch file. */\nmz_bool mz_zip_reader_is_file_supported(mz_zip_archive *pZip, mz_uint file_index);\n\n/* Retrieves the filename of an archive file entry. */\n/* Returns the number of bytes written to pFilename, or if filename_buf_size is 0 this function returns the number of bytes needed to fully store the filename. */\nmz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size);\n\n/* Attempts to locates a file in the archive's central directory. */\n/* Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH */\n/* Returns -1 if the file cannot be found. */\nint mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags);\nint mz_zip_reader_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *file_index);\n\n/* Returns detailed information about an archive file entry. */\nmz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat);\n\n/* MZ_TRUE if the file is in zip64 format. */\n/* A file is considered zip64 if it contained a zip64 end of central directory marker, or if it contained any zip64 extended file information fields in the central directory. */\nmz_bool mz_zip_is_zip64(mz_zip_archive *pZip);\n\n/* Returns the total central directory size in bytes. */\n/* The current max supported size is <= MZ_UINT32_MAX. */\nsize_t mz_zip_get_central_dir_size(mz_zip_archive *pZip);\n\n/* Extracts a archive file to a memory buffer using no memory allocation. */\n/* There must be at least enough room on the stack to store the inflator's state (~34KB or so). */\nmz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size);\nmz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size);\n\n/* Extracts a archive file to a memory buffer. */\nmz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags);\nmz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags);\n\n/* Extracts a archive file to a dynamically allocated heap buffer. */\n/* The memory will be allocated via the mz_zip_archive's alloc/realloc functions. */\n/* Returns NULL and sets the last error on failure. */\nvoid *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags);\nvoid *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags);\n\n/* Extracts a archive file using a callback function to output the file's data. */\nmz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags);\nmz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags);\n\n/* Extract a file iteratively */\nmz_zip_reader_extract_iter_state* mz_zip_reader_extract_iter_new(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags);\nmz_zip_reader_extract_iter_state* mz_zip_reader_extract_file_iter_new(mz_zip_archive *pZip, const char *pFilename, mz_uint flags);\nsize_t mz_zip_reader_extract_iter_read(mz_zip_reader_extract_iter_state* pState, void* pvBuf, size_t buf_size);\nmz_bool mz_zip_reader_extract_iter_free(mz_zip_reader_extract_iter_state* pState);\n\n#ifndef MINIZ_NO_STDIO\n/* Extracts a archive file to a disk file and sets its last accessed and modified times. */\n/* This function only extracts files, not archive directory records. */\nmz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags);\nmz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags);\n\n/* Extracts a archive file starting at the current position in the destination FILE stream. */\nmz_bool mz_zip_reader_extract_to_cfile(mz_zip_archive *pZip, mz_uint file_index, MZ_FILE *File, mz_uint flags);\nmz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pArchive_filename, MZ_FILE *pFile, mz_uint flags);\n#endif\n\n#if 0\n/* TODO */\n\ttypedef void *mz_zip_streaming_extract_state_ptr;\n\tmz_zip_streaming_extract_state_ptr mz_zip_streaming_extract_begin(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags);\n\tuint64_t mz_zip_streaming_extract_get_size(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState);\n\tuint64_t mz_zip_streaming_extract_get_cur_ofs(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState);\n\tmz_bool mz_zip_streaming_extract_seek(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState, uint64_t new_ofs);\n\tsize_t mz_zip_streaming_extract_read(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState, void *pBuf, size_t buf_size);\n\tmz_bool mz_zip_streaming_extract_end(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState);\n#endif\n\n/* This function compares the archive's local headers, the optional local zip64 extended information block, and the optional descriptor following the compressed data vs. the data in the central directory. */\n/* It also validates that each file can be successfully uncompressed unless the MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY is specified. */\nmz_bool mz_zip_validate_file(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags);\n\n/* Validates an entire archive by calling mz_zip_validate_file() on each file. */\nmz_bool mz_zip_validate_archive(mz_zip_archive *pZip, mz_uint flags);\n\n/* Misc utils/helpers, valid for ZIP reading or writing */\nmz_bool mz_zip_validate_mem_archive(const void *pMem, size_t size, mz_uint flags, mz_zip_error *pErr);\nmz_bool mz_zip_validate_file_archive(const char *pFilename, mz_uint flags, mz_zip_error *pErr);\n\n/* Universal end function - calls either mz_zip_reader_end() or mz_zip_writer_end(). */\nmz_bool mz_zip_end(mz_zip_archive *pZip);\n\n/* -------- ZIP writing */\n\n#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS\n\n/* Inits a ZIP archive writer. */\n/*Set pZip->m_pWrite (and pZip->m_pIO_opaque) before calling mz_zip_writer_init or mz_zip_writer_init_v2*/\n/*The output is streamable, i.e. file_ofs in mz_file_write_func always increases only by n*/\nmz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size);\nmz_bool mz_zip_writer_init_v2(mz_zip_archive *pZip, mz_uint64 existing_size, mz_uint flags);\n\nmz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size);\nmz_bool mz_zip_writer_init_heap_v2(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size, mz_uint flags);\n\n#ifndef MINIZ_NO_STDIO\nmz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning);\nmz_bool mz_zip_writer_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning, mz_uint flags);\nmz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint flags);\n#endif\n\n/* Converts a ZIP archive reader object into a writer object, to allow efficient in-place file appends to occur on an existing archive. */\n/* For archives opened using mz_zip_reader_init_file, pFilename must be the archive's filename so it can be reopened for writing. If the file can't be reopened, mz_zip_reader_end() will be called. */\n/* For archives opened using mz_zip_reader_init_mem, the memory block must be growable using the realloc callback (which defaults to realloc unless you've overridden it). */\n/* Finally, for archives opened using mz_zip_reader_init, the mz_zip_archive's user provided m_pWrite function cannot be NULL. */\n/* Note: In-place archive modification is not recommended unless you know what you're doing, because if execution stops or something goes wrong before */\n/* the archive is finalized the file's central directory will be hosed. */\nmz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename);\nmz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags);\n\n/* Adds the contents of a memory buffer to an archive. These functions record the current local time into the archive. */\n/* To add a directory entry, call this method with an archive name ending in a forwardslash with an empty buffer. */\n/* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */\nmz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags);\n\n/* Like mz_zip_writer_add_mem(), except you can specify a file comment field, and optionally supply the function with already compressed data. */\n/* uncomp_size/uncomp_crc32 are only used if the MZ_ZIP_FLAG_COMPRESSED_DATA flag is specified. */\nmz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags,\n                                 mz_uint64 uncomp_size, mz_uint32 uncomp_crc32);\n\nmz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags,\n                                    mz_uint64 uncomp_size, mz_uint32 uncomp_crc32, MZ_TIME_T *last_modified, const char *user_extra_data_local, mz_uint user_extra_data_local_len,\n                                    const char *user_extra_data_central, mz_uint user_extra_data_central_len);\n\n/* Adds the contents of a file to an archive. This function also records the disk file's modified time into the archive. */\n/* File data is supplied via a read callback function. User mz_zip_writer_add_(c)file to add a file directly.*/\nmz_bool mz_zip_writer_add_read_buf_callback(mz_zip_archive *pZip, const char *pArchive_name, mz_file_read_func read_callback, void* callback_opaque, mz_uint64 size_to_add,\n\tconst MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, const char *user_extra_data_local, mz_uint user_extra_data_local_len,\n\tconst char *user_extra_data_central, mz_uint user_extra_data_central_len);\n\n#ifndef MINIZ_NO_STDIO\n/* Adds the contents of a disk file to an archive. This function also records the disk file's modified time into the archive. */\n/* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */\nmz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags);\n\n/* Like mz_zip_writer_add_file(), except the file data is read from the specified FILE stream. */\nmz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 size_to_add,\n                                const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, const char *user_extra_data_local, mz_uint user_extra_data_local_len,\n                                const char *user_extra_data_central, mz_uint user_extra_data_central_len);\n#endif\n\n/* Adds a file to an archive by fully cloning the data from another archive. */\n/* This function fully clones the source file's compressed data (no recompression), along with its full filename, extra data (it may add or modify the zip64 local header extra data field), and the optional descriptor following the compressed data. */\nmz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint src_file_index);\n\n/* Finalizes the archive by writing the central directory records followed by the end of central directory record. */\n/* After an archive is finalized, the only valid call on the mz_zip_archive struct is mz_zip_writer_end(). */\n/* An archive must be manually finalized by calling this function for it to be valid. */\nmz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip);\n\n/* Finalizes a heap archive, returning a poiner to the heap block and its size. */\n/* The heap block will be allocated using the mz_zip_archive's alloc/realloc callbacks. */\nmz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **ppBuf, size_t *pSize);\n\n/* Ends archive writing, freeing all allocations, and closing the output file if mz_zip_writer_init_file() was used. */\n/* Note for the archive to be valid, it *must* have been finalized before ending (this function will not do it for you). */\nmz_bool mz_zip_writer_end(mz_zip_archive *pZip);\n\n/* -------- Misc. high-level helper functions: */\n\n/* mz_zip_add_mem_to_archive_file_in_place() efficiently (but not atomically) appends a memory blob to a ZIP archive. */\n/* Note this is NOT a fully safe operation. If it crashes or dies in some way your archive can be left in a screwed up state (without a central directory). */\n/* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */\n/* TODO: Perhaps add an option to leave the existing central dir in place in case the add dies? We could then truncate the file (so the old central dir would be at the end) if something goes wrong. */\nmz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags);\nmz_bool mz_zip_add_mem_to_archive_file_in_place_v2(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_zip_error *pErr);\n\n/* Reads a single file from an archive into a heap block. */\n/* If pComment is not NULL, only the file with the specified comment will be extracted. */\n/* Returns NULL on failure. */\nvoid *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags);\nvoid *mz_zip_extract_archive_file_to_heap_v2(const char *pZip_filename, const char *pArchive_name, const char *pComment, size_t *pSize, mz_uint flags, mz_zip_error *pErr);\n\n#endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS */\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* MINIZ_NO_ARCHIVE_APIS */\n"
  },
  {
    "path": "windows/CodePush/miniz/readme.md",
    "content": "## Miniz\n\nMiniz is a lossless, high performance data compression library in a single source file that implements the zlib (RFC 1950) and Deflate (RFC 1951) compressed data format specification standards. It supports the most commonly used functions exported by the zlib library, but is a completely independent implementation so zlib's licensing requirements do not apply. Miniz also contains simple to use functions for writing .PNG format image files and reading/writing/appending .ZIP format archives. Miniz's compression speed has been tuned to be comparable to zlib's, and it also has a specialized real-time compressor function designed to compare well against fastlz/minilzo.\n\n## Usage\n\nPlease use the files from the [releases page](https://github.com/richgel999/miniz/releases) in your projects. Do not use the git checkout directly! The different source and header files are [amalgamated](https://www.sqlite.org/amalgamation.html) into one `miniz.c`/`miniz.h` pair in a build step (`amalgamate.sh`). Include `miniz.c` and `miniz.h` in your project to use Miniz.\n\n## Features\n\n* MIT licensed\n* A portable, single source and header file library written in plain C. Tested with GCC, clang and Visual Studio.\n* Easily tuned and trimmed down by defines\n* A drop-in replacement for zlib's most used API's (tested in several open source projects that use zlib, such as libpng and libzip).\n* Fills a single threaded performance vs. compression ratio gap between several popular real-time compressors and zlib. For example, at level 1, miniz.c compresses around 5-9% better than minilzo, but is approx. 35% slower. At levels 2-9, miniz.c is designed to compare favorably against zlib's ratio and speed. See the miniz performance comparison page for example timings.\n* Not a block based compressor: miniz.c fully supports stream based processing using a coroutine-style implementation. The zlib-style API functions can be called a single byte at a time if that's all you've got.\n* Easy to use. The low-level compressor (tdefl) and decompressor (tinfl) have simple state structs which can be saved/restored as needed with simple memcpy's. The low-level codec API's don't use the heap in any way.\n* Entire inflater (including optional zlib header parsing and Adler-32 checking) is implemented in a single function as a coroutine, which is separately available in a small (~550 line) source file: miniz_tinfl.c\n* A fairly complete (but totally optional) set of .ZIP archive manipulation and extraction API's. The archive functionality is intended to solve common problems encountered in embedded, mobile, or game development situations. (The archive API's are purposely just powerful enough to write an entire archiver given a bit of additional higher-level logic.)\n\n## Known Problems\n\n* No support for encrypted archives. Not sure how useful this stuff is in practice.\n* Minimal documentation. The assumption is that the user is already familiar with the basic zlib API. I need to write an API wiki - for now I've tried to place key comments before each enum/API, and I've included 6 examples that demonstrate how to use the module's major features.\n\n## Special Thanks\n\nThanks to Alex Evans for the PNG writer function. Also, thanks to Paul Holden and Thorsten Scheuermann for feedback and testing, Matt Pritchard for all his encouragement, and Sean Barrett's various public domain libraries for inspiration (and encouraging me to write miniz.c in C, which was much more enjoyable and less painful than I thought it would be considering I've been programming in C++ for so long).\n\nThanks to Bruce Dawson for reporting a problem with the level_and_flags archive API parameter (which is fixed in v1.12) and general feedback, and Janez Zemva for indirectly encouraging me into writing more examples.\n\n## Patents\n\nI was recently asked if miniz avoids patent issues. miniz purposely uses the same core algorithms as the ones used by zlib. The compressor uses vanilla hash chaining as described [here](http://www.gzip.org/zlib/rfc-deflate.html#algorithm). Also see the [gzip FAQ](http://www.gzip.org/#faq11). In my opinion, if miniz falls prey to a patent attack then zlib/gzip are likely to be at serious risk too.\n\n\n[![Build Status](https://travis-ci.org/uroni/miniz.svg?branch=master)](https://travis-ci.org/uroni/miniz)\n"
  },
  {
    "path": "windows/CodePush/packages.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<packages>\n  <package id=\"Microsoft.Windows.CppWinRT\" version=\"2.0.200615.7\" targetFramework=\"native\" />\n</packages>\n"
  },
  {
    "path": "windows/CodePush/pch.cpp",
    "content": "﻿#include \"pch.h\"\n"
  },
  {
    "path": "windows/CodePush/pch.h",
    "content": "﻿#pragma once\n#include <unknwn.h>\n#include <winrt/Windows.Foundation.h>\n#include <winrt/Windows.Foundation.Collections.h>\n"
  },
  {
    "path": "windows/Directory.Build.props",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project>\n  <PropertyGroup>\n    <!-- We use the CodePushDemoAppCpp example for module development and testing -->\n    <ReactNativeWindowsDir Condition=\"'$(SolutionName)' == 'CodePushDemoAppCpp' and Exists('$(SolutionDir)\\..\\node_modules\\react-native-windows\\package.json')\">$([MSBuild]::NormalizeDirectory('$(SolutionDir)\\..\\node_modules\\react-native-windows\\'))</ReactNativeWindowsDir>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "windows-legacy/.gitignore",
    "content": "*AppPackages*\n*BundleArtifacts*\n*ReactAssets*\n\n#OS junk files\n[Tt]humbs.db\n*.DS_Store\n\n#Visual Studio files\n*.[Oo]bj\n*.user\n*.aps\n*.pch\n*.vspscc\n*.vssscc\n*_i.c\n*_p.c\n*.ncb\n*.suo\n*.tlb\n*.tlh\n*.bak\n*.[Cc]ache\n*.ilk\n*.log\n*.lib\n*.sbr\n*.sdf\n*.opensdf\n*.opendb\n*.unsuccessfulbuild\nipch/\n[Oo]bj/\n[Bb]in\n[Dd]ebug*/\n[Rr]elease*/\nAnkh.NoLoad\n\n#MonoDevelop\n*.pidb\n*.userprefs\n\n#Tooling\n_ReSharper*/\n*.resharper\n[Tt]est[Rr]esult*\n*.sass-cache\n\n#Project files\n[Bb]uild/\n\n#Subversion files\n.svn\n\n# Office Temp Files\n~$*\n\n# vim Temp Files\n*~\n\n#NuGet\npackages/\n*.nupkg\n\n#ncrunch\n*ncrunch*\n*crunch*.local.xml\n\n# visual studio database projects\n*.dbmdl\n\n#Test files\n*.testsettings\n\n#Other files\n*.DotSettings\n.vs/\n*project.lock.json\n"
  },
  {
    "path": "windows-legacy/.npmignore",
    "content": "# Make sure we don't publish build artifacts to NPM\nARM/\nDebug/\nx64/\nx86/\nbin/\nobj/\n.vs/\n"
  },
  {
    "path": "windows-legacy/CodePush/.gitignore",
    "content": "## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n\n# User-specific files\n*.suo\n*.user\n*.userosscache\n*.sln.docstates\n\n# User-specific files (MonoDevelop/Xamarin Studio)\n*.userprefs\n\n# Build results\n[Dd]ebug/\n[Dd]ebugPublic/\n[Rr]elease/\n[Rr]eleases/\nx64/\nx86/\nbld/\n[Bb]in/\n[Oo]bj/\n[Ll]og/\n\n# Visual Studio 2015 cache/options directory\n.vs/\n# Uncomment if you have tasks that create the project's static files in wwwroot\n#wwwroot/\n\n# MSTest test Results\n[Tt]est[Rr]esult*/\n[Bb]uild[Ll]og.*\n\n# NUNIT\n*.VisualState.xml\nTestResult.xml\n\n# Build Results of an ATL Project\n[Dd]ebugPS/\n[Rr]eleasePS/\ndlldata.c\n\n# DNX\nproject.lock.json\nartifacts/\n\n*_i.c\n*_p.c\n*_i.h\n*.ilk\n*.meta\n*.obj\n*.pch\n*.pdb\n*.pgc\n*.pgd\n*.rsp\n*.sbr\n*.tlb\n*.tli\n*.tlh\n*.tmp\n*.tmp_proj\n*.log\n*.vspscc\n*.vssscc\n.builds\n*.pidb\n*.svclog\n*.scc\n\n# Chutzpah Test files\n_Chutzpah*\n\n# Visual C++ cache files\nipch/\n*.aps\n*.ncb\n*.opendb\n*.opensdf\n*.sdf\n*.cachefile\n*.VC.db\n*.VC.VC.opendb\n\n# Visual Studio profiler\n*.psess\n*.vsp\n*.vspx\n*.sap\n\n# TFS 2012 Local Workspace\n$tf/\n\n# Guidance Automation Toolkit\n*.gpState\n\n# ReSharper is a .NET coding add-in\n_ReSharper*/\n*.[Rr]e[Ss]harper\n*.DotSettings.user\n\n# JustCode is a .NET coding add-in\n.JustCode\n\n# TeamCity is a build add-in\n_TeamCity*\n\n# DotCover is a Code Coverage Tool\n*.dotCover\n\n# NCrunch\n_NCrunch_*\n.*crunch*.local.xml\nnCrunchTemp_*\n\n# MightyMoose\n*.mm.*\nAutoTest.Net/\n\n# Web workbench (sass)\n.sass-cache/\n\n# Installshield output folder\n[Ee]xpress/\n\n# DocProject is a documentation generator add-in\nDocProject/buildhelp/\nDocProject/Help/*.HxT\nDocProject/Help/*.HxC\nDocProject/Help/*.hhc\nDocProject/Help/*.hhk\nDocProject/Help/*.hhp\nDocProject/Help/Html2\nDocProject/Help/html\n\n# Click-Once directory\npublish/\n\n# Publish Web Output\n*.[Pp]ublish.xml\n*.azurePubxml\n# TODO: Comment the next line if you want to checkin your web deploy settings\n# but database connection strings (with potential passwords) will be unencrypted\n*.pubxml\n*.publishproj\n\n# Microsoft Azure Web App publish settings. Comment the next line if you want to\n# checkin your Azure Web App publish settings, but sensitive information contained\n# in these scripts will be unencrypted\nPublishScripts/\n\n# NuGet Packages\n*.nupkg\n# The packages folder can be ignored because of Package Restore\n**/packages/*\n# except build/, which is used as an MSBuild target.\n!**/packages/build/\n# Uncomment if necessary however generally it will be regenerated when needed\n#!**/packages/repositories.config\n# NuGet v3's project.json files produces more ignoreable files\n*.nuget.props\n*.nuget.targets\n\n# Microsoft Azure Build Output\ncsx/\n*.build.csdef\n\n# Microsoft Azure Emulator\necf/\nrcf/\n\n# Windows Store app package directories and files\nAppPackages/\nBundleArtifacts/\nPackage.StoreAssociation.xml\n_pkginfo.txt\n\n# Visual Studio cache files\n# files ending in .cache can be ignored\n*.[Cc]ache\n# but keep track of directories ending in .cache\n!*.[Cc]ache/\n\n# Others\nClientBin/\n~$*\n*~\n*.dbmdl\n*.dbproj.schemaview\n*.pfx\n*.publishsettings\nnode_modules/\norleans.codegen.cs\n\n# Since there are multiple workflows, uncomment next line to ignore bower_components\n# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)\n#bower_components/\n\n# RIA/Silverlight projects\nGenerated_Code/\n\n# Backup & report files from converting an old project file\n# to a newer Visual Studio version. Backup files are not needed,\n# because we have git ;-)\n_UpgradeReport_Files/\nBackup*/\nUpgradeLog*.XML\nUpgradeLog*.htm\n\n# SQL Server files\n*.mdf\n*.ldf\n\n# Business Intelligence projects\n*.rdl.data\n*.bim.layout\n*.bim_*.settings\n\n# Microsoft Fakes\nFakesAssemblies/\n\n# GhostDoc plugin setting file\n*.GhostDoc.xml\n\n# Node.js Tools for Visual Studio\n.ntvs_analysis.dat\n\n# Visual Studio 6 build log\n*.plg\n\n# Visual Studio 6 workspace options file\n*.opt\n\n# Visual Studio LightSwitch build output\n**/*.HTMLClient/GeneratedArtifacts\n**/*.DesktopClient/GeneratedArtifacts\n**/*.DesktopClient/ModelManifest.xml\n**/*.Server/GeneratedArtifacts\n**/*.Server/ModelManifest.xml\n_Pvt_Extensions\n\n# Paket dependency manager\n.paket/paket.exe\npaket-files/\n\n# FAKE - F# Make\n.fake/\n\n# JetBrains Rider\n.idea/\n*.sln.iml"
  },
  {
    "path": "windows-legacy/CodePush/CodePush.csproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"14.0\" DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <Import Project=\"$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props\" Condition=\"Exists('$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props')\" />\n  <PropertyGroup>\n    <Configuration Condition=\" '$(Configuration)' == '' \">Debug</Configuration>\n    <Platform Condition=\" '$(Platform)' == '' \">AnyCPU</Platform>\n    <ProjectGuid>{446A85D9-55EB-4C7D-8B9D-448306C833D6}</ProjectGuid>\n    <OutputType>Library</OutputType>\n    <AppDesignerFolder>Properties</AppDesignerFolder>\n    <RootNamespace>CodePush</RootNamespace>\n    <AssemblyName>CodePush</AssemblyName>\n    <DefaultLanguage>en-US</DefaultLanguage>\n    <TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>\n    <TargetPlatformVersion>10.0.14393.0</TargetPlatformVersion>\n    <TargetPlatformMinVersion>10.0.14393.0</TargetPlatformMinVersion>\n    <MinimumVisualStudioVersion>14</MinimumVisualStudioVersion>\n    <FileAlignment>512</FileAlignment>\n    <ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x86'\">\n    <PlatformTarget>x86</PlatformTarget>\n    <DebugSymbols>true</DebugSymbols>\n    <OutputPath>bin\\x86\\Debug\\</OutputPath>\n    <DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>\n    <NoWarn>;2008</NoWarn>\n    <DebugType>full</DebugType>\n    <PlatformTarget>x86</PlatformTarget>\n    <UseVSHostingProcess>false</UseVSHostingProcess>\n    <ErrorReport>prompt</ErrorReport>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|x86'\">\n    <PlatformTarget>x86</PlatformTarget>\n    <OutputPath>bin\\x86\\Release\\</OutputPath>\n    <DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>\n    <Optimize>true</Optimize>\n    <NoWarn>;2008</NoWarn>\n    <DebugType>pdbonly</DebugType>\n    <PlatformTarget>x86</PlatformTarget>\n    <UseVSHostingProcess>false</UseVSHostingProcess>\n    <ErrorReport>prompt</ErrorReport>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|ARM'\">\n    <PlatformTarget>ARM</PlatformTarget>\n    <DebugSymbols>true</DebugSymbols>\n    <OutputPath>bin\\ARM\\Debug\\</OutputPath>\n    <DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>\n    <NoWarn>;2008</NoWarn>\n    <DebugType>full</DebugType>\n    <PlatformTarget>ARM</PlatformTarget>\n    <UseVSHostingProcess>false</UseVSHostingProcess>\n    <ErrorReport>prompt</ErrorReport>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|ARM'\">\n    <PlatformTarget>ARM</PlatformTarget>\n    <OutputPath>bin\\ARM\\Release\\</OutputPath>\n    <DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>\n    <Optimize>true</Optimize>\n    <NoWarn>;2008</NoWarn>\n    <DebugType>pdbonly</DebugType>\n    <PlatformTarget>ARM</PlatformTarget>\n    <UseVSHostingProcess>false</UseVSHostingProcess>\n    <ErrorReport>prompt</ErrorReport>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x64'\">\n    <PlatformTarget>x64</PlatformTarget>\n    <DebugSymbols>true</DebugSymbols>\n    <OutputPath>bin\\x64\\Debug\\</OutputPath>\n    <DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>\n    <NoWarn>;2008</NoWarn>\n    <DebugType>full</DebugType>\n    <PlatformTarget>x64</PlatformTarget>\n    <UseVSHostingProcess>false</UseVSHostingProcess>\n    <ErrorReport>prompt</ErrorReport>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|x64'\">\n    <PlatformTarget>x64</PlatformTarget>\n    <OutputPath>bin\\x64\\Release\\</OutputPath>\n    <DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>\n    <Optimize>true</Optimize>\n    <NoWarn>;2008</NoWarn>\n    <DebugType>pdbonly</DebugType>\n    <PlatformTarget>x64</PlatformTarget>\n    <UseVSHostingProcess>false</UseVSHostingProcess>\n    <ErrorReport>prompt</ErrorReport>\n  </PropertyGroup>\n  <PropertyGroup>\n    <RestoreProjectStyle>PackageReference</RestoreProjectStyle>\n  </PropertyGroup>\n  <ItemGroup>\n    <Compile Include=\"UpdateManager.cs\" />\n    <Compile Include=\"UpdateUtils.cs\" />\n    <Compile Include=\"CodePushUtils.cs\" />\n    <Compile Include=\"FileUtils.cs\" />\n    <Compile Include=\"Properties\\AssemblyInfo.cs\" />\n    <EmbeddedResource Include=\"Properties\\CodePush.rd.xml\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\..\\react-native-windows\\ReactWindows\\ReactNative\\ReactNative.csproj\">\n      <Project>{c7673ad5-e3aa-468c-a5fd-fa38154e205c}</Project>\n      <Name>ReactNative</Name>\n    </ProjectReference>\n  </ItemGroup>\n  <ItemGroup>\n    <PackageReference Include=\"Newtonsoft.Json\">\n      <Version>13.0.1</Version>\n    </PackageReference>\n    <PackageReference Include=\"Microsoft.NETCore.UniversalWindowsPlatform\">\n      <Version>6.0.6</Version>\n    </PackageReference>\n  </ItemGroup>\n  <ItemGroup>\n    <SDKReference Include=\"WindowsMobile, Version=10.0.14393.0\">\n      <Name>Windows Mobile Extensions for the UWP</Name>\n    </SDKReference>\n  </ItemGroup>\n  <Import Project=\"..\\CodePush.Shared\\CodePush.Shared.projitems\" Label=\"Shared\" />\n  <PropertyGroup Condition=\" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '14.0' \">\n    <VisualStudioVersion>14.0</VisualStudioVersion>\n  </PropertyGroup>\n  <Import Project=\"$(MSBuildExtensionsPath)\\Microsoft\\WindowsXaml\\v$(VisualStudioVersion)\\Microsoft.Windows.UI.Xaml.CSharp.targets\" />\n  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. \n       Other similar extension points exist, see Microsoft.Common.targets.\n  <Target Name=\"BeforeBuild\">\n  </Target>\n  <Target Name=\"AfterBuild\">\n  </Target>\n  -->\n</Project>"
  },
  {
    "path": "windows-legacy/CodePush/CodePushUtils.cs",
    "content": "﻿using Newtonsoft.Json.Linq;\nusing System;\nusing System.Threading.Tasks;\nusing Windows.Storage;\nusing Windows.Storage.Streams;\nusing Windows.System.Profile;\n\nnamespace CodePush.ReactNative\n{\n    internal partial class CodePushUtils\n    {\n        internal static string GetFileBundlePrefix()\n        {\n            return CodePushConstants.FileBundlePrefix;\n        }\n\n        internal async static Task<JObject> GetJObjectFromFileAsync(StorageFile file)\n        {\n            string jsonString = await FileIO.ReadTextAsync(file).AsTask().ConfigureAwait(false);\n            if (jsonString.Length == 0)\n            {\n                return new JObject();\n            }\n\n            try\n            {\n                return JObject.Parse(jsonString);\n            }\n            catch (Exception)\n            {\n                return null;\n            }\n        }\n\n        static string GetDeviceIdImpl()\n        {\n            HardwareToken token = HardwareIdentification.GetPackageSpecificToken(null);\n            IBuffer hardwareId = token.Id;\n            var dataReader = DataReader.FromBuffer(hardwareId);\n\n            var bytes = new byte[hardwareId.Length];\n            dataReader.ReadBytes(bytes);\n\n            return BitConverter.ToString(bytes);\n        }\n    }\n}\n"
  },
  {
    "path": "windows-legacy/CodePush/FileUtils.cs",
    "content": "﻿using System;\nusing System.Threading.Tasks;\nusing Windows.Storage;\n\nnamespace CodePush.ReactNative\n{\n    internal class FileUtils\n    {\n        internal async static Task MergeFoldersAsync(StorageFolder source, StorageFolder target)\n        {\n            foreach (StorageFile sourceFile in await source.GetFilesAsync().AsTask().ConfigureAwait(false))\n            {\n                await sourceFile.CopyAndReplaceAsync(await target.CreateFileAsync(sourceFile.Name, CreationCollisionOption.OpenIfExists).AsTask().ConfigureAwait(false)).AsTask().ConfigureAwait(false);\n            }\n            \n            foreach (StorageFolder sourceDirectory in await source.GetFoldersAsync().AsTask().ConfigureAwait(false))\n            {\n                StorageFolder nextTargetSubDir = await target.CreateFolderAsync(sourceDirectory.Name, CreationCollisionOption.OpenIfExists).AsTask().ConfigureAwait(false);\n                await MergeFoldersAsync(sourceDirectory, nextTargetSubDir).ConfigureAwait(false);\n            }\n        }\n\n        internal async static Task ClearReactDevBundleCacheAsync()\n        {\n            var devBundleCacheFile = (StorageFile)await ApplicationData.Current.LocalFolder.TryGetItemAsync(CodePushConstants.ReactDevBundleCacheFileName).AsTask().ConfigureAwait(false);\n            if (devBundleCacheFile != null)\n            {\n                await devBundleCacheFile.DeleteAsync().AsTask().ConfigureAwait(false);\n            }\n        }\n\n        internal async static Task<long> GetBinaryResourcesModifiedTimeAsync(string fileName)\n        {\n            var assetJSBundleFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri(CodePushConstants.AssetsBundlePrefix + fileName)).AsTask().ConfigureAwait(false);\n            var fileProperties = await assetJSBundleFile.GetBasicPropertiesAsync().AsTask().ConfigureAwait(false);\n            return fileProperties.DateModified.ToUnixTimeMilliseconds();\n        }\n\n    }\n}\n"
  },
  {
    "path": "windows-legacy/CodePush/Properties/AssemblyInfo.cs",
    "content": "﻿using System.Reflection;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\n\n// General Information about an assembly is controlled through the following \n// set of attributes. Change these attribute values to modify the information\n// associated with an assembly.\n[assembly: AssemblyTitle(\"CodePush\")]\n[assembly: AssemblyDescription(\"\")]\n[assembly: AssemblyConfiguration(\"\")]\n[assembly: AssemblyCompany(\"\")]\n[assembly: AssemblyProduct(\"CodePush\")]\n[assembly: AssemblyCopyright(\"Copyright ©  2016\")]\n[assembly: AssemblyTrademark(\"\")]\n[assembly: AssemblyCulture(\"\")]\n\n// Version information for an assembly consists of the following four values:\n//\n//      Major Version\n//      Minor Version \n//      Build Number\n//      Revision\n//\n// You can specify all the values or you can default the Build and Revision Numbers \n// by using the '*' as shown below:\n// [assembly: AssemblyVersion(\"1.0.*\")]\n[assembly: AssemblyVersion(\"1.0.0.0\")]\n[assembly: AssemblyFileVersion(\"1.0.0.0\")]\n[assembly: ComVisible(false)]"
  },
  {
    "path": "windows-legacy/CodePush/Properties/CodePush.rd.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n    This file contains Runtime Directives, specifications about types your application accesses\n    through reflection and other dynamic code patterns. Runtime Directives are used to control the\n    .NET Native optimizer and ensure that it does not remove code accessed by your library. If your\n    library does not do any reflection, then you generally do not need to edit this file. However,\n    if your library reflects over types, especially types passed to it or derived from its types,\n    then you should write Runtime Directives.\n\n    The most common use of reflection in libraries is to discover information about types passed\n    to the library. Runtime Directives have three ways to express requirements on types passed to\n    your library.\n\n    1.  Parameter, GenericParameter, TypeParameter, TypeEnumerableParameter\n        Use these directives to reflect over types passed as a parameter.\n\n    2.  SubTypes\n        Use a SubTypes directive to reflect over types derived from another type.\n\n    3.  AttributeImplies\n        Use an AttributeImplies directive to indicate that your library needs to reflect over\n        types or methods decorated with an attribute.\n\n    For more information on writing Runtime Directives for libraries, please visit\n    http://go.microsoft.com/fwlink/?LinkID=391919\n-->\n<Directives xmlns=\"http://schemas.microsoft.com/netfx/2013/01/metadata\">\n  <Library Name=\"CodePush\">\n\n  \t<!-- add directives for your library here -->\n\n  </Library>\n</Directives>\n"
  },
  {
    "path": "windows-legacy/CodePush/UpdateManager.cs",
    "content": "﻿using Newtonsoft.Json;\nusing Newtonsoft.Json.Linq;\nusing System;\nusing System.IO;\nusing System.IO.Compression;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Windows.Storage;\nusing Windows.Storage.Streams;\nusing Windows.Web.Http;\n\nnamespace CodePush.ReactNative\n{\n    internal class UpdateManager\n    {\n        #region Internal methods\n\n        internal async Task ClearUpdatesAsync()\n        {\n            await (await GetCodePushFolderAsync().ConfigureAwait(false)).DeleteAsync().AsTask().ConfigureAwait(false);\n        }\n\n        internal async Task DownloadPackageAsync(JObject updatePackage, string expectedBundleFileName, Progress<HttpProgress> downloadProgress)\n        {\n            // Using its hash, get the folder where the new update will be saved\n            StorageFolder codePushFolder = await GetCodePushFolderAsync().ConfigureAwait(false);\n            var newUpdateHash = (string)updatePackage[CodePushConstants.PackageHashKey];\n            StorageFolder newUpdateFolder = await GetPackageFolderAsync(newUpdateHash, false).ConfigureAwait(false);\n            if (newUpdateFolder != null)\n            {\n                // This removes any stale data in newUpdateFolder that could have been left\n                // uncleared due to a crash or error during the download or install process.\n                await newUpdateFolder.DeleteAsync().AsTask().ConfigureAwait(false);\n            }\n\n            newUpdateFolder = await GetPackageFolderAsync(newUpdateHash, true).ConfigureAwait(false);\n            StorageFile newUpdateMetadataFile = await newUpdateFolder.CreateFileAsync(CodePushConstants.PackageFileName).AsTask().ConfigureAwait(false);\n            var downloadUrlString = (string)updatePackage[CodePushConstants.DownloadUrlKey];\n            StorageFile downloadFile = await GetDownloadFileAsync().ConfigureAwait(false);\n            var downloadUri = new Uri(downloadUrlString);\n\n            // Download the file and send progress event asynchronously\n            var request = new HttpRequestMessage(HttpMethod.Get, downloadUri);\n            var client = new HttpClient();\n            var cancellationTokenSource = new CancellationTokenSource();\n            using (HttpResponseMessage response = await client.SendRequestAsync(request).AsTask(cancellationTokenSource.Token, downloadProgress).ConfigureAwait(false))\n            using (IInputStream inputStream = await response.Content.ReadAsInputStreamAsync().AsTask().ConfigureAwait(false))\n            using (IRandomAccessStream downloadFileStream = await downloadFile.OpenAsync(FileAccessMode.ReadWrite).AsTask().ConfigureAwait(false))\n            {\n                await RandomAccessStream.CopyAsync(inputStream, downloadFileStream).AsTask().ConfigureAwait(false);\n            }\n\n            try\n            {\n                // Unzip the downloaded file and then delete the zip\n                StorageFolder unzippedFolder = await CreateUnzippedFolderAsync().ConfigureAwait(false);\n                ZipFile.ExtractToDirectory(downloadFile.Path, unzippedFolder.Path);\n                await downloadFile.DeleteAsync().AsTask().ConfigureAwait(false);\n\n                // Merge contents with current update based on the manifest\n                StorageFile diffManifestFile = (StorageFile)await unzippedFolder.TryGetItemAsync(CodePushConstants.DiffManifestFileName).AsTask().ConfigureAwait(false);\n                if (diffManifestFile != null)\n                {\n                    StorageFolder currentPackageFolder = await GetCurrentPackageFolderAsync().ConfigureAwait(false);\n                    if (currentPackageFolder == null)\n                    {\n                        throw new InvalidDataException(\"Received a diff update, but there is no current version to diff against.\");\n                    }\n\n                    await UpdateUtils.CopyNecessaryFilesFromCurrentPackageAsync(diffManifestFile, currentPackageFolder, newUpdateFolder).ConfigureAwait(false);\n                    await diffManifestFile.DeleteAsync().AsTask().ConfigureAwait(false);\n                }\n\n                await FileUtils.MergeFoldersAsync(unzippedFolder, newUpdateFolder).ConfigureAwait(false);\n                await unzippedFolder.DeleteAsync().AsTask().ConfigureAwait(false);\n\n                // For zip updates, we need to find the relative path to the jsBundle and save it in the\n                // metadata so that we can find and run it easily the next time.\n                string relativeBundlePath = await UpdateUtils.FindJSBundleInUpdateContentsAsync(newUpdateFolder, expectedBundleFileName).ConfigureAwait(false);\n                if (relativeBundlePath == null)\n                {\n                    throw new InvalidDataException(\"Update is invalid - A JS bundle file named \\\"\" + expectedBundleFileName + \"\\\" could not be found within the downloaded contents. Please check that you are releasing your CodePush updates using the exact same JS bundle file name that was shipped with your app's binary.\");\n                }\n                else\n                {\n                    if (diffManifestFile != null)\n                    {\n                        // TODO verify hash for diff update\n                        // CodePushUpdateUtils.verifyHashForDiffUpdate(newUpdateFolderPath, newUpdateHash);\n                    }\n\n                    updatePackage[CodePushConstants.RelativeBundlePathKey] = relativeBundlePath;\n                }\n            }\n            catch (InvalidDataException)\n            {\n                // Downloaded file is not a zip, assume it is a jsbundle\n                await downloadFile.RenameAsync(expectedBundleFileName).AsTask().ConfigureAwait(false);\n                await downloadFile.MoveAsync(newUpdateFolder).AsTask().ConfigureAwait(false);\n            }\n            /*TODO: ZipFile.ExtractToDirectory is not reliable and throws exceptions if:\n            - path is too long\n            it needs to be handled\n            */\n\n            // Save metadata to the folder\n            await FileIO.WriteTextAsync(newUpdateMetadataFile, JsonConvert.SerializeObject(updatePackage)).AsTask().ConfigureAwait(false);\n        }\n\n        internal async Task<JObject> GetCurrentPackageAsync()\n        {\n            string packageHash = await GetCurrentPackageHashAsync().ConfigureAwait(false);\n            return packageHash == null ? null : await GetPackageAsync(packageHash).ConfigureAwait(false);\n        }\n\n        internal async Task<StorageFile> GetCurrentPackageBundleAsync(string bundleFileName)\n        {\n            StorageFolder packageFolder = await GetCurrentPackageFolderAsync().ConfigureAwait(false);\n            if (packageFolder == null)\n            {\n                return null;\n            }\n\n            JObject currentPackage = await GetCurrentPackageAsync().ConfigureAwait(false);\n            var relativeBundlePath = (string)currentPackage[CodePushConstants.RelativeBundlePathKey];\n\n            return relativeBundlePath == null\n                ? await packageFolder.GetFileAsync(bundleFileName).AsTask().ConfigureAwait(false)\n                : await packageFolder.GetFileAsync(relativeBundlePath).AsTask().ConfigureAwait(false);\n        }\n\n        internal async Task<string> GetCurrentPackageHashAsync()\n        {\n            JObject info = await GetCurrentPackageInfoAsync().ConfigureAwait(false);\n            string currentPackageShortHash = (string)info[CodePushConstants.CurrentPackageKey];\n            if (currentPackageShortHash == null)\n            {\n                return null;\n            }\n\n            JObject currentPackageMetadata = await GetPackageAsync(currentPackageShortHash).ConfigureAwait(false);\n            return currentPackageMetadata == null ? null : (string)currentPackageMetadata[CodePushConstants.PackageHashKey];\n        }\n\n        internal async Task<JObject> GetPackageAsync(string packageHash)\n        {\n            StorageFolder packageFolder = await GetPackageFolderAsync(packageHash, false).ConfigureAwait(false);\n            if (packageFolder == null)\n            {\n                return null;\n            }\n\n            try\n            {\n                StorageFile packageFile = await packageFolder.GetFileAsync(CodePushConstants.PackageFileName).AsTask().ConfigureAwait(false);\n                return await CodePushUtils.GetJObjectFromFileAsync(packageFile).ConfigureAwait(false);\n            }\n            catch (IOException)\n            {\n                return null;\n            }\n        }\n\n        internal async Task<StorageFolder> GetPackageFolderAsync(string packageHash, bool createIfNotExists)\n        {\n            StorageFolder codePushFolder = await GetCodePushFolderAsync().ConfigureAwait(false);\n            try\n            {\n                packageHash = ShortenPackageHash(packageHash);\n                return createIfNotExists\n                    ? await codePushFolder.CreateFolderAsync(packageHash, CreationCollisionOption.OpenIfExists).AsTask().ConfigureAwait(false)\n                    : await codePushFolder.GetFolderAsync(packageHash).AsTask().ConfigureAwait(false);\n            }\n            catch (FileNotFoundException)\n            {\n                return null;\n            }\n        }\n\n        internal async Task<JObject> GetPreviousPackageAsync()\n        {\n            string packageHash = await GetPreviousPackageHashAsync().ConfigureAwait(false);\n            return packageHash == null ? null : await GetPackageAsync(packageHash).ConfigureAwait(false);\n        }\n\n        internal async Task<string> GetPreviousPackageHashAsync()\n        {\n            JObject info = await GetCurrentPackageInfoAsync().ConfigureAwait(false);\n            string previousPackageShortHash = (string)info[CodePushConstants.PreviousPackageKey];\n            if (previousPackageShortHash == null)\n            {\n                return null;\n            }\n\n            JObject previousPackageMetadata = await GetPackageAsync(previousPackageShortHash).ConfigureAwait(false);\n            return previousPackageMetadata == null ? null : (string)previousPackageMetadata[CodePushConstants.PackageHashKey];\n        }\n\n        internal async Task InstallPackageAsync(JObject updatePackage, bool currentUpdateIsPending)\n        {\n            var packageHash = (string)updatePackage[CodePushConstants.PackageHashKey];\n            JObject info = await GetCurrentPackageInfoAsync().ConfigureAwait(false);\n            if (currentUpdateIsPending)\n            {\n                // Don't back up current update to the \"previous\" position because\n                // it is an unverified update which should not be rolled back to.\n                StorageFolder currentPackageFolder = await GetCurrentPackageFolderAsync().ConfigureAwait(false);\n                if (currentPackageFolder != null)\n                {\n                    await currentPackageFolder.DeleteAsync().AsTask().ConfigureAwait(false);\n                }\n            }\n            else\n            {\n                string previousPackageHash = await GetPreviousPackageHashAsync().ConfigureAwait(false);\n                if (previousPackageHash != null && !previousPackageHash.Equals(packageHash))\n                {\n                    StorageFolder previousPackageFolder = await GetPackageFolderAsync(previousPackageHash, false).ConfigureAwait(false);\n                    if (previousPackageFolder != null)\n                    {\n                        await previousPackageFolder.DeleteAsync().AsTask().ConfigureAwait(false);\n                    }\n                }\n\n                info[CodePushConstants.PreviousPackageKey] = info[CodePushConstants.CurrentPackageKey];\n            }\n\n            info[CodePushConstants.CurrentPackageKey] = packageHash;\n            await UpdateCurrentPackageInfoAsync(info).ConfigureAwait(false);\n        }\n\n        internal async Task RollbackPackageAsync()\n        {\n            JObject info = await GetCurrentPackageInfoAsync().ConfigureAwait(false);\n            StorageFolder currentPackageFolder = await GetCurrentPackageFolderAsync().ConfigureAwait(false);\n            if (currentPackageFolder != null)\n            {\n                await currentPackageFolder.DeleteAsync().AsTask().ConfigureAwait(false);\n            }\n\n            info[CodePushConstants.CurrentPackageKey] = info[CodePushConstants.PreviousPackageKey];\n            info[CodePushConstants.PreviousPackageKey] = null;\n            await UpdateCurrentPackageInfoAsync(info).ConfigureAwait(false);\n        }\n\n        #endregion\n\n        #region Private methods\n\n        private async Task<StorageFolder> GetCodePushFolderAsync()\n        {\n            return await ApplicationData.Current.LocalFolder.CreateFolderAsync(CodePushConstants.CodePushFolderPrefix, CreationCollisionOption.OpenIfExists).AsTask().ConfigureAwait(false);\n        }\n\n        private async Task<StorageFolder> GetCurrentPackageFolderAsync()\n        {\n            JObject info = await GetCurrentPackageInfoAsync().ConfigureAwait(false);\n            var packageHash = (string)info[CodePushConstants.CurrentPackageKey];\n            return packageHash == null ? null : await GetPackageFolderAsync(packageHash, false).ConfigureAwait(false);\n        }\n\n        private async Task<JObject> GetCurrentPackageInfoAsync()\n        {\n            StorageFile statusFile = await GetStatusFileAsync().ConfigureAwait(false);\n            return await CodePushUtils.GetJObjectFromFileAsync(statusFile).ConfigureAwait(false);\n        }\n\n        private async Task<StorageFile> GetDownloadFileAsync()\n        {\n            var codePushFolder = await GetCodePushFolderAsync().ConfigureAwait(false);\n            return await codePushFolder.CreateFileAsync(CodePushConstants.DownloadFileName, CreationCollisionOption.OpenIfExists).AsTask().ConfigureAwait(false);\n        }\n\n        private async Task<StorageFile> GetStatusFileAsync()\n        {\n            StorageFolder codePushFolder = await GetCodePushFolderAsync().ConfigureAwait(false);\n            return await codePushFolder.CreateFileAsync(CodePushConstants.StatusFileName, CreationCollisionOption.OpenIfExists).AsTask().ConfigureAwait(false);\n        }\n\n        private async Task<StorageFolder> CreateUnzippedFolderAsync()\n        {\n            StorageFolder codePushFolder = await GetCodePushFolderAsync().ConfigureAwait(false);\n            var unzippedFolder = await codePushFolder.TryGetItemAsync(CodePushConstants.UnzippedFolderName).AsTask().ConfigureAwait(false);\n\n            if (unzippedFolder != null)\n            {\n                await unzippedFolder.DeleteAsync();\n            }\n\n            return await codePushFolder.CreateFolderAsync(CodePushConstants.UnzippedFolderName, CreationCollisionOption.OpenIfExists).AsTask().ConfigureAwait(false);\n        }\n\n        private string ShortenPackageHash(string longPackageHash)\n        {\n            return longPackageHash.Substring(0, 8);\n        }\n\n        private async Task UpdateCurrentPackageInfoAsync(JObject packageInfo)\n        {\n            await FileIO.WriteTextAsync(await GetStatusFileAsync().ConfigureAwait(false), JsonConvert.SerializeObject(packageInfo)).AsTask().ConfigureAwait(false);\n        }\n\n        #endregion\n    }\n}\n"
  },
  {
    "path": "windows-legacy/CodePush/UpdateUtils.cs",
    "content": "﻿using Newtonsoft.Json.Linq;\nusing System;\nusing System.IO;\nusing System.Threading.Tasks;\nusing Windows.Storage;\n\nnamespace CodePush.ReactNative\n{\n    internal class UpdateUtils\n    {\n        internal async static Task CopyNecessaryFilesFromCurrentPackageAsync(StorageFile diffManifestFile, StorageFolder currentPackageFolder, StorageFolder newPackageFolder)\n        {\n            await FileUtils.MergeFoldersAsync(currentPackageFolder, newPackageFolder).ConfigureAwait(false);\n            JObject diffManifest = await CodePushUtils.GetJObjectFromFileAsync(diffManifestFile).ConfigureAwait(false);\n            var deletedFiles = (JArray)diffManifest[\"deletedFiles\"];\n            foreach (string fileNameToDelete in deletedFiles)\n            {\n                StorageFile fileToDelete = await newPackageFolder.GetFileAsync(fileNameToDelete.Replace(\"/\", \"\\\\\")).AsTask().ConfigureAwait(false);\n                await fileToDelete.DeleteAsync().AsTask().ConfigureAwait(false);\n            }\n        }\n\n        internal async static Task<string> FindJSBundleInUpdateContentsAsync(StorageFolder updateFolder, string expectedFileName)\n        {\n            foreach (StorageFile file in await updateFolder.GetFilesAsync().AsTask().ConfigureAwait(false))\n            {\n                string fileName = file.Name;\n                if (fileName.Equals(expectedFileName))\n                {\n                    return fileName;\n                }\n            }\n\n            foreach (StorageFolder folder in await updateFolder.GetFoldersAsync().AsTask().ConfigureAwait(false))\n            {\n                string mainBundlePathInSubFolder = await FindJSBundleInUpdateContentsAsync(folder, expectedFileName).ConfigureAwait(false);\n                if (mainBundlePathInSubFolder != null)\n                {\n                    return Path.Combine(folder.Name, mainBundlePathInSubFolder);\n                }\n            }\n\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "windows-legacy/CodePush.Net46/.gitignore",
    "content": "## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n\n# User-specific files\n*.suo\n*.user\n*.userosscache\n*.sln.docstates\n\n# User-specific files (MonoDevelop/Xamarin Studio)\n*.userprefs\n\n# Build results\n[Dd]ebug/\n[Dd]ebugPublic/\n[Rr]elease/\n[Rr]eleases/\nx64/\nx86/\nbld/\n[Bb]in/\n[Oo]bj/\n[Ll]og/\n\n# Visual Studio 2015 cache/options directory\n.vs/\n# Uncomment if you have tasks that create the project's static files in wwwroot\n#wwwroot/\n\n# MSTest test Results\n[Tt]est[Rr]esult*/\n[Bb]uild[Ll]og.*\n\n# NUNIT\n*.VisualState.xml\nTestResult.xml\n\n# Build Results of an ATL Project\n[Dd]ebugPS/\n[Rr]eleasePS/\ndlldata.c\n\n# DNX\nproject.lock.json\nartifacts/\n\n*_i.c\n*_p.c\n*_i.h\n*.ilk\n*.meta\n*.obj\n*.pch\n*.pdb\n*.pgc\n*.pgd\n*.rsp\n*.sbr\n*.tlb\n*.tli\n*.tlh\n*.tmp\n*.tmp_proj\n*.log\n*.vspscc\n*.vssscc\n.builds\n*.pidb\n*.svclog\n*.scc\n\n# Chutzpah Test files\n_Chutzpah*\n\n# Visual C++ cache files\nipch/\n*.aps\n*.ncb\n*.opendb\n*.opensdf\n*.sdf\n*.cachefile\n*.VC.db\n*.VC.VC.opendb\n\n# Visual Studio profiler\n*.psess\n*.vsp\n*.vspx\n*.sap\n\n# TFS 2012 Local Workspace\n$tf/\n\n# Guidance Automation Toolkit\n*.gpState\n\n# ReSharper is a .NET coding add-in\n_ReSharper*/\n*.[Rr]e[Ss]harper\n*.DotSettings.user\n\n# JustCode is a .NET coding add-in\n.JustCode\n\n# TeamCity is a build add-in\n_TeamCity*\n\n# DotCover is a Code Coverage Tool\n*.dotCover\n\n# NCrunch\n_NCrunch_*\n.*crunch*.local.xml\nnCrunchTemp_*\n\n# MightyMoose\n*.mm.*\nAutoTest.Net/\n\n# Web workbench (sass)\n.sass-cache/\n\n# Installshield output folder\n[Ee]xpress/\n\n# DocProject is a documentation generator add-in\nDocProject/buildhelp/\nDocProject/Help/*.HxT\nDocProject/Help/*.HxC\nDocProject/Help/*.hhc\nDocProject/Help/*.hhk\nDocProject/Help/*.hhp\nDocProject/Help/Html2\nDocProject/Help/html\n\n# Click-Once directory\npublish/\n\n# Publish Web Output\n*.[Pp]ublish.xml\n*.azurePubxml\n# TODO: Comment the next line if you want to checkin your web deploy settings\n# but database connection strings (with potential passwords) will be unencrypted\n*.pubxml\n*.publishproj\n\n# Microsoft Azure Web App publish settings. Comment the next line if you want to\n# checkin your Azure Web App publish settings, but sensitive information contained\n# in these scripts will be unencrypted\nPublishScripts/\n\n# NuGet Packages\n*.nupkg\n# The packages folder can be ignored because of Package Restore\n**/packages/*\n# except build/, which is used as an MSBuild target.\n!**/packages/build/\n# Uncomment if necessary however generally it will be regenerated when needed\n#!**/packages/repositories.config\n# NuGet v3's project.json files produces more ignoreable files\n*.nuget.props\n*.nuget.targets\n\n# Microsoft Azure Build Output\ncsx/\n*.build.csdef\n\n# Microsoft Azure Emulator\necf/\nrcf/\n\n# Windows Store app package directories and files\nAppPackages/\nBundleArtifacts/\nPackage.StoreAssociation.xml\n_pkginfo.txt\n\n# Visual Studio cache files\n# files ending in .cache can be ignored\n*.[Cc]ache\n# but keep track of directories ending in .cache\n!*.[Cc]ache/\n\n# Others\nClientBin/\n~$*\n*~\n*.dbmdl\n*.dbproj.schemaview\n*.pfx\n*.publishsettings\nnode_modules/\norleans.codegen.cs\n\n# Since there are multiple workflows, uncomment next line to ignore bower_components\n# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)\n#bower_components/\n\n# RIA/Silverlight projects\nGenerated_Code/\n\n# Backup & report files from converting an old project file\n# to a newer Visual Studio version. Backup files are not needed,\n# because we have git ;-)\n_UpgradeReport_Files/\nBackup*/\nUpgradeLog*.XML\nUpgradeLog*.htm\n\n# SQL Server files\n*.mdf\n*.ldf\n\n# Business Intelligence projects\n*.rdl.data\n*.bim.layout\n*.bim_*.settings\n\n# Microsoft Fakes\nFakesAssemblies/\n\n# GhostDoc plugin setting file\n*.GhostDoc.xml\n\n# Node.js Tools for Visual Studio\n.ntvs_analysis.dat\n\n# Visual Studio 6 build log\n*.plg\n\n# Visual Studio 6 workspace options file\n*.opt\n\n# Visual Studio LightSwitch build output\n**/*.HTMLClient/GeneratedArtifacts\n**/*.DesktopClient/GeneratedArtifacts\n**/*.DesktopClient/ModelManifest.xml\n**/*.Server/GeneratedArtifacts\n**/*.Server/ModelManifest.xml\n_Pvt_Extensions\n\n# Paket dependency manager\n.paket/paket.exe\npaket-files/\n\n# FAKE - F# Make\n.fake/\n\n# JetBrains Rider\n.idea/\n*.sln.iml"
  },
  {
    "path": "windows-legacy/CodePush.Net46/Adapters/Http/HttpProgress.cs",
    "content": "﻿using System;\n\nnamespace CodePush.Net46.Adapters.Http\n{\n    public enum HttpProgressStage\n    {\n        None = 0,\n        DetectingProxy = 10,\n        ResolvingName = 20,\n        ConnectingToServer = 30,\n        NegotiatingSsl = 40,\n        SendingHeaders = 50,\n        SendingContent = 60,\n        WaitingForResponse = 70,\n        ReceivingHeaders = 80,\n        ReceivingContent = 90\n    }\n\n    public struct HttpProgress\n    {\n        public UInt64 BytesReceived;\n        public UInt64 BytesSent;\n        public UInt32 Retries;\n        public HttpProgressStage Stage;\n        public UInt64? TotalBytesToReceive;\n        public UInt64? TotalBytesToSend;\n    }\n}\n"
  },
  {
    "path": "windows-legacy/CodePush.Net46/Adapters/Storage/ApplicationDataContainer.cs",
    "content": "﻿using CodePush.ReactNative;\nusing Newtonsoft.Json;\nusing Newtonsoft.Json.Linq;\nusing PCLStorage;\nusing System;\nusing System.Collections.Generic;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace CodePush.Net46.Adapters.Storage\n{\n    public enum ApplicationDataCreateDisposition\n    {\n        Always = 0,\n        Existing = 1\n    }\n\n    public class DictionaryWithDefault<TKey, TValue> : Dictionary<TKey, TValue>\n    {\n        TValue _default;\n        public TValue DefaultValue\n        {\n            get { return _default; }\n            set { _default = value; }\n        }\n        public DictionaryWithDefault() : base() { }\n        public DictionaryWithDefault(TValue defaultValue) : base()\n        {\n            _default = defaultValue;\n        }\n        public new TValue this[TKey key]\n        {\n            get\n            {\n                TValue t;\n                return base.TryGetValue(key, out t) ? t : _default;\n            }\n            set\n            {\n                base[key] = value;\n                DataChanged(this, null);\n            }\n        }\n\n        public new bool Remove(TKey key)\n        {\n            var found = base.Remove(key);\n            if (found)\n                DataChanged(this, null);\n\n            return found;\n        }\n\n        public event EventHandler DataChanged;\n\n    }\n\n    // A naive implementation of Windows.Storage.ApplicationDataContainer\n    public class ApplicationDataContainer\n    {\n        public DictionaryWithDefault<string, string> Values;\n        private readonly SemaphoreSlim mutex = new SemaphoreSlim(1, 1);\n\n        const string STORAGE_NAME = \"AppStorage.data\";\n        string storageFileName = null;\n\n        public ApplicationDataContainer(string name = STORAGE_NAME)\n        {\n            storageFileName = name;\n            var storageFile = FileSystem.Current.LocalStorage.CreateFileAsync(storageFileName, CreationCollisionOption.OpenIfExists).Result;\n            var data = CodePushUtils.GetJObjectFromFileAsync(storageFile).Result;\n\n            if (data != null)\n            {\n                Values = data.ToObject<DictionaryWithDefault<string, string>>();\n            }\n            else\n            {\n                Values = new DictionaryWithDefault<string, string>();\n            }\n\n            Values.DataChanged += async (s, e) => await SaveAsync();\n        }\n\n        ~ApplicationDataContainer()\n        {\n            mutex.Dispose();\n        }\n\n        async Task SaveAsync()\n        {\n            await mutex.WaitAsync().ConfigureAwait(false);\n            var jobject = JObject.FromObject(Values);\n            var storageFile = await FileSystem.Current.LocalStorage.CreateFileAsync(storageFileName, CreationCollisionOption.OpenIfExists).ConfigureAwait(false);\n            await storageFile.WriteAllTextAsync(JsonConvert.SerializeObject(jobject)).ConfigureAwait(false);\n            mutex.Release();\n        }\n\n        public async Task DeleteAsync()\n        {\n            Values.Clear();\n            var storageFile = await FileSystem.Current.LocalStorage.CreateFileAsync(storageFileName, CreationCollisionOption.OpenIfExists).ConfigureAwait(false);\n            await storageFile.DeleteAsync().ConfigureAwait(false);\n        }\n    }\n}\n"
  },
  {
    "path": "windows-legacy/CodePush.Net46/CodePush.Net46.csproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"14.0\" DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <Import Project=\"$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props\" Condition=\"Exists('$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props')\" />\n  <PropertyGroup>\n    <Configuration Condition=\" '$(Configuration)' == '' \">Debug</Configuration>\n    <Platform Condition=\" '$(Platform)' == '' \">AnyCPU</Platform>\n    <ProjectGuid>{4DFE3F9F-5E15-4F17-8FD4-33FF0519348E}</ProjectGuid>\n    <OutputType>Library</OutputType>\n    <AppDesignerFolder>Properties</AppDesignerFolder>\n    <RootNamespace>CodePush.Net46</RootNamespace>\n    <AssemblyName>CodePush.Net46</AssemblyName>\n    <TargetFrameworkVersion>v4.6</TargetFrameworkVersion>\n    <FileAlignment>512</FileAlignment>\n    <TargetFrameworkProfile />\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x86'\">\n    <DebugSymbols>true</DebugSymbols>\n    <OutputPath>bin\\x86\\Debug\\</OutputPath>\n    <DefineConstants>DEBUG;TRACE</DefineConstants>\n    <DebugType>full</DebugType>\n    <PlatformTarget>x86</PlatformTarget>\n    <ErrorReport>prompt</ErrorReport>\n    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|x86'\">\n    <OutputPath>bin\\x86\\Release\\</OutputPath>\n    <DefineConstants>TRACE</DefineConstants>\n    <Optimize>true</Optimize>\n    <DebugType>pdbonly</DebugType>\n    <PlatformTarget>x86</PlatformTarget>\n    <ErrorReport>prompt</ErrorReport>\n    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x64'\">\n    <DebugSymbols>true</DebugSymbols>\n    <OutputPath>bin\\x64\\Debug\\</OutputPath>\n    <DefineConstants>DEBUG;TRACE</DefineConstants>\n    <DebugType>full</DebugType>\n    <PlatformTarget>x64</PlatformTarget>\n    <ErrorReport>prompt</ErrorReport>\n    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|x64'\">\n    <OutputPath>bin\\x64\\Release\\</OutputPath>\n    <DefineConstants>TRACE</DefineConstants>\n    <Optimize>true</Optimize>\n    <DebugType>pdbonly</DebugType>\n    <PlatformTarget>x64</PlatformTarget>\n    <ErrorReport>prompt</ErrorReport>\n    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>\n  </PropertyGroup>\n  <ItemGroup>\n    <Reference Include=\"Newtonsoft.Json, Version=13.0.1.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL\">\n      <HintPath>$(SolutionDir)\\packages\\Newtonsoft.Json.13.0.1\\lib\\net45\\Newtonsoft.Json.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"PCLStorage, Version=1.0.2.0, Culture=neutral, PublicKeyToken=286fe515a2c35b64, processorArchitecture=MSIL\">\n      <SpecificVersion>False</SpecificVersion>\n      <HintPath>$(SolutionDir)\\packages\\PCLStorage.1.0.2\\lib\\net45\\PCLStorage.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"PCLStorage.Abstractions, Version=1.0.2.0, Culture=neutral, PublicKeyToken=286fe515a2c35b64, processorArchitecture=MSIL\">\n      <SpecificVersion>False</SpecificVersion>\n      <HintPath>$(SolutionDir)\\packages\\PCLStorage.1.0.2\\lib\\net45\\PCLStorage.Abstractions.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System\" />\n    <Reference Include=\"System.Core\" />\n    <Reference Include=\"System.IO.Compression\" />\n    <Reference Include=\"System.IO.Compression.FileSystem\" />\n    <Reference Include=\"System.Management\" />\n    <Reference Include=\"System.Data.DataSetExtensions\" />\n    <Reference Include=\"System.Data\" />\n    <Reference Include=\"System.Net.Http\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Compile Include=\"Adapters\\Http\\HttpProgress.cs\" />\n    <Compile Include=\"Adapters\\Storage\\ApplicationDataContainer.cs\" />\n    <Compile Include=\"CodePushUtils.cs\" />\n    <Compile Include=\"FileUtils.cs\" />\n    <Compile Include=\"Properties\\AssemblyInfo.cs\" />\n    <Compile Include=\"UpdateManager.cs\" />\n    <Compile Include=\"UpdateUtils.cs\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"packages.config\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\..\\react-native-windows\\ReactWindows\\ReactNative.Net46\\ReactNative.Net46.csproj\">\n      <Project>{22cbff9c-fe36-43e8-a246-266c7635e662}</Project>\n      <Name>ReactNative.Net46</Name>\n    </ProjectReference>\n  </ItemGroup>\n  <Import Project=\"..\\CodePush.Shared\\CodePush.Shared.projitems\" Label=\"Shared\" />\n  <Import Project=\"$(MSBuildToolsPath)\\Microsoft.CSharp.targets\" />\n  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. \n       Other similar extension points exist, see Microsoft.Common.targets.\n  <Target Name=\"BeforeBuild\">\n  </Target>\n  <Target Name=\"AfterBuild\">\n  </Target>\n  -->\n</Project>"
  },
  {
    "path": "windows-legacy/CodePush.Net46/CodePushUtils.cs",
    "content": "﻿using Newtonsoft.Json.Linq;\nusing PCLStorage;\nusing System;\nusing System.Diagnostics;\nusing System.IO;\nusing System.Management;\nusing System.Threading.Tasks;\n\nnamespace CodePush.ReactNative\n{\n    internal partial class CodePushUtils\n    {\n        class ApplicationInfo\n        {\n            public ApplicationInfo()\n            {\n                var info = FileVersionInfo.GetVersionInfo(Environment.GetCommandLineArgs()[0]);\n                Version = $\"{info.FileMajorPart}.{info.FileMinorPart}.{info.FileBuildPart}\";\n                CompanyName = string.IsNullOrEmpty(info.CompanyName) ? info.ProductName : info.CompanyName;\n                ProductName = info.ProductName;\n            }\n\n            public string Version { private set; get; }\n            public string CompanyName { private set; get; }\n            public string ProductName { private set; get; }\n        }\n\n        static ApplicationInfo applicationInfo = new ApplicationInfo();\n        static string _bundlePath;\n\n        internal static string GetFileBundlePrefix()\n        {\n            // For Windows desktop application the prefix of a bundle is the full path to the folder where\n            // bundle should be installed.\n            //\n            // Desktop application can be installed at any location, the most popular are:\n            // - User local data folder, in this case the bundle can be stored in the same location and be\n            // unique for the user.\n            // - Program Files folder, in this case the application is unique for the system and will be shared\n            // amoung all users of the system, the bundle should be unique for the system as well.\n            // Commonly, user has no write access to Program Files folder or at least admin privileges have to been requested.\n            // In this case the bundle will be stored in ProgramData folder as it is recommended by MS.\n\n            if (!string.IsNullOrEmpty(_bundlePath))\n            {\n                return _bundlePath;\n            }\n\n            _bundlePath = GetAppFolder();\n\n            if (!HasWriteAccessToFolder(_bundlePath))\n            {\n                _bundlePath = $\"{Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), applicationInfo.CompanyName, applicationInfo.ProductName, applicationInfo.Version)}\\\\\";\n            }\n\n            return _bundlePath;\n        }\n\n        internal async static Task<JObject> GetJObjectFromFileAsync(IFile file)\n        {\n            string jsonString = await file.ReadAllTextAsync().ConfigureAwait(false);\n            if (jsonString.Length == 0)\n            {\n                return new JObject();\n            }\n\n            try\n            {\n                return JObject.Parse(jsonString);\n            }\n            catch (Exception)\n            {\n                return null;\n            }\n        }\n\n        static string GetDeviceIdImpl()\n        {\n            var mbId = GetSerialNumber();\n            var procId = GetProcId();\n\n            if (string.IsNullOrEmpty(procId))\n            {\n                procId = GetMAC();\n            }\n\n            return procId + '-' + mbId;\n        }\n\n        static string GetSerialNumber()\n        {\n            var mos = new ManagementObjectSearcher(\"SELECT * FROM Win32_BaseBoard\");\n            var moc = mos.Get();\n            var mbId = String.Empty;\n\n            foreach (ManagementObject mo in moc)\n            {\n                mbId = (string)mo[\"SerialNumber\"];\n                if (!string.IsNullOrEmpty(mbId))\n                    break;\n            }\n\n            return mbId;\n        }\n\n        static string GetProcId()\n        {\n            var mos = new ManagementObjectSearcher(\"Select * From Win32_processor\");\n            var moc = mos.Get();\n            var procId = string.Empty;\n\n            foreach (ManagementObject mo in moc)\n            {\n                procId = (string)mo[\"ProcessorID\"];\n                if (!string.IsNullOrEmpty(procId))\n                    break;\n            }\n            return procId;\n        }\n\n        static string GetMAC()\n        {\n            var mos = new ManagementObjectSearcher(\"Select * From Win32_NetworkAdapterConfiguration\");\n            var moc = mos.Get();\n            var mac = string.Empty;\n\n            foreach (ManagementObject mo in moc)\n            {\n                try\n                {\n                    if ((bool)mo[\"IPEnabled\"])\n                    {\n                        mac = (string)mo[\"MacAddress\"];\n                        break;\n                    }\n                }\n                catch (Exception)\n                {\n                }\n            }\n\n            return mac;\n        }\n\n        static bool HasWriteAccessToFolder(string path)\n        {\n            try\n            {\n                File.Open(Path.Combine(path, \".security-check\"), FileMode.OpenOrCreate).Close();\n                return true;\n            }\n            catch\n            {\n                return false;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "windows-legacy/CodePush.Net46/FileUtils.cs",
    "content": "﻿using PCLStorage;\nusing System;\nusing System.IO;\nusing System.Threading.Tasks;\n\nnamespace CodePush.ReactNative\n{\n    internal class FileUtils\n    {\n        internal async static Task MergeFoldersAsync(IFolder source, IFolder target)\n        {\n            foreach (IFile sourceFile in await source.GetFilesAsync().ConfigureAwait(false))\n            {\n                await CopyFileAsync(sourceFile.Path, Path.Combine(target.Path, sourceFile.Name)).ConfigureAwait(false);\n            }\n\n            foreach (IFolder sourceDirectory in await source.GetFoldersAsync().ConfigureAwait(false))\n            {\n                var nextTargetSubDir = await target.CreateFolderAsync(sourceDirectory.Name, CreationCollisionOption.OpenIfExists).ConfigureAwait(false);\n                await MergeFoldersAsync(sourceDirectory, nextTargetSubDir).ConfigureAwait(false);\n            }\n        }\n\n        internal async static Task ClearReactDevBundleCacheAsync()\n        {\n\n            if (await FileSystem.Current.LocalStorage.CheckExistsAsync(CodePushConstants.ReactDevBundleCacheFileName).ConfigureAwait(false) != ExistenceCheckResult.FileExists)\n                return;\n\n            var devBundleCacheFile = await FileSystem.Current.LocalStorage.GetFileAsync(CodePushConstants.ReactDevBundleCacheFileName).ConfigureAwait(false);\n            await devBundleCacheFile.DeleteAsync().ConfigureAwait(false);\n        }\n\n        internal static Task<long> GetBinaryResourcesModifiedTimeAsync(string fileName)\n        {\n            var pathToAssembly = CodePushUtils.GetAppFolder();\n            var pathToAssemblyResource = Path.Combine(pathToAssembly, CodePushConstants.AssetsBundlePrefix, fileName);\n            var lastUpdateTime = File.GetCreationTime(pathToAssemblyResource);\n\n            return Task.FromResult(new DateTimeOffset(lastUpdateTime).ToUnixTimeMilliseconds());\n        }\n\n        internal async static Task CopyFileAsync(string sourcePath, string destinationPath)\n        {\n            using (var source = File.Open(sourcePath, FileMode.Open, System.IO.FileAccess.Read))\n            {\n                using (var destination = File.Create(destinationPath)) // Replace if exists\n                {\n                    await source.CopyToAsync(destination);\n                }\n            }\n        }\n\n    }\n}\n"
  },
  {
    "path": "windows-legacy/CodePush.Net46/Properties/AssemblyInfo.cs",
    "content": "﻿using System.Reflection;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\n\n// General Information about an assembly is controlled through the following \n// set of attributes. Change these attribute values to modify the information\n// associated with an assembly.\n[assembly: AssemblyTitle(\"CodePush.Net46\")]\n[assembly: AssemblyDescription(\"\")]\n[assembly: AssemblyConfiguration(\"\")]\n[assembly: AssemblyCompany(\"\")]\n[assembly: AssemblyProduct(\"CodePush.Net46\")]\n[assembly: AssemblyCopyright(\"Copyright ©  2017\")]\n[assembly: AssemblyTrademark(\"\")]\n[assembly: AssemblyCulture(\"\")]\n\n// Setting ComVisible to false makes the types in this assembly not visible \n// to COM components.  If you need to access a type in this assembly from \n// COM, set the ComVisible attribute to true on that type.\n[assembly: ComVisible(false)]\n\n// The following GUID is for the ID of the typelib if this project is exposed to COM\n[assembly: Guid(\"4dfe3f9f-5e15-4f17-8fd4-33ff0519348e\")]\n\n// Version information for an assembly consists of the following four values:\n//\n//      Major Version\n//      Minor Version \n//      Build Number\n//      Revision\n//\n// You can specify all the values or you can default the Build and Revision Numbers \n// by using the '*' as shown below:\n// [assembly: AssemblyVersion(\"1.0.*\")]\n[assembly: AssemblyVersion(\"1.0.0.0\")]\n[assembly: AssemblyFileVersion(\"1.0.0.0\")]\n"
  },
  {
    "path": "windows-legacy/CodePush.Net46/UpdateManager.cs",
    "content": "﻿using CodePush.Net46.Adapters.Http;\nusing Newtonsoft.Json;\nusing Newtonsoft.Json.Linq;\nusing PCLStorage;\nusing System;\nusing System.IO;\nusing System.IO.Compression;\nusing System.Runtime.CompilerServices;\nusing System.Threading.Tasks;\n\nnamespace CodePush.ReactNative\n{\n    internal class UpdateManager\n    {\n        #region Internal methods\n\n        internal async Task ClearUpdatesAsync()\n        {\n            await (await UpdateUtils.GetCodePushFolderAsync().ConfigureAwait(false)).DeleteAsync().ConfigureAwait(false);\n        }\n\n        internal async Task DownloadPackageAsync(JObject updatePackage, string expectedBundleFileName, Progress<HttpProgress> downloadProgress)\n        {\n            // Using its hash, get the folder where the new update will be saved\n            var codePushFolder = await UpdateUtils.GetCodePushFolderAsync().ConfigureAwait(false);\n            var newUpdateHash = (string)updatePackage[CodePushConstants.PackageHashKey];\n            var newUpdateFolder = await GetPackageFolderAsync(newUpdateHash, false).ConfigureAwait(false);\n            if (newUpdateFolder != null)\n            {\n                // This removes any stale data in newUpdateFolder that could have been left\n                // uncleared due to a crash or error during the download or install process.\n                await newUpdateFolder.DeleteAsync().ConfigureAwait(false);\n            }\n\n            newUpdateFolder = await GetPackageFolderAsync(newUpdateHash, true).ConfigureAwait(false);\n            var newUpdateMetadataFile = await newUpdateFolder.CreateFileAsync(CodePushConstants.PackageFileName, CreationCollisionOption.ReplaceExisting).ConfigureAwait(false);\n            var downloadUrlString = (string)updatePackage[CodePushConstants.DownloadUrlKey];\n            var downloadFile = await GetDownloadFileAsync().ConfigureAwait(false);\n\n            await UpdateUtils.DownloadBundleAsync(downloadUrlString, downloadFile.Path, downloadProgress);\n\n            try\n            {\n                // Unzip the downloaded file and then delete the zip\n                var unzippedFolder = await CreateUnzippedFolderAsync().ConfigureAwait(false);\n                /**\n                 * TODO:\n                 *  1) ZipFile.ExtractToDirectory is not reliable and throws exception if:\n                 *      - path is too long (> 250 chars)\n                 *\n                 *  2) Un-zipping is quite long operation. Does it make sense for async?\n                 *  await UpdateUtils.UnzipBundleAsync(downloadFile.Path, unzippedFolder.Path);\n                 *\n                 *  Possible implementation\n                 *\n                 *  internal async static Task UnzipBundleAsync(string zipFileName, string targetDir)\n                 *  {\n                 *    await Task.Run(() =>\n                 *      {\n                 *        ZipFile.ExtractToDirectory(zipFileName, targetDir)\n                 *        return Task.CompletedTask;\n                 *      });\n                 *  }\n                */\n                ZipFile.ExtractToDirectory(downloadFile.Path, unzippedFolder.Path);\n                await downloadFile.DeleteAsync().ConfigureAwait(false);\n\n                // Merge contents with current update based on the manifest\n                IFile diffManifestFile = null;\n                try\n                {\n                    diffManifestFile = await unzippedFolder.GetFileAsync(CodePushConstants.DiffManifestFileName).ConfigureAwait(false);\n                }\n                catch (FileNotFoundException)\n                {\n                    //file may not be present in folder just skip it\n                }\n                if (diffManifestFile != null)\n                {\n                    var currentPackageFolder = await GetCurrentPackageFolderAsync().ConfigureAwait(false);\n                    if (currentPackageFolder == null)\n                    {\n                        throw new InvalidDataException(\"Received a diff update, but there is no current version to diff against.\");\n                    }\n\n                    await UpdateUtils.CopyNecessaryFilesFromCurrentPackageAsync(diffManifestFile, currentPackageFolder, newUpdateFolder).ConfigureAwait(false);\n                    await diffManifestFile.DeleteAsync().ConfigureAwait(false);\n                }\n\n                await FileUtils.MergeFoldersAsync(unzippedFolder, newUpdateFolder).ConfigureAwait(false);\n                await unzippedFolder.DeleteAsync().ConfigureAwait(false);\n\n                // For zip updates, we need to find the relative path to the jsBundle and save it in the\n                // metadata so that we can find and run it easily the next time.\n                var relativeBundlePath = await UpdateUtils.FindJSBundleInUpdateContentsAsync(newUpdateFolder, expectedBundleFileName).ConfigureAwait(false);\n                if (relativeBundlePath == null)\n                {\n                    throw new InvalidDataException(\"Update is invalid - A JS bundle file named \\\"\" + expectedBundleFileName + \"\\\" could not be found within the downloaded contents. Please check that you are releasing your CodePush updates using the exact same JS bundle file name that was shipped with your app's binary.\");\n                }\n                else\n                {\n                    if (diffManifestFile != null)\n                    {\n                        // TODO verify hash for diff update\n                        // CodePushUpdateUtils.verifyHashForDiffUpdate(newUpdateFolderPath, newUpdateHash);\n                    }\n\n                    updatePackage[CodePushConstants.RelativeBundlePathKey] = relativeBundlePath;\n                }\n            }\n            catch (InvalidDataException)\n            {\n                // Downloaded file is not a zip, assume it is a jsbundle\n                await downloadFile.RenameAsync(expectedBundleFileName).ConfigureAwait(false);\n                await downloadFile.MoveAsync(newUpdateFolder.Path, NameCollisionOption.ReplaceExisting).ConfigureAwait(false);\n            }\n\n            // Save metadata to the folder\n            await newUpdateMetadataFile.WriteAllTextAsync(JsonConvert.SerializeObject(updatePackage)).ConfigureAwait(false);\n        }\n\n        internal async Task<JObject> GetCurrentPackageAsync()\n        {\n            var packageHash = await GetCurrentPackageHashAsync().ConfigureAwait(false);\n            return packageHash == null ? null : await GetPackageAsync(packageHash).ConfigureAwait(false);\n        }\n\n        internal async Task<IFile> GetCurrentPackageBundleAsync(string bundleFileName)\n        {\n            var packageFolder = await GetCurrentPackageFolderAsync().ConfigureAwait(false);\n            if (packageFolder == null)\n            {\n                return null;\n            }\n\n            var currentPackage = await GetCurrentPackageAsync().ConfigureAwait(false);\n            var relativeBundlePath = (string)currentPackage[CodePushConstants.RelativeBundlePathKey];\n\n            return relativeBundlePath == null\n                ? await packageFolder.GetFileAsync(bundleFileName).ConfigureAwait(false)\n                : await packageFolder.GetFileAsync(relativeBundlePath).ConfigureAwait(false);\n        }\n\n        internal async Task<string> GetCurrentPackageHashAsync()\n        {\n            var info = await GetCurrentPackageInfoAsync().ConfigureAwait(false);\n            var currentPackageShortHash = (string)info[CodePushConstants.CurrentPackageKey];\n            if (currentPackageShortHash == null)\n            {\n                return null;\n            }\n\n            var currentPackageMetadata = await GetPackageAsync(currentPackageShortHash).ConfigureAwait(false);\n            return currentPackageMetadata == null ? null : (string)currentPackageMetadata[CodePushConstants.PackageHashKey];\n        }\n\n        internal async Task<JObject> GetPackageAsync(string packageHash)\n        {\n            var packageFolder = await GetPackageFolderAsync(packageHash, false).ConfigureAwait(false);\n            if (packageFolder == null)\n            {\n                return null;\n            }\n\n            try\n            {\n                var packageFile = await packageFolder.GetFileAsync(CodePushConstants.PackageFileName).ConfigureAwait(false);\n                return await CodePushUtils.GetJObjectFromFileAsync(packageFile).ConfigureAwait(false);\n            }\n            catch (IOException)\n            {\n                return null;\n            }\n        }\n\n        internal async Task<IFolder> GetPackageFolderAsync(string packageHash, bool createIfNotExists)\n        {\n            var codePushFolder = await UpdateUtils.GetCodePushFolderAsync().ConfigureAwait(false);\n            try\n            {\n                packageHash = ShortenPackageHash(packageHash);\n                return createIfNotExists\n                    ? await codePushFolder.CreateFolderAsync(packageHash, CreationCollisionOption.OpenIfExists).ConfigureAwait(false)\n                    : await codePushFolder.GetFolderAsync(packageHash).ConfigureAwait(false);\n            }\n            catch (FileNotFoundException)\n            {\n                return null;\n            }\n            catch (DirectoryNotFoundException)\n            {\n                return null;\n            }\n        }\n\n        internal async Task<JObject> GetPreviousPackageAsync()\n        {\n            var packageHash = await GetPreviousPackageHashAsync().ConfigureAwait(false);\n            return packageHash == null ? null : await GetPackageAsync(packageHash).ConfigureAwait(false);\n        }\n\n        internal async Task<string> GetPreviousPackageHashAsync()\n        {\n            var info = await GetCurrentPackageInfoAsync().ConfigureAwait(false);\n            var previousPackageShortHash = (string)info[CodePushConstants.PreviousPackageKey];\n            if (previousPackageShortHash == null)\n            {\n                return null;\n            }\n\n            var previousPackageMetadata = await GetPackageAsync(previousPackageShortHash).ConfigureAwait(false);\n            return previousPackageMetadata == null ? null : (string)previousPackageMetadata[CodePushConstants.PackageHashKey];\n        }\n\n        internal async Task InstallPackageAsync(JObject updatePackage, bool currentUpdateIsPending)\n        {\n            var packageHash = (string)updatePackage[CodePushConstants.PackageHashKey];\n            var info = await GetCurrentPackageInfoAsync().ConfigureAwait(false);\n            if (currentUpdateIsPending)\n            {\n                // Don't back up current update to the \"previous\" position because\n                // it is an unverified update which should not be rolled back to.\n                var currentPackageFolder = await GetCurrentPackageFolderAsync().ConfigureAwait(false);\n                if (currentPackageFolder != null)\n                {\n                    await currentPackageFolder.DeleteAsync().ConfigureAwait(false);\n                }\n            }\n            else\n            {\n                var previousPackageHash = await GetPreviousPackageHashAsync().ConfigureAwait(false);\n                if (previousPackageHash != null && !previousPackageHash.Equals(packageHash))\n                {\n                    var previousPackageFolder = await GetPackageFolderAsync(previousPackageHash, false).ConfigureAwait(false);\n                    if (previousPackageFolder != null)\n                    {\n                        await previousPackageFolder.DeleteAsync().ConfigureAwait(false);\n                    }\n                }\n\n                info[CodePushConstants.PreviousPackageKey] = info[CodePushConstants.CurrentPackageKey];\n            }\n\n            info[CodePushConstants.CurrentPackageKey] = packageHash;\n            await UpdateCurrentPackageInfoAsync(info).ConfigureAwait(false);\n        }\n\n        internal async Task RollbackPackageAsync()\n        {\n            var info = await GetCurrentPackageInfoAsync().ConfigureAwait(false);\n            var currentPackageFolder = await GetCurrentPackageFolderAsync().ConfigureAwait(false);\n            if (currentPackageFolder != null)\n            {\n                await currentPackageFolder.DeleteAsync().ConfigureAwait(false);\n            }\n\n            info[CodePushConstants.CurrentPackageKey] = info[CodePushConstants.PreviousPackageKey];\n            info[CodePushConstants.PreviousPackageKey] = null;\n            await UpdateCurrentPackageInfoAsync(info).ConfigureAwait(false);\n        }\n\n        #endregion\n\n        #region Private methods\n\n        private async Task<IFolder> GetCurrentPackageFolderAsync()\n        {\n            var info = await GetCurrentPackageInfoAsync().ConfigureAwait(false);\n            if (info == null)\n            {\n                return null;\n            }\n            var packageHash = (string)info[CodePushConstants.CurrentPackageKey];\n            return packageHash == null ? null : await GetPackageFolderAsync(packageHash, false).ConfigureAwait(false);\n        }\n\n        private async Task<JObject> GetCurrentPackageInfoAsync()\n        {\n            var statusFile = await GetStatusFileAsync().ConfigureAwait(false);\n            var info = await CodePushUtils.GetJObjectFromFileAsync(statusFile).ConfigureAwait(false);\n\n            if (info != null)\n            {\n                return info;\n            }\n\n            // info file has been corrupted - re-create it\n            await statusFile.DeleteAsync().ConfigureAwait(false);\n            statusFile = await GetStatusFileAsync().ConfigureAwait(false);\n            return await CodePushUtils.GetJObjectFromFileAsync(statusFile).ConfigureAwait(false);\n        }\n\n        private async Task<IFile> GetDownloadFileAsync()\n        {\n            var codePushFolder = await UpdateUtils.GetCodePushFolderAsync().ConfigureAwait(false);\n            return await codePushFolder.CreateFileAsync(CodePushConstants.DownloadFileName, CreationCollisionOption.OpenIfExists).ConfigureAwait(false);\n        }\n\n        private async Task<IFile> GetStatusFileAsync()\n        {\n            var codePushFolder = await UpdateUtils.GetCodePushFolderAsync().ConfigureAwait(false);\n            return await codePushFolder.CreateFileAsync(CodePushConstants.StatusFileName, CreationCollisionOption.OpenIfExists).ConfigureAwait(false);\n        }\n\n        private async Task<IFolder> CreateUnzippedFolderAsync()\n        {\n            var codePushFolder = await UpdateUtils.GetCodePushFolderAsync().ConfigureAwait(false);\n            var isUnzippedFolderExists = await codePushFolder.CheckExistsAsync(CodePushConstants.UnzippedFolderName).ConfigureAwait(false);\n\n            if (isUnzippedFolderExists != ExistenceCheckResult.NotFound)\n            {\n                await codePushFolder.GetFolderAsync(CodePushConstants.UnzippedFolderName).ContinueWith((existingFolder) => existingFolder.Result.DeleteAsync());\n            }\n\n            return await codePushFolder.CreateFolderAsync(CodePushConstants.UnzippedFolderName, CreationCollisionOption.OpenIfExists).ConfigureAwait(false);\n        }\n\n        private string ShortenPackageHash(string longPackageHash)\n        {\n            return longPackageHash.Substring(0, 8);\n        }\n\n        private async Task UpdateCurrentPackageInfoAsync(JObject packageInfo)\n        {\n            var file = await GetStatusFileAsync().ConfigureAwait(false);\n            await file.WriteAllTextAsync(JsonConvert.SerializeObject(packageInfo)).ConfigureAwait(false);\n        }\n        #endregion\n    }\n}\n"
  },
  {
    "path": "windows-legacy/CodePush.Net46/UpdateUtils.cs",
    "content": "﻿using CodePush.Net46.Adapters.Http;\nusing Newtonsoft.Json.Linq;\nusing PCLStorage;\nusing System;\nusing System.IO;\nusing System.Net;\nusing System.Threading.Tasks;\n\nnamespace CodePush.ReactNative\n{\n    internal class UpdateUtils\n    {\n        internal async static Task CopyNecessaryFilesFromCurrentPackageAsync(IFile diffManifestFile, IFolder currentPackageFolder, IFolder newPackageFolder)\n        {\n            await FileUtils.MergeFoldersAsync(currentPackageFolder, newPackageFolder).ConfigureAwait(false);\n            JObject diffManifest = await CodePushUtils.GetJObjectFromFileAsync(diffManifestFile).ConfigureAwait(false);\n            var deletedFiles = (JArray)diffManifest[\"deletedFiles\"];\n            foreach (string fileNameToDelete in deletedFiles)\n            {\n                var fileToDelete = await newPackageFolder.GetFileAsync(fileNameToDelete).ConfigureAwait(false);\n                await fileToDelete.DeleteAsync().ConfigureAwait(false);\n            }\n        }\n\n        internal async static Task<string> FindJSBundleInUpdateContentsAsync(IFolder updateFolder, string expectedFileName)\n        {\n            foreach (IFile file in await updateFolder.GetFilesAsync().ConfigureAwait(false))\n            {\n                string fileName = file.Name;\n                if (fileName.Equals(expectedFileName))\n                {\n                    return fileName;\n                }\n            }\n\n            foreach (IFolder folder in await updateFolder.GetFoldersAsync().ConfigureAwait(false))\n            {\n                string mainBundlePathInSubFolder = await FindJSBundleInUpdateContentsAsync(folder, expectedFileName).ConfigureAwait(false);\n                if (mainBundlePathInSubFolder != null)\n                {\n                    return Path.Combine(folder.Name, mainBundlePathInSubFolder);\n                }\n            }\n\n            return null;\n        }\n\n        internal async static Task DownloadBundleAsync(string url, string fileName, IProgress<HttpProgress> downloadProgress)\n        {\n            var uri = new Uri(url);\n            var client = new WebClient();\n            client.DownloadProgressChanged += (s, e) =>\n            {\n                downloadProgress.Report(new HttpProgress\n                {\n                    BytesReceived = (ulong)e.BytesReceived,            //conversion long to ulong is safe\n                    TotalBytesToReceive = (ulong)e.TotalBytesToReceive //because size can't be negative\n                });\n            };\n\n            await client.DownloadFileTaskAsync(uri, fileName);\n        }\n\n        internal static async Task<IFolder> GetCodePushFolderAsync()\n        {\n            var pathToCodePush = Path.Combine(CodePushUtils.GetFileBundlePrefix(), CodePushConstants.CodePushFolderPrefix);\n            return await FileSystem.Current.LocalStorage.CreateFolderAsync(pathToCodePush, CreationCollisionOption.OpenIfExists).ConfigureAwait(false);\n        }\n    }\n}\n"
  },
  {
    "path": "windows-legacy/CodePush.Net46/packages.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<packages>\n  <package id=\"Newtonsoft.Json\" version=\"13.0.1\" targetFramework=\"net452\" />\n  <package id=\"PCLStorage\" version=\"1.0.2\" targetFramework=\"net46\" />\n</packages>"
  },
  {
    "path": "windows-legacy/CodePush.Net46.Test/ApplicationDataContainerTest.cs",
    "content": "﻿using System;\nusing Microsoft.VisualStudio.TestTools.UnitTesting;\nusing CodePush.Net46.Adapters.Storage;\nusing System.Threading.Tasks;\n\nnamespace CodePush.Net46.Test\n{\n    [TestClass]\n    public class ApplicationDataContainerTest\n    {\n        readonly static string key1 = \"key1\";\n        readonly static string key2 = \"key2\";\n        readonly static string key3 = \"key3\";\n\n        readonly static string val1 = \"string data1\";\n        readonly static string val2 = \"string data2\";\n        readonly static string val3 = \"string data1\";\n\n        [TestMethod]\n        public void TestInMemmorySet()\n        {\n            var settings = new ApplicationDataContainer();\n\n            settings.Values[key1] = val1;\n            settings.Values[key2] = val2;\n            settings.Values[key3] = val3;\n\n            Assert.AreEqual(settings.Values[key1], val1);\n            Assert.AreEqual(settings.Values[key2], val2);\n            Assert.AreEqual(settings.Values[key3], val3);\n\n            settings.DeleteAsync().Wait();\n        }\n\n        [TestMethod]\n        public void TestInMemmoryReset()\n        {\n            var settings = new ApplicationDataContainer();\n\n            settings.Values[key1] = val1;\n            settings.Values[key1] = val2;\n            settings.Values[key1] = val3;\n\n            Assert.AreEqual(settings.Values[key1], val3);\n\n            settings.DeleteAsync().Wait();\n        }\n\n        [TestMethod]\n        public void TestInMemmoryRemove()\n        {\n            var settings = new ApplicationDataContainer();\n\n            settings.Values[key1] = val1;\n            settings.Values[key2] = val2;\n            settings.Values[key3] = val3;\n\n            settings.Values.Remove(key2);\n\n            Assert.AreEqual(settings.Values[key1], val1);\n            Assert.IsNull(settings.Values[key2]);\n            Assert.AreEqual(settings.Values[key3], val3);\n\n            settings.DeleteAsync().Wait();\n        }\n\n        [TestMethod]\n        public void TestPersistentSet()\n        {\n            var settings = new ApplicationDataContainer();\n\n            settings.Values[key1] = val1;\n            settings.Values[key2] = val2;\n            settings.Values[key3] = val3;\n\n            settings = new ApplicationDataContainer();\n\n            Assert.AreEqual(settings.Values[key1], val1);\n            Assert.AreEqual(settings.Values[key2], val2);\n            Assert.AreEqual(settings.Values[key3], val3);\n\n            settings.DeleteAsync().Wait();\n        }\n\n        [TestMethod]\n        public void TestPersistentRemove()\n        {\n            var settings = new ApplicationDataContainer();\n\n            settings.Values[key1] = val1;\n            settings.Values[key2] = val2;\n            settings.Values[key3] = val3;\n\n            settings.Values.Remove(key2);\n\n            settings = new ApplicationDataContainer();\n\n            Assert.AreEqual(settings.Values[key1], val1);\n            Assert.IsNull(settings.Values[key2]);\n            Assert.AreEqual(settings.Values[key3], val3);\n\n            settings.DeleteAsync().Wait();\n        }\n    }\n}\n"
  },
  {
    "path": "windows-legacy/CodePush.Net46.Test/CodePush.Net46.Test.csproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"14.0\" DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup>\n    <Configuration Condition=\" '$(Configuration)' == '' \">Debug</Configuration>\n    <Platform Condition=\" '$(Platform)' == '' \">AnyCPU</Platform>\n    <ProjectGuid>{BBB48F0B-AF6F-4A14-AFA4-306D3FB0B7CF}</ProjectGuid>\n    <OutputType>Library</OutputType>\n    <AppDesignerFolder>Properties</AppDesignerFolder>\n    <RootNamespace>CodePush.Net46.Test</RootNamespace>\n    <AssemblyName>CodePush.Net46.Test</AssemblyName>\n    <TargetFrameworkVersion>v4.6</TargetFrameworkVersion>\n    <FileAlignment>512</FileAlignment>\n    <ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>\n    <VisualStudioVersion Condition=\"'$(VisualStudioVersion)' == ''\">10.0</VisualStudioVersion>\n    <VSToolsPath Condition=\"'$(VSToolsPath)' == ''\">$(MSBuildExtensionsPath32)\\Microsoft\\VisualStudio\\v$(VisualStudioVersion)</VSToolsPath>\n    <ReferencePath>$(ProgramFiles)\\Common Files\\microsoft shared\\VSTT\\$(VisualStudioVersion)\\UITestExtensionPackages</ReferencePath>\n    <IsCodedUITest>False</IsCodedUITest>\n    <TestProjectType>UnitTest</TestProjectType>\n  </PropertyGroup>\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' \">\n    <DebugSymbols>true</DebugSymbols>\n    <DebugType>full</DebugType>\n    <Optimize>false</Optimize>\n    <OutputPath>bin\\Debug\\</OutputPath>\n    <DefineConstants>DEBUG;TRACE</DefineConstants>\n    <ErrorReport>prompt</ErrorReport>\n    <WarningLevel>4</WarningLevel>\n  </PropertyGroup>\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' \">\n    <DebugType>pdbonly</DebugType>\n    <Optimize>true</Optimize>\n    <OutputPath>bin\\Release\\</OutputPath>\n    <DefineConstants>TRACE</DefineConstants>\n    <ErrorReport>prompt</ErrorReport>\n    <WarningLevel>4</WarningLevel>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x64'\">\n    <DebugSymbols>true</DebugSymbols>\n    <OutputPath>bin\\x64\\Debug\\</OutputPath>\n    <DefineConstants>DEBUG;TRACE</DefineConstants>\n    <DebugType>full</DebugType>\n    <PlatformTarget>x64</PlatformTarget>\n    <ErrorReport>prompt</ErrorReport>\n    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|x64'\">\n    <OutputPath>bin\\x64\\Release\\</OutputPath>\n    <DefineConstants>TRACE</DefineConstants>\n    <Optimize>true</Optimize>\n    <DebugType>pdbonly</DebugType>\n    <PlatformTarget>x64</PlatformTarget>\n    <ErrorReport>prompt</ErrorReport>\n    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x86'\">\n    <DebugSymbols>true</DebugSymbols>\n    <OutputPath>bin\\x86\\Debug\\</OutputPath>\n    <DefineConstants>DEBUG;TRACE</DefineConstants>\n    <DebugType>full</DebugType>\n    <PlatformTarget>x86</PlatformTarget>\n    <ErrorReport>prompt</ErrorReport>\n    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|x86'\">\n    <OutputPath>bin\\x86\\Release\\</OutputPath>\n    <DefineConstants>TRACE</DefineConstants>\n    <Optimize>true</Optimize>\n    <DebugType>pdbonly</DebugType>\n    <PlatformTarget>x86</PlatformTarget>\n    <ErrorReport>prompt</ErrorReport>\n    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>\n  </PropertyGroup>\n  <ItemGroup>\n    <Reference Include=\"Newtonsoft.Json, Version=13.0.1.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL\">\n      <SpecificVersion>False</SpecificVersion>\n      <HintPath>..\\..\\Examples\\CodePushDemoApp\\windows\\packages\\Newtonsoft.Json.13.0.1\\lib\\net45\\Newtonsoft.Json.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System\" />\n  </ItemGroup>\n  <Choose>\n    <When Condition=\"('$(VisualStudioVersion)' == '10.0' or '$(VisualStudioVersion)' == '') and '$(TargetFrameworkVersion)' == 'v3.5'\">\n      <ItemGroup>\n        <Reference Include=\"Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL\" />\n      </ItemGroup>\n    </When>\n    <Otherwise>\n      <ItemGroup>\n        <Reference Include=\"Microsoft.VisualStudio.QualityTools.UnitTestFramework\">\n          <Private>False</Private>\n        </Reference>\n      </ItemGroup>\n    </Otherwise>\n  </Choose>\n  <ItemGroup>\n    <Compile Include=\"ApplicationDataContainerTest.cs\" />\n    <Compile Include=\"Properties\\AssemblyInfo.cs\" />\n    <Compile Include=\"TelemetryManagerTest.cs\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\CodePush.Net46\\CodePush.Net46.csproj\">\n      <Project>{4dfe3f9f-5e15-4f17-8fd4-33ff0519348e}</Project>\n      <Name>CodePush.Net46</Name>\n    </ProjectReference>\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"app.config\" />\n    <None Include=\"packages.config\" />\n  </ItemGroup>\n  <Choose>\n    <When Condition=\"'$(VisualStudioVersion)' == '10.0' And '$(IsCodedUITest)' == 'True'\">\n      <ItemGroup>\n        <Reference Include=\"Microsoft.VisualStudio.QualityTools.CodedUITestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL\">\n          <Private>False</Private>\n        </Reference>\n        <Reference Include=\"Microsoft.VisualStudio.TestTools.UITest.Common, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL\">\n          <Private>False</Private>\n        </Reference>\n        <Reference Include=\"Microsoft.VisualStudio.TestTools.UITest.Extension, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL\">\n          <Private>False</Private>\n        </Reference>\n        <Reference Include=\"Microsoft.VisualStudio.TestTools.UITesting, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL\">\n          <Private>False</Private>\n        </Reference>\n      </ItemGroup>\n    </When>\n  </Choose>\n  <Import Project=\"$(VSToolsPath)\\TeamTest\\Microsoft.TestTools.targets\" Condition=\"Exists('$(VSToolsPath)\\TeamTest\\Microsoft.TestTools.targets')\" />\n  <Import Project=\"$(MSBuildToolsPath)\\Microsoft.CSharp.targets\" />\n  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. \n       Other similar extension points exist, see Microsoft.Common.targets.\n  <Target Name=\"BeforeBuild\">\n  </Target>\n  <Target Name=\"AfterBuild\">\n  </Target>\n  -->\n</Project>"
  },
  {
    "path": "windows-legacy/CodePush.Net46.Test/Properties/AssemblyInfo.cs",
    "content": "﻿using System.Reflection;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\n\n// General Information about an assembly is controlled through the following \n// set of attributes. Change these attribute values to modify the information\n// associated with an assembly.\n[assembly: AssemblyTitle(\"CodePush.Net46.Test\")]\n[assembly: AssemblyDescription(\"\")]\n[assembly: AssemblyConfiguration(\"\")]\n[assembly: AssemblyCompany(\"\")]\n[assembly: AssemblyProduct(\"CodePush.Net46.Test\")]\n[assembly: AssemblyCopyright(\"Copyright ©  2017\")]\n[assembly: AssemblyTrademark(\"\")]\n[assembly: AssemblyCulture(\"\")]\n\n// Setting ComVisible to false makes the types in this assembly not visible \n// to COM components.  If you need to access a type in this assembly from \n// COM, set the ComVisible attribute to true on that type.\n[assembly: ComVisible(false)]\n\n// The following GUID is for the ID of the typelib if this project is exposed to COM\n[assembly: Guid(\"bbb48f0b-af6f-4a14-afa4-306d3fb0b7cf\")]\n\n// Version information for an assembly consists of the following four values:\n//\n//      Major Version\n//      Minor Version \n//      Build Number\n//      Revision\n//\n// You can specify all the values or you can default the Build and Revision Numbers \n// by using the '*' as shown below:\n// [assembly: AssemblyVersion(\"1.0.*\")]\n[assembly: AssemblyVersion(\"1.0.0.0\")]\n[assembly: AssemblyFileVersion(\"1.0.0.0\")]\n"
  },
  {
    "path": "windows-legacy/CodePush.Net46.Test/TelemetryManagerTest.cs",
    "content": "﻿using CodePush.ReactNative;\nusing Microsoft.VisualStudio.TestTools.UnitTesting;\nusing Newtonsoft.Json;\nusing Newtonsoft.Json.Linq;\n\nnamespace CodePush.Net46.Test\n{\n    /// <summary>\n    /// Some tests for telemetry manager\n    /// As implementation of TelemetryManager was ported from android version, we do not test logic here.\n    /// Here are tests for some tricky parts of implementation, or check some data transformation that\n    /// has no full equvalent in C#\n    /// </summary>\n    [TestClass]\n    public class TelemetryManagerTest\n    {\n        #region Constants from TelemetryManager\n        //private static readonly string APP_VERSION_KEY = \"appVersion\";\n        private static readonly string DEPLOYMENT_FAILED_STATUS = \"DeploymentFailed\";\n        private static readonly string DEPLOYMENT_KEY_KEY = \"deploymentKey\";\n        private static readonly string DEPLOYMENT_SUCCEEDED_STATUS = \"DeploymentSucceeded\";\n        private static readonly string LABEL_KEY = \"label\";\n        private static readonly string LAST_DEPLOYMENT_REPORT_KEY = \"CODE_PUSH_LAST_DEPLOYMENT_REPORT\";\n        //private static readonly string PACKAGE_KEY = \"package\";\n        //private static readonly string PREVIOUS_DEPLOYMENT_KEY_KEY = \"previousDeploymentKey\";\n        //private static readonly string PREVIOUS_LABEL_OR_APP_VERSION_KEY = \"previousLabelOrAppVersion\";\n        private static readonly string RETRY_DEPLOYMENT_REPORT_KEY = \"CODE_PUSH_RETRY_DEPLOYMENT_REPORT\";\n        private static readonly string STATUS_KEY = \"status\";\n        #endregion\n\n        [TestMethod]\n        public void TestGetUpdateReportNoPreviousUpdate()\n        {\n            var input = new JObject();\n            input.Add(DEPLOYMENT_KEY_KEY, \"depKeyParam\");\n            input.Add(LABEL_KEY, \"labelParam\");\n\n            var output = TelemetryManager.GetUpdateReport(input);\n            Assert.IsNotNull(output);\n            Assert.IsTrue(output.ToString(Formatting.None).Contains(\"\\\"status\\\":\\\"DeploymentSucceeded\\\"\"));\n        }\n\n        [TestMethod]\n        public void TestGetUpdateReportWithPreviousUpdate()\n        {\n            SettingsManager.SetString(LAST_DEPLOYMENT_REPORT_KEY, \"prevKey:prevLabel\");\n            var input = new JObject();\n            input.Add(DEPLOYMENT_KEY_KEY, \"depKeyParam\");\n            input.Add(LABEL_KEY, \"labelParam\");\n\n            var output = TelemetryManager.GetUpdateReport(input);\n            Assert.IsNotNull(output);\n            Assert.IsTrue(output.ToString(Formatting.None).Contains(\"\\\"status\\\":\\\"DeploymentSucceeded\\\"\"));\n            Assert.IsTrue(output.ToString(Formatting.None).Contains(\"\\\"previousDeploymentKey\\\":\\\"prevKey\\\",\\\"previousLabelOrAppVersion\\\":\\\"prevLabel\\\"\"));\n\n            //Clean Up\n            SettingsManager.RemoveString(LAST_DEPLOYMENT_REPORT_KEY);\n        }\n\n        [TestMethod]\n        public void TestGetUpdateReportNegative()\n        {\n            var inputNoLabel = new JObject();\n            inputNoLabel.Add(DEPLOYMENT_KEY_KEY, \"depKeyParam\");\n            Assert.IsNull(TelemetryManager.GetUpdateReport(inputNoLabel));\n\n            var inputNoKey = new JObject();\n            inputNoKey.Add(LABEL_KEY, \"labelParam\");\n            Assert.IsNull(TelemetryManager.GetUpdateReport(inputNoKey));\n        }\n\n        [TestMethod]\n        public void TestRecordStatusReportWithRollback()\n        {\n            var report = new JObject();\n            report.Add(STATUS_KEY, DEPLOYMENT_FAILED_STATUS);\n\n            TelemetryManager.RecordStatusReported(report);\n            Assert.IsTrue(true);\n        }\n\n        [TestMethod]\n        public void TestRecordStatusReportWithoutRollback()\n        {\n            var reportSuccess = new JObject();\n            reportSuccess.Add(STATUS_KEY, DEPLOYMENT_SUCCEEDED_STATUS);\n            TelemetryManager.RecordStatusReported(reportSuccess);\n\n            var reportNoStatus = new JObject();\n            TelemetryManager.RecordStatusReported(reportNoStatus);\n\n            Assert.IsTrue(true);\n        }\n\n        [TestMethod]\n        public void TestStatusReportForRetrySerialization()\n        {\n            SettingsManager.RemoveString(RETRY_DEPLOYMENT_REPORT_KEY);\n            var original = new JObject();\n            original.Add(\"keyString\", \"stringValue\");\n            original.Add(\"keyInt\", 42);\n            original.Add(\"keyBool\", true);\n\n            TelemetryManager.SaveStatusReportForRetry(original);\n\n            var stringified = SettingsManager.GetString(RETRY_DEPLOYMENT_REPORT_KEY);\n            SettingsManager.RemoveString(RETRY_DEPLOYMENT_REPORT_KEY);\n\n            Assert.IsNotNull(stringified);\n            var result = JObject.Parse(stringified);\n\n            Assert.IsTrue((bool)result.GetValue(\"keyBool\"));\n            Assert.AreEqual(42, (int)result.GetValue(\"keyInt\"));\n            Assert.AreEqual(\"stringValue\", (string)result.GetValue(\"keyString\"));\n        }\n    }\n}\n"
  },
  {
    "path": "windows-legacy/CodePush.Net46.Test/app.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<configuration>\n  <runtime>\n    <assemblyBinding xmlns=\"urn:schemas-microsoft-com:asm.v1\">\n      <dependentAssembly>\n        <assemblyIdentity name=\"System.Reactive.Core\" publicKeyToken=\"94bc3704cddfc263\" culture=\"neutral\" />\n        <bindingRedirect oldVersion=\"0.0.0.0-3.0.3000.0\" newVersion=\"3.0.3000.0\" />\n      </dependentAssembly>\n    </assemblyBinding>\n  </runtime>\n</configuration>"
  },
  {
    "path": "windows-legacy/CodePush.Net46.Test/packages.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<packages>\n  <package id=\"Newtonsoft.Json\" version=\"13.0.1\" targetFramework=\"net46\" />\n</packages>"
  },
  {
    "path": "windows-legacy/CodePush.Shared/CodePush.Shared.projitems",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup>\n    <MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>\n    <HasSharedItems>true</HasSharedItems>\n    <SharedGUID>4ad4c826-cc26-4f1d-b60d-b97b22f52e90</SharedGUID>\n  </PropertyGroup>\n  <PropertyGroup Label=\"Configuration\">\n    <Import_RootNamespace>CodePush.Shared</Import_RootNamespace>\n  </PropertyGroup>\n  <ItemGroup>\n    <Compile Include=\"$(MSBuildThisFileDirectory)CodePushConstants.cs\" />\n    <Compile Include=\"$(MSBuildThisFileDirectory)CodePushNativeModule.cs\" />\n    <Compile Include=\"$(MSBuildThisFileDirectory)CodePushReactPackage.cs\" />\n    <Compile Include=\"$(MSBuildThisFileDirectory)CodePushUtils.cs\" />\n    <Compile Include=\"$(MSBuildThisFileDirectory)InstallMode.cs\" />\n    <Compile Include=\"$(MSBuildThisFileDirectory)MinimumBackgroundListener.cs\" />\n    <Compile Include=\"$(MSBuildThisFileDirectory)SettingsManager.cs\" />\n    <Compile Include=\"$(MSBuildThisFileDirectory)TelemetryManager.cs\" />\n    <Compile Include=\"$(MSBuildThisFileDirectory)UpdateState.cs\" />\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "windows-legacy/CodePush.Shared/CodePush.Shared.shproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"14.0\" DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>4ad4c826-cc26-4f1d-b60d-b97b22f52e90</ProjectGuid>\n    <MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>\n  </PropertyGroup>\n  <Import Project=\"$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props\" Condition=\"Exists('$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props')\" />\n  <Import Project=\"$(MSBuildExtensionsPath32)\\Microsoft\\VisualStudio\\v$(VisualStudioVersion)\\CodeSharing\\Microsoft.CodeSharing.Common.Default.props\" />\n  <Import Project=\"$(MSBuildExtensionsPath32)\\Microsoft\\VisualStudio\\v$(VisualStudioVersion)\\CodeSharing\\Microsoft.CodeSharing.Common.props\" />\n  <PropertyGroup />\n  <Import Project=\"CodePush.Shared.projitems\" Label=\"Shared\" />\n  <Import Project=\"$(MSBuildExtensionsPath32)\\Microsoft\\VisualStudio\\v$(VisualStudioVersion)\\CodeSharing\\Microsoft.CodeSharing.CSharp.targets\" />\n</Project>\n"
  },
  {
    "path": "windows-legacy/CodePush.Shared/CodePushConstants.cs",
    "content": "﻿namespace CodePush.ReactNative\n{\n    internal class CodePushConstants\n    {\n        internal const string BinaryModifiedTimeKey = \"binaryModifiedTime\";\n        internal const string CodePushServerUrl = \"https://codepush.appcenter.ms/\";\n        internal const string CodePushFolderPrefix = \"CodePush\";\n        internal const string CodePushPreferences = \"CodePush\";\n        internal const string CurrentPackageKey = \"currentPackage\";\n        internal const string DefaultJsBundleName = \"index.windows.bundle\";\n        internal const string DiffManifestFileName = \"hotcodepush.json\";\n        internal const string DownloadFileName = \"download.zip\";\n        internal const string DownloadProgressEventName = \"CodePushDownloadProgress\";\n        internal const string DownloadUrlKey = \"downloadUrl\";\n        internal const string FailedUpdatesKey = \"CODE_PUSH_FAILED_UPDATES\";\n        internal const string PackageFileName = \"app.json\";\n        internal const string PackageHashKey = \"packageHash\";\n        internal const string PendingUpdateHashKey = \"hash\";\n        internal const string PendingUpdateKey = \"CODE_PUSH_PENDING_UPDATE\";\n        internal const string PendingUpdateIsLoadingKey = \"isLoading\";\n        internal const string PreviousPackageKey = \"previousPackage\";\n        // This needs to be kept in sync with https://github.com/ReactWindows/react-native-windows/blob/master/ReactWindows/ReactNative/DevSupport/DevSupportManager.cs#L22\n        internal const string ReactDevBundleCacheFileName = \"ReactNativeDevBundle.js\";\n        internal const string ReactNativeLogCategory = \"ReactNative\";\n        internal const string RelativeBundlePathKey = \"bundlePath\";\n        internal const string StatusFileName = \"codepush.json\";\n        internal const string UnzippedFolderName = \"unzipped\";\n#if WINDOWS_UWP\n        internal const string AssetsBundlePrefix = \"ms-appx:///ReactAssets/\";\n        internal const string FileBundlePrefix = \"ms-appdata:///local/\";\n#else\n        internal const string AssetsBundlePrefix = \"ReactAssets/\";\n#endif\n    }\n}\n"
  },
  {
    "path": "windows-legacy/CodePush.Shared/CodePushNativeModule.cs",
    "content": "﻿using Newtonsoft.Json.Linq;\nusing ReactNative;\nusing ReactNative.Bridge;\nusing ReactNative.Modules.Core;\nusing System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Reflection;\nusing System.Threading;\nusing System.Threading.Tasks;\n#if WINDOWS_UWP\nusing Windows.Web.Http;\n#else\nusing CodePush.Net46.Adapters.Http;\n#endif\n\nnamespace CodePush.ReactNative\n{\n    internal class CodePushNativeModule : ReactContextNativeModuleBase\n    {\n        private CodePushReactPackage _codePush;\n        private MinimumBackgroundListener _minimumBackgroundListener;\n        private ReactContext _reactContext;\n\n        public CodePushNativeModule(ReactContext reactContext, CodePushReactPackage codePush)\n            : base(reactContext)\n        {\n            _reactContext = reactContext;\n            _codePush = codePush;\n        }\n\n        public override string Name\n        {\n            get\n            {\n                return \"CodePush\";\n            }\n        }\n\n        public override IReadOnlyDictionary<string, object> Constants\n        {\n            get\n            {\n                return new Dictionary<string, object>\n                {\n                    { \"codePushInstallModeImmediate\", InstallMode.Immediate },\n                    { \"codePushInstallModeOnNextResume\", InstallMode.OnNextResume },\n                    { \"codePushInstallModeOnNextRestart\", InstallMode.OnNextRestart },\n                    { \"codePushUpdateStateRunning\", UpdateState.Running },\n                    { \"codePushUpdateStatePending\", UpdateState.Pending },\n                    { \"codePushUpdateStateLatest\", UpdateState.Latest },\n                };\n            }\n        }\n\n        public override void Initialize()\n        {\n            _codePush.InitializeUpdateAfterRestart();\n        }\n\n        [ReactMethod]\n        public async void downloadUpdate(JObject updatePackage, bool notifyProgress, IPromise promise)\n        {\n            try\n            {\n                updatePackage[CodePushConstants.BinaryModifiedTimeKey] = \"\" + await FileUtils.GetBinaryResourcesModifiedTimeAsync(_codePush.AssetsBundleFileName).ConfigureAwait(false);\n                await _codePush.UpdateManager.DownloadPackageAsync(\n                    updatePackage,\n                    _codePush.AssetsBundleFileName,\n                    new Progress<HttpProgress>(\n                        (HttpProgress progress) =>\n                        {\n                            if (!notifyProgress)\n                            {\n                                return;\n                            }\n\n                            var downloadProgress = new JObject()\n                            {\n                                { \"totalBytes\", progress.TotalBytesToReceive },\n                                { \"receivedBytes\", progress.BytesReceived }\n                            };\n\n                            _reactContext\n                                .GetJavaScriptModule<RCTDeviceEventEmitter>()\n                                .emit(CodePushConstants.DownloadProgressEventName, downloadProgress);\n                        }\n                    )\n                ).ConfigureAwait(false);\n\n                JObject newPackage = await _codePush.UpdateManager.GetPackageAsync((string)updatePackage[CodePushConstants.PackageHashKey]).ConfigureAwait(false);\n                promise.Resolve(newPackage);\n            }\n            catch (InvalidDataException e)\n            {\n                CodePushUtils.Log(e.ToString());\n                SettingsManager.SaveFailedUpdate(updatePackage);\n                promise.Reject(e);\n            }\n            catch (Exception e)\n            {\n                CodePushUtils.Log(e.ToString());\n                promise.Reject(e);\n            }\n        }\n\n        [ReactMethod]\n        public void getConfiguration(IPromise promise)\n        {\n            var config = new JObject\n            {\n                { \"appVersion\", _codePush.AppVersion },\n                { \"clientUniqueId\", CodePushUtils.GetDeviceId() },\n                { \"deploymentKey\", _codePush.DeploymentKey },\n                { \"serverUrl\", CodePushConstants.CodePushServerUrl }\n            };\n\n            // TODO generate binary hash\n            // string binaryHash = CodePushUpdateUtils.getHashForBinaryContents(mainActivity, isDebugMode);\n            /*if (binaryHash != null)\n            {\n                configMap.putString(PACKAGE_HASH_KEY, binaryHash);\n            }*/\n            promise.Resolve(config);\n        }\n\n        [ReactMethod]\n        public async void getUpdateMetadata(UpdateState updateState, IPromise promise)\n        {\n            JObject currentPackage = await _codePush.UpdateManager.GetCurrentPackageAsync().ConfigureAwait(false);\n            if (currentPackage == null)\n            {\n                promise.Resolve(\"\");\n                return;\n            }\n\n            var currentUpdateIsPending = false;\n\n            if (currentPackage[CodePushConstants.PackageHashKey] != null)\n            {\n                var currentHash = (string)currentPackage[CodePushConstants.PackageHashKey];\n                currentUpdateIsPending = SettingsManager.IsPendingUpdate(currentHash);\n            }\n\n            if (updateState == UpdateState.Pending && !currentUpdateIsPending)\n            {\n                // The caller wanted a pending update\n                // but there isn't currently one.\n                promise.Resolve(\"\");\n            }\n            else if (updateState == UpdateState.Running && currentUpdateIsPending)\n            {\n                // The caller wants the running update, but the current\n                // one is pending, so we need to grab the previous.\n                promise.Resolve(await _codePush.UpdateManager.GetPreviousPackageAsync().ConfigureAwait(false));\n            }\n            else\n            {\n                // The current package satisfies the request:\n                // 1) Caller wanted a pending, and there is a pending update\n                // 2) Caller wanted the running update, and there isn't a pending\n                // 3) Caller wants the latest update, regardless if it's pending or not\n                if (_codePush.IsRunningBinaryVersion)\n                {\n                    // This only matters in Debug builds. Since we do not clear \"outdated\" updates,\n                    // we need to indicate to the JS side that somehow we have a current update on\n                    // disk that is not actually running.\n                    currentPackage[\"_isDebugOnly\"] = true;\n                }\n\n                // Enable differentiating pending vs. non-pending updates\n                currentPackage[\"isPending\"] = currentUpdateIsPending;\n                promise.Resolve(currentPackage);\n            }\n        }\n\n\n        [ReactMethod]\n        public async void getNewStatusReport(IPromise promise)\n        {\n            await Task.Run(() =>\n            {\n                if (_codePush.NeedToReportRollback)\n                {\n                    _codePush.NeedToReportRollback = false;\n\n                    var failedUpdates = SettingsManager.GetFailedUpdates();\n                    if (failedUpdates != null && failedUpdates.Count > 0)\n                    {\n                        var lastFailedPackage = (JObject)failedUpdates[failedUpdates.Count - 1];\n                        var failedStatusReport = TelemetryManager.GetRollbackReport(lastFailedPackage);\n                        if (failedStatusReport != null)\n                        {\n                            promise.Resolve(failedStatusReport);\n                            return;\n                        }\n                    }\n                }\n                else if (_codePush.DidUpdate)\n                {\n                    var currentPackage = _codePush.UpdateManager.GetCurrentPackageAsync().Result;\n                    if (currentPackage != null)\n                    {\n                        var newPackageStatusReport = TelemetryManager.GetUpdateReport(currentPackage);\n                        if (newPackageStatusReport != null)\n                        {\n                            promise.Resolve(newPackageStatusReport);\n                            return;\n                        }\n                    }\n                }\n                else if (_codePush.IsRunningBinaryVersion)\n                {\n                    var newAppVersionStatusReport = TelemetryManager.GetBinaryUpdateReport(_codePush.AppVersion);\n                    if (newAppVersionStatusReport != null)\n                    {\n                        promise.Resolve(newAppVersionStatusReport);\n                        return;\n                    }\n                }\n                else\n                {\n                    var retryStatusReport = TelemetryManager.GetRetryStatusReport();\n                    if (retryStatusReport != null)\n                    {\n                        promise.Resolve(retryStatusReport);\n                        return;\n                    }\n                }\n\n                promise.Resolve(\"\");\n            }).ConfigureAwait(false);\n        }\n\n        [ReactMethod]\n        public async void installUpdate(JObject updatePackage, InstallMode installMode, int minimumBackgroundDuration, IPromise promise)\n        {\n            await _codePush.UpdateManager.InstallPackageAsync(updatePackage, SettingsManager.IsPendingUpdate(null)).ConfigureAwait(false);\n            var pendingHash = (string)updatePackage[CodePushConstants.PackageHashKey];\n            SettingsManager.SavePendingUpdate(pendingHash, /* isLoading */false);\n            if (installMode == InstallMode.OnNextResume)\n            {\n                if (_minimumBackgroundListener == null)\n                {\n                    // Ensure we do not add the listener twice.\n                    Action loadBundleAction = () =>\n                    {\n                        Context.RunOnNativeModulesQueueThread(async () =>\n                        {\n                            await LoadBundleAsync().ConfigureAwait(false);\n                        });\n                    };\n\n                    _minimumBackgroundListener = new MinimumBackgroundListener(loadBundleAction, minimumBackgroundDuration);\n                    _reactContext.AddLifecycleEventListener(_minimumBackgroundListener);\n                }\n                else\n                {\n                    _minimumBackgroundListener.MinimumBackgroundDuration = minimumBackgroundDuration;\n                }\n            }\n\n            promise.Resolve(\"\");\n        }\n\n        [ReactMethod]\n        public void isFailedUpdate(string packageHash, IPromise promise)\n        {\n            promise.Resolve(SettingsManager.IsFailedHash(packageHash));\n        }\n\n        [ReactMethod]\n        public async void isFirstRun(string packageHash, IPromise promise)\n        {\n            bool isFirstRun = _codePush.DidUpdate\n                && packageHash != null\n                && packageHash.Length > 0\n                && packageHash.Equals(await _codePush.UpdateManager.GetCurrentPackageHashAsync().ConfigureAwait(false));\n            promise.Resolve(isFirstRun);\n        }\n\n        [ReactMethod]\n        public void notifyApplicationReady(IPromise promise)\n        {\n            SettingsManager.RemovePendingUpdate();\n            promise.Resolve(\"\");\n        }\n\n        [ReactMethod]\n        public async void restartApp(bool onlyIfUpdateIsPending)\n        {\n            // If this is an unconditional restart request, or there\n            // is current pending update, then reload the app.\n            if (!onlyIfUpdateIsPending || SettingsManager.IsPendingUpdate(null))\n            {\n                await LoadBundleAsync().ConfigureAwait(false);\n            }\n        }\n\n        [ReactMethod]\n        public async void recordStatusReported(JObject statusReport)\n        {\n            await Task.Run(() => TelemetryManager.RecordStatusReported(statusReport)).ConfigureAwait(false);\n        }\n\n        [ReactMethod]\n        public async void saveStatusReportForRetry(JObject statusReport)\n        {\n            await Task.Run(() => TelemetryManager.SaveStatusReportForRetry(statusReport)).ConfigureAwait(false);\n        }\n\n        internal async Task LoadBundleAsync()\n        {\n            // #1) Get the private ReactInstanceManager, which is what includes\n            //     the logic to reload the current React context.\n            var reactInstanceManager = _codePush.ReactInstanceManager;\n\n            // #2) Update the locally stored JS bundle file path\n            Type reactInstanceManagerType = typeof(ReactInstanceManager);\n            string latestJSBundleFile = await _codePush.GetJavaScriptBundleFileAsync(_codePush.AssetsBundleFileName).ConfigureAwait(false);\n            reactInstanceManagerType\n                .GetField(\"_jsBundleFile\", BindingFlags.NonPublic | BindingFlags.Instance)\n                .SetValue(reactInstanceManager, latestJSBundleFile);\n\n            // #3) Get the context creation method and fire it on the UI thread (which RN enforces)\n            Context.RunOnDispatcherQueueThread(() => reactInstanceManager.RecreateReactContextAsync(CancellationToken.None));\n        }\n    }\n}"
  },
  {
    "path": "windows-legacy/CodePush.Shared/CodePushReactPackage.cs",
    "content": "﻿using Newtonsoft.Json.Linq;\nusing ReactNative;\nusing ReactNative.Bridge;\nusing ReactNative.Modules.Core;\nusing ReactNative.UIManager;\nusing System;\nusing System.Collections.Generic;\nusing System.Reflection;\nusing System.Threading.Tasks;\n\n\nnamespace CodePush.ReactNative\n{\n    public sealed class CodePushReactPackage : IReactPackage\n    {\n        private static CodePushReactPackage CurrentInstance;\n\n        internal string AppVersion { get; private set; }\n        internal string DeploymentKey { get; private set; }\n        internal string AssetsBundleFileName { get; private set; }\n        internal bool NeedToReportRollback { get; set; } = false;\n        internal bool DidUpdate { get; private set; } = false;\n        internal bool IsRunningBinaryVersion { get; private set; } = false;\n#pragma warning disable CS0618 // Keeping for backward compatibility\n        internal ReactPage MainPage { get; private set; }\n#pragma warning restore CS0618 // Keeping for backward compatibility\n        internal ReactNativeHost Host { get; private set; }\n        internal UpdateManager UpdateManager { get; private set; }\n\n        internal ReactInstanceManager ReactInstanceManager\n        {\n            get\n            {\n                if (Host != null)\n                {\n                    return Host.ReactInstanceManager;\n                }\n\n#if WINDOWS_UWP\n#pragma warning disable CS0618 // Keeping for backward compatibility\n                return (ReactInstanceManager)typeof(ReactPage)\n#pragma warning restore CS0618 // Keeping for backward compatibility\n                    .GetField(\"_reactInstanceManager\", BindingFlags.NonPublic | BindingFlags.Instance)\n                    .GetValue(MainPage);\n#else\n                return ((Lazy<ReactInstanceManager>)typeof(ReactPage)\n                    .GetField(\"_reactInstanceManager\", BindingFlags.NonPublic | BindingFlags.Instance)\n                    .GetValue(MainPage)).Value as ReactInstanceManager;\n#endif\n            }\n        }\n\n        internal bool UseDeveloperSupport\n        {\n            get\n            {\n                return Host?.UseDeveloperSupport ?? MainPage.UseDeveloperSupport;\n            }\n        }\n\n\n#pragma warning disable CS0618 // Keeping for backward compatibility\n        public CodePushReactPackage(string deploymentKey, ReactPage mainPage)\n#pragma warning restore CS0618 // Keeping for backward compatibility\n        {\n            AppVersion = CodePushUtils.GetAppVersion();\n            DeploymentKey = deploymentKey;\n            MainPage = mainPage;\n            UpdateManager = new UpdateManager();\n\n            if (CurrentInstance != null)\n            {\n                CodePushUtils.Log(\"More than one CodePush instance has been initialized. Please use the instance method codePush.getBundleUrlInternal() to get the correct bundleURL for a particular instance.\");\n            }\n\n            CurrentInstance = this;\n        }\n\n        public CodePushReactPackage(string deploymentKey, ReactNativeHost host)\n        {\n            AppVersion = CodePushUtils.GetAppVersion();\n            DeploymentKey = deploymentKey;\n            Host = host;\n            UpdateManager = new UpdateManager();\n\n            if (CurrentInstance != null)\n            {\n                CodePushUtils.Log(\"More than one CodePush instance has been initialized. Please use the instance method codePush.getBundleUrlInternal() to get the correct bundleURL for a particular instance.\");\n            }\n\n            CurrentInstance = this;\n        }\n\n#region Public methods\n        public IReadOnlyList<Type> CreateJavaScriptModulesConfig()\n        {\n            return new List<Type>();\n        }\n\n        public IReadOnlyList<INativeModule> CreateNativeModules(ReactContext reactContext)\n        {\n            return new List<INativeModule>\n            {\n                 new CodePushNativeModule(reactContext, this)\n            };\n        }\n\n        public IReadOnlyList<IViewManager> CreateViewManagers(ReactContext reactContext)\n        {\n            return new List<IViewManager>();\n        }\n\n        public string GetJavaScriptBundleFile()\n        {\n            return GetJavaScriptBundleFile(CodePushConstants.DefaultJsBundleName);\n        }\n\n        public string GetJavaScriptBundleFile(string assetsBundleFileName)\n        {\n            if (CurrentInstance == null)\n            {\n                throw new InvalidOperationException(\"A CodePush instance has not been created yet. Have you added it to your app's list of ReactPackages?\");\n            }\n\n            return CurrentInstance.GetJavaScriptBundleFileAsync(assetsBundleFileName).Result;\n        }\n\n        public async Task<string> GetJavaScriptBundleFileAsync(string assetsBundleFileName)\n        {\n            AssetsBundleFileName = assetsBundleFileName;\n            string binaryJsBundleUrl = CodePushUtils.GetAssetsBundlePrefix() + assetsBundleFileName;\n\n            var binaryResourcesModifiedTime = await FileUtils.GetBinaryResourcesModifiedTimeAsync(AssetsBundleFileName).ConfigureAwait(false);\n            var packageFile = await UpdateManager.GetCurrentPackageBundleAsync(AssetsBundleFileName).ConfigureAwait(false);\n            if (packageFile == null)\n            {\n                // There has not been any downloaded updates.\n                CodePushUtils.LogBundleUrl(binaryJsBundleUrl);\n                IsRunningBinaryVersion = true;\n                return binaryJsBundleUrl;\n            }\n\n            var packageMetadata = await UpdateManager.GetCurrentPackageAsync().ConfigureAwait(false);\n            long? binaryModifiedDateDuringPackageInstall = null;\n            var binaryModifiedDateDuringPackageInstallString = (string)packageMetadata[CodePushConstants.BinaryModifiedTimeKey];\n            if (binaryModifiedDateDuringPackageInstallString != null)\n            {\n                binaryModifiedDateDuringPackageInstall = long.Parse(binaryModifiedDateDuringPackageInstallString);\n            }\n\n            var packageAppVersion = (string)packageMetadata[\"appVersion\"];\n\n            if (binaryModifiedDateDuringPackageInstall != null &&\n                    binaryModifiedDateDuringPackageInstall == binaryResourcesModifiedTime &&\n                    AppVersion.Equals(packageAppVersion))\n            {\n                CodePushUtils.LogBundleUrl(packageFile.Path);\n                IsRunningBinaryVersion = false;\n\n                return CodePushUtils.GetFileBundlePrefix() + CodePushUtils.ExtractSubFolder(packageFile.Path);\n            }\n            else\n            {\n                // The binary version is newer.\n                DidUpdate = false;\n                if (!UseDeveloperSupport || !AppVersion.Equals(packageAppVersion))\n                {\n                    await ClearUpdatesAsync().ConfigureAwait(false);\n                }\n\n                CodePushUtils.LogBundleUrl(binaryJsBundleUrl);\n                IsRunningBinaryVersion = true;\n                return binaryJsBundleUrl;\n            }\n        }\n\n#endregion\n\n#region Internal methods\n\n        internal void InitializeUpdateAfterRestart()\n        {\n            // Reset the state which indicates that\n            // the app was just freshly updated.\n            DidUpdate = false;\n\n            JObject pendingUpdate = SettingsManager.GetPendingUpdate();\n            if (pendingUpdate != null)\n            {\n                var updateIsLoading = (bool)pendingUpdate[CodePushConstants.PendingUpdateIsLoadingKey];\n                if (updateIsLoading)\n                {\n                    // Pending update was initialized, but notifyApplicationReady was not called.\n                    // Therefore, deduce that it is a broken update and rollback.\n                    CodePushUtils.Log(\"Update did not finish loading the last time, rolling back to a previous version.\");\n                    NeedToReportRollback = true;\n                    RollbackPackageAsync().Wait();\n                }\n                else\n                {\n                    DidUpdate = true;\n                    // Clear the React dev bundle cache so that new updates can be loaded.\n                    if (UseDeveloperSupport)\n                    {\n                        FileUtils.ClearReactDevBundleCacheAsync().Wait();\n                    }\n                    // Mark that we tried to initialize the new update, so that if it crashes,\n                    // we will know that we need to rollback when the app next starts.\n                    SettingsManager.SavePendingUpdate((string)pendingUpdate[CodePushConstants.PendingUpdateHashKey], /* isLoading */true);\n                }\n            }\n        }\n\n        internal async Task ClearUpdatesAsync()\n        {\n            await UpdateManager.ClearUpdatesAsync().ConfigureAwait(false);\n            SettingsManager.RemovePendingUpdate();\n            SettingsManager.RemoveFailedUpdates();\n        }\n\n#endregion\n\n#region Private methods\n\n        private async Task RollbackPackageAsync()\n        {\n            JObject failedPackage = await UpdateManager.GetCurrentPackageAsync().ConfigureAwait(false);\n            SettingsManager.SaveFailedUpdate(failedPackage);\n            await UpdateManager.RollbackPackageAsync().ConfigureAwait(false);\n            SettingsManager.RemovePendingUpdate();\n        }\n\n#endregion\n    }\n}"
  },
  {
    "path": "windows-legacy/CodePush.Shared/CodePushUtils.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.IO;\n#if WINDOWS_UWP\nusing Windows.ApplicationModel;\nusing Windows.Storage;\n#endif\n\nnamespace CodePush.ReactNative\n{\n    internal partial class CodePushUtils\n    {\n        internal static void Log(string message)\n        {\n            Debug.WriteLine(\"[CodePush] \" + message, CodePushConstants.ReactNativeLogCategory);\n        }\n\n        internal static void LogBundleUrl(string path)\n        {\n            Log(\"Loading JS bundle from \\\"\" + path + \"\\\"\");\n        }\n\n        static string _deviceId = String.Empty;\n\n        internal static string GetDeviceId()\n        {\n            //It's quite long operation, cache it\n            if (!String.IsNullOrEmpty(_deviceId))\n                return _deviceId;\n\n            _deviceId = GetDeviceIdImpl();\n            return _deviceId;\n        }\n\n        internal static string GetAppVersion()\n        {\n#if WINDOWS_UWP\n            return Package.Current.Id.Version.Major + \".\" + Package.Current.Id.Version.Minor + \".\" + Package.Current.Id.Version.Build;\n#else\n            return applicationInfo.Version;\n#endif\n        }\n\n        internal static string GetAppFolder()\n        {\n#if WINDOWS_UWP\n            return ApplicationData.Current.LocalFolder.Path;\n#else\n            return AppDomain.CurrentDomain.BaseDirectory;\n#endif\n        }\n\n        internal static string GetAssetsBundlePrefix()\n        {\n#if WINDOWS_UWP\n            return CodePushConstants.AssetsBundlePrefix;\n#else\n            return Path.Combine(GetAppFolder(), CodePushConstants.AssetsBundlePrefix);\n#endif\n        }\n\n        internal static string ExtractSubFolder(string fullPath)\n        {\n            var codePushSubPathArray = fullPath.Split(Path.DirectorySeparatorChar);\n            return String.Join(\"/\", codePushSubPathArray.SkipWhile((value, index) => codePushSubPathArray.Length - index > 4).ToArray());\n        }\n\n    }\n}\n"
  },
  {
    "path": "windows-legacy/CodePush.Shared/InstallMode.cs",
    "content": "﻿namespace CodePush.ReactNative\n{\n    enum InstallMode\n    {\n        Immediate,\n        OnNextRestart,\n        OnNextResume\n    }\n}"
  },
  {
    "path": "windows-legacy/CodePush.Shared/MinimumBackgroundListener.cs",
    "content": "﻿using ReactNative.Bridge;\nusing System;\n\nnamespace CodePush.ReactNative\n{\n    internal class MinimumBackgroundListener : ILifecycleEventListener\n    {\n        private DateTimeOffset? _lastSuspendDate;\n        private Action _resumeAction;\n\n        internal int MinimumBackgroundDuration { get; set; }\n\n        internal MinimumBackgroundListener(Action resumeAction, int minimumBackgroundDuration)\n        {\n            _resumeAction = resumeAction;\n            MinimumBackgroundDuration = minimumBackgroundDuration;\n        }\n\n        public void OnDestroy()\n        {\n        }\n\n        public void OnResume()\n        {\n            if (_lastSuspendDate != null)\n            {\n                // Determine how long the app was in the background and ensure\n                // that it meets the minimum duration amount of time.\n                double durationInBackground = (DateTimeOffset.Now - _lastSuspendDate.Value).TotalSeconds;\n                if (durationInBackground >= MinimumBackgroundDuration)\n                {\n                    _resumeAction.Invoke();\n                }\n            }\n        }\n\n        public void OnSuspend()\n        {\n            // Save the current time so that when the app is later\n            // resumed, we can detect how long it was in the background.\n            _lastSuspendDate = DateTimeOffset.Now;\n        }\n    }\n}\n"
  },
  {
    "path": "windows-legacy/CodePush.Shared/SettingsManager.cs",
    "content": "﻿using Newtonsoft.Json;\nusing Newtonsoft.Json.Linq;\nusing System;\n#if WINDOWS_UWP\nusing Windows.Storage;\n#else\nusing CodePush.Net46.Adapters.Storage;\nusing System.IO;\n#endif\n\nnamespace CodePush.ReactNative\n{\n    internal class SettingsManager\n    {\n        private static ApplicationDataContainer Settings = null;\n\n        static SettingsManager ()\n        {\n\n#if WINDOWS_UWP\n            Settings = ApplicationData.Current.LocalSettings.CreateContainer(CodePushConstants.CodePushPreferences, ApplicationDataCreateDisposition.Always);\n#else\n            var folder = UpdateUtils.GetCodePushFolderAsync().Result;\n            Settings = new ApplicationDataContainer(Path.Combine(folder.Path, CodePushConstants.CodePushPreferences));\n#endif\n        }\n\n        public static JArray GetFailedUpdates()\n        {\n            var failedUpdatesString = (string)Settings.Values[CodePushConstants.FailedUpdatesKey];\n            if (failedUpdatesString == null)\n            {\n                return new JArray();\n            }\n\n            try\n            {\n                return JArray.Parse(failedUpdatesString);\n            }\n            catch (Exception)\n            {\n                var emptyArray = new JArray();\n                Settings.Values[CodePushConstants.FailedUpdatesKey] = JsonConvert.SerializeObject(emptyArray);\n                return emptyArray;\n            }\n        }\n\n        internal static JObject GetPendingUpdate()\n        {\n            var pendingUpdateString = (string)Settings.Values[CodePushConstants.PendingUpdateKey];\n            if (pendingUpdateString == null)\n            {\n                return null;\n            }\n\n            try\n            {\n                return JObject.Parse(pendingUpdateString);\n            }\n            catch (Exception)\n            {\n                // Should not happen.\n                CodePushUtils.Log(\"Unable to parse pending update metadata \" + pendingUpdateString +\n                        \" stored in SharedPreferences\");\n                return null;\n            }\n        }\n\n        internal static bool IsFailedHash(string packageHash)\n        {\n            JArray failedUpdates = SettingsManager.GetFailedUpdates();\n            if (packageHash != null)\n            {\n                foreach (var failedPackage in failedUpdates)\n                {\n                    var failedPackageHash = (string)failedPackage[CodePushConstants.PackageHashKey];\n                    if (packageHash.Equals(failedPackageHash))\n                    {\n                        return true;\n                    }\n                }\n            }\n\n            return false;\n        }\n\n        internal static bool IsPendingUpdate(string packageHash)\n        {\n            JObject pendingUpdate = SettingsManager.GetPendingUpdate();\n            return pendingUpdate != null &&\n                    !(bool)pendingUpdate[CodePushConstants.PendingUpdateIsLoadingKey] &&\n                    (packageHash == null || ((string)pendingUpdate[CodePushConstants.PendingUpdateHashKey]).Equals(packageHash));\n        }\n\n        internal static void RemoveFailedUpdates()\n        {\n            Settings.Values.Remove(CodePushConstants.FailedUpdatesKey);\n        }\n\n        internal static void RemovePendingUpdate()\n        {\n            Settings.Values.Remove(CodePushConstants.PendingUpdateKey);\n        }\n\n        internal static void SaveFailedUpdate(JObject failedPackage)\n        {\n            var failedUpdatesString = (string)Settings.Values[CodePushConstants.FailedUpdatesKey];\n            JArray failedUpdates;\n            if (failedUpdatesString == null)\n            {\n                failedUpdates = new JArray();\n            }\n            else\n            {\n                failedUpdates = JArray.Parse(failedUpdatesString);\n            }\n\n            failedUpdates.Add(failedPackage);\n            Settings.Values[CodePushConstants.FailedUpdatesKey] = JsonConvert.SerializeObject(failedUpdates);\n        }\n\n        internal static void SavePendingUpdate(string packageHash, bool isLoading)\n        {\n            var pendingUpdate = new JObject()\n            {\n                { CodePushConstants.PendingUpdateHashKey, packageHash },\n                { CodePushConstants.PendingUpdateIsLoadingKey, isLoading }\n            };\n\n            Settings.Values[CodePushConstants.PendingUpdateKey] = JsonConvert.SerializeObject(pendingUpdate);\n        }\n\n        internal static void SetString(string key, string value)\n        {\n            Settings.Values[key] = value;\n        }\n\n        internal static string GetString(string key)\n        {\n            return (string)Settings.Values[key];\n        }\n\n        internal static void RemoveString(string key)\n        {\n            Settings.Values.Remove(key);\n        }\n    }\n}"
  },
  {
    "path": "windows-legacy/CodePush.Shared/TelemetryManager.cs",
    "content": "﻿using Newtonsoft.Json;\nusing Newtonsoft.Json.Linq;\nusing System;\nusing System.Runtime.CompilerServices;\n\n[assembly: InternalsVisibleTo(\"CodePush.Net46.Test\")]\n\nnamespace CodePush.ReactNative\n{\n    /// <summary>\n    /// Implementation is ported from \n    /// android\\app\\src\\main\\java\\com\\microsoft\\codepush\\react\\CodePushTelemetry.java\n    /// I've tried to leave all logic, comments and structure without significant modification.\n    /// </summary>\n\n    internal class TelemetryManager\n    {\n        #region Constants\n        private static readonly string APP_VERSION_KEY = \"appVersion\";\n        private static readonly string DEPLOYMENT_FAILED_STATUS = \"DeploymentFailed\";\n        private static readonly string DEPLOYMENT_KEY_KEY = \"deploymentKey\";\n        private static readonly string DEPLOYMENT_SUCCEEDED_STATUS = \"DeploymentSucceeded\";\n        private static readonly string LABEL_KEY = \"label\";\n        private static readonly string LAST_DEPLOYMENT_REPORT_KEY = \"CODE_PUSH_LAST_DEPLOYMENT_REPORT\";\n        private static readonly string PACKAGE_KEY = \"package\";\n        private static readonly string PREVIOUS_DEPLOYMENT_KEY_KEY = \"previousDeploymentKey\";\n        private static readonly string PREVIOUS_LABEL_OR_APP_VERSION_KEY = \"previousLabelOrAppVersion\";\n        private static readonly string RETRY_DEPLOYMENT_REPORT_KEY = \"CODE_PUSH_RETRY_DEPLOYMENT_REPORT\";\n        private static readonly string STATUS_KEY = \"status\";\n        #endregion\n\n        #region Internal methods\n\n        internal static JObject GetBinaryUpdateReport(string appVersion)\n        {\n            var previousStatusReportIdentifier = GetPreviousStatusReportIdentifier();\n\n            if (previousStatusReportIdentifier == null)\n            {\n                ClearRetryStatusReport();\n\n                var report = new JObject();\n                report.Add(APP_VERSION_KEY, appVersion);\n                return report;\n            }\n\n            if (!previousStatusReportIdentifier.Equals(appVersion))\n            {\n                ClearRetryStatusReport();\n\n                var report = new JObject();\n                report.Add(APP_VERSION_KEY, appVersion);\n                if (IsStatusReportIdentifierCodePushLabel(previousStatusReportIdentifier))\n                {\n                    var previousDeploymentKey = GetDeploymentKeyFromStatusReportIdentifier(previousStatusReportIdentifier);\n                    var previousLabel = GetVersionLabelFromStatusReportIdentifier(previousStatusReportIdentifier);\n\n                    report.Add(PREVIOUS_DEPLOYMENT_KEY_KEY, previousDeploymentKey);\n                    report.Add(PREVIOUS_LABEL_OR_APP_VERSION_KEY, previousLabel);\n                }\n                else\n                {\n                    // Previous status report was with a binary app version.\n                    report.Add(PREVIOUS_LABEL_OR_APP_VERSION_KEY, previousStatusReportIdentifier);\n                }\n                return report;\n            }\n\n            return null;\n        }\n\n        internal static JObject GetRetryStatusReport()\n        {\n            var retryStatusReportString = SettingsManager.GetString(RETRY_DEPLOYMENT_REPORT_KEY);\n\n            if (retryStatusReportString != null)\n            {\n                ClearRetryStatusReport();\n                try\n                {\n                    var report = JObject.Parse(retryStatusReportString);\n                    return report;\n                }\n                catch (Exception)\n                {\n                    //TODO: should be reported error\n                }\n            }\n\n            return null;\n        }\n\n        internal static JObject GetRollbackReport(JObject lastFailedPackage)\n        {\n            var report = new JObject();\n            report.Add(STATUS_KEY, DEPLOYMENT_FAILED_STATUS);\n            report.Add(PACKAGE_KEY, lastFailedPackage);\n\n            return report;\n        }\n\n        internal static JObject GetUpdateReport(JObject currentPackage)\n        {\n            var currentPackageIdentifier = GetPackageStatusReportIdentifier(currentPackage);\n            if (currentPackageIdentifier == null)\n            {\n                return null;\n            }\n\n            var previousStatusReportIdentifier = GetPreviousStatusReportIdentifier();\n            if (previousStatusReportIdentifier == null)\n            {\n                ClearRetryStatusReport();\n                var report = new JObject();\n                report.Add(PACKAGE_KEY, currentPackage);\n                report.Add(STATUS_KEY, DEPLOYMENT_SUCCEEDED_STATUS);\n                return report;\n            }\n\n            if (!previousStatusReportIdentifier.Equals(currentPackageIdentifier))\n            {\n                ClearRetryStatusReport();\n                var report = new JObject();\n                report.Add(PACKAGE_KEY, currentPackage);\n                report.Add(STATUS_KEY, DEPLOYMENT_SUCCEEDED_STATUS);\n\n                if (IsStatusReportIdentifierCodePushLabel(previousStatusReportIdentifier))\n                {\n                    var previousDeploymentKey = GetDeploymentKeyFromStatusReportIdentifier(previousStatusReportIdentifier);\n                    var previousLabel = GetVersionLabelFromStatusReportIdentifier(previousStatusReportIdentifier);\n\n                    report.Add(PREVIOUS_DEPLOYMENT_KEY_KEY, previousDeploymentKey);\n                    report.Add(PREVIOUS_LABEL_OR_APP_VERSION_KEY, previousLabel);\n                }\n                else\n                {\n                    // Previous status report was with a binary app version.\n                    report.Add(PREVIOUS_LABEL_OR_APP_VERSION_KEY, previousStatusReportIdentifier);\n                }\n\n                return report;\n            }\n\n            return null;\n        }\n\n        internal static void RecordStatusReported(JObject statusReport)\n        {\n            // We don't need to record rollback reports, so exit early if that's what was specified.\n            var status = (string)statusReport.GetValue(STATUS_KEY);\n            if ((!string.IsNullOrEmpty(status)) && DEPLOYMENT_FAILED_STATUS.Equals(status))\n            {\n                return;\n            }\n\n            var appVersion = (string)statusReport.GetValue(APP_VERSION_KEY);\n            if (!string.IsNullOrEmpty(appVersion))\n            {\n                SaveStatusReportedForIdentifier(appVersion);\n            }\n            else\n            {\n                var package = (JObject)statusReport.GetValue(PACKAGE_KEY);\n                if (package == null)\n                {\n                    return;\n                }\n\n                var packageIdentifier = GetPackageStatusReportIdentifier(package);\n                SaveStatusReportedForIdentifier(packageIdentifier);\n            }\n        }\n\n        internal static void SaveStatusReportForRetry(JObject statusReport)\n        {\n            SettingsManager.SetString(RETRY_DEPLOYMENT_REPORT_KEY, statusReport.ToString(Formatting.None));\n        }\n\n        #endregion\n\n        #region Private methods\n        static string GetPackageStatusReportIdentifier(JObject updatePackage)\n        {\n            // Because deploymentKeys can be dynamically switched, we use a\n            // combination of the deploymentKey and label as the packageIdentifier.\n            try\n            {\n                var deploymentKey = (string)updatePackage[DEPLOYMENT_KEY_KEY];\n                var label = (string)updatePackage[LABEL_KEY];\n                if (string.IsNullOrEmpty(deploymentKey) || string.IsNullOrEmpty(label))\n                {\n                    return null;\n                }\n\n                return $\"{deploymentKey}:{label}\";\n            }\n            catch\n            {\n                return null;\n            }\n        }\n\n        static string GetPreviousStatusReportIdentifier()\n        {\n            return SettingsManager.GetString(LAST_DEPLOYMENT_REPORT_KEY);\n        }\n\n        static private void ClearRetryStatusReport()\n        {\n            SettingsManager.RemoveString(RETRY_DEPLOYMENT_REPORT_KEY);\n        }\n\n        static bool IsStatusReportIdentifierCodePushLabel(string statusReportIdentifier)\n        {\n            return (!string.IsNullOrEmpty(statusReportIdentifier)) && statusReportIdentifier.Contains(\":\");\n        }\n\n        static string GetDeploymentKeyFromStatusReportIdentifier(string statusReportIdentifier)\n        {\n            string[] parsedIdentifier = statusReportIdentifier.Split(':');\n            if (parsedIdentifier.Length > 0)\n            {\n                return parsedIdentifier[0];\n            }\n            else\n            {\n                return null;\n            }\n        }\n\n        static string GetVersionLabelFromStatusReportIdentifier(string statusReportIdentifier)\n        {\n            string[] parsedIdentifier = statusReportIdentifier.Split(':');\n            if (parsedIdentifier.Length > 1)\n            {\n                return parsedIdentifier[1];\n            }\n            else\n            {\n                return null;\n            }\n        }\n\n        static void SaveStatusReportedForIdentifier(string appVersionOrPackageIdentifier)\n        {\n            SettingsManager.SetString(LAST_DEPLOYMENT_REPORT_KEY, appVersionOrPackageIdentifier);\n        }\n        #endregion\n    }\n}\n"
  },
  {
    "path": "windows-legacy/CodePush.Shared/UpdateState.cs",
    "content": "﻿namespace CodePush.ReactNative\n{\n    enum UpdateState\n    {\n        Running,\n        Pending,\n        Latest\n    }\n}"
  }
]