[
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Describe the bug**\nA clear and concise description of what the bug is.\n\n**To reproduce**\nSteps to reproduce the behavior.\n\n**Expected behavior**\nA clear and concise description of what you expected to happen.\n\n**Logs**\nIf applicable, add any log output related to your problem.\n\n**Library version**\nThe version that you are using.\n\n**XCode and Swift version**\nFor instance, XCode 11.5, Swift 5.1.\n\n**Platform the issue occurs on**\niPhone, iPad, macOS, tvOS, or watchOS.\n\n**Additional context**\nAdd any other context about the problem here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Is your feature request related to a problem? Please describe.**\nA clear and concise description of what the problem is. Ex. I would love to see the library [...does something new...]\n\n**Describe the solution you'd like**\nA clear and concise description of what you want to happen.\n\n**Describe alternatives you've considered**\nA clear and concise description of any alternative solutions or features you've considered.\n\n**Additional context**\nAdd any other context about the feature request here.\n"
  },
  {
    "path": ".github/actions/build-docs/action.yml",
    "content": "name: Build Documentation\ndescription: 'Build Documentation.'\n\nruns:\n  using: composite\n  steps:\n    - name: Install jazzy gem\n      shell: bash\n      run: gem install jazzy\n\n    - name: Build Documentation\n      shell: bash\n      run: jazzy -o docs\n\n    - name: Validate coverage\n      shell: bash\n      run: |\n        FULLDOC=`jq '.warnings | length == 0' docs/undocumented.json`\n        [ $FULLDOC == \"true\" ]\n"
  },
  {
    "path": ".github/actions/build-ios/action.yml",
    "content": "name: Build & Test iOS\ndescription: 'Build for iOS device and run tests on iOS Simulator.'\ninputs:\n  ios-sim:\n    description: 'iOS Simulator to use for testing'\n    required: true\n\nruns:\n  using: composite\n  steps:\n    # Workaround for intermittent macos-15 runner issue where simulator\n    # runtimes aren't loaded. Listing devices forces the simulator service\n    # to initialize. See https://github.com/actions/runner-images/issues/12948\n    - name: Prepare iOS Simulator runtime\n      shell: bash\n      run: xcrun simctl list devices available\n\n    - name: Build Tests for iOS device\n      shell: bash\n      run: xcodebuild build-for-testing -scheme 'LDSwiftEventSource' -sdk iphoneos CODE_SIGN_IDENTITY= | xcpretty\n\n    - name: Build & Test on iOS Simulator\n      shell: bash\n      run: xcodebuild test -scheme 'LDSwiftEventSource' -sdk iphonesimulator -destination '${{ inputs.ios-sim }}' CODE_SIGN_IDENTITY= | xcpretty\n"
  },
  {
    "path": ".github/actions/build-macos/action.yml",
    "content": "name: Build & Test macOS\ndescription: 'Build and test for macOS.'\n\nruns:\n  using: composite\n  steps:\n    - name: Build & Test on macOS\n      shell: bash\n      run: xcodebuild test -scheme 'LDSwiftEventSource' -sdk macosx -destination 'platform=macOS' | xcpretty\n\n    - name: Build for ARM64 macOS\n      shell: bash\n      run: xcodebuild build -scheme 'LDSwiftEventSource' -arch arm64e -sdk macosx | xcpretty\n"
  },
  {
    "path": ".github/actions/build-tvos/action.yml",
    "content": "name: Build & Test tvOS\ndescription: 'Build for tvOS device and run tests on tvOS Simulator.'\n\nruns:\n  using: composite\n  steps:\n    # Workaround for intermittent macos-15 runner issue where simulator\n    # runtimes aren't loaded. Listing devices forces the simulator service\n    # to initialize. See https://github.com/actions/runner-images/issues/12948\n    - name: Prepare tvOS Simulator runtime\n      shell: bash\n      run: xcrun simctl list devices available\n\n    - name: Build Tests for tvOS device\n      shell: bash\n      run: xcodebuild build-for-testing -scheme 'LDSwiftEventSource' -sdk appletvos CODE_SIGN_IDENTITY= | xcpretty\n\n    - name: Build & Test on tvOS Simulator\n      shell: bash\n      run: xcodebuild test -scheme 'LDSwiftEventSource' -sdk appletvsimulator -destination 'platform=tvOS Simulator,name=Apple TV' | xcpretty\n"
  },
  {
    "path": ".github/actions/build-watchos/action.yml",
    "content": "name: Build watchOS\ndescription: 'Build for watchOS device and simulator.'\n\nruns:\n  using: composite\n  steps:\n    # Workaround for intermittent macos-15 runner issue where simulator\n    # runtimes aren't loaded. Listing devices forces the simulator service\n    # to initialize. See https://github.com/actions/runner-images/issues/12948\n    - name: Prepare watchOS Simulator runtime\n      shell: bash\n      run: xcrun simctl list devices available\n\n    - name: Build for watchOS simulator\n      shell: bash\n      run: xcodebuild build -scheme 'LDSwiftEventSource' -sdk watchsimulator | xcpretty\n\n    - name: Build for watchOS device\n      shell: bash\n      run: xcodebuild build -scheme 'LDSwiftEventSource' -sdk watchos | xcpretty\n"
  },
  {
    "path": ".github/actions/contract-tests/action.yml",
    "content": "name: Contract Tests\ndescription: 'Build and run SDK contract tests.'\ninputs:\n  token:\n    description: 'GH token used to download SDK test harness.'\n    required: true\n\nruns:\n  using: composite\n  steps:\n    - name: Build contract test service\n      shell: bash\n      run: make build-contract-tests\n\n    - name: Start contract test service\n      shell: bash\n      run: make start-contract-test-service-bg\n\n    - name: Run contract tests\n      uses: launchdarkly/gh-actions/actions/contract-tests@main\n      with:\n        repo: sse-contract-tests\n        branch: main\n        version: v2\n        token: ${{ inputs.token }}\n        test_service_port: '8000'\n        debug_logging: 'true'\n        enable_persistence_tests: 'false'\n        extra_params: \"-skip 'basic parsing/large message in one chunk' -skip 'basic parsing/large message in two chunks'\"\n"
  },
  {
    "path": ".github/actions/lint/action.yml",
    "content": "name: Lint\ndescription: 'Run podspec and swiftlint checks.'\n\nruns:\n  using: composite\n  steps:\n    - name: Install swiftlint\n      shell: bash\n      run: brew install swiftlint\n\n    - name: Install cocoapods\n      shell: bash\n      run: gem install cocoapods\n\n    - name: Lint the podspec\n      shell: bash\n      # --quick skips building since dedicated build jobs already compile all platforms\n      run: pod lib lint LDSwiftEventSource.podspec --allow-warnings --quick\n\n    - name: Run swiftlint\n      shell: bash\n      run: swiftlint lint\n"
  },
  {
    "path": ".github/actions/publish/action.yml",
    "content": "name: Publish Package\ndescription: 'Publish the package to Cocoapods'\ninputs:\n  dry_run:\n    description: 'Is this a dry run. If so no package will be published.'\n    required: true\n\nruns:\n  using: composite\n  steps:\n    - name: Push to cocoapods\n      if: ${{ inputs.dry_run == 'false' }}\n      shell: bash\n      run: pod trunk push LDSwiftEventSource.podspec --allow-warnings --verbose\n"
  },
  {
    "path": ".github/actions/publish-docs/action.yml",
    "content": "name: Publish Documentation\ndescription: 'Publish the documentation to GitHub pages'\ninputs:\n  token:\n    description: 'Token to use for publishing.'\n    required: true\n\nruns:\n  using: composite\n  steps:\n    - uses: launchdarkly/gh-actions/actions/publish-pages@publish-pages-v1.0.2\n      name: 'Publish to GitHub pages'\n      with:\n        docs_path: docs\n        github_token: ${{ inputs.token }}\n"
  },
  {
    "path": ".github/actions/test-swiftpm/action.yml",
    "content": "name: Test SwiftPM\ndescription: 'Build and test using Swift Package Manager.'\n\nruns:\n  using: composite\n  steps:\n    - name: Build & Test with SwiftPM\n      shell: bash\n      run: swift test -v 2>&1 | xcpretty\n"
  },
  {
    "path": ".github/actions/update-versions/action.yml",
    "content": "name: Update xcode project version numbers\ndescription: 'Update xcode project version numbers'\ninputs:\n  branch:\n    description: 'The branch to checkout and push updates to'\n    required: true\n\nruns:\n  using: composite\n  steps:\n    - uses: actions/checkout@v4\n      with:\n        ref: ${{ inputs.branch }}\n\n    - name: Calculate version numbers\n      id: version\n      shell: bash\n      run: |\n        version=$(jq -r '.\".\"' .release-please-manifest.json)\n        major=$(echo \"$version\" | cut -f1 -d.)\n        minor=$(echo \"$version\" | cut -f2 -d.)\n        patch=$(echo \"$version\" | cut -f3 -d.)\n        # 64 + version gives us a letter offset for the framework version.\n        framework=$(echo $((major + 64)) | awk '{ printf(\"%c\", $1) }')\n\n        echo \"major=${major}\" >> \"$GITHUB_OUTPUT\"\n        echo \"minor=${minor}\" >> \"$GITHUB_OUTPUT\"\n        echo \"patch=${patch}\" >> \"$GITHUB_OUTPUT\"\n        echo \"framework=${framework}\" >> \"$GITHUB_OUTPUT\"\n\n    - name: Update other version numbers\n      shell: bash\n      run: |\n        sed -i .bak -E \\\n            -e 's/MARKETING_VERSION = [^;]+/MARKETING_VERSION = ${{ steps.version.outputs.major }}.${{ steps.version.outputs.minor }}.${{ steps.version.outputs.patch }}/' \\\n            -e 's/DYLIB_CURRENT_VERSION = [^;]+/DYLIB_CURRENT_VERSION = ${{ steps.version.outputs.major }}.${{ steps.version.outputs.minor }}.${{ steps.version.outputs.patch }}/' \\\n            -e 's/DYLIB_COMPATIBILITY_VERSION = [^;]+/DYLIB_COMPATIBILITY_VERSION = ${{ steps.version.outputs.major }}.0.0/' \\\n            -e 's/FRAMEWORK_VERSION = .*/FRAMEWORK_VERSION = ${{ steps.version.outputs.framework }};/' \\\n        LDSwiftEventSource.xcodeproj/project.pbxproj\n\n        sed -i .bak -E \\\n            -e \"s/pod 'LDSwiftEventSource', '~> [0-9]+.[0-9]+'/pod 'LDSwiftEventSource', '~> ${{ steps.version.outputs.major }}.${{ steps.version.outputs.minor }}'/\" \\\n            -e \"s/github \\\"LaunchDarkly\\/swift-eventsource\\\" ~> [0-9]+.[0-9]+/github \\\"LaunchDarkly\\/swift-eventsource\\\" ~> ${{ steps.version.outputs.major }}.${{ steps.version.outputs.minor }}/\" README.md\n\n        rm -f LDSwiftEventSource.xcodeproj/project.pbxproj.bak README.md.bak\n        if [ $(git status --porcelain | wc -l) -gt 0 ]; then\n          git config --global user.name 'LaunchDarklyReleaseBot'\n          git config --global user.email 'LaunchDarklyReleaseBot@launchdarkly.com'\n\n          git add LDSwiftEventSource.xcodeproj/project.pbxproj\n          git add README.md\n\n          git commit -m 'Updating generated project and readme files'\n          git push\n        fi\n"
  },
  {
    "path": ".github/pull_request_template.md",
    "content": "**Requirements**\n\n- [ ] I have added test coverage for new or changed functionality\n- [ ] I have followed the repository's [pull request submission guidelines](../blob/main/CONTRIBUTING.md#submitting-pull-requests)\n- [ ] I have validated my changes against all supported platform versions\n\n**Related issues**\n\nProvide links to any issues in this repository or elsewhere relating to this pull request.\n\n**Describe the solution you've provided**\n\nProvide a clear and concise description of what you expect to happen.\n\n**Describe alternatives you've considered**\n\nProvide a clear and concise description of any alternative solutions or features you've considered.\n\n**Additional context**\n\nAdd any other context about the pull request here.\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "name: Run CI\non:\n  push:\n    branches: [ main ]\n    paths-ignore:\n      - '**.md' # Do not need to run CI for markdown changes.\n  pull_request:\n    branches: [ main ]\n    paths-ignore:\n      - '**.md'\n\njobs:\n  lint:\n    runs-on: macos-15\n\n    steps:\n      - uses: actions/checkout@v4\n\n      - uses: maxim-lobanov/setup-xcode@60606e260d2fc5762a71e64e74b2174e8ea3c8bd\n        with:\n          xcode-version: 16.4\n\n      - uses: ./.github/actions/lint\n\n  build-ios:\n    runs-on: macos-15\n\n    steps:\n      - uses: actions/checkout@v4\n\n      - uses: maxim-lobanov/setup-xcode@60606e260d2fc5762a71e64e74b2174e8ea3c8bd\n        with:\n          xcode-version: 16.4\n\n      - uses: ./.github/actions/build-ios\n        with:\n          ios-sim: 'platform=iOS Simulator,name=iPhone 16'\n\n  build-macos:\n    runs-on: macos-15\n\n    steps:\n      - uses: actions/checkout@v4\n\n      - uses: maxim-lobanov/setup-xcode@60606e260d2fc5762a71e64e74b2174e8ea3c8bd\n        with:\n          xcode-version: 16.4\n\n      - uses: ./.github/actions/build-macos\n\n  build-tvos:\n    runs-on: macos-15\n\n    steps:\n      - uses: actions/checkout@v4\n\n      - uses: maxim-lobanov/setup-xcode@60606e260d2fc5762a71e64e74b2174e8ea3c8bd\n        with:\n          xcode-version: 16.4\n\n      - uses: ./.github/actions/build-tvos\n\n  build-watchos:\n    runs-on: macos-15\n\n    steps:\n      - uses: actions/checkout@v4\n\n      - uses: maxim-lobanov/setup-xcode@60606e260d2fc5762a71e64e74b2174e8ea3c8bd\n        with:\n          xcode-version: 16.4\n\n      - uses: ./.github/actions/build-watchos\n\n  test-swiftpm:\n    runs-on: macos-15\n\n    steps:\n      - uses: actions/checkout@v4\n\n      - uses: maxim-lobanov/setup-xcode@60606e260d2fc5762a71e64e74b2174e8ea3c8bd\n        with:\n          xcode-version: 16.4\n\n      - uses: ./.github/actions/test-swiftpm\n\n  contract-tests:\n    runs-on: macos-15\n\n    steps:\n      - uses: actions/checkout@v4\n\n      - uses: maxim-lobanov/setup-xcode@60606e260d2fc5762a71e64e74b2174e8ea3c8bd\n        with:\n          xcode-version: 16.4\n\n      - uses: ./.github/actions/contract-tests\n        with:\n          token: ${{ secrets.GITHUB_TOKEN }}\n\n  build-docs:\n    runs-on: macos-15\n\n    steps:\n      - uses: actions/checkout@v4\n\n      - uses: maxim-lobanov/setup-xcode@60606e260d2fc5762a71e64e74b2174e8ea3c8bd\n        with:\n          xcode-version: 16.4\n\n      - uses: ./.github/actions/build-docs\n\n  linux-build:\n    runs-on: ubuntu-latest\n\n    strategy:\n      fail-fast: false\n      matrix:\n        swift-version:\n          - 5.7\n          - 5.8\n          - 5.9\n\n    container: swift:${{ matrix.swift-version }}\n\n    steps:\n      - uses: actions/checkout@v4\n\n      - name: Build and test\n        run: swift test --enable-test-discovery\n\n  windows-build:\n    name: Windows - Swift 6.1\n    runs-on: windows-latest\n    steps:\n      - uses: actions/checkout@v4\n      - name: Install Swift\n        uses: compnerd/gha-setup-swift@cd348eb89f2f450b0664c07fb1cb66880addf17d\n        with:\n          branch: swift-6.1-release\n          tag: 6.1-RELEASE\n      - name: Build and test\n        run: swift test\n"
  },
  {
    "path": ".github/workflows/lint-pr-title.yml",
    "content": "name: Lint PR title\n\non:\n  pull_request_target:\n    types:\n      - opened\n      - edited\n      - synchronize\n\njobs:\n  lint-pr-title:\n    uses: launchdarkly/gh-actions/.github/workflows/lint-pr-title.yml@main\n"
  },
  {
    "path": ".github/workflows/manual-publish-docs.yml",
    "content": "on:\n  workflow_dispatch:\n\nname: Publish Documentation\njobs:\n  build-publish:\n    runs-on: macos-15\n\n    permissions:\n      id-token: write # Needed if using OIDC to get release secrets.\n      contents: write # Needed in this case to write github pages.\n\n    steps:\n      - uses: actions/checkout@v4\n\n      - uses: maxim-lobanov/setup-xcode@60606e260d2fc5762a71e64e74b2174e8ea3c8bd\n        with:\n          xcode-version: 16.4\n\n      - uses: ./.github/actions/lint\n\n      - uses: ./.github/actions/build-ios\n        with:\n          ios-sim: 'platform=iOS Simulator,name=iPhone 16'\n\n      - uses: ./.github/actions/build-macos\n\n      - uses: ./.github/actions/build-tvos\n\n      - uses: ./.github/actions/build-watchos\n\n      - uses: ./.github/actions/test-swiftpm\n\n      - uses: ./.github/actions/contract-tests\n        with:\n          token: ${{ secrets.GITHUB_TOKEN }}\n\n      - uses: ./.github/actions/build-docs\n\n      - uses: ./.github/actions/publish-docs\n        with:\n          token: ${{ secrets.GITHUB_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/manual-publish.yml",
    "content": "name: Publish Package\non:\n  workflow_dispatch:\n    inputs:\n      dry_run:\n        description: 'Is this a dry run. If so no package will be published.'\n        type: boolean\n        required: true\n\njobs:\n  build-publish:\n    runs-on: macos-15\n\n    # Needed to get tokens during publishing.\n    permissions:\n      id-token: write\n      contents: read\n\n    steps:\n      - uses: actions/checkout@v4\n\n      - uses: launchdarkly/gh-actions/actions/release-secrets@release-secrets-v1.2.0\n        name: 'Get Cocoapods token'\n        with:\n          aws_assume_role: ${{ vars.AWS_ROLE_ARN }}\n          ssm_parameter_pairs: '/production/common/releasing/cocoapods/token = COCOAPODS_TRUNK_TOKEN'\n\n      - uses: maxim-lobanov/setup-xcode@60606e260d2fc5762a71e64e74b2174e8ea3c8bd\n        with:\n          xcode-version: 16.4\n\n      - uses: ./.github/actions/lint\n\n      - uses: ./.github/actions/build-ios\n        with:\n          ios-sim: 'platform=iOS Simulator,name=iPhone 16'\n\n      - uses: ./.github/actions/build-macos\n\n      - uses: ./.github/actions/build-tvos\n\n      - uses: ./.github/actions/build-watchos\n\n      - uses: ./.github/actions/test-swiftpm\n\n      - uses: ./.github/actions/contract-tests\n        with:\n          token: ${{ secrets.GITHUB_TOKEN }}\n\n      - uses: ./.github/actions/publish\n        with:\n          dry_run: ${{ inputs.dry_run }}\n"
  },
  {
    "path": ".github/workflows/release-please.yml",
    "content": "name: Run Release Please\n\non:\n  push:\n    branches:\n      - main\n\njobs:\n  release-package:\n    runs-on: macos-15\n\n    permissions:\n      id-token: write # Needed if using OIDC to get release secrets.\n      contents: write # Contents and pull-requests are for release-please to make releases.\n      pull-requests: write\n\n    steps:\n      - uses: googleapis/release-please-action@16a9c90856f42705d54a6fda1823352bdc62cf38 # v4.4.0\n        id: release\n        with:\n          target-branch: ${{ github.ref_name }}\n\n      - uses: actions/checkout@v4\n        with:\n          fetch-depth: 0 # Full history is required for proper changelog generation\n\n      #\n      # This step runs and updates an existing PR\n      #\n      - uses: ./.github/actions/update-versions\n        if: ${{ steps.release.outputs.prs_created == 'true' }}\n        with:\n          branch: ${{ fromJSON(steps.release.outputs.pr).headBranchName }}\n\n      #\n      # These remaining steps are ONLY run if a release was actually created\n      #\n      - uses: launchdarkly/gh-actions/actions/release-secrets@release-secrets-v1.2.0\n        if: ${{ steps.release.outputs.releases_created == 'true' }}\n        name: 'Get Cocoapods token'\n        with:\n          aws_assume_role: ${{ vars.AWS_ROLE_ARN }}\n          ssm_parameter_pairs: '/production/common/releasing/cocoapods/token = COCOAPODS_TRUNK_TOKEN'\n\n      - uses: maxim-lobanov/setup-xcode@60606e260d2fc5762a71e64e74b2174e8ea3c8bd # 60606e260d2fc5762a71e64e74b2174e8ea3c8bd\n        if: ${{ steps.release.outputs.releases_created == 'true' }}\n        with:\n          xcode-version: 16.4\n\n      - uses: ./.github/actions/lint\n        if: ${{ steps.release.outputs.releases_created == 'true' }}\n\n      - uses: ./.github/actions/build-ios\n        if: ${{ steps.release.outputs.releases_created == 'true' }}\n        with:\n          ios-sim: 'platform=iOS Simulator,name=iPhone 16'\n\n      - uses: ./.github/actions/build-macos\n        if: ${{ steps.release.outputs.releases_created == 'true' }}\n\n      - uses: ./.github/actions/build-tvos\n        if: ${{ steps.release.outputs.releases_created == 'true' }}\n\n      - uses: ./.github/actions/build-watchos\n        if: ${{ steps.release.outputs.releases_created == 'true' }}\n\n      - uses: ./.github/actions/test-swiftpm\n        if: ${{ steps.release.outputs.releases_created == 'true' }}\n\n      - uses: ./.github/actions/contract-tests\n        if: ${{ steps.release.outputs.releases_created == 'true' }}\n        with:\n          token: ${{ secrets.GITHUB_TOKEN }}\n\n      - uses: ./.github/actions/build-docs\n        if: ${{ steps.release.outputs.releases_created == 'true' }}\n\n      - uses: ./.github/actions/publish\n        if: ${{ steps.release.outputs.releases_created == 'true' }}\n        with:\n          token: ${{secrets.GITHUB_TOKEN}}\n          dry_run: false\n\n      - uses: ./.github/actions/publish-docs\n        if: ${{ steps.release.outputs.releases_created == 'true' }}\n        with:\n          token: ${{secrets.GITHUB_TOKEN}}\n"
  },
  {
    "path": ".github/workflows/stale.yml",
    "content": "name: \"Close stale issues and PRs\"\non:\n  workflow_dispatch:\n  schedule:\n    # Happen once per day at 1:30 AM\n    - cron: \"30 1 * * *\"\n\npermissions:\n  issues: write\n  pull-requests: write\n\njobs:\n  sdk-close-stale:\n    uses: launchdarkly/gh-actions/.github/workflows/sdk-stale.yml@main\n"
  },
  {
    "path": ".gitignore",
    "content": "*~\n\\#*\n.\\#*\n.DS_Store\n/.build\nxcuserdata/\nIDEWorkspaceChecks.plist\n.swiftpm\n/docs"
  },
  {
    "path": ".jazzy.yaml",
    "content": "module: LDSwiftEventSource\nauthor: LaunchDarkly\nauthor_url: https://launchdarkly.com\ngithub_url: https://github.com/launchdarkly/swift-eventsource\nclean: true\nswift_build_tool: spm\nreadme: README.md\ndocumentation:\n  - CHANGELOG.md\n  - CONTRIBUTING.md\n  - LICENSE.txt\n\ncopyright: 'Copyright © 2020 Catamorphic Co.'\n"
  },
  {
    "path": ".release-please-manifest.json",
    "content": "{\n  \".\": \"3.3.0\"\n}\n"
  },
  {
    "path": ".swiftlint.yml",
    "content": "# See sub-configurations at `Source/.swiftlint.yml` and `Tests/.swiftlint.yml`.\n\ndisabled_rules:\n  - identifier_name\n  - weak_delegate\n\nopt_in_rules:\n  - anyobject_protocol\n  - array_init\n  - attributes\n  - closure_body_length\n  - closure_end_indentation\n  - closure_spacing\n  - collection_alignment\n  - conditional_returns_on_newline\n  - contains_over_filter_count\n  - contains_over_filter_is_empty\n  - contains_over_first_not_nil\n  - contains_over_range_nil_comparison\n  - discouraged_object_literal\n  - discouraged_optional_boolean\n  - discouraged_optional_collection\n  - empty_collection_literal\n  - empty_count\n  - empty_string\n  - empty_xctest_method\n  - enum_case_associated_values_count\n  - expiring_todo\n  - explicit_init\n  - explicit_self\n  - extension_access_modifier\n  - fallthrough\n  - fatal_error_message\n  - file_header\n  - file_name_no_space\n  - first_where\n  - flatmap_over_map_reduce\n  - function_default_parameter_at_end\n  - identical_operands\n  - implicit_return\n  - joined_default_parameter\n  - last_where\n  - legacy_multiple\n  - legacy_random\n  - let_var_whitespace\n  - literal_expression_end_indentation\n  - missing_docs\n  - modifier_order\n  - no_grouping_extension\n  - nslocalizedstring_key\n  - nslocalizedstring_require_bundle\n  - number_separator\n  - object_literal\n  - operator_usage_whitespace\n  - optional_enum_case_matching\n  - overridden_super_call\n  - override_in_extension\n  - pattern_matching_keywords\n  - prefer_self_type_over_type_of_self\n  - prefixed_toplevel_constant\n  - private_action\n  - private_outlet\n  - prohibited_interface_builder\n  - prohibited_super_call\n  - raw_value_for_camel_cased_codable_enum\n  - reduce_into\n  - redundant_nil_coalescing\n  - required_enum_case\n  - single_test_class\n  - sorted_first_last\n  - static_operator\n  - strict_fileprivate\n  - strong_iboutlet\n  - switch_case_on_newline\n  - toggle_bool\n  - trailing_closure\n  - unavailable_function\n  - unneeded_parentheses_in_closure_argument\n  - unowned_variable_capture\n  - untyped_error_in_catch\n  - unused_declaration\n  - unused_import\n  - vertical_parameter_alignment_on_call\n  - vertical_whitespace_closing_braces\n  - vertical_whitespace_opening_braces\n  - yoda_condition\n\nincluded:\n  - Source\n  - Tests\n\nreporter: \"xcode\"\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Change log\n\nAll notable changes to the LaunchDarkly Swift EventSource library will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org).\n\n## [3.3.0](https://github.com/launchdarkly/swift-eventsource/compare/3.2.0...3.3.0) (2024-05-31)\n\n\n### Features\n\n* adds ability to provide a OSLog instance via the Config.logger property ([c10ec29](https://github.com/launchdarkly/swift-eventsource/commit/c10ec2936e77959f828a041b71ea56e454e39ff2))\n* adds ability to provide a OSLog instance via the Config.logger property ([#78](https://github.com/launchdarkly/swift-eventsource/issues/78)) ([2220929](https://github.com/launchdarkly/swift-eventsource/commit/2220929cbc98edd88e0e7d8b5ccb1f3992b4cf4f))\n\n## [3.2.0](https://github.com/launchdarkly/swift-eventsource/compare/3.1.1...3.2.0) (2023-12-29)\n\n\n### Features\n\n* Add Compilation & Testing On Windows ([#68](https://github.com/launchdarkly/swift-eventsource/issues/68)) ([ac5f18c](https://github.com/launchdarkly/swift-eventsource/commit/ac5f18ccb5b197bbc9f37f9f799017a397eee43e))\n\n## [3.1.1] - 2023-06-12\n### Fixed:\n- Per the SSE spec, an HTTP 204 will now halt retry attempts by default.\n\n## [3.1.0] - 2023-06-05\n### Changed:\n- Enforce TLS v1.2 as a required minimum.\n\n### Fixed:\n- Fix re-entrancy issue with `start` command. (Thanks, [g-mark](https://github.com/launchdarkly/swift-eventsource/pull/56)!)\n\n## [3.0.0] - 2022-10-06\n### Changed\n- Dropped support for older versions in accordance with the new [Xcode 14 release](https://developer.apple.com/documentation/xcode-release-notes/xcode-14-release-notes).\n\n## [2.0.0] - 2022-08-29\n### Changed\n- The CI build now incorporates the cross-platform contract tests defined in https://github.com/launchdarkly/sse-contract-tests to ensure consistent test coverage across different LaunchDarkly SSE implementations.\n- Removed explicit typed package products. Thanks to @simba909 for the PR ([#48](https://github.com/launchdarkly/swift-eventsource/pull/48)).\n\n## [1.3.1] - 2022-03-11\n### Fixed\n- Fixed a race condition that could cause a crash when `stop()` is called when there is a pending reconnection attempt.\n\n## [1.3.0] - 2022-01-18\n### Added\n- Added the configuration option `urlSessionConfiguration` to `EventSource.Config` which allows setting the `URLSessionConfiguration` used by the `EventSource` to create `URLSession` instances.\n\n### Fixed\n- Fixed a retain cycle issue when the stream connection is ended.\n- Removed deprecated `VALID_ARCHS` build setting from Xcode project.\n- Unterminated events will no longer be dispatched when the stream connection is dropped.\n- Stream events that set the `lastEventId` will now record the updated `lastEventId` even if the event does not generate a `MessageEvent`.\n- Empty stream \"data\" fields will now always record a newline to the resultant `MessageEvent` data.\n- Empty stream \"event\" fields will result in now result in the default \"message\" event type rather than an event type of \"\".\n\n## [1.2.1] - 2021-02-10\n### Added\n- [SwiftLint](https://github.com/realm/SwiftLint) configuration. Linting will be automatically run as part of the build if [Mint](https://github.com/yonaskolb/Mint) is installed.\n- Support for building docs with [jazzy](https://github.com/realm/jazzy). These docs are available through [GitHub Pages](https://launchdarkly.github.io/swift-eventsource/).\n\n### Fixed\n- Reconnection backoff was always reset if the  previous successful connection was at least `backoffResetThreshold` prior to the scheduling of a reconnection attempt. The connection backoff has been corrected to not reset after the first reconnection attempt until the next successful connection. Thanks to  @tomasf for the PR ([#14](https://github.com/launchdarkly/swift-eventsource/pull/14)).\n- On an `UnsuccessfulResponseError` the configured `connectionErrorHandler` would be called twice, the second time with a `URLError.cancelled` error. Only if the second call returned `ConnectionErrorAction.shutdown` would the `EventSource` client actually shutdown. This has been corrected to only call the `connectionErrorHandler` once, and will shutdown the client if `ConnectionErrorAction.shutdown` is returned. Thanks to  @tomasf for the PR ([#13](https://github.com/launchdarkly/swift-eventsource/pull/13)).\n- A race condition that could cause the `EventSource` client to restart after shutting down has been fixed.\n\n## [1.2.0] - 2020-10-21\n### Added\n- Added `headerTransform` closure to `LDConfig` to allow dynamic http header configuration.\n\n## [1.1.0] - 2020-07-20\n### Added\n- Support `arm64e` on `appletvos`, `iphoneos`, and `macosx` SDKs by extending valid architectures.\n- Support for building LDSwiftEventSource on Linux. Currently this library will not generate log messages on Linux, and may not behave correctly on Linux due to Foundation being [incomplete](https://github.com/apple/swift-corelibs-foundation/blob/main/Docs/Status.md).\n\n## [1.0.0] - 2020-07-16\nThis is the first public release of the LDSwiftEventSource library. The following notes are what changed since the previous pre-release version.\n### Changed\n- Renamed `EventHandler.onMessage` parameter `event` to `eventType`.\n- The `EventSource` class no longer extends `NSObject` or `URLSessionDataDelegate` to not expose `urlSession` functions.\n\n## [0.5.0] - 2020-07-14\n### Changed\n- Default `LDSwiftEventSource` product defined for the SwiftPM package is now explicitly a dynamic product. An explicitly static product is now available as `LDSwiftEventSourceStatic`.\n\n## [0.4.0] - 2020-07-13\n### Changed\n- Converted build system to use a single target to produce a universal framework, rather than separate targets for each platform that share a product name. This is to prevent issues with `xcodebuild` resolving the build scheme to an incorrect platform when building dependent packages with 'Find Implicit Dependencies' enabled. This is due to a bug in `xcodebuild`, for more information see [http://www.openradar.me/20490378](http://www.openradar.me/20490378) and [http://www.openradar.me/22008701](http://www.openradar.me/22008701).\n\n## [0.3.0] - 2020-06-02\n### Added\n- Added `stop()` method to shutdown the EventSource connection.\n### Changed\n- Logging `subsystem` renamed from `com.launchdarkly.swift-event-source` to `com.launchdarkly.swift-eventsource`\n\n## [0.2.0] - 2020-05-21\n### Added\n- Public constructors for `UnsuccessfulResponseError` and `MessageEvent` to allow consumers of the library to use them for unit tests.\n\n## [0.1.0] - 2020-05-09\n### Added\n- Initial implementation for internal alpha testing.\n"
  },
  {
    "path": "CODEOWNERS",
    "content": "# Repository Maintainers\n* @launchdarkly/team-sdk-swift\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "Contributing to the LDSwiftEventSource library\n================================================\n\nSubmitting bug reports and feature requests\n------------------\n\nThe LaunchDarkly SDK team monitors the [issue tracker](https://github.com/launchdarkly/swift-eventsource/issues) for the EventSource repository. Bug reports and feature requests specific to this library should be filed in this issue tracker.\n\nSubmitting pull requests\n------------------\n\nWe encourage pull requests and other contributions from the community. Before submitting pull requests, ensure that all temporary or unintended code is removed. Don't worry about adding reviewers to the pull request; the LaunchDarkly SDK team will add themselves.\n\nBuild instructions\n------------------\n\n### Prerequisites\n\nThis library is built with [XCode](https://developer.apple.com/xcode/) or [SwiftPM](https://swift.org/package-manager/). The [CI build](https://github.com/launchdarkly/swift-eventsource/actions/workflows/ci.yml) builds and tests various configurations of the library on various systems, platforms, and devices. For details, see [the GitHub action CI configuration][ci-config].\n\n### Building And Testing\n\nThis library can be built directly with the Swift package manager, or through XCode. To build and run tests using SwiftPM simply:\n\n```bash\nswift test\n```\n\nOr in XCode, simply select the desired target and select `Product -> Test`.\n\nFor building on the command line with `xcodebuild`, see the [continuous integration build configuration][ci-config] for examples on building and running tests.\n\n### Running contract tests\n\nTo run the standardized contract tests that are run against all LaunchDarkly SSE client implementations:\n```\nmake contract-tests\n```\n\n### Generating API documentation\n\nDocs are built with [jazzy](https://github.com/realm/jazzy), which is configured [here](https://github.com/launchdarkly/swift-eventsource/blob/main/.jazzy.yaml). To build them, simply run `jazzy`. Pull requests should keep our documentation coverage at 100%.\n\n[ci-config]: https://github.com/launchdarkly/swift-eventsource/blob/main/.github/workflows/ci.yml\n"
  },
  {
    "path": "ContractTestService/.gitignore",
    "content": ".DS_Store\n/.build\n/Packages\n/*.xcodeproj\nxcuserdata/\nDerivedData/\n.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata\n"
  },
  {
    "path": "ContractTestService/Package.resolved",
    "content": "{\n  \"object\": {\n    \"pins\": [\n      {\n        \"package\": \"Socket\",\n        \"repositoryURL\": \"https://github.com/Kitura/BlueSocket.git\",\n        \"state\": {\n          \"branch\": null,\n          \"revision\": \"c9894fd117457f1d006575fbfb2fdfd6f79eac03\",\n          \"version\": \"1.0.200\"\n        }\n      },\n      {\n        \"package\": \"SSLService\",\n        \"repositoryURL\": \"https://github.com/Kitura/BlueSSLService.git\",\n        \"state\": {\n          \"branch\": null,\n          \"revision\": \"ae5889d2a8b068d2d3ab91ec73aa8f557c03cd8a\",\n          \"version\": \"1.0.200\"\n        }\n      },\n      {\n        \"package\": \"Kitura\",\n        \"repositoryURL\": \"https://github.com/Kitura/Kitura\",\n        \"state\": {\n          \"branch\": null,\n          \"revision\": \"daf6479097469a0c1fe64755db6e23f788a3ec29\",\n          \"version\": \"2.9.200\"\n        }\n      },\n      {\n        \"package\": \"Kitura-net\",\n        \"repositoryURL\": \"https://github.com/Kitura/Kitura-net.git\",\n        \"state\": {\n          \"branch\": null,\n          \"revision\": \"e017a57772eb477c294d72b25ab9ae38d25539f5\",\n          \"version\": \"2.4.200\"\n        }\n      },\n      {\n        \"package\": \"Kitura-TemplateEngine\",\n        \"repositoryURL\": \"https://github.com/Kitura/Kitura-TemplateEngine.git\",\n        \"state\": {\n          \"branch\": null,\n          \"revision\": \"1670b09bfb63b66f7dffff627a06b50492485407\",\n          \"version\": \"2.0.200\"\n        }\n      },\n      {\n        \"package\": \"KituraContracts\",\n        \"repositoryURL\": \"https://github.com/Kitura/KituraContracts.git\",\n        \"state\": {\n          \"branch\": null,\n          \"revision\": \"8a4778c3aa7833e9e1af884e8819d436c237cd70\",\n          \"version\": \"1.2.201\"\n        }\n      },\n      {\n        \"package\": \"LoggerAPI\",\n        \"repositoryURL\": \"https://github.com/Kitura/LoggerAPI.git\",\n        \"state\": {\n          \"branch\": null,\n          \"revision\": \"e82d34eab3f0b05391082b11ea07d3b70d2f65bb\",\n          \"version\": \"1.9.200\"\n        }\n      },\n      {\n        \"package\": \"swift-log\",\n        \"repositoryURL\": \"https://github.com/apple/swift-log.git\",\n        \"state\": {\n          \"branch\": null,\n          \"revision\": \"5d66f7ba25daf4f94100e7022febf3c75e37a6c7\",\n          \"version\": \"1.4.2\"\n        }\n      },\n      {\n        \"package\": \"TypeDecoder\",\n        \"repositoryURL\": \"https://github.com/Kitura/TypeDecoder.git\",\n        \"state\": {\n          \"branch\": null,\n          \"revision\": \"28ec01815c0aea9236f92982ca8d351e7112a4a0\",\n          \"version\": \"1.3.201\"\n        }\n      }\n    ]\n  },\n  \"version\": 1\n}\n"
  },
  {
    "path": "ContractTestService/Package.swift",
    "content": "// swift-tools-version:5.0\n\nimport PackageDescription\n\nlet package = Package(\n  name: \"ContractTestService\",\n  platforms: [\n    .iOS(.v11),\n    .macOS(.v10_13),\n    .watchOS(.v4),\n    .tvOS(.v11),\n  ],\n  products: [\n    .executable(\n      name: \"contract-test-service\",\n      targets: [\"ContractTestService\"]\n    )\n  ],\n  dependencies: [\n    // Local dependency to LDSwiftEventSource\n    .package(path: \"..\"),\n    .package(url: \"https://github.com/Kitura/Kitura\", from: \"2.9.200\")\n  ],\n  targets: [\n    .target(\n      name: \"ContractTestService\",\n      dependencies: [\n        \"LDSwiftEventSource\",\n        \"Kitura\"\n      ]\n    )\n  ]\n)\n"
  },
  {
    "path": "ContractTestService/README.md",
    "content": "# SSE client contract test service\n\nThis directory contains an implementation of the cross-platform SSE testing protocol defined by https://github.com/launchdarkly/sse-contract-tests. See that project's `README` for details of this protocol, and the kinds of SSE client capabilities that are relevant to the contract tests. This code should not need to be updated unless the SSE client has added or removed such capabilities.\n\nTo run these tests locally, run `make contract-tests` from the project root directory. This downloads the correct version of the test harness tool automatically.\n"
  },
  {
    "path": "ContractTestService/Sources/ContractTestService/main.swift",
    "content": "import Dispatch\nimport Foundation\nimport Kitura\nimport LDSwiftEventSource\n\nstruct StatusResp: Encodable {\n    let name = \"swift-eventsource\"\n    let capabilities = [\"server-directed-shutdown-request\", \"comments\", \"headers\", \"last-event-id\", \"post\", \"read-timeout\", \"report\"]\n}\n\nstruct CreateStreamReq: Decodable {\n    let streamUrl: URL\n    let callbackUrl: URL\n    let initialDelayMs: Int?\n    let readTimeoutMs: Int?\n    let lastEventId: String?\n    let headers: [String: String]?\n    let method: String?\n    let body: String?\n\n    func createEventSourceConfig() -> EventSource.Config {\n        var esConfig = EventSource.Config(handler: CallbackHandler(baseUrl: callbackUrl), url: streamUrl)\n        if let initialDelayMs = initialDelayMs { esConfig.reconnectTime = Double(initialDelayMs) / 1000.0 }\n        if let readTimeoutMs = readTimeoutMs { esConfig.idleTimeout = Double(readTimeoutMs) / 1000.0 }\n        if let lastEventId = lastEventId { esConfig.lastEventId = lastEventId }\n        if let headers = headers { esConfig.headers = headers }\n        if let method = method { esConfig.method = method }\n        if let body = body { esConfig.body = Data(body.utf8) }\n        return esConfig\n    }\n}\n\nclass CallbackHandler: EventHandler {\n    struct EventPayloadEvent: Encodable {\n        let type: String\n        let data: String\n        let id: String?\n    }\n\n    struct EventPayload: Encodable {\n        let kind = \"event\"\n        let event: EventPayloadEvent\n    }\n\n    struct CommentPayload: Encodable {\n        let kind = \"comment\"\n        let comment: String\n    }\n\n    struct ErrorPayload: Encodable {\n        let kind = \"error\"\n    }\n\n    let baseUrl: URL\n    var count = 0\n\n    init(baseUrl: URL) {\n        self.baseUrl = baseUrl\n    }\n\n    func onOpened() { }\n    func onClosed() { }\n\n    func sendUpdate<T: Encodable>(_ update: T) {\n        count += 1\n        var request = URLRequest(url: baseUrl.appendingPathComponent(String(count), isDirectory: false))\n        request.httpMethod = \"POST\"\n        let data = try! JSONEncoder().encode(update)\n        URLSession.shared.uploadTask(with: request, from: data) { _, _, _ in }.resume()\n    }\n\n    func onMessage(eventType type: String, messageEvent msg: MessageEvent) {\n        sendUpdate(EventPayload(event: EventPayloadEvent(type: type, data: msg.data, id: msg.lastEventId)))\n    }\n\n    func onComment(comment: String) {\n        sendUpdate(CommentPayload(comment: comment))\n    }\n\n    func onError(error: Error) {\n        sendUpdate(ErrorPayload())\n    }\n}\n\nlet stateQueue = DispatchQueue(label: \"StateQueue\")\nvar nextId: Int = 0\nvar state: [String: EventSource] = [:]\n\nlet router = Router()\n\nrouter.get(\"/\") { _, resp, next in\n    resp.send(StatusResp())\n    next()\n}\n\nrouter.delete(\"/\") { _, resp, next in\n    resp.send([\"message\": \"Shutting down contract test service\"])\n    next()\n    Kitura.stop()\n}\n\nrouter.post(\"/\") { req, resp, next in\n    guard let createStreamReq = try? req.read(as: CreateStreamReq.self)\n    else {\n        resp.status(.badRequest).send([\"message\": \"Body of POST to '/' invalid\"])\n        return next()\n    }\n    let es = EventSource(config: createStreamReq.createEventSourceConfig())\n    let location: String = stateQueue.sync {\n        state[String(nextId)] = es\n        nextId += 1\n        return \"/control/\\(nextId - 1)\"\n    }\n    es.start()\n    resp.headers[\"Location\"] = location\n    resp.send([\"message\": \"Created test service entity at \\(location)\"])\n    next()\n}\n\nrouter.delete(\"/control/:id\") { req, resp, next in\n    stateQueue.sync {\n        if let es = state.removeValue(forKey: req.parameters[\"id\"]!) {\n            es.stop()\n            resp.send([\"message\": \"Shut down test service entity at \\(req.matchedPath)\"])\n        } else {\n            resp.status(.notFound).send([\"message\": \"Test service entity not found at \\(req.matchedPath)\"])\n        }\n    }\n    next()\n}\n\nKitura.addHTTPServer(onPort: 8000, onAddress: \"localhost\", with: router)\nKitura.run()\n"
  },
  {
    "path": "LDSwiftEventSource.podspec",
    "content": "Pod::Spec.new do |s|\n  s.name         = \"LDSwiftEventSource\"\n  s.version      = \"3.3.0\" # x-release-please-version\n  s.summary      = \"Swift EventSource library\"\n  s.homepage     = \"https://github.com/launchdarkly/swift-eventsource\"\n  s.license      = { :type => \"Apache License, Version 2.0\", :file => \"LICENSE.txt\" }\n  s.author       = { \"LaunchDarkly\" => \"sdks@launchdarkly.com\" }\n\n  s.ios.deployment_target     = \"11.0\"\n  s.watchos.deployment_target = \"4.0\"\n  s.tvos.deployment_target    = \"11.0\"\n  s.osx.deployment_target     = \"10.13\"\n\n  s.source       = { :git => s.homepage + '.git', :tag => s.version}\n  s.source_files = \"Source/**/*.swift\"\n\n  s.swift_versions = ['5.0', '5.1', '5.2', '5.3', '5.4', '5.5', '5.6', '5.7']\nend\n"
  },
  {
    "path": "LDSwiftEventSource.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\tB426585E272849AF007B711A /* MockHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = B426585D272849AF007B711A /* MockHandler.swift */; };\n\t\tB495D4A9248652DF00AE9233 /* Types.swift in Sources */ = {isa = PBXBuildFile; fileRef = B495D4A7248652DF00AE9233 /* Types.swift */; };\n\t\tB49B5E4B24667F62008BF867 /* UTF8LineParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = B49B5E4524667F43008BF867 /* UTF8LineParser.swift */; };\n\t\tB49B5E4C24667F62008BF867 /* EventParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = B49B5E4624667F43008BF867 /* EventParser.swift */; };\n\t\tB49B5E4D24667F62008BF867 /* LDSwiftEventSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = B49B5E4724667F43008BF867 /* LDSwiftEventSource.swift */; };\n\t\tB49B5E5824668031008BF867 /* EventParserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B49B5E4024667F43008BF867 /* EventParserTests.swift */; };\n\t\tB49B5E5A24668031008BF867 /* UTF8LineParserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B49B5E4224667F43008BF867 /* UTF8LineParserTests.swift */; };\n\t\tB49B5E5B24668031008BF867 /* LDSwiftEventSourceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B49B5E4324667F43008BF867 /* LDSwiftEventSourceTests.swift */; };\n\t\tB49B5E67246684B9008BF867 /* LDSwiftEventSource.h in Headers */ = {isa = PBXBuildFile; fileRef = B49B5E65246684B9008BF867 /* LDSwiftEventSource.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\tB49B5E72246C4796008BF867 /* LDSwiftEventSource.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B49B5DFC24667D41008BF867 /* LDSwiftEventSource.framework */; };\n\t\tB4BCAE6E272753FA000EBD43 /* TestUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4BCAE6D272753FA000EBD43 /* TestUtil.swift */; };\n\t\tB4C29CC826FF743D008B6DE2 /* Logs.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4C29CC726FF743C008B6DE2 /* Logs.swift */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXContainerItemProxy section */\n\t\tB49B5E0624667D42008BF867 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = B49B5DB824667C44008BF867 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = B49B5DFB24667D41008BF867;\n\t\t\tremoteInfo = \"LDSwiftEventSource macOS\";\n\t\t};\n/* End PBXContainerItemProxy section */\n\n/* Begin PBXFileReference section */\n\t\tB426585D272849AF007B711A /* MockHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockHandler.swift; sourceTree = \"<group>\"; };\n\t\tB495D4A7248652DF00AE9233 /* Types.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Types.swift; sourceTree = \"<group>\"; };\n\t\tB49B5DE324667D06008BF867 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\tB49B5DFC24667D41008BF867 /* LDSwiftEventSource.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = LDSwiftEventSource.framework; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tB49B5E0424667D42008BF867 /* LDSwiftEventSource Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = \"LDSwiftEventSource Tests.xctest\"; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tB49B5E4024667F43008BF867 /* EventParserTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventParserTests.swift; sourceTree = \"<group>\"; };\n\t\tB49B5E4224667F43008BF867 /* UTF8LineParserTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UTF8LineParserTests.swift; sourceTree = \"<group>\"; };\n\t\tB49B5E4324667F43008BF867 /* LDSwiftEventSourceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LDSwiftEventSourceTests.swift; sourceTree = \"<group>\"; };\n\t\tB49B5E4524667F43008BF867 /* UTF8LineParser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UTF8LineParser.swift; sourceTree = \"<group>\"; };\n\t\tB49B5E4624667F43008BF867 /* EventParser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventParser.swift; sourceTree = \"<group>\"; };\n\t\tB49B5E4724667F43008BF867 /* LDSwiftEventSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LDSwiftEventSource.swift; sourceTree = \"<group>\"; };\n\t\tB49B5E65246684B9008BF867 /* LDSwiftEventSource.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LDSwiftEventSource.h; sourceTree = \"<group>\"; };\n\t\tB49B5E6B2466875F008BF867 /* LDSwiftEventSource.podspec */ = {isa = PBXFileReference; lastKnownFileType = text; path = LDSwiftEventSource.podspec; sourceTree = \"<group>\"; };\n\t\tB49B5E6C2466875F008BF867 /* CHANGELOG.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = CHANGELOG.md; sourceTree = \"<group>\"; };\n\t\tB49B5E6D2466875F008BF867 /* CONTRIBUTING.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = CONTRIBUTING.md; sourceTree = \"<group>\"; };\n\t\tB49B5E6E2466875F008BF867 /* LICENSE.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE.txt; sourceTree = \"<group>\"; };\n\t\tB49B5E6F2466875F008BF867 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = \"<group>\"; };\n\t\tB49B5E702466875F008BF867 /* Package.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = \"<group>\"; };\n\t\tB4BCAE6D272753FA000EBD43 /* TestUtil.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestUtil.swift; sourceTree = \"<group>\"; };\n\t\tB4C29CC726FF743C008B6DE2 /* Logs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Logs.swift; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\tB49B5DF924667D41008BF867 /* 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\tB49B5E0124667D42008BF867 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tB49B5E72246C4796008BF867 /* LDSwiftEventSource.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\tB49B5DB724667C44008BF867 = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB49B5E6A2466873F008BF867 /* Misc */,\n\t\t\t\tB49B5E4424667F43008BF867 /* Source */,\n\t\t\t\tB49B5E3F24667F43008BF867 /* Tests */,\n\t\t\t\tB49B5DC224667C44008BF867 /* Products */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB49B5DC224667C44008BF867 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB49B5DFC24667D41008BF867 /* LDSwiftEventSource.framework */,\n\t\t\t\tB49B5E0424667D42008BF867 /* LDSwiftEventSource Tests.xctest */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB49B5E3F24667F43008BF867 /* Tests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB49B5E4024667F43008BF867 /* EventParserTests.swift */,\n\t\t\t\tB49B5E4224667F43008BF867 /* UTF8LineParserTests.swift */,\n\t\t\t\tB49B5E4324667F43008BF867 /* LDSwiftEventSourceTests.swift */,\n\t\t\t\tB4BCAE6D272753FA000EBD43 /* TestUtil.swift */,\n\t\t\t\tB426585D272849AF007B711A /* MockHandler.swift */,\n\t\t\t);\n\t\t\tpath = Tests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB49B5E4424667F43008BF867 /* Source */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB49B5DE324667D06008BF867 /* Info.plist */,\n\t\t\t\tB49B5E4524667F43008BF867 /* UTF8LineParser.swift */,\n\t\t\t\tB49B5E4624667F43008BF867 /* EventParser.swift */,\n\t\t\t\tB49B5E4724667F43008BF867 /* LDSwiftEventSource.swift */,\n\t\t\t\tB49B5E65246684B9008BF867 /* LDSwiftEventSource.h */,\n\t\t\t\tB495D4A7248652DF00AE9233 /* Types.swift */,\n\t\t\t\tB4C29CC726FF743C008B6DE2 /* Logs.swift */,\n\t\t\t);\n\t\t\tpath = Source;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB49B5E6A2466873F008BF867 /* Misc */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB49B5E6C2466875F008BF867 /* CHANGELOG.md */,\n\t\t\t\tB49B5E6D2466875F008BF867 /* CONTRIBUTING.md */,\n\t\t\t\tB49B5E6B2466875F008BF867 /* LDSwiftEventSource.podspec */,\n\t\t\t\tB49B5E6E2466875F008BF867 /* LICENSE.txt */,\n\t\t\t\tB49B5E702466875F008BF867 /* Package.swift */,\n\t\t\t\tB49B5E6F2466875F008BF867 /* README.md */,\n\t\t\t);\n\t\t\tname = Misc;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXHeadersBuildPhase section */\n\t\tB49B5DF724667D41008BF867 /* Headers */ = {\n\t\t\tisa = PBXHeadersBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tB49B5E67246684B9008BF867 /* LDSwiftEventSource.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\tB49B5DFB24667D41008BF867 /* LDSwiftEventSource */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = B49B5E0D24667D42008BF867 /* Build configuration list for PBXNativeTarget \"LDSwiftEventSource\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tB46C1C6B24CF348B00283630 /* Linter Script */,\n\t\t\t\tB49B5DF724667D41008BF867 /* Headers */,\n\t\t\t\tB49B5DF824667D41008BF867 /* Sources */,\n\t\t\t\tB49B5DF924667D41008BF867 /* Frameworks */,\n\t\t\t\tB49B5DFA24667D41008BF867 /* 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 = LDSwiftEventSource;\n\t\t\tproductName = \"LDSwiftEventSource macOS\";\n\t\t\tproductReference = B49B5DFC24667D41008BF867 /* LDSwiftEventSource.framework */;\n\t\t\tproductType = \"com.apple.product-type.framework\";\n\t\t};\n\t\tB49B5E0324667D42008BF867 /* LDSwiftEventSource Tests */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = B49B5E1024667D42008BF867 /* Build configuration list for PBXNativeTarget \"LDSwiftEventSource Tests\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tB49B5E0024667D42008BF867 /* Sources */,\n\t\t\t\tB49B5E0124667D42008BF867 /* Frameworks */,\n\t\t\t\tB49B5E0224667D42008BF867 /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\tB49B5E0724667D42008BF867 /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = \"LDSwiftEventSource Tests\";\n\t\t\tproductName = \"LDSwiftEventSource macOSTests\";\n\t\t\tproductReference = B49B5E0424667D42008BF867 /* LDSwiftEventSource Tests.xctest */;\n\t\t\tproductType = \"com.apple.product-type.bundle.unit-test\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\tB49B5DB824667C44008BF867 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastSwiftUpdateCheck = 1140;\n\t\t\t\tLastUpgradeCheck = 1140;\n\t\t\t\tORGANIZATIONNAME = LaunchDarkly;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\tB49B5DFB24667D41008BF867 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 11.4;\n\t\t\t\t\t};\n\t\t\t\t\tB49B5E0324667D42008BF867 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 11.4;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = B49B5DBB24667C44008BF867 /* Build configuration list for PBXProject \"LDSwiftEventSource\" */;\n\t\t\tcompatibilityVersion = \"Xcode 10.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 = B49B5DB724667C44008BF867;\n\t\t\tproductRefGroup = B49B5DC224667C44008BF867 /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\tB49B5DFB24667D41008BF867 /* LDSwiftEventSource */,\n\t\t\t\tB49B5E0324667D42008BF867 /* LDSwiftEventSource Tests */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\tB49B5DFA24667D41008BF867 /* 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\tB49B5E0224667D42008BF867 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXShellScriptBuildPhase section */\n\t\tB46C1C6B24CF348B00283630 /* Linter Script */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\talwaysOutOfDate = 1;\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 = \"Linter Script\";\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 = \"# Adds support for Apple Silicon brew directory\\nexport PATH=\\\"$PATH:/opt/homebrew/bin\\\"\\n\\nif which mint >/dev/null; then\\n  /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint\\nelse\\n  echo \\\"warning: mint not installed, available from https://github.com/yonaskolb/Mint\\\"\\nfi\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n/* End PBXShellScriptBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\tB49B5DF824667D41008BF867 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tB49B5E4B24667F62008BF867 /* UTF8LineParser.swift in Sources */,\n\t\t\t\tB4C29CC826FF743D008B6DE2 /* Logs.swift in Sources */,\n\t\t\t\tB495D4A9248652DF00AE9233 /* Types.swift in Sources */,\n\t\t\t\tB49B5E4C24667F62008BF867 /* EventParser.swift in Sources */,\n\t\t\t\tB49B5E4D24667F62008BF867 /* LDSwiftEventSource.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tB49B5E0024667D42008BF867 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tB49B5E5824668031008BF867 /* EventParserTests.swift in Sources */,\n\t\t\t\tB49B5E5A24668031008BF867 /* UTF8LineParserTests.swift in Sources */,\n\t\t\t\tB426585E272849AF007B711A /* MockHandler.swift in Sources */,\n\t\t\t\tB49B5E5B24668031008BF867 /* LDSwiftEventSourceTests.swift in Sources */,\n\t\t\t\tB4BCAE6E272753FA000EBD43 /* TestUtil.swift 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\tB49B5E0724667D42008BF867 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = B49B5DFB24667D41008BF867 /* LDSwiftEventSource */;\n\t\t\ttargetProxy = B49B5E0624667D42008BF867 /* PBXContainerItemProxy */;\n\t\t};\n/* End PBXTargetDependency section */\n\n/* Begin XCBuildConfiguration section */\n\t\tB49B5DD324667C44008BF867 /* 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_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++14\";\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_ENABLE_OBJC_WEAK = 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_DOCUMENTATION_COMMENTS = YES;\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_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\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\t\"COMBINE_HIDPI_IMAGES[sdk=macosx]\" = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tFRAMEWORK_VERSION = C;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tINFOPLIST_FILE = Source/Info.plist;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 11.0;\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.13;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.launchdarkly.LDSwiftEventSource;\n\t\t\t\tPRODUCT_NAME = LDSwiftEventSource;\n\t\t\t\tSDKROOT = macosx;\n\t\t\t\tSUPPORTED_PLATFORMS = \"macosx iphoneos iphonesimulator appletvos appletvsimulator watchos watchsimulator\";\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTVOS_DEPLOYMENT_TARGET = 11.0;\n\t\t\t\tVERSIONING_SYSTEM = \"apple-generic\";\n\t\t\t\tVERSION_INFO_PREFIX = \"\";\n\t\t\t\tWATCHOS_DEPLOYMENT_TARGET = 4.0;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tB49B5DD424667C44008BF867 /* 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_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++14\";\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_ENABLE_OBJC_WEAK = 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_DOCUMENTATION_COMMENTS = YES;\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_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\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\t\"COMBINE_HIDPI_IMAGES[sdk=macosx]\" = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tFRAMEWORK_VERSION = C;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\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\tINFOPLIST_FILE = Source/Info.plist;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 11.0;\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.13;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.launchdarkly.LDSwiftEventSource;\n\t\t\t\tPRODUCT_NAME = LDSwiftEventSource;\n\t\t\t\tSDKROOT = macosx;\n\t\t\t\tSUPPORTED_PLATFORMS = \"macosx iphoneos iphonesimulator appletvos appletvsimulator watchos watchsimulator\";\n\t\t\t\tSWIFT_COMPILATION_MODE = wholemodule;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-O\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTVOS_DEPLOYMENT_TARGET = 11.0;\n\t\t\t\tVERSIONING_SYSTEM = \"apple-generic\";\n\t\t\t\tVERSION_INFO_PREFIX = \"\";\n\t\t\t\tWATCHOS_DEPLOYMENT_TARGET = 4.0;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tB49B5E0E24667D42008BF867 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tAPPLICATION_EXTENSION_API_ONLY = YES;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEFINES_MODULE = YES;\n\t\t\t\tDYLIB_COMPATIBILITY_VERSION = 3.0.0;\n\t\t\t\tDYLIB_CURRENT_VERSION = 3.3.0;\n\t\t\t\tDYLIB_INSTALL_NAME_BASE = \"@rpath\";\n\t\t\t\tENABLE_BITCODE = YES;\n\t\t\t\t\"ENABLE_BITCODE[sdk=macosx*]\" = NO;\n\t\t\t\tINFOPLIST_FILE = \"$(inherited)\";\n\t\t\t\tINSTALL_PATH = \"$(LOCAL_LIBRARY_DIR)/Frameworks\";\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\t\"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]\" = (\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\tMARKETING_VERSION = 3.3.0;\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t\t\"TARGETED_DEVICE_FAMILY[sdk=appletvos*]\" = 3;\n\t\t\t\t\"TARGETED_DEVICE_FAMILY[sdk=appletvsimulator*]\" = 3;\n\t\t\t\t\"TARGETED_DEVICE_FAMILY[sdk=iphoneos*]\" = \"1,2\";\n\t\t\t\t\"TARGETED_DEVICE_FAMILY[sdk=iphonesimulator*]\" = \"1,2\";\n\t\t\t\t\"TARGETED_DEVICE_FAMILY[sdk=watchos*]\" = 4;\n\t\t\t\t\"TARGETED_DEVICE_FAMILY[sdk=watchsimulator*]\" = 4;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tB49B5E0F24667D42008BF867 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tAPPLICATION_EXTENSION_API_ONLY = YES;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEFINES_MODULE = YES;\n\t\t\t\tDYLIB_COMPATIBILITY_VERSION = 3.0.0;\n\t\t\t\tDYLIB_CURRENT_VERSION = 3.3.0;\n\t\t\t\tDYLIB_INSTALL_NAME_BASE = \"@rpath\";\n\t\t\t\tENABLE_BITCODE = YES;\n\t\t\t\t\"ENABLE_BITCODE[sdk=macosx*]\" = NO;\n\t\t\t\tINFOPLIST_FILE = \"$(inherited)\";\n\t\t\t\tINSTALL_PATH = \"$(LOCAL_LIBRARY_DIR)/Frameworks\";\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\t\"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]\" = (\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\tMARKETING_VERSION = 3.3.0;\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t\t\"TARGETED_DEVICE_FAMILY[sdk=appletvos*]\" = 3;\n\t\t\t\t\"TARGETED_DEVICE_FAMILY[sdk=appletvsimulator*]\" = 3;\n\t\t\t\t\"TARGETED_DEVICE_FAMILY[sdk=iphoneos*]\" = \"1,2\";\n\t\t\t\t\"TARGETED_DEVICE_FAMILY[sdk=iphonesimulator*]\" = \"1,2\";\n\t\t\t\t\"TARGETED_DEVICE_FAMILY[sdk=watchos*]\" = 4;\n\t\t\t\t\"TARGETED_DEVICE_FAMILY[sdk=watchsimulator*]\" = 4;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tB49B5E1124667D42008BF867 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tINFOPLIST_FILE = \"$(inherited)\";\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\t\"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]\" = (\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\tPRODUCT_BUNDLE_IDENTIFIER = com.launchdarkly.LDSwiftEventSourceTests;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSUPPORTED_PLATFORMS = \"macosx iphoneos iphonesimulator appletvos appletvsimulator\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tB49B5E1224667D42008BF867 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tINFOPLIST_FILE = \"$(inherited)\";\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\t\"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]\" = (\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\tPRODUCT_BUNDLE_IDENTIFIER = com.launchdarkly.LDSwiftEventSourceTests;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSUPPORTED_PLATFORMS = \"macosx iphoneos iphonesimulator appletvos appletvsimulator\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\tB49B5DBB24667C44008BF867 /* Build configuration list for PBXProject \"LDSwiftEventSource\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tB49B5DD324667C44008BF867 /* Debug */,\n\t\t\t\tB49B5DD424667C44008BF867 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tB49B5E0D24667D42008BF867 /* Build configuration list for PBXNativeTarget \"LDSwiftEventSource\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tB49B5E0E24667D42008BF867 /* Debug */,\n\t\t\t\tB49B5E0F24667D42008BF867 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tB49B5E1024667D42008BF867 /* Build configuration list for PBXNativeTarget \"LDSwiftEventSource Tests\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tB49B5E1124667D42008BF867 /* Debug */,\n\t\t\t\tB49B5E1224667D42008BF867 /* 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 = B49B5DB824667C44008BF867 /* Project object */;\n}\n"
  },
  {
    "path": "LDSwiftEventSource.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"self:LDSwiftEventSource.xcodeproj\">\n   </FileRef>\n</Workspace>\n"
  },
  {
    "path": "LDSwiftEventSource.xcodeproj/xcshareddata/xcschemes/LDSwiftEventSource.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1140\"\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 = \"B49B5DFB24667D41008BF867\"\n               BuildableName = \"LDSwiftEventSource.framework\"\n               BlueprintName = \"LDSwiftEventSource\"\n               ReferencedContainer = \"container:LDSwiftEventSource.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      systemAttachmentLifetime = \"keepNever\"\n      codeCoverageEnabled = \"YES\">\n      <Testables>\n         <TestableReference\n            skipped = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"B49B5E0324667D42008BF867\"\n               BuildableName = \"LDSwiftEventSource Tests.xctest\"\n               BlueprintName = \"LDSwiftEventSource Tests\"\n               ReferencedContainer = \"container:LDSwiftEventSource.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"B49B5DFB24667D41008BF867\"\n            BuildableName = \"LDSwiftEventSource.framework\"\n            BlueprintName = \"LDSwiftEventSource\"\n            ReferencedContainer = \"container:LDSwiftEventSource.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"B49B5DFB24667D41008BF867\"\n            BuildableName = \"LDSwiftEventSource.framework\"\n            BlueprintName = \"LDSwiftEventSource\"\n            ReferencedContainer = \"container:LDSwiftEventSource.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "LICENSE.txt",
    "content": "Copyright 2020 Catamorphic, Co.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n"
  },
  {
    "path": "Makefile",
    "content": "build:\n\tswift build\n\nclean:\n\tswift clean\n\ntest:\n\tswift test\n\nTEMP_TEST_OUTPUT=/tmp/sse-contract-test-service.log\n\nbuild-contract-tests:\n\tcd ContractTestService && swift build\n\nstart-contract-test-service:\n\t./ContractTestService/.build/debug/contract-test-service\n\nstart-contract-test-service-bg:\n\techo \"Test service output will be captured in $(TEMP_TEST_OUTPUT)\"\n\tmake start-contract-test-service >$(TEMP_TEST_OUTPUT) 2>&1 &\n\nrun-contract-tests:\n\tcurl -s https://raw.githubusercontent.com/launchdarkly/sse-contract-tests/main/downloader/run.sh \\\n\t\t| VERSION=v2 PARAMS=\"-url http://localhost:8000 -debug -stop-service-at-end -skip 'basic parsing/large message in one chunk' -skip 'basic parsing/large message in two chunks'\" sh\n\ncontract-tests: build-contract-tests start-contract-test-service-bg run-contract-tests\n\n.PHONY: build clean test build-contract-tests start-contract-test-service run-contract-tests contract-tests\n"
  },
  {
    "path": "Package.swift",
    "content": "// swift-tools-version:5.0\n\nimport PackageDescription\n\nlet package = Package(\n    name: \"LDSwiftEventSource\",\n    platforms: [\n        .iOS(.v11),\n        .macOS(.v10_13),\n        .watchOS(.v4),\n        .tvOS(.v11)\n    ],\n    products: [\n        .library(name: \"LDSwiftEventSource\", targets: [\"LDSwiftEventSource\"]),\n    ],\n    dependencies: [],\n    targets: [\n        .target(\n            name: \"LDSwiftEventSource\",\n            path: \"Source\"),\n        .testTarget(\n            name: \"LDSwiftEventSourceTests\",\n            dependencies: [\"LDSwiftEventSource\"],\n            path: \"Tests\"),\n    ],\n    swiftLanguageVersions: [.v5])\n"
  },
  {
    "path": "README.md",
    "content": "# LDSwiftEventSource\n\n[![Run CI](https://github.com/launchdarkly/swift-eventsource/actions/workflows/ci.yml/badge.svg)](https://github.com/launchdarkly/swift-eventsource/actions/workflows/ci.yml)\n[![CocoaPods](https://img.shields.io/cocoapods/v/LDSwiftEventSource.svg)](https://cocoapods.org/pods/LDSwiftEventSource)\n[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)\n[![SwiftPM compatible](https://img.shields.io/badge/SwiftPM-compatible-4BC51D.svg?style=flat)](https://swift.org/package-manager/)\n[![Platform](https://img.shields.io/cocoapods/p/LDSwiftEventSource.svg?style=flat)](https://cocoapods.org/pods/LDSwiftEventSource)\n\nLDSwiftEventSource is a cross platform implementation of the [EventSource specification](https://html.spec.whatwg.org/multipage/server-sent-events.html) written in Swift. It was developed for use in the [LaunchDarkly iOS SDK](https://github.com/launchdarkly/ios-client-sdk). Generated API docs are available on [GitHub Pages](https://launchdarkly.github.io/swift-eventsource/).\n\n## Requirements\n- iOS 11.0+ / watchOS 4.0+ / tvOS 11.0+ / macOS 10.13+\n- Swift 5.1+\n\n## Installation\n\n### CocoaPods\n\nTo use the [CocoaPods](https://cocoapods.org) dependency manager to integrate LDSwiftEventSource into your Xcode project, specify it in your `Podfile`:\n\n```ruby\npod 'LDSwiftEventSource', '~> 3.3'\n```\n\n### Carthage\n\nTo use the [Carthage](https://github.com/Carthage/Carthage) dependency manager to integrate LDSwiftEventSource into your Xcode project, specify it in your `Cartfile`:\n\n```ogdl\ngithub \"LaunchDarkly/swift-eventsource\" ~> 3.3\n```\n\n### Swift Package Manager\n\nThe [Swift Package Manager](https://swift.org/package-manager/) is a dependency manager integrated into the `swift` compiler and Xcode. Note that the LDSwiftEventSource Swift package provides both a `LDSwiftEventSource` product, which is explicitly dynamic, and a `LDSwiftEventSourceStatic` product which is explicitly static.\n\nTo integrate LDSwiftEventSource into an Xcode project, go to the project editor, and select `Swift Packages`. From here hit the `+` button and follow the prompts using  `https://github.com/LaunchDarkly/swift-eventsource.git` as the URL.\n\nTo include LDSwiftEventSource in a Swift package, simply add it to the dependencies section of your `Package.swift` file. And add the desired product as a dependency for your targets.\n\n<!-- x-release-please-start-version -->\n```swift\ndependencies: [\n    .package(url: \"https://github.com/LaunchDarkly/swift-eventsource.git\", .upToNextMajor(from: \"3.3.0\"))\n]\n```\n<!-- x-release-please-end -->\n\n## Contributing\n\nWe encourage pull requests and other contributions from the community. Check out our [contributing guidelines](https://github.com/LaunchDarkly/swift-eventsource/blob/main/CONTRIBUTING.md) for instructions on how to contribute to this SDK.\n\n## About LaunchDarkly\n\n* LaunchDarkly is a continuous delivery platform that provides feature flags as a service and allows developers to iterate quickly and safely. We allow you to easily flag your features and manage them from the LaunchDarkly dashboard.  With LaunchDarkly, you can:\n    * Roll out a new feature to a subset of your users (like a group of users who opt-in to a beta tester group), gathering feedback and bug reports from real-world use cases.\n    * Gradually roll out a feature to an increasing percentage of users, and track the effect that the feature has on key metrics (for instance, how likely is a user to complete a purchase if they have feature A versus feature B?).\n    * Turn off a feature that you realize is causing performance problems in production, without needing to re-deploy, or even restart the application with a changed configuration file.\n    * Grant access to certain features based on user attributes, like payment plan (eg: users on the ‘gold’ plan get access to more features than users in the ‘silver’ plan). Disable parts of your application to facilitate maintenance, without taking everything offline.\n* LaunchDarkly provides feature flag SDKs for a wide variety of languages and technologies. Check out [our documentation](https://docs.launchdarkly.com/sdk) for a complete list.\n* Explore LaunchDarkly\n    * [launchdarkly.com](https://www.launchdarkly.com/ \"LaunchDarkly Main Website\") for more information\n    * [docs.launchdarkly.com](https://docs.launchdarkly.com/  \"LaunchDarkly Documentation\") for our documentation and SDK reference guides\n    * [apidocs.launchdarkly.com](https://apidocs.launchdarkly.com/  \"LaunchDarkly API Documentation\") for our API documentation\n    * [blog.launchdarkly.com](https://blog.launchdarkly.com/  \"LaunchDarkly Blog Documentation\") for the latest product updates\n"
  },
  {
    "path": "SECURITY.md",
    "content": "# Reporting and Fixing Security Issues\n\nPlease report all security issues to the LaunchDarkly security team by submitting a bug bounty report to our [HackerOne program](https://hackerone.com/launchdarkly?type=team). LaunchDarkly will triage and address all valid security issues following the response targets defined in our program policy. Valid security issues may be eligible for a bounty.\n\nPlease do not open issues or pull requests for security issues. This makes the problem immediately visible to everyone, including potentially malicious actors.\n"
  },
  {
    "path": "Source/.swiftlint.yml",
    "content": "disabled_rules:\n\nopt_in_rules:\n  - force_unwrapping\n  - implicitly_unwrapped_optional\n"
  },
  {
    "path": "Source/EventParser.swift",
    "content": "import Foundation\n\nclass EventParser {\n    private struct Constants {\n        static let dataLabel: Substring = \"data\"\n        static let idLabel: Substring = \"id\"\n        static let eventLabel: Substring = \"event\"\n        static let retryLabel: Substring = \"retry\"\n    }\n\n    private let handler: EventHandler\n\n    private var data: String = \"\"\n    private var eventType: String = \"\"\n    private var lastEventIdBuffer: String?\n    private var lastEventId: String\n    private var currentRetry: TimeInterval\n\n    init(handler: EventHandler, initialEventId: String, initialRetry: TimeInterval) {\n        self.handler = handler\n        self.lastEventId = initialEventId\n        self.currentRetry = initialRetry\n    }\n\n    func parse(line: String) {\n        let splitByColon = line.split(separator: \":\", maxSplits: 1, omittingEmptySubsequences: false)\n\n        switch (splitByColon[0], splitByColon[safe: 1]) {\n        case (\"\", nil): // Empty line\n            dispatchEvent()\n        case let (\"\", .some(comment)): // Line starting with ':' is a comment\n            handler.onComment(comment: String(comment))\n        case let (field, data):\n            processField(field: field, value: dropLeadingSpace(str: data ?? \"\"))\n        }\n    }\n\n    func getLastEventId() -> String { lastEventId }\n\n    func reset() -> TimeInterval {\n        data = \"\"\n        eventType = \"\"\n        lastEventIdBuffer = nil\n        return currentRetry\n    }\n\n    private func dropLeadingSpace(str: Substring) -> Substring {\n        if str.first == \" \" {\n            return str[str.index(after: str.startIndex)...]\n        }\n        return str\n    }\n\n    private func processField(field: Substring, value: Substring) {\n        switch field {\n        case Constants.dataLabel:\n            data.append(contentsOf: value)\n            data.append(contentsOf: \"\\n\")\n        case Constants.idLabel:\n            // See https://github.com/whatwg/html/issues/689 for reasoning on not setting lastEventId if the value\n            // contains a null code point.\n            if !value.contains(\"\\u{0000}\") {\n                lastEventIdBuffer = String(value)\n            }\n        case Constants.eventLabel:\n            eventType = String(value)\n        case Constants.retryLabel:\n            if value.allSatisfy((\"0\"...\"9\").contains), let reconnectionTime = Int64(value) {\n                currentRetry = Double(reconnectionTime) * 0.001\n            }\n        default:\n            break\n        }\n    }\n\n    private func dispatchEvent() {\n        lastEventId = lastEventIdBuffer ?? lastEventId\n        lastEventIdBuffer = nil\n        guard !data.isEmpty\n        else {\n            eventType = \"\"\n            return\n        }\n        // remove the last LF\n        _ = data.popLast()\n        let messageEvent = MessageEvent(data: data, lastEventId: lastEventId)\n        handler.onMessage(eventType: eventType.isEmpty ? \"message\" : eventType, messageEvent: messageEvent)\n        data = \"\"\n        eventType = \"\"\n    }\n}\n\nprivate extension Array {\n    /// Returns the element at the specified index if it is within bounds, otherwise nil.\n    subscript (safe index: Index) -> Element? {\n        index >= startIndex && index < endIndex ? self[index] : nil\n    }\n}\n"
  },
  {
    "path": "Source/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>$(DEVELOPMENT_LANGUAGE)</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>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>$(MARKETING_VERSION)</string>\n\t<key>CFBundleVersion</key>\n\t<string>$(CURRENT_PROJECT_VERSION)</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Source/LDSwiftEventSource.h",
    "content": "@import Foundation;\n\nFOUNDATION_EXPORT double LDSwiftEventSourceVersionNumber;\nFOUNDATION_EXPORT const unsigned char LDSwiftEventSourceVersionString[];\n"
  },
  {
    "path": "Source/LDSwiftEventSource.swift",
    "content": "import Foundation\n\n#if os(Linux) || os(Windows)\nimport FoundationNetworking\n#endif\n\n#if canImport(os)\n// os_log is not supported on some platforms, but we want to use it for most of our customer's\n// use cases that use Apple OSs\nimport os.log\n#endif\n\n/**\n Provides an EventSource client for consuming Server-Sent Events.\n\n See the [Server-Sent Events spec](https://html.spec.whatwg.org/multipage/server-sent-events.html) for more details.\n */\npublic class EventSource {\n    private let esDelegate: EventSourceDelegate\n\n    /**\n     Initialize the `EventSource` client with the given configuration.\n\n     - Parameter config: The configuration for initializing the `EventSource` client.\n     */\n    public init(config: Config) {\n        esDelegate = EventSourceDelegate(config: config)\n    }\n\n    /**\n     Start the `EventSource` client.\n\n     This will initiate a streaming connection to the configured URL. The application will be informed of received\n     events and state changes using the configured `EventHandler`.\n     */\n    public func start() {\n        esDelegate.start()\n    }\n\n    /// Shuts down the `EventSource` client. It is not valid to restart the client after calling this function.\n    public func stop() {\n        esDelegate.stop()\n    }\n\n    /// Get the most recently received event ID, or the value of `EventSource.Config.lastEventId` if no event IDs have\n    /// been received.\n    public func getLastEventId() -> String? { esDelegate.getLastEventId() }\n\n    /// Struct for configuring the EventSource.\n    public struct Config {\n        /// The `EventHandler` called in response to activity on the stream.\n        public let handler: EventHandler\n        /// The `URL` of the request used when connecting to the EventSource API.\n        public let url: URL\n\n        /// The HTTP method to use for the API request.\n        public var method: String = \"GET\"\n        /// Optional HTTP body to be included in the API request.\n        public var body: Data?\n        /// Additional HTTP headers to be set on the request\n        public var headers: [String: String] = [:]\n        /// Transform function to allow dynamically configuring the headers on each API request.\n        public var headerTransform: HeaderTransform = { $0 }\n        /// An initial value for the last-event-id header to be sent on the initial request\n        public var lastEventId: String = \"\"\n        \n#if canImport(os)\n        /// Configure the logger that will be used.\n        public var logger: OSLog = OSLog(subsystem: \"com.launchdarkly.swift-eventsource\", category: \"LDEventSource\")\n#endif\n        \n        /// The minimum amount of time to wait before reconnecting after a failure\n        public var reconnectTime: TimeInterval = 1.0\n        /// The maximum amount of time to wait before reconnecting after a failure\n        public var maxReconnectTime: TimeInterval = 30.0\n        /// The minimum amount of time for an `EventSource` connection to remain open before allowing the connection\n        /// backoff to reset.\n        public var backoffResetThreshold: TimeInterval = 60.0\n        /// The maximum amount of time between receiving any data before considering the connection to have timed out.\n        public var idleTimeout: TimeInterval = 300.0\n\n        private var _urlSessionConfiguration: URLSessionConfiguration = URLSessionConfiguration.default\n        /**\n         The `URLSessionConfiguration` used to create the `URLSession`.\n\n         - Important:\n            Note that this copies the given `URLSessionConfiguration` when set, and returns copies (updated with any\n         overrides specified by other configuration options) when the value is retrieved. This prevents updating the\n         `URLSessionConfiguration` after initializing `EventSource` with the `Config`, and prevents the `EventSource`\n         from updating any properties of the given `URLSessionConfiguration`.\n\n         - Since: 1.3.0\n         */\n        public var urlSessionConfiguration: URLSessionConfiguration {\n            get {\n                // swiftlint:disable:next force_cast\n                let sessionConfig = _urlSessionConfiguration.copy() as! URLSessionConfiguration\n                sessionConfig.httpAdditionalHeaders = [\"Accept\": \"text/event-stream\", \"Cache-Control\": \"no-cache\"]\n                sessionConfig.timeoutIntervalForRequest = idleTimeout\n\n                #if !os(Linux) && !os(Windows)\n                if #available(iOS 13, macOS 10.15, tvOS 13, watchOS 6, *) {\n                    sessionConfig.tlsMinimumSupportedProtocolVersion = .TLSv12\n                } else {\n                    sessionConfig.tlsMinimumSupportedProtocol = .tlsProtocol12\n                }\n                #endif\n                return sessionConfig\n            }\n            set {\n                // swiftlint:disable:next force_cast\n                _urlSessionConfiguration = newValue.copy() as! URLSessionConfiguration\n            }\n        }\n\n        /**\n         An error handler that is called when an error occurs and can shut down the client in response.\n\n         The default error handler will always attempt to reconnect on an\n         error, unless `EventSource.stop()` is called or the error code is 204.\n         */\n        public var connectionErrorHandler: ConnectionErrorHandler = { error in\n            guard let unsuccessfulResponseError = error as? UnsuccessfulResponseError\n            else { return .proceed }\n\n            let responseCode: Int = unsuccessfulResponseError.responseCode\n            if 204 == responseCode {\n                return .shutdown\n            }\n            return .proceed\n        }\n\n        /// Create a new configuration with an `EventHandler` and a `URL`\n        public init(handler: EventHandler, url: URL) {\n            self.handler = handler\n            self.url = url\n        }\n    }\n}\n\nclass ReconnectionTimer {\n    private let maxDelay: TimeInterval\n    private let resetInterval: TimeInterval\n\n    var backoffCount: Int = 0\n    var connectedTime: Date?\n\n    init(maxDelay: TimeInterval, resetInterval: TimeInterval) {\n        self.maxDelay = maxDelay\n        self.resetInterval = resetInterval\n    }\n\n    func reconnectDelay(baseDelay: TimeInterval) -> TimeInterval {\n        backoffCount += 1\n        if let connectedTime = connectedTime, Date().timeIntervalSince(connectedTime) >= resetInterval {\n            backoffCount = 0\n        }\n        self.connectedTime = nil\n        let maxSleep = min(maxDelay, baseDelay * pow(2.0, Double(backoffCount)))\n        return maxSleep / 2 + Double.random(in: 0...(maxSleep / 2))\n    }\n}\n\n// MARK: EventSourceDelegate\nclass EventSourceDelegate: NSObject, URLSessionDataDelegate {\n    private let delegateQueue: DispatchQueue = DispatchQueue(label: \"ESDelegateQueue\")\n    \n    public var logger: InternalLogging\n    \n    private let config: EventSource.Config\n\n    private var readyState: ReadyState = .raw {\n        didSet {\n            logger.log(.debug, \"State: %@ -> %@\", oldValue.rawValue, readyState.rawValue)\n        }\n    }\n\n    private let utf8LineParser: UTF8LineParser = UTF8LineParser()\n    private let eventParser: EventParser\n    private let reconnectionTimer: ReconnectionTimer\n    private var urlSession: URLSession?\n    private var sessionTask: URLSessionDataTask?\n\n    init(config: EventSource.Config) {\n        self.config = config\n        \n#if canImport(os)\n        self.logger = OSLogAdapter(osLog: config.logger)\n#else\n        self.logger = NoOpLogging()\n#endif\n        \n        \n        self.eventParser = EventParser(handler: config.handler,\n                                       initialEventId: config.lastEventId,\n                                       initialRetry: config.reconnectTime)\n        self.reconnectionTimer = ReconnectionTimer(maxDelay: config.maxReconnectTime,\n                                                   resetInterval: config.backoffResetThreshold)\n    }\n\n    func start() {\n        delegateQueue.async { [weak self] in\n            guard let self = self\n            else { return }\n            guard self.readyState == .raw\n            else {\n                self.logger.log(.info, \"start() called on already-started EventSource object. Returning\")\n                return\n            }\n            self.readyState = .connecting\n            self.urlSession = self.createSession()\n            self.connect()\n        }\n    }\n\n    func stop() {\n        delegateQueue.async {\n            let previousState = self.readyState\n            self.readyState = .shutdown\n            self.sessionTask?.cancel()\n            if previousState == .open {\n                self.config.handler.onClosed()\n            }\n            self.urlSession?.invalidateAndCancel()\n            self.urlSession = nil\n        }\n    }\n\n    func getLastEventId() -> String { eventParser.getLastEventId() }\n\n    func createSession() -> URLSession {\n        let opQueue = OperationQueue()\n        opQueue.underlyingQueue = self.delegateQueue\n        return URLSession(configuration: config.urlSessionConfiguration, delegate: self, delegateQueue: opQueue)\n    }\n\n    func createRequest() -> URLRequest {\n        var urlRequest = URLRequest(url: self.config.url,\n                                    cachePolicy: URLRequest.CachePolicy.reloadIgnoringLocalAndRemoteCacheData,\n                                    timeoutInterval: self.config.idleTimeout)\n        urlRequest.httpMethod = self.config.method\n        urlRequest.httpBody = self.config.body\n        if !eventParser.getLastEventId().isEmpty {\n            urlRequest.setValue(eventParser.getLastEventId(), forHTTPHeaderField: \"Last-Event-Id\")\n        }\n        urlRequest.allHTTPHeaderFields = self.config.headerTransform(\n            urlRequest.allHTTPHeaderFields?.merging(self.config.headers) { $1 } ?? self.config.headers\n        )\n        return urlRequest\n    }\n\n    private func connect() {\n        logger.log(.info, \"Starting EventSource client\")\n        let task = urlSession?.dataTask(with: createRequest())\n        task?.resume()\n        sessionTask = task\n    }\n\n    func dispatchError(error: Error) -> ConnectionErrorAction {\n        let action: ConnectionErrorAction = config.connectionErrorHandler(error)\n        if action != .shutdown {\n            config.handler.onError(error: error)\n        }\n        return action\n    }\n\n    // MARK: URLSession Delegates\n\n    // Tells the delegate that the task finished transferring data.\n    public func urlSession(_ session: URLSession,\n                           task: URLSessionTask,\n                           didCompleteWithError error: Error?) {\n        utf8LineParser.closeAndReset()\n        let currentRetry = eventParser.reset()\n\n        guard readyState != .shutdown\n        else { return }\n\n        if let error = error {\n            if (error as NSError).code != NSURLErrorCancelled {\n                logger.log(.info, \"Connection error: %@\", error.localizedDescription)\n                if dispatchError(error: error) == .shutdown {\n                    logger.log(.info, \"Connection has been explicitly shut down by error handler\")\n                    if readyState == .open {\n                        config.handler.onClosed()\n                    }\n                    readyState = .shutdown\n                    return\n                }\n            }\n        } else {\n            logger.log(.info, \"Connection unexpectedly closed.\")\n        }\n\n        if readyState == .open {\n            config.handler.onClosed()\n        }\n\n        readyState = .closed\n        let sleep = reconnectionTimer.reconnectDelay(baseDelay: currentRetry)\n        // this formatting shenanigans is to workaround String not implementing CVarArg on Swift<5.4 on Linux\n        logger.log(.info, \"Waiting %@ seconds before reconnecting...\", String(format: \"%.3f\", sleep))\n        delegateQueue.asyncAfter(deadline: .now() + sleep) { [weak self] in\n            self?.connect()\n        }\n    }\n\n    // Tells the delegate that the data task received the initial reply (headers) from the server.\n    public func urlSession(_ session: URLSession,\n                           dataTask: URLSessionDataTask,\n                           didReceive response: URLResponse,\n                           completionHandler: @escaping (URLSession.ResponseDisposition) -> Void) {\n        logger.log(.debug, \"Initial reply received\")\n\n        guard readyState != .shutdown\n        else {\n            completionHandler(.cancel)\n            return\n        }\n\n        // swiftlint:disable:next force_cast\n        let httpResponse = response as! HTTPURLResponse\n        let statusCode = httpResponse.statusCode\n        if (200..<300).contains(statusCode) && statusCode != 204 {\n            reconnectionTimer.connectedTime = Date()\n            readyState = .open\n            config.handler.onOpened()\n            completionHandler(.allow)\n        } else {\n            // this formatting shenanigans is to workaround String not implementing CVarArg on Swift<5.4 on Linux\n            logger.log(.info, \"Unsuccessful response: %@\", String(format: \"%d\", statusCode))\n            if dispatchError(error: UnsuccessfulResponseError(responseCode: statusCode)) == .shutdown {\n                logger.log(.info, \"Connection has been explicitly shut down by error handler\")\n                readyState = .shutdown\n            }\n            completionHandler(.cancel)\n        }\n    }\n\n    public func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {\n        utf8LineParser.append(data).forEach(eventParser.parse)\n    }\n}\n"
  },
  {
    "path": "Source/Logs.swift",
    "content": "import Foundation\n\n#if canImport(os)\nimport os.log\n#endif\n\nprotocol InternalLogging {\n    func log(_ level: Level, _ staticMsg: StaticString)\n    func log(_ level: Level, _ staticMsg: StaticString, _ arg: String)\n    func log(_ level: Level, _ staticMsg: StaticString, _ arg1: String, _ arg2: String)\n}\n\nenum Level {\n    case debug, info, warn, error\n\n#if canImport(os)\n    private static let osLogTypes = [ Level.debug: OSLogType.debug,\n                                      Level.info: OSLogType.info,\n                                      Level.warn: OSLogType.default,\n                                      Level.error: OSLogType.error]\n    var osLogType: OSLogType { Level.osLogTypes[self]! }\n#endif\n}\n\n#if canImport(os)\nclass OSLogAdapter: InternalLogging {\n    \n    private let osLog: OSLog\n    \n    init(osLog: OSLog) {\n        self.osLog = osLog\n    }\n    \n    func log(_ level: Level, _ staticMsg: StaticString) {\n        os_log(staticMsg, log: self.osLog, type: level.osLogType)\n    }\n    \n    func log(_ level: Level, _ staticMsg: StaticString, _ arg: String) {\n        os_log(staticMsg, log: self.osLog, type: level.osLogType, arg)\n    }\n    \n    func log(_ level: Level, _ staticMsg: StaticString, _ arg1: String, _ arg2: String) {\n        os_log(staticMsg, log: self.osLog, type: level.osLogType, arg1, arg2)\n    }\n}\n#endif\n\nclass NoOpLogging: InternalLogging {\n    func log(_ level: Level, _ staticMsg: StaticString) {}\n    func log(_ level: Level, _ staticMsg: StaticString, _ arg: String) {}\n    func log(_ level: Level, _ staticMsg: StaticString, _ arg1: String, _ arg2: String) {}\n}\n"
  },
  {
    "path": "Source/Types.swift",
    "content": "import Foundation\n\n/**\n Type for a function that will be notified when the `EventSource` client encounters a connection failure.\n\n This is different from `EventHandler.onError(error:)` in that it will not be called for other kinds of errors; also,\n it has the ability to tell the client to stop reconnecting by returning a `ConnectionErrorAction.shutdown`.\n*/\npublic typealias ConnectionErrorHandler = (Error) -> ConnectionErrorAction\n\n/**\n Type for a function that will take in the current HTTP headers and return a new set of HTTP headers to be used when\n connecting and reconnecting to a stream.\n */\npublic typealias HeaderTransform = ([String: String]) -> [String: String]\n\n/// Potential actions a `ConnectionErrorHandler` can return\npublic enum ConnectionErrorAction {\n    /**\n     Specifies that the error should be logged normally and dispatched to the `EventHandler`. Connection retrying will\n     proceed normally if appropriate.\n     */\n    case proceed\n    /**\n     Specifies that the connection should be immediately shut down and not retried. The error will not be dispatched\n     to the `EventHandler`\n     */\n    case shutdown\n}\n\n/// Struct representing received event from the stream.\npublic struct MessageEvent: Equatable, Hashable {\n    /// The event data of the event.\n    public let data: String\n    /// The last seen event id, or the event id set in the Config if none have been received.\n    public let lastEventId: String\n\n    /**\n     Constructor for a `MessageEvent`\n\n     - Parameter data: The `data` field of the `MessageEvent`.\n     - Parameter eventType: The `lastEventId` field of the `MessageEvent`.\n     */\n    public init(data: String, lastEventId: String = \"\") {\n        self.data = data\n        self.lastEventId = lastEventId\n    }\n}\n\n/// Protocol for an object that will receive SSE events.\npublic protocol EventHandler {\n    /// EventSource calls this method when the stream connection has been opened.\n    func onOpened()\n\n    /// EventSource calls this method when the stream connection has been closed.\n    func onClosed()\n\n    /**\n     EventSource calls this method when it has received a new event from the stream.\n\n     - Parameter eventType: The type of the event.\n     - Parameter messageEvent: The data for the event.\n     */\n    func onMessage(eventType: String, messageEvent: MessageEvent)\n\n    /**\n     EventSource calls this method when it has received a comment line from the stream.\n\n     - Parameter comment: The comment received.\n     */\n    func onComment(comment: String)\n\n    /**\n     This method will be called for all exceptions that occur on the network connection (including an\n     `UnsuccessfulResponseError` if the server returns an unexpected HTTP status), but only after the\n     ConnectionErrorHandler (if any) has processed it.  If you need to do anything that affects the state of the\n     connection, use ConnectionErrorHandler.\n\n     - Parameter error: The error received.\n     */\n    func onError(error: Error)\n}\n\n/// Enum values representing the states of an EventSource\npublic enum ReadyState: String, Equatable {\n    /// The `EventSource` client has not been started yet.\n    case raw\n    /// The `EventSource` client is attempting to make a connection.\n    case connecting\n    /// The `EventSource` client is active and listening for events.\n    case open\n    /// The connection has been closed or has failed, and the `EventSource` will attempt to reconnect.\n    case closed\n    /// The connection has been permanently closed and the `EventSource` not reconnect.\n    case shutdown\n}\n\n/// Error class that indicates the remote server returned an unsuccessful HTTP response code.\npublic class UnsuccessfulResponseError: Error {\n    /// The HTTP response code received.\n    public let responseCode: Int\n\n    /**\n     Constructor for an `UnsuccessfulResponseError`.\n\n     - Parameter responseCode: The HTTP response code of the unsuccessful response.\n     */\n    public init(responseCode: Int) {\n        self.responseCode = responseCode\n    }\n}\n"
  },
  {
    "path": "Source/UTF8LineParser.swift",
    "content": "import Foundation\n\nstruct DataIter: IteratorProtocol {\n    var data: Data\n    var position: Data.Index { data.startIndex }\n\n    mutating func next() -> UInt8? {\n        data.popFirst()\n    }\n}\n\nclass UTF8LineParser {\n    private let lf = Unicode.Scalar(0x0A)\n    private let cr = Unicode.Scalar(0x0D)\n    private let replacement = String(Unicode.UTF8.decode(Unicode.UTF8.encodedReplacementCharacter))\n\n    var utf8Parser = Unicode.UTF8.ForwardParser()\n    var remainder: Data = Data()\n    var currentString: String = \"\"\n    var seenCr = false\n\n    func append(_ body: Data) -> [String] {\n        let data = remainder + body\n        var dataIter = DataIter(data: data)\n        var remainderPos = data.endIndex\n        var lines: [String] = []\n\n        Decode: while true {\n            switch utf8Parser.parseScalar(from: &dataIter) {\n            case .valid(let scalarResult):\n                let scalar = Unicode.UTF8.decode(scalarResult)\n\n                if seenCr && scalar == lf {\n                    seenCr = false\n                    continue\n                }\n\n                seenCr = scalar == cr\n                if scalar == cr || scalar == lf {\n                    lines.append(currentString)\n                    currentString = \"\"\n                } else {\n                    currentString.append(String(scalar))\n                }\n            case .emptyInput:\n                break Decode\n            case .error(let len):\n                seenCr = false\n                if dataIter.position == data.endIndex {\n                    // Error at end of block, carry over in case of split code point\n                    remainderPos = data.index(data.endIndex, offsetBy: -len)\n                    // May as well break here as next will be .emptyInput\n                    break Decode\n                } else {\n                    // Invalid character, replace with replacement character\n                    currentString.append(replacement)\n                }\n            }\n        }\n\n        remainder = data.subdata(in: remainderPos..<data.endIndex)\n        return lines\n    }\n\n    func closeAndReset() {\n        seenCr = false\n        currentString = \"\"\n        remainder = Data()\n    }\n}\n"
  },
  {
    "path": "Tests/.swiftlint.yml",
    "content": "disabled_rules:\n\nopt_in_rules:\n  # Must specify even though enabled by default to update configuration of rule below.\n  - line_length\n  - type_body_length\n\n# Provide a little extra lenience for test code line and body length.\nline_length:\n  warning: 140\ntype_body_length:\n  warning: 400\n  error: 500\n\nexcluded:\n  # Autogenerated manifest of tests\n  - XCTestManifests.swift\n"
  },
  {
    "path": "Tests/EventParserTests.swift",
    "content": "import XCTest\n@testable import LDSwiftEventSource\n\nfinal class EventParserTests: XCTestCase {\n    var handler: MockHandler!\n    var parser: EventParser!\n\n    override func setUp() {\n        super.setUp()\n        handler = MockHandler()\n        parser = EventParser(handler: handler, initialEventId: \"\", initialRetry: 1.0)\n    }\n\n    override func tearDown() {\n        super.tearDown()\n        XCTAssertNil(handler.events.maybeEvent())\n    }\n\n    // MARK: Retry time tests\n    func testUnsetRetryReturnsConfigured() {\n        parser = EventParser(handler: handler, initialEventId: \"\", initialRetry: 5.0)\n        XCTAssertEqual(parser.reset(), 5.0)\n    }\n\n    func testSetsRetryTimeToSevenSeconds() {\n        parser.parse(line: \"retry: 7000\")\n        XCTAssertEqual(parser.reset(), 7.0)\n        XCTAssertEqual(parser.getLastEventId(), \"\")\n    }\n\n    func testRetryWithNoSpace() {\n        parser.parse(line: \"retry:7000\")\n        XCTAssertEqual(parser.reset(), 7.0)\n        XCTAssertEqual(parser.getLastEventId(), \"\")\n    }\n\n    func testDoesNotSetRetryTimeUnlessEntireValueIsNumeric() {\n        parser.parse(line: \"retry: 7000L\")\n        XCTAssertEqual(parser.reset(), 1.0)\n    }\n\n    func testSafeToUseEmptyRetryTime() {\n        parser.parse(line: \"retry\")\n        XCTAssertEqual(parser.reset(), 1.0)\n    }\n\n    func testSafeToAttemptToSetRetryToOutOfBoundsValue() {\n        parser.parse(line: \"retry: 10000000000000000000000000\")\n        XCTAssertEqual(parser.reset(), 1.0)\n    }\n\n    func testResetDoesNotResetRetry() {\n        parser.parse(line: \"retry: 7000\")\n        XCTAssertEqual(parser.reset(), 7.0)\n        XCTAssertEqual(parser.reset(), 7.0)\n    }\n\n    func testRetryNotChangedDuringOtherMessages() {\n        parser.parse(line: \"retry: 7000\")\n        parser.parse(line: \"\")\n        parser.parse(line: \":123\")\n        parser.parse(line: \"event: 123\")\n        parser.parse(line: \"data: 123\")\n        parser.parse(line: \"id: 123\")\n        parser.parse(line: \"none: 123\")\n        parser.parse(line: \"\")\n        XCTAssertEqual(parser.reset(), 7.0)\n        _ = handler.events.maybeEvent()\n        _ = handler.events.maybeEvent()\n    }\n\n    // MARK: Comment tests\n    func testEmptyComment() {\n        parser.parse(line: \":\")\n        XCTAssertEqual(handler.events.maybeEvent(), .comment(\"\"))\n    }\n\n    func testCommentBody() {\n        parser.parse(line: \": comment\")\n        XCTAssertEqual(handler.events.maybeEvent(), .comment(\" comment\"))\n    }\n\n    func testCommentCanContainColon() {\n        parser.parse(line: \":comment:line\")\n        XCTAssertEqual(handler.events.maybeEvent(), .comment(\"comment:line\"))\n    }\n\n    // MARK: Message data tests\n    func testDispatchesEmptyMessageData() {\n        parser.parse(line: \"data\")\n        parser.parse(line: \"\")\n        parser.parse(line: \"data:\")\n        parser.parse(line: \"\")\n        parser.parse(line: \"data: \")\n        parser.parse(line: \"\")\n        XCTAssertEqual(handler.events.maybeEvent(), .message(\"message\", MessageEvent(data: \"\", lastEventId: \"\")))\n        XCTAssertEqual(handler.events.maybeEvent(), .message(\"message\", MessageEvent(data: \"\", lastEventId: \"\")))\n        XCTAssertEqual(handler.events.maybeEvent(), .message(\"message\", MessageEvent(data: \"\", lastEventId: \"\")))\n    }\n\n    func testDoesNotRemoveTrailingSpaceWhenColonNotPresent() {\n        parser.parse(line: \"data \")\n        parser.parse(line: \"\")\n        XCTAssertNil(handler.events.maybeEvent())\n    }\n\n    func testEmptyFirstDataAppendsNewline() {\n        parser.parse(line: \"data:\")\n        parser.parse(line: \"data:\")\n        parser.parse(line: \"\")\n        XCTAssertEqual(handler.events.maybeEvent(), .message(\"message\", MessageEvent(data: \"\\n\", lastEventId: \"\")))\n    }\n\n    func testDispatchesSingleLineMessage() {\n        parser.parse(line: \"data: hello\")\n        parser.parse(line: \"\")\n        XCTAssertEqual(handler.events.maybeEvent(), .message(\"message\", MessageEvent(data: \"hello\", lastEventId: \"\")))\n    }\n\n    func testEmptyDataWithBufferedDataAppendsNewline() {\n        parser.parse(line: \"data: data1\")\n        parser.parse(line: \"data: \")\n        parser.parse(line: \"\")\n        XCTAssertEqual(handler.events.maybeEvent(), .message(\"message\", MessageEvent(data: \"data1\\n\", lastEventId: \"\")))\n    }\n\n    func testDataResetAfterEvent() {\n        parser.parse(line: \"data: hello\")\n        parser.parse(line: \"\")\n        parser.parse(line: \"\")\n        XCTAssertEqual(handler.events.maybeEvent(), .message(\"message\", MessageEvent(data: \"hello\", lastEventId: \"\")))\n    }\n\n    func testRemovesOnlyFirstSpace() {\n        parser.parse(line: \"data:  {\\\"foo\\\": \\\"bar baz\\\"}\")\n        parser.parse(line: \"\")\n        XCTAssertEqual(handler.events.maybeEvent(), .message(\"message\", MessageEvent(data: \" {\\\"foo\\\": \\\"bar baz\\\"}\", lastEventId: \"\")))\n    }\n\n    func testDoesNotRemoveOtherWhitespace() {\n        parser.parse(line: \"data:\\t{\\\"foo\\\": \\\"bar baz\\\"}\")\n        parser.parse(line: \"\")\n        XCTAssertEqual(handler.events.maybeEvent(), .message(\"message\", MessageEvent(data: \"\\t{\\\"foo\\\": \\\"bar baz\\\"}\", lastEventId: \"\")))\n    }\n\n    func testAllowsNoLeadingSpace() {\n        parser.parse(line: \"data:{\\\"foo\\\": \\\"bar baz\\\"}\")\n        parser.parse(line: \"\")\n        XCTAssertEqual(handler.events.maybeEvent(), .message(\"message\", MessageEvent(data: \"{\\\"foo\\\": \\\"bar baz\\\"}\", lastEventId: \"\")))\n    }\n\n    func testMultipleDataDispatch() {\n        parser.parse(line: \"data: data1\")\n        parser.parse(line: \"data: data2\")\n        parser.parse(line: \"\")\n        XCTAssertEqual(handler.events.maybeEvent(), .message(\"message\", MessageEvent(data: \"data1\\ndata2\", lastEventId: \"\")))\n    }\n\n    // MARK: Event type tests\n    func testDispatchesMessageWithCustomEventType() {\n        parser.parse(line: \"event: customEvent\")\n        parser.parse(line: \"data: hello\")\n        parser.parse(line: \"\")\n        XCTAssertEqual(handler.events.maybeEvent(), .message(\"customEvent\", MessageEvent(data: \"hello\", lastEventId: \"\")))\n    }\n\n    func testCustomEventTypeWithoutSpace() {\n        parser.parse(line: \"event:customEvent\")\n        parser.parse(line: \"data: hello\")\n        parser.parse(line: \"\")\n        XCTAssertEqual(handler.events.maybeEvent(), .message(\"customEvent\", MessageEvent(data: \"hello\", lastEventId: \"\")))\n    }\n\n    func testCustomEventAfterData() {\n        parser.parse(line: \"data: hello\")\n        parser.parse(line: \"event: customEvent\")\n        parser.parse(line: \"\")\n        XCTAssertEqual(handler.events.maybeEvent(), .message(\"customEvent\", MessageEvent(data: \"hello\", lastEventId: \"\")))\n    }\n\n    func testEmptyEventTypesDefaultToMessage() {\n        [\"event\", \"event:\", \"event: \"].forEach {\n            parser.parse(line: $0)\n            parser.parse(line: \"data: foo\")\n            parser.parse(line: \"\")\n        }\n        XCTAssertEqual(handler.events.maybeEvent(), .message(\"message\", MessageEvent(data: \"foo\", lastEventId: \"\")))\n        XCTAssertEqual(handler.events.maybeEvent(), .message(\"message\", MessageEvent(data: \"foo\", lastEventId: \"\")))\n        XCTAssertEqual(handler.events.maybeEvent(), .message(\"message\", MessageEvent(data: \"foo\", lastEventId: \"\")))\n    }\n\n    func testDispatchWithoutDataResetsMessageType() {\n        parser.parse(line: \"event: customEvent\")\n        parser.parse(line: \"\")\n        parser.parse(line: \"data: foo\")\n        parser.parse(line: \"\")\n        XCTAssertEqual(handler.events.maybeEvent(), .message(\"message\", MessageEvent(data: \"foo\", lastEventId: \"\")))\n    }\n\n    func testDispatchWithDataResetsMessageType() {\n        parser.parse(line: \"event: customEvent\")\n        parser.parse(line: \"data: foo\")\n        parser.parse(line: \"\")\n        parser.parse(line: \"data: bar\")\n        parser.parse(line: \"\")\n        XCTAssertEqual(handler.events.maybeEvent(), .message(\"customEvent\", MessageEvent(data: \"foo\", lastEventId: \"\")))\n        XCTAssertEqual(handler.events.maybeEvent(), .message(\"message\", MessageEvent(data: \"bar\", lastEventId: \"\")))\n    }\n\n    // MARK: Last event ID tests\n    func testLastEventIdNotReturnedUntilDispatch() {\n        XCTAssertEqual(parser.getLastEventId(), \"\")\n        parser.parse(line: \"id: 1\")\n        XCTAssertNil(handler.events.maybeEvent())\n        XCTAssertEqual(parser.getLastEventId(), \"\")\n    }\n\n    func testRecordsLastEventIdWithoutData() {\n        parser.parse(line: \"id: 1\")\n        parser.parse(line: \"\")\n        XCTAssertNil(handler.events.maybeEvent())\n        XCTAssertEqual(parser.getLastEventId(), \"1\")\n    }\n\n    func testEventIdIncludedInMessageEvent() {\n        parser.parse(line: \"data: hello\")\n        parser.parse(line: \"id: 1\")\n        parser.parse(line: \"\")\n        XCTAssertEqual(handler.events.maybeEvent(), .message(\"message\", MessageEvent(data: \"hello\", lastEventId: \"1\")))\n    }\n\n    func testReusesEventIdIfNotSet() {\n        parser.parse(line: \"data: hello\")\n        parser.parse(line: \"id: reused\")\n        parser.parse(line: \"\")\n        parser.parse(line: \"data: world\")\n        parser.parse(line: \"\")\n        XCTAssertEqual(handler.events.maybeEvent(), .message(\"message\", MessageEvent(data: \"hello\", lastEventId: \"reused\")))\n        XCTAssertEqual(handler.events.maybeEvent(), .message(\"message\", MessageEvent(data: \"world\", lastEventId: \"reused\")))\n        XCTAssertEqual(parser.getLastEventId(), \"reused\")\n    }\n\n    func testEventIdSetTwiceInEvent() {\n        parser.parse(line: \"id: abc\")\n        parser.parse(line: \"id: def\")\n        parser.parse(line: \"data\")\n        XCTAssertEqual(parser.getLastEventId(), \"\")\n        parser.parse(line: \"\")\n        XCTAssertEqual(handler.events.maybeEvent(), .message(\"message\", MessageEvent(data: \"\", lastEventId: \"def\")))\n        XCTAssertEqual(parser.getLastEventId(), \"def\")\n    }\n\n    func testEventIdContainingNullIgnored() {\n        parser.parse(line: \"id: reused\")\n        parser.parse(line: \"id: abc\\u{0000}def\")\n        parser.parse(line: \"data\")\n        parser.parse(line: \"\")\n        XCTAssertEqual(handler.events.maybeEvent(), .message(\"message\", MessageEvent(data: \"\", lastEventId: \"reused\")))\n        XCTAssertEqual(parser.getLastEventId(), \"reused\")\n    }\n\n    func testResetDoesResetLastEventIdBuffer() {\n        parser.parse(line: \"id: 1\")\n        _ = parser.reset()\n        parser.parse(line: \"data: hello\")\n        parser.parse(line: \"\")\n        XCTAssertEqual(handler.events.maybeEvent(), .message(\"message\", MessageEvent(data: \"hello\", lastEventId: \"\")))\n        XCTAssertEqual(parser.getLastEventId(), \"\")\n    }\n\n    func testResetDoesNotResetLastEventId() {\n        parser.parse(line: \"id: 1\")\n        parser.parse(line: \"\")\n        _ = parser.reset()\n        parser.parse(line: \"data: hello\")\n        parser.parse(line: \"\")\n        XCTAssertEqual(handler.events.maybeEvent(), .message(\"message\", MessageEvent(data: \"hello\", lastEventId: \"1\")))\n        XCTAssertEqual(parser.getLastEventId(), \"1\")\n    }\n\n    // MARK: Mixed and other tests\n    func testRepeatedEmptyLines() {\n        parser.parse(line: \"\")\n        parser.parse(line: \"\")\n        parser.parse(line: \"\")\n        XCTAssertNil(handler.events.maybeEvent())\n    }\n\n    func testNothingDoneForInvalidFieldName() {\n        parser.parse(line: \"invalid: bar\")\n        XCTAssertNil(handler.events.maybeEvent())\n    }\n\n    func testInvalidFieldNameIgnoredInEvent() {\n        parser.parse(line: \"data: foo\")\n        parser.parse(line: \"invalid: bar\")\n        parser.parse(line: \"event: msg\")\n        parser.parse(line: \"\")\n        XCTAssertEqual(handler.events.maybeEvent(), .message(\"msg\", MessageEvent(data: \"foo\", lastEventId: \"\")))\n    }\n\n    func testCommentInEvent() {\n        parser.parse(line: \"data: foo\")\n        parser.parse(line: \":bar\")\n        parser.parse(line: \"event: msg\")\n        parser.parse(line: \"\")\n        XCTAssertEqual(handler.events.maybeEvent(), .comment(\"bar\"))\n        XCTAssertEqual(handler.events.maybeEvent(), .message(\"msg\", MessageEvent(data: \"foo\", lastEventId: \"\")))\n    }\n}\n"
  },
  {
    "path": "Tests/LDSwiftEventSourceTests.swift",
    "content": "import XCTest\n@testable import LDSwiftEventSource\n\n#if os(Linux) || os(Windows)\nimport FoundationNetworking\n#endif\n\nfinal class LDSwiftEventSourceTests: XCTestCase {\n    private var mockHandler: MockHandler!\n\n    override func setUp() {\n        super.setUp()\n        mockHandler = MockHandler()\n        XCTAssertTrue(URLProtocol.registerClass(MockingProtocol.self))\n    }\n\n    override func tearDown() {\n        super.tearDown()\n        URLProtocol.unregisterClass(MockingProtocol.self)\n        // Enforce that tests consume all mocked network requests\n        MockingProtocol.requested.expectNoEvent(within: 0.01)\n        MockingProtocol.resetRequested()\n        // Enforce that tests consume all calls to the mock handler\n        mockHandler.events.expectNoEvent(within: 0.01)\n        mockHandler = nil\n    }\n\n    func testConfigDefaults() {\n        let url = URL(string: \"abc\")!\n        let config = EventSource.Config(handler: mockHandler, url: url)\n        XCTAssertEqual(config.url, url)\n        XCTAssertEqual(config.method, \"GET\")\n        XCTAssertEqual(config.body, nil)\n        XCTAssertEqual(config.lastEventId, \"\")\n        XCTAssertEqual(config.headers, [:])\n        XCTAssertEqual(config.reconnectTime, 1.0)\n        XCTAssertEqual(config.maxReconnectTime, 30.0)\n        XCTAssertEqual(config.backoffResetThreshold, 60.0)\n        XCTAssertEqual(config.idleTimeout, 300.0)\n        XCTAssertEqual(config.headerTransform([\"abc\": \"123\"]), [\"abc\": \"123\"])\n        XCTAssertEqual(config.connectionErrorHandler(DummyError()), .proceed)\n    }\n\n    func testConfigModification() {\n        let url = URL(string: \"abc\")!\n        var config = EventSource.Config(handler: mockHandler, url: url)\n\n        let testBody = \"test data\".data(using: .utf8)\n        let testHeaders = [\"Authorization\": \"basic abc\"]\n\n        config.method = \"REPORT\"\n        config.body = testBody\n        config.lastEventId = \"eventId\"\n        config.headers = testHeaders\n        config.reconnectTime = 2.0\n        config.maxReconnectTime = 60.0\n        config.backoffResetThreshold = 120.0\n        config.idleTimeout = 180.0\n        config.headerTransform = { _ in [:] }\n        config.connectionErrorHandler = { _ in .shutdown }\n\n        XCTAssertEqual(config.url, url)\n        XCTAssertEqual(config.method, \"REPORT\")\n        XCTAssertEqual(config.body, testBody)\n        XCTAssertEqual(config.lastEventId, \"eventId\")\n        XCTAssertEqual(config.headers, testHeaders)\n        XCTAssertEqual(config.headerTransform(config.headers), [:])\n        XCTAssertEqual(config.reconnectTime, 2.0)\n        XCTAssertEqual(config.maxReconnectTime, 60.0)\n        XCTAssertEqual(config.backoffResetThreshold, 120.0)\n        XCTAssertEqual(config.idleTimeout, 180.0)\n        XCTAssertEqual(config.connectionErrorHandler(DummyError()), .shutdown)\n    }\n\n    func testConfigUrlSession() {\n        var config = EventSource.Config(handler: mockHandler, url: URL(string: \"abc\")!)\n        let defaultSessionConfig = config.urlSessionConfiguration\n        XCTAssertEqual(defaultSessionConfig.timeoutIntervalForRequest, 300.0)\n        XCTAssertEqual(defaultSessionConfig.httpAdditionalHeaders?[\"Accept\"] as? String, \"text/event-stream\")\n        XCTAssertEqual(defaultSessionConfig.httpAdditionalHeaders?[\"Cache-Control\"] as? String, \"no-cache\")\n        // Configuration should return a fresh session configuration each retrieval\n        XCTAssertTrue(defaultSessionConfig !== config.urlSessionConfiguration)\n        // Updating idleTimeout should effect session config\n        config.idleTimeout = 600.0\n        XCTAssertEqual(config.urlSessionConfiguration.timeoutIntervalForRequest, 600.0)\n        XCTAssertEqual(defaultSessionConfig.timeoutIntervalForRequest, 300.0)\n        // Updating returned urlSessionConfiguration without setting should not update the Config until set\n        let sessionConfig = config.urlSessionConfiguration\n        sessionConfig.allowsCellularAccess = false\n        XCTAssertTrue(config.urlSessionConfiguration.allowsCellularAccess)\n        config.urlSessionConfiguration = sessionConfig\n        XCTAssertFalse(config.urlSessionConfiguration.allowsCellularAccess)\n        XCTAssertTrue(sessionConfig !== config.urlSessionConfiguration)\n    }\n\n    func testLastEventIdFromConfig() {\n        var config = EventSource.Config(handler: mockHandler, url: URL(string: \"abc\")!)\n        var es = EventSource(config: config)\n        XCTAssertEqual(es.getLastEventId(), \"\")\n        config.lastEventId = \"def\"\n        es = EventSource(config: config)\n        XCTAssertEqual(es.getLastEventId(), \"def\")\n    }\n\n    func testCreatedSession() {\n        let config = EventSource.Config(handler: mockHandler, url: URL(string: \"abc\")!)\n        let session = EventSourceDelegate(config: config).createSession()\n        XCTAssertEqual(session.configuration.timeoutIntervalForRequest, config.idleTimeout)\n        XCTAssertEqual(session.configuration.httpAdditionalHeaders?[\"Accept\"] as? String, \"text/event-stream\")\n        XCTAssertEqual(session.configuration.httpAdditionalHeaders?[\"Cache-Control\"] as? String, \"no-cache\")\n    }\n\n    func testCreateRequest() {\n        // 192.0.2.1 is assigned as TEST-NET-1 reserved usage.\n        var config = EventSource.Config(handler: mockHandler, url: URL(string: \"http://192.0.2.1\")!)\n        // Testing default configs\n        var request = EventSourceDelegate(config: config).createRequest()\n        XCTAssertEqual(request.url, config.url)\n        XCTAssertEqual(request.httpMethod, config.method)\n        XCTAssertEqual(request.httpBody, config.body)\n        XCTAssertEqual(request.timeoutInterval, config.idleTimeout)\n        XCTAssertEqual(request.allHTTPHeaderFields, config.headers)\n        // Testing customized configs\n        let testBody = \"test data\".data(using: .utf8)\n        let testHeaders = [\"removing\": \"a\", \"updating\": \"b\"]\n        let overrideHeaders = [\"updating\": \"c\", \"last-event-id\": \"eventId2\"]\n        config.method = \"REPORT\"\n        config.body = testBody\n        config.lastEventId = \"eventId\"\n        config.headers = testHeaders\n        config.idleTimeout = 180.0\n        config.headerTransform = { provided in\n            XCTAssertEqual(provided, [\"removing\": \"a\", \"updating\": \"b\", \"Last-Event-Id\": \"eventId\"])\n            return overrideHeaders\n        }\n        request = EventSourceDelegate(config: config).createRequest()\n        XCTAssertEqual(request.url, config.url)\n        XCTAssertEqual(request.httpMethod, config.method)\n        XCTAssertEqual(request.httpBody, config.body)\n        XCTAssertEqual(request.timeoutInterval, config.idleTimeout)\n        XCTAssertEqual(request.allHTTPHeaderFields, overrideHeaders)\n    }\n\n    func testDispatchError() {\n        var connectionErrorHandlerCallCount = 0\n        var connectionErrorAction: ConnectionErrorAction = .proceed\n        var config = EventSource.Config(handler: mockHandler, url: URL(string: \"abc\")!)\n        config.connectionErrorHandler = { _ in\n            connectionErrorHandlerCallCount += 1\n            return connectionErrorAction\n        }\n        let es = EventSourceDelegate(config: config)\n        XCTAssertEqual(es.dispatchError(error: DummyError()), .proceed)\n        XCTAssertEqual(connectionErrorHandlerCallCount, 1)\n        guard case .error(let err) = mockHandler.events.expectEvent(), err is DummyError\n        else {\n            XCTFail(\"handler should receive error if EventSource is not shutting down\")\n            return\n        }\n        mockHandler.events.expectNoEvent()\n        connectionErrorAction = .shutdown\n        XCTAssertEqual(es.dispatchError(error: DummyError()), .shutdown)\n        XCTAssertEqual(connectionErrorHandlerCallCount, 2)\n    }\n\n    func sessionWithMockProtocol() -> URLSessionConfiguration {\n        let sessionConfig = URLSessionConfiguration.default\n        sessionConfig.protocolClasses = [MockingProtocol.self] + (sessionConfig.protocolClasses ?? [])\n        return sessionConfig\n    }\n\n#if !os(Linux) && !os(Windows)\n    func testStartDefaultRequest() {\n        var config = EventSource.Config(handler: mockHandler, url: URL(string: \"http://example.com\")!)\n        config.urlSessionConfiguration = sessionWithMockProtocol()\n        let es = EventSource(config: config)\n        es.start()\n        let handler = MockingProtocol.requested.expectEvent()\n        XCTAssertEqual(handler.request.url, config.url)\n        XCTAssertEqual(handler.request.httpMethod, config.method)\n        XCTAssertEqual(handler.request.httpBody, config.body)\n        XCTAssertEqual(handler.request.timeoutInterval, config.idleTimeout)\n        XCTAssertEqual(handler.request.allHTTPHeaderFields?[\"Accept\"], \"text/event-stream\")\n        XCTAssertEqual(handler.request.allHTTPHeaderFields?[\"Cache-Control\"], \"no-cache\")\n        XCTAssertNil(handler.request.allHTTPHeaderFields?[\"Last-Event-Id\"])\n        es.stop()\n    }\n\n    func testStartRequestWithConfiguration() {\n        var config = EventSource.Config(handler: mockHandler, url: URL(string: \"http://example.com\")!)\n        config.urlSessionConfiguration = sessionWithMockProtocol()\n        config.method = \"REPORT\"\n        config.body = Data(\"test body\".utf8)\n        config.idleTimeout = 500.0\n        config.lastEventId = \"abc\"\n        config.headers = [\"X-LD-Header\": \"def\"]\n        let es = EventSource(config: config)\n        es.start()\n        let handler = MockingProtocol.requested.expectEvent()\n        XCTAssertEqual(handler.request.url, config.url)\n        XCTAssertEqual(handler.request.httpMethod, config.method)\n        XCTAssertEqual(handler.request.bodyStreamAsData(), config.body)\n        XCTAssertEqual(handler.request.timeoutInterval, config.idleTimeout)\n        XCTAssertEqual(handler.request.allHTTPHeaderFields?[\"Accept\"], \"text/event-stream\")\n        XCTAssertEqual(handler.request.allHTTPHeaderFields?[\"Cache-Control\"], \"no-cache\")\n        XCTAssertEqual(handler.request.allHTTPHeaderFields?[\"Last-Event-Id\"], config.lastEventId)\n        XCTAssertEqual(handler.request.allHTTPHeaderFields?[\"X-LD-Header\"], \"def\")\n        es.stop()\n    }\n\n    func testStartRequestIsNotReentrant() {\n        var config = EventSource.Config(handler: mockHandler, url: URL(string: \"http://example.com\")!)\n        config.urlSessionConfiguration = sessionWithMockProtocol()\n        let es = EventSource(config: config)\n        es.start()\n        es.start()\n        _ = MockingProtocol.requested.expectEvent()\n        MockingProtocol.requested.expectNoEvent()\n        es.stop()\n    }\n\n    func testSuccessfulResponseOpens() {\n        var config = EventSource.Config(handler: mockHandler, url: URL(string: \"http://example.com\")!)\n        config.urlSessionConfiguration = sessionWithMockProtocol()\n        let es = EventSource(config: config)\n        es.start()\n        let handler = MockingProtocol.requested.expectEvent()\n        handler.respond(statusCode: 200)\n        XCTAssertEqual(mockHandler.events.expectEvent(), .opened)\n        es.stop()\n        XCTAssertEqual(mockHandler.events.expectEvent(), .closed)\n    }\n\n    func testLastEventIdUpdatedByEvents() {\n        var config = EventSource.Config(handler: mockHandler, url: URL(string: \"http://example.com\")!)\n        config.urlSessionConfiguration = sessionWithMockProtocol()\n        config.reconnectTime = 0.1\n        let es = EventSource(config: config)\n        es.start()\n        let handler = MockingProtocol.requested.expectEvent()\n        handler.respond(statusCode: 200)\n        XCTAssertEqual(mockHandler.events.expectEvent(), .opened)\n        XCTAssertEqual(es.getLastEventId(), \"\")\n        handler.respond(didLoad: \"id: abc\\n\\n\")\n        // Comment used for synchronization\n        handler.respond(didLoad: \":comment\\n\")\n        XCTAssertEqual(mockHandler.events.expectEvent(), .comment(\"comment\"))\n        XCTAssertEqual(es.getLastEventId(), \"abc\")\n        handler.finish()\n        XCTAssertEqual(mockHandler.events.expectEvent(), .closed)\n        // Expect to reconnect and include new event id\n        let reconnectHandler = MockingProtocol.requested.expectEvent()\n        XCTAssertEqual(reconnectHandler.request.allHTTPHeaderFields?[\"Last-Event-Id\"], \"abc\")\n        es.stop()\n    }\n\n    func testUsesRetryTime() {\n        var config = EventSource.Config(handler: mockHandler, url: URL(string: \"http://example.com\")!)\n        config.urlSessionConfiguration = sessionWithMockProtocol()\n        // Long enough to cause a timeout if the retry time is not updated\n        config.reconnectTime = 5\n        let es = EventSource(config: config)\n        es.start()\n        let handler = MockingProtocol.requested.expectEvent()\n        handler.respond(statusCode: 200)\n        XCTAssertEqual(mockHandler.events.expectEvent(), .opened)\n        handler.respond(didLoad: \"retry: 100\\n\\n\")\n        handler.finish()\n        XCTAssertEqual(mockHandler.events.expectEvent(), .closed)\n        // Expect to reconnect before this times out\n        _ = MockingProtocol.requested.expectEvent()\n        es.stop()\n    }\n\n    func testCallsHandlerWithMessage() {\n        var config = EventSource.Config(handler: mockHandler, url: URL(string: \"http://example.com\")!)\n        config.urlSessionConfiguration = sessionWithMockProtocol()\n        let es = EventSource(config: config)\n        es.start()\n        let handler = MockingProtocol.requested.expectEvent()\n        handler.respond(statusCode: 200)\n        XCTAssertEqual(mockHandler.events.expectEvent(), .opened)\n        handler.respond(didLoad: \"event: custom\\ndata: {}\\n\\n\")\n        XCTAssertEqual(mockHandler.events.expectEvent(), .message(\"custom\", MessageEvent(data: \"{}\")))\n        es.stop()\n        XCTAssertEqual(mockHandler.events.expectEvent(), .closed)\n    }\n\n    func testRetryOnInvalidResponseCode() {\n        var config = EventSource.Config(handler: mockHandler, url: URL(string: \"http://example.com\")!)\n        config.urlSessionConfiguration = sessionWithMockProtocol()\n        config.reconnectTime = 0.1\n        let es = EventSource(config: config)\n        es.start()\n        let handler = MockingProtocol.requested.expectEvent()\n        handler.respond(statusCode: 400)\n        guard case let .error(err) = mockHandler.events.expectEvent(),\n              let responseErr = err as? UnsuccessfulResponseError\n        else {\n            XCTFail(\"Expected UnsuccessfulResponseError to be given to handler\")\n            return\n        }\n        XCTAssertEqual(responseErr.responseCode, 400)\n        // Expect the client to reconnect\n        _ = MockingProtocol.requested.expectEvent()\n        es.stop()\n    }\n\n    func testShutdownByErrorHandlerOnInitialErrorResponse() {\n        var config = EventSource.Config(handler: mockHandler, url: URL(string: \"http://example.com\")!)\n        config.urlSessionConfiguration = sessionWithMockProtocol()\n        config.reconnectTime = 0.1\n        config.connectionErrorHandler = { err in\n            if let responseErr = err as? UnsuccessfulResponseError {\n                XCTAssertEqual(responseErr.responseCode, 400)\n            } else {\n                XCTFail(\"Expected UnsuccessfulResponseError to be given to handler\")\n            }\n            return .shutdown\n        }\n        let es = EventSource(config: config)\n        es.start()\n        let handler = MockingProtocol.requested.expectEvent()\n        handler.respond(statusCode: 400)\n        // Expect the client not to reconnect\n        MockingProtocol.requested.expectNoEvent(within: 1.0)\n        es.stop()\n        // Error should not have been given to the handler\n        mockHandler.events.expectNoEvent()\n    }\n\n    func testShutdownByErrorHandlerOnResponseCompletionError() {\n        var config = EventSource.Config(handler: mockHandler, url: URL(string: \"http://example.com\")!)\n        config.urlSessionConfiguration = sessionWithMockProtocol()\n        config.reconnectTime = 0.1\n        config.connectionErrorHandler = { _ in\n            .shutdown\n        }\n        let es = EventSource(config: config)\n        es.start()\n        let handler = MockingProtocol.requested.expectEvent()\n        handler.respond(statusCode: 200)\n        XCTAssertEqual(mockHandler.events.expectEvent(), .opened)\n        handler.finishWith(error: DummyError())\n        XCTAssertEqual(mockHandler.events.expectEvent(), .closed)\n        // Expect the client not to reconnect\n        MockingProtocol.requested.expectNoEvent(within: 1.0)\n        es.stop()\n        // Error should not have been given to the handler\n        mockHandler.events.expectNoEvent()\n    }\n\n    func testShutdownBy204Response() {\n        var config = EventSource.Config(handler: mockHandler, url: URL(string: \"http://example.com\")!)\n        config.urlSessionConfiguration = sessionWithMockProtocol()\n        config.reconnectTime = 0.1\n\n        let es = EventSource(config: config)\n        es.start()\n\n        let handler = MockingProtocol.requested.expectEvent()\n        handler.respond(statusCode: 204)\n\n        MockingProtocol.requested.expectNoEvent(within: 1.0)\n\n        es.stop()\n        // Error should not have been given to the handler\n        mockHandler.events.expectNoEvent()\n    }\n\n    func testCanOverride204DefaultBehavior() {\n        var config = EventSource.Config(handler: mockHandler, url: URL(string: \"http://example.com\")!)\n        config.urlSessionConfiguration = sessionWithMockProtocol()\n        config.reconnectTime = 0.1\n        config.connectionErrorHandler = { err in\n            if let responseErr = err as? UnsuccessfulResponseError {\n                XCTAssertEqual(responseErr.responseCode, 204)\n            } else {\n                XCTFail(\"Expected UnsuccessfulResponseError to be given to handler\")\n            }\n            return .shutdown\n        }\n        let es = EventSource(config: config)\n        es.start()\n        let handler = MockingProtocol.requested.expectEvent()\n        handler.respond(statusCode: 204)\n        // Expect the client not to reconnect\n        MockingProtocol.requested.expectNoEvent(within: 1.0)\n        es.stop()\n        // Error should not have been given to the handler\n        mockHandler.events.expectNoEvent()\n    }\n#endif\n}\n\nprivate class DummyError: Error { }\n"
  },
  {
    "path": "Tests/MockHandler.swift",
    "content": "@testable import LDSwiftEventSource\n\nenum ReceivedEvent: Equatable {\n    case opened, closed, message(String, MessageEvent), comment(String), error(Error)\n\n    static func == (lhs: ReceivedEvent, rhs: ReceivedEvent) -> Bool {\n        switch (lhs, rhs) {\n        case (.opened, .opened):\n            return true\n        case (.closed, .closed):\n            return true\n        case let (.message(typeLhs, eventLhs), .message(typeRhs, eventRhs)):\n            return typeLhs == typeRhs && eventLhs == eventRhs\n        case let (.comment(lhs), .comment(rhs)):\n            return lhs == rhs\n        case (.error, .error):\n            return true\n        default:\n            return false\n        }\n    }\n}\n\nclass MockHandler: EventHandler {\n    var events = EventSink<ReceivedEvent>()\n\n    func onOpened() { events.record(.opened) }\n    func onClosed() { events.record(.closed) }\n    func onMessage(eventType: String, messageEvent: MessageEvent) { events.record(.message(eventType, messageEvent)) }\n    func onComment(comment: String) { events.record(.comment(comment)) }\n    func onError(error: Error) { events.record(.error(error)) }\n}\n"
  },
  {
    "path": "Tests/TestUtil.swift",
    "content": "import XCTest\n\n#if os(Linux) || os(Windows)\nimport FoundationNetworking\n#endif\n\nstruct EventSink<T> {\n    private let semaphore = DispatchSemaphore(value: 0)\n    private let queue = DispatchQueue(label: \"EventSinkQueue.\" + UUID().uuidString)\n\n    var receivedEvents: [T] = []\n\n    mutating func record(_ event: T) {\n        queue.sync { receivedEvents.append(event) }\n        semaphore.signal()\n    }\n\n    mutating func expectEvent(maxWait: TimeInterval = 1.0) -> T {\n        switch semaphore.wait(timeout: DispatchTime.now() + maxWait) {\n        case .success:\n            return queue.sync { receivedEvents.remove(at: 0) }\n        case .timedOut:\n            XCTFail(\"Expected mock handler to be called\")\n            return (nil as T?)!\n        }\n    }\n\n    mutating func maybeEvent() -> T? {\n        switch semaphore.wait(timeout: DispatchTime.now()) {\n        case .success:\n            return queue.sync { receivedEvents.remove(at: 0) }\n        case .timedOut:\n            return nil\n        }\n    }\n\n    func expectNoEvent(within: TimeInterval = 0.1) {\n        if case .success = semaphore.wait(timeout: DispatchTime.now() + within) {\n            XCTFail(\"Expected no events in sink, found \\(String(describing: receivedEvents.first))\")\n        }\n    }\n}\n\nclass RequestHandler {\n    let proto: URLProtocol\n    let request: URLRequest\n    let client: URLProtocolClient?\n\n    var stopped = false\n\n    init(proto: URLProtocol, request: URLRequest, client: URLProtocolClient?) {\n        self.proto = proto\n        self.request = request\n        self.client = client\n    }\n\n    func respond(statusCode: Int) {\n        let headers = [\"Content-Type\": \"text/event-stream; charset=utf-8\", \"Transfer-Encoding\": \"chunked\"]\n        let resp = HTTPURLResponse(url: request.url!, statusCode: statusCode, httpVersion: nil, headerFields: headers)!\n        client?.urlProtocol(proto, didReceive: resp, cacheStoragePolicy: .notAllowed)\n    }\n\n    func respond(didLoad: String) {\n        respond(didLoad: Data(didLoad.utf8))\n    }\n\n    func respond(didLoad: Data) {\n        client?.urlProtocol(proto, didLoad: didLoad)\n    }\n\n    func finishWith(error: Error) {\n        client?.urlProtocol(proto, didFailWithError: error)\n    }\n\n    func finish() {\n        client?.urlProtocolDidFinishLoading(proto)\n    }\n\n    func stop() {\n        stopped = true\n    }\n}\n\nclass MockingProtocol: URLProtocol {\n    override class func canonicalRequest(for request: URLRequest) -> URLRequest { request }\n    override class func canInit(with request: URLRequest) -> Bool { true }\n    override class func canInit(with task: URLSessionTask) -> Bool { true }\n\n    static var requested = EventSink<RequestHandler>()\n\n    class func resetRequested() {\n        requested = EventSink<RequestHandler>()\n    }\n\n    private var currentlyLoading: RequestHandler?\n\n    override func startLoading() {\n        let handler = RequestHandler(proto: self, request: request, client: client)\n        currentlyLoading = handler\n        MockingProtocol.requested.record(handler)\n    }\n\n    override func stopLoading() {\n        currentlyLoading?.stop()\n        currentlyLoading = nil\n    }\n}\n\nextension URLRequest {\n    func bodyStreamAsData() -> Data? {\n        guard let bodyStream = self.httpBodyStream\n        else { return nil }\n\n        bodyStream.open()\n        defer { bodyStream.close() }\n\n        let bufSize: Int = 16\n        let buf = UnsafeMutablePointer<UInt8>.allocate(capacity: bufSize)\n        defer { buf.deallocate() }\n\n        var data = Data()\n        while bodyStream.hasBytesAvailable {\n            let readDat = bodyStream.read(buf, maxLength: bufSize)\n            data.append(buf, count: readDat)\n        }\n        return data\n    }\n}\n"
  },
  {
    "path": "Tests/UTF8LineParserTests.swift",
    "content": "import XCTest\n@testable import LDSwiftEventSource\n\nfinal class UTF8LineParserTests: XCTestCase {\n    var parser = UTF8LineParser()\n\n    override func setUp() {\n        super.setUp()\n        parser = UTF8LineParser()\n    }\n\n    override func tearDown() {\n        super.tearDown()\n        // Validate that `closeAndReset` completely resets the parser\n        parser.closeAndReset()\n        XCTAssertEqual(parser.append(Data(\"\\n\".utf8)), [\"\"])\n    }\n\n    // swiftlint:disable:next empty_xctest_method - Only runs test in tearDown\n    func testNoData() { }\n\n    func testEmptyData() {\n        XCTAssertEqual(parser.append(Data()), [])\n    }\n\n    func testEmptyCrLine() {\n        XCTAssertEqual(parser.append(Data(\"\\r\".utf8)), [\"\"])\n    }\n\n    func testBasicLineUnterminated() {\n        let line = \"test string\"\n        XCTAssertEqual(parser.append(Data(line.utf8)), [])\n    }\n\n    func testBasicLineCr() {\n        let line = \"test string\"\n        let data = Data((line + \"\\r\").utf8)\n        XCTAssertEqual(parser.append(data), [line])\n    }\n\n    func testBasicLineLf() {\n        let line = \"test string\"\n        let data = Data((line + \"\\n\").utf8)\n        XCTAssertEqual(parser.append(data), [line])\n    }\n\n    func testBasicLineCrLf() {\n        let line = \"test string\"\n        let data = Data((line + \"\\r\\n\").utf8)\n        XCTAssertEqual(parser.append(data), [line])\n    }\n\n    func testBasicSplit() {\n        XCTAssertEqual(parser.append(Data(\"test \".utf8)), [])\n        XCTAssertEqual(parser.append(Data(\"string\\r\".utf8)), [\"test string\"])\n    }\n\n    func testUnicodeString() {\n        let line = \"¯\\\\_(ツ)_/¯0️⃣🇺🇸Z̮̞̠͙͔ͅḀ̗̞͈̻̗Ḷ͙͎̯̹̞͓G̻O̭̗̮𝓯𝓸𝔁\"\n        XCTAssertEqual(parser.append(Data((line + \"\\n\").utf8)), [line])\n    }\n\n    func testNullCodePoint() {\n        let line = \"\\u{0000}\"\n        XCTAssertEqual(parser.append(Data((line + \"\\n\").utf8)), [line])\n    }\n\n    func testInvalidCharacterReplaced() {\n        let line = \"test✨string\"\n        var data = Data((line + \"\\n\").utf8)\n        // Remove 3rd and last byte of \"✨\"\n        data.remove(at: 6)\n        let expected = \"test�string\"\n        XCTAssertEqual(parser.append(data), [expected])\n    }\n\n    // Simulates a multi-code-unit code point being split across received chunks from the network.\n    func testCodePointSplitNotReplaced() {\n        let line = \"test✨string\"\n        let data = Data((line + \"\\r\").utf8)\n        let data1 = data.subdata(in: 0..<6)\n        let data2 = data.subdata(in: 6..<14)\n        XCTAssertEqual(parser.append(data1), [])\n        XCTAssertEqual(parser.append(data2), [line])\n    }\n\n    // Simulates the stream dropping part way through a multi-code-unit code point.\n    func testResetAfterPartialInvalid() {\n        var data = Data(\"test✨\".utf8)\n        data.remove(at: 6)\n        XCTAssertEqual(parser.append(data), [])\n    }\n\n    func testInvalidCharacterReplacedOnNextLineAfterCr() {\n        let line = \"test\\r✨string\\r\"\n        var data = Data(line.utf8)\n        // Remove 3rd and last byte of \"✨\"\n        data.remove(at: 7)\n        XCTAssertEqual(parser.append(data), [\"test\", \"�string\"])\n    }\n\n    func testMultiLineDataMixedLineEnding() {\n        let line = \"test1\\rtest2\\ntest3\\r\\ntest4\\r\\rtest5\\n\\n\"\n        let data = Data(line.utf8)\n        let expected = [\"test1\", \"test2\", \"test3\", \"test4\", \"\", \"test5\", \"\"]\n        XCTAssertEqual(parser.append(data), expected)\n    }\n}\n"
  },
  {
    "path": "release-please-config.json",
    "content": "{\n  \"packages\": {\n    \".\": {\n      \"release-type\": \"simple\",\n      \"bump-minor-pre-major\": true,\n      \"versioning\": \"default\",\n      \"include-v-in-tag\": false,\n      \"include-component-in-tag\": false,\n      \"extra-files\": [\n        \"LDSwiftEventSource.podspec\",\n        \"README.md\"\n      ]\n    }\n  }\n}\n"
  }
]