[
  {
    "path": ".ci/buildkite/pipeline.sh",
    "content": "#!/bin/bash\ncat <<-YAML\n\nsteps:\n\n  - name: \":aws: Generate Docs\"\n    trigger: \"procedurekit-documentation\"\n    build:\n      message: \"Generating documentation for ProcedureKit\"\n      commit: \"HEAD\"\n      branch: \"master\"\n      env:\n        PROCEDUREKIT_HASH: \"$COMMIT\"\n        PROCEDUREKIT_BRANCH: \"$BRANCH\"\nYAML"
  },
  {
    "path": ".ci/buildkite/upload",
    "content": "#!/bin/bash\n\nset -eu\n\n# Makes sure all the steps run on this same agent\nsed \"s~\\$XCODE~$BUILDKITE_AGENT_META_DATA_XCODE~;s~\\$COMMIT~$BUILDKITE_COMMIT~;s~\\$BRANCH~$BUILDKITE_BRANCH~\" .ci/buildkite/pipeline.sh | sh\n"
  },
  {
    "path": ".github/CONTRIBUTING.md",
    "content": "# Contributing Guidelines\n\nThis document contains information and guidelines about contributing to this project.\n\n## Before creating a GitHub Issue\nBefore creating an issue, please search the project first. Your question or bug may have already been asked, answered and or reported. \n\nAdditionally, frequently asked questions are collected in the Wiki.\n\n## Asking Questions\n1. Create an issue in the project.\n    Please prefix your subject with `[Question]:`, it will get labelled as such. Please try to reduce your question into elements which are specific to _ProcedureKit_.\n3. Ask a question on [Stack Overflow](http://stackoverflow.com).\n    Add a tag `procedure-kit` to your question, or reference core contributors such as [@Daniel.Thorpe](http://stackoverflow.com/users/197626/daniel-thorpe).\n\n## Reporting Bugs\nA great way to contribute to the project is to send a detailed issue when you encounter a problem. A well written and detailed bug report is always welcome.\n\nPlease include verbose log output. Verbose logging can be enabled globally:\n\n```swift\nLogManager.severity = .Verbose\n```\n\nor for a single operation:\n\n```swift\noperation.log.severity = .Verbose\n```\n\nthis will print out lifecycle event, and is very useful for debugging scheduling issues.\n\n## Contributing Code\nBefore contributing code, create an issue to engage with core contributors about the feature or changes you wish to make.\n\n1. Install SwiftLint\n    The project uses [SwiftLint](https://github.com/realm/SwiftLint) to maintain a consistent Swift style. Linting occurs during an Xcode build phase, at which time white space issues are automatically corrected.\n    \n    ```\n    brew install swiftlint\n    ```    \n2. Write unit tests \n    We are aiming for maximum test coverage. Most importantly, we want to always increase coverage which is currently ~ 75%. Please ask (in your GitHub issue) if you are unsure how to write unit tests for features you are adding.\n3. Write documentation\n    Add source code documentation in English for any public interfaces. Try to follow the tone of the existing documentation. Please ask (in your GitHub issue) for clarity on how to write documentation if you are unsure.\n4. Prefix your commit messages\n    Use the GitHub ticket number, browse the commit history for examples.\n\n## Developer's Certificate of Origin 1.1\n\nBy making a contribution to this project, I certify that:\n\n- (a) The contribution was created in whole or in part by me and I have the right to submit it under the open source license indicated in the file; or\n\n- (b) The contribution is based upon previous work that, to the best of my knowledge, is covered under an appropriate open source license and I have the right under that license to submit that work with modifications, whether created in whole or in part by me, under the same open source license (unless I am permitted to submit under a different license), as indicated in the file; or\n\n- (c) The contribution was provided directly to me by some other person who certified (a), (b) or (c) and I have not modified it.\n\n- (d) I understand and agree that this project and the contribution are public and that a record of the contribution (including all personal information I submit with it, including my sign-off) is maintained indefinitely and may be redistributed consistent with this project or the open source license(s) involved.\n\n## Code of Conduct\nThe code of conduct governs how we behave in public or in private whenever the project will be judged by our actions. We expect it to be honored by everyone who contributes to this project. See [CONDUCT.md](CONDUCT.md).\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "name: ProcedureKit CI\n\non: push\n\njobs:\n\n  macOS:\n    name: Test macOS \n    runs-on: macOS-latest\n    steps:\n      - uses: actions/checkout@v1    \n      - name: macOS\n        run: xcodebuild -project \"ProcedureKit.xcodeproj\" -scheme \"Mac\" -destination \"platform=macOS\" clean test | tee .ci/results/xcodebuild-mac.log\n  iOS:\n    name: Test iOS \n    runs-on: macOS-latest\n    steps:\n      - uses: actions/checkout@v1            \n      - name: iOS\n        run: xcodebuild -project \"ProcedureKit.xcodeproj\" -scheme \"iOS\" -destination \"platform=iOS Simulator,name=iPhone X\" clean test | tee .ci/results/xcodebuild-ios.log\n  tvOS:\n    name: Test tvOS \n    runs-on: macOS-latest\n    steps:\n      - uses: actions/checkout@v1            \n      - name: tvOS\n        run: xcodebuild -project \"ProcedureKit.xcodeproj\" -scheme \"tvOS\" -destination \"platform=tvOS Simulator,name=Apple TV\" clean test | tee .ci/results/xcodebuild-tvOS.log\n\n  stressTest:\n    name: Stress Test\n    runs-on: macOS-latest\n    steps:\n      - uses: actions/checkout@v1            \n      - name: Stress Test\n        run: xcodebuild -project \"ProcedureKit.xcodeproj\" -scheme \"Stress Tests\" -destination \"platform=macOS\" clean test | tee .ci/results/xcodebuild-stress.log\n        \n  cocoapods:\n    name: Test Integration with Cocoapods\n    runs-on: macOS-latest    \n    needs: [macOS, iOS, tvOS, stressTest]\n    steps:\n      - uses: actions/checkout@v1\n      - uses: actions/setup-ruby@v1\n        with:\n          ruby-version: '2.x'      \n      - name: Install Ruby dependencies\n        run: bundle install --quiet\n      - name: CocoaPods Install\n        run: |      \n          cd 'Integrations/CocoaPods'\n          bundle exec pod install\n      - name: Mac Build & Test\n        run: |      \n          cd 'Integrations/CocoaPods'\n          bundle exec xcodebuild -workspace TryProcedureKit.xcworkspace -scheme TryProcedureKit clean build test | xcpretty\n\n  spm:\n    name: Test Integration with SPM\n    runs-on: macOS-latest    \n    needs: [macOS, iOS, tvOS, stressTest]\n    steps:\n      - uses: actions/checkout@v1\n      - name: SPM Build & Test\n        run: |      \n          cd 'Integrations/SPM'\n          swift package update\n          swift build\n          swift test\n"
  },
  {
    "path": ".gitignore",
    "content": "# Xcode\n#\nbuild/\n*.pbxuser\n!default.pbxuser\n*.mode1v3\n!default.mode1v3\n*.mode2v3\n!default.mode2v3\n*.perspectivev3\n!default.perspectivev3\nxcuserdata\n*.xccheckout\n*.moved-aside\nDerivedData\n*.hmap\n*.ipa\n*.xcuserstate\n\n# CocoaPods\n#\n# We recommend against adding the Pods directory to your .gitignore. However\n# you should judge for yourself, the pros and cons are mentioned at:\n# http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control\n#\nPods/\n**/**/Pods\n\n# Carthage\n#\n# Add this line if you want to avoid checking in source code from Carthage dependencies.\n# Carthage/Checkouts\n\nCarthage/Build\n.fastlane/report.xml\n.fastlane/xcodebuild-data\n\n# Jazzy\ndocs\n\n# Swift Package Manager\n/.build\n/Packages\n.DS_Store\n.ci/xcodebuild-data/*\n.fastlane/README.md\n.ci/results/**\n/Integrations/SPM/Package.resolved\n"
  },
  {
    "path": ".jazzy.json",
    "content": "{\n  \"xcodebuild_arguments\": [\n  \t\"-project\", \"ProcedureKit.xcodeproj\", \n  \t\"-scheme\", \"ProcedureKit\"],\n  \"author\": \"ProcedureKit Contributors\",\n  \"author_url\": \"https://github.com/ProcedureKit\",\n  \"module\": \"ProcedureKit\",\n  \"readme\": \"README.md\",\n  \"theme\": \"Documentation/Themes/fullwidth_pk\",\n  \"documentation\": \"Documentation/Guides/**/*.md\",\n  \n  \"custom_categories\": [{\n\t\"name\": \"Getting Started\",\n\t\"children\": [\n\t\t\"What is ProcedureKit?\",\n\t\t\"Installing ProcedureKit\",\n\t\t\"MyFirstProcedure\",\n\t\t\"Scheduling\",\n\t\t\"Dependencies\"\n\t]}, {\n\t\"name\": \"Migrating\",\n\t\"children\": [\n\t    \"From NSOperation\",\n\t    \"From WWDC2015\",\n\t    \"From PSOperations\",\n\t    \"From v3 Operations\"\n\t]}, {\n\t\"name\": \"Basic Features\",\n\t\"children\": [\n\t    \"Observers\",\n\t    \"Conditions\",\n\t    \"Groups\",\n\t    \"Result Injection\",\n\t    \"Logging\"\n\t]}, {\n\t\"name\": \"Cancellation\",\n\t\"children\": [\n\t    \"Handling Cancellation\",\n\t    \"In Synchronous Procedures\",\t\n\t    \"In Asynchronous Procedures\"\n\t]}, {\n\t\"name\": \"Advanced Features\",\n\t\"children\": [\n\t    \"Custom Observers\",\t\n\t    \"Mutual Exclusion\",\t\n\t    \"Advanced Conditions\",\n\t    \"Capabilities\",\n\t    \"Advanced Groups\",\n\t    \"Advanced Result Injection\",\n\t    \"Custom Logging\"\n\t]}, {\n\t\"name\": \"Built-in Procedures\",\n\t\"children\": [\n\t    \"BlockProcedure\",\t\n\t    \"ComposedProcedure\",\t\n\t    \"GatedProcedure\",\n\t    \"DelayProcedure\",\n\t    \"RepeatProcedure\",\n\t    \"RetryProcedure\"\n\t]}, {\n\t\"name\": \"Core\",\n\t\"children\": [\n\t    \"Procedure\",\n\t    \"ProcedureQueue\",\n\t    \"ProcedureObserver\",\n\t    \"ProcedureProtocol\",\n\t    \"Condition\"\n\t]}, {\n\t\"name\": \"Built-in Conditions\",\n\t\"children\": [\n\t    \"BlockCondition\",\n\t    \"NegatedContion\",\n\t    \"SilentCondition\",\n\t    \"NoFailedDependenciesCondition\",\n\t    \"MutualExclusion\"\n\t]}, {\n\t\"name\": \"Built-in Observers\",\n\t\"children\": [\n\t    \"BlockObserver\",\n\t    \"WillExecuteObserver\",\n\t    \"DidExecuteObserver\",\n\t    \"DidCancelObserver\",\n\t    \"WillAddOperationObserver\",\n\t    \"DidAddOperationObserver\",\n\t    \"WillFinishObserver\",\n\t    \"DidFinishObserver\"\n\t]}\n  ]\n}"
  },
  {
    "path": ".ruby-gemset",
    "content": "procedurekit\n"
  },
  {
    "path": ".ruby-version",
    "content": "2.5.0\n"
  },
  {
    "path": ".swiftlint.yml",
    "content": "included:\n  - Sources\ndisabled_rules:\n  - valid_docs\n  - statement_position\n  - line_length\n  - type_name\n  - large_tuple\n  - identifier_name\n  - implicit_getter\n  - syntactic_sugar\nfile_length:\n  warning: 750\n  error: 1200\nvariable_name:\n  excluded:\n    - id\n    - URL\n    - of\n    - in\n    - on\n    - x\n    - y  "
  },
  {
    "path": ".travis.yml",
    "content": "language: objective-c\nosx_image: xcode10\njobs:\n  include:\n    - stage: Stress Test\n      script: .ci/scripts/test-stress\n    - stage: Mac\n      script: .ci/scripts/test-macosx\n    - stage: iOS\n      script: .ci/scripts/test-ios\n    - stage: tvOS\n      script: .ci/scripts/test-tvos\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# 5.2.0\nXcode 10.2 & Swift 5 compatible.\n\n# 5.1.0\nThis will be the last update specifically supporting Xcode 10.1 and Swift 4.2. \n\n## New Procedures\n\n1. [[919](https://github.com/ProcedureKit/ProcedureKit/pull/919)]: JSON Coding procedures.\n\n    This changes introduced a generic `JSONDecodingProcedure` and `JSONEncodingProcedure` which can be used to decode/decode a `Data` representing a UTF-8 encoded JSON string into a suitable `Codable` type. The procedure allows full injection of the `JSONDecoder` with a convenience initializer to user or override the default behavior. Additionally, the  `Data` can be inject from a network procedure. For decoding errors - the procedure will fail with the coding error from the `JSONDecoder`. This might be quite tricky to recover from and manage in production code, so in some cases it would make sense to decode into a type which can handle JSON error responses, e.g. `{\"message\": \"Failed to authorize\"}`.\n\n## Other Changes\n\n1. [[908](https://github.com/ProcedureKit/ProcedureKit/pull/908), [909](https://github.com/ProcedureKit/ProcedureKit/pull/909)]: Updates the parameter names in method signature named `with: Error?` to include `error`. This greatly improves code completion. Thanks to [@pronebird](https://github.com/pronebird) and [@juliensagot](https://github.com/juliensagot) for these.\n2. [[906](https://github.com/ProcedureKit/ProcedureKit/pull/906)]: Updates to the logging mechanisms.\n3. [[918](https://github.com/ProcedureKit/ProcedureKit/pull/918)]: The `Identity` property of `Procedure` now uses `ObjectIdentifier` and `Hasher` under the hood instead of UUIDs. Thanks to \n4. [[912](https://github.com/ProcedureKit/ProcedureKit/pull/912)]: Fixes some public accessor attributes for `NetworkRecovery` - thanks to [@ericyanush](https://github.com/ericyanush) for this one.\n5. [[923](https://github.com/ProcedureKit/ProcedureKit/pull/923)]: Added an integration point in CI to check that SwiftPM was correctly integrating.\n6. [[924](https://github.com/ProcedureKit/ProcedureKit/pull/924)]: Fixes public accessor methods to the `LaunchRequest` type in `ProcessProcedure`.\n\n# 5.0.0\nThis is a _rather long-awaited_ next major version of ProcedureKit.\n\n## Headline Changes\n1. Networking procedures no longer use an associated type for the `URLSession`. Instead `Session` is a free-floating protocol. This makes general usage, subclassing and composing much simpler.\n2. There is now a Core Data module\n3. `BlockProcedure` API has changed.\n4. `Procedure` only supports a single `Error` value, instead of `[Error]` - this has had some fairly wide reaching changes to APIs.\n5. New built-in logger, which uses `os_log` by default.\n6. Changes to `UIProcedure` in _ProcedureKitMobile_ module.\n\n## Breaking Changes\n1. [[823](https://github.com/ProcedureKit/ProcedureKit/pull/823)]: Removes associated types from Network\n\n    Originally raised as an [issue](https://github.com/ProcedureKit/ProcedureKit/issues/814) by [@ericyanush](https://github.com/ericyanush) in which I totally missed the point initially. But, after thinking about it more, made so much sense. Instead of having a generic `URLSessionTaskFactory` protocol, where the various types of tasks were associated types, we now just have a non-generic `NetworkSession` protocol, to which `URLSession` conforms. The impact of this subtle change, is that what was once: `NetworkDataProcedure<Session: URLSessionTaskFactory>` is now `NetworkDataProcedure`. In otherwords, no longer generic, and now super easy to use as that generic `Session` doesn't leak all over the place.\n    \n2. [[#875](https://github.com/ProcedureKit/ProcedureKit/pull/875)]: Refactored `BlockProcedure`\n\n    There has been a long-standing wish for `BlockProcedure` instances to \"receive themselves\" in their block to allow for access to its logger etc. In v5, the following is all possible, see this [comment](https://github.com/ProcedureKit/ProcedureKit/pull/875#issuecomment-410502324):\n    \n    1. Simple synchronous block (existing functionality):\n        ```swift\n        let block = BlockProcedure { \n            print(\"Hello World\")\n        }\n        ```\n\n    2. Synchonous block, accessing the procedure inside the block:\n        ```swift\n        let block = BlockProcedure { this in\n            this.log.debug.message(\"Hello World\")\n            this.finish()\n        }\n        ```\n        Note that here, the block is responsible for finishing itself - i.e. call `.finish()` or `.finish(with:)` to finish the Procedure. Using this initializer, by default, `BlockProcedure` will add a `TimeoutObserver` to itself, using `defaultTimeoutInterval` which is set to 3 seconds. This can be modified if needed.\n        ```swift\n        BlockProcedure.defaultTimeoutInterval = 5\n        ```\n\n    3. Asynchronous block with cancellation check, `AsyncBlockProcedure` and `CancellableBlockProcedure` get deprecated warnings.\n        ```swift\n        let block = BlockProcedure { this in\n            guard !this.isCancelled else { this.finish() }\n            DispatchQueue.default.async {\n               print(\"Hello world\")\n               this.finish()\n            }\n        }\n        ```\n\n    4. `ResultProcedure` as been re-written as a subclass of `BlockProcedure` (previously, it was the superclass). Existing functionality has been maintained:\n        ```swift\n        let hello = ResultProcedure { \"Hello World\" }\n        ```\n3. [[#851](https://github.com/ProcedureKit/ProcedureKit/pull/851)]: Errors\n    \n    At WWDC18 I spent some time with some Swift engineers from Apple talking about framework design and error handling. The key take-away from these discussions was to _increase clarity_ which reduces confusion, and makes _intent_ clear. \n    \n    This theme drove some significant changes. To increase clarity, each Procedure can only have a single `Error`, because ultimately, how can a framework consumer \"handle\" an array of `Error` values over just a single one? I realised that the only reason `Procedure` has an `[Error]` property at all was from `GroupProcedure` collecting all of the errors from its children, yet the impact of this is felt throughout the codebase. \n    \n    This means, to finish a procedure with an error, use:    \n    ```swift\n    finish(with: .downloadFailedError) // this is a made up error type\n    ```\n    \n    Observers only receive a single error now:\n    ```swift\n    procedure.addDidFinishBlockObserver { (this, error) in\n        guard let error = error else {\n            // there is an error, the block argument is Error? type\n\t    return\n        }\n\t\n\t// etc\n    }\n    ```\n    \n    Plus more API changes in `Procedure` and `GroupProcedure` which will result in deprecation warnings for framework consumers.\n    \n    For `GroupProcedure` itself, it will now only set its own error to the first error received. However, to access the errors from child procedures, use the `.children` property. Something like:\n    ```swift\n    let errors = group.children.operationsAndProcedures.1.compactMap { $0.error }\n    ```\n    \n4. [[#861](https://github.com/ProcedureKit/ProcedureKit/pull/861), [#870](https://github.com/ProcedureKit/ProcedureKit/pull/870)]: Logger\n\n    _ProcedureKit_ has its own logging system, which has received an overhawl in v5. The changes are:\n    \n        1. Now uses `os_log` instead of `print()` where available.\n\t2. Dedicated severity levels for caveman debugging & user event. See this [comment](https://github.com/ProcedureKit/ProcedureKit/pull/861#issuecomment-404058717).\n\t3. Slight API change:\n\t    ```swift\n   \t    procedure.log.info.message(\"This is my debug message\")\n\t    ```\n\t    previously, it was:\n\t    ```swift\n\t    procedure.log.info(\"This is my debug message\")\n\t    ```\n\t    For module-wide settings:\n\t    ```swift\n\t    Log.enabled = true\n\t    Log.severity = .debug // default is .warning\n\t    Log.writer = CustomLogWriter() // See LogWriter protocol\n\t    Log.formatter = CustomLogFormatter() // See LogFormatter protocol\n\t    ```\n5. [[#860](https://github.com/ProcedureKit/ProcedureKit/pull/860)]: Swift 3/4 API naming & conventions\n\n    [@lukeredpath](https://github.com/lukeredpath) initially raised the issue in [#796](https://github.com/ProcedureKit/ProcedureKit/issues/796), that some APIs such as `add(condition: aCondition)` did not Swift 3/4 API guidelines, and contributed to inconsistency within the framework. These have now been tidied up.\n\n## New Features & Improvements\n1. [[#830](https://github.com/ProcedureKit/ProcedureKit/pull/830), [#837](https://github.com/ProcedureKit/ProcedureKit/pull/837)]: Swift 4.1 & Xcode 9.3 support, (Xcode 10 is ready to go).\n    \n    These changes take advantage of Swift 4.1 capabilities, such as synthesized `Equatable` and conditional conformance.\n\n2. [[#828](https://github.com/ProcedureKit/ProcedureKit/pull/828), [#833](https://github.com/ProcedureKit/ProcedureKit/pull/833)]: Result Injection & Binding\n    \n    Result Injection conformance is added to `RepeatProcedure` (and subclasses such as `RetryProcedure` & `NetworkProcedure`). This means the input can be set on the out `RepeatProcedure`, and this value will be set on every instance of the target procedure (assuming it also conforms to `InputProcedure`). This avoids having to jump through hoops like [this](https://github.com/ProcedureKit/ProcedureKit/issues/876).\n    \n    Additionally, a new _binding_ API can be used, particularly with `GroupProcedure` subclasses, so that the input of a child procedure is \"bound\" to that of the group itself, likewise, the output of the group is bound to a child. This makes it very easy to encapsulate a chain of procedures which use result injection into a `GroupProcedure` subclass. See [the docs](http://procedure.kit.run/development/advanced-result-injection.html).\n\n3. [[#834](https://github.com/ProcedureKit/ProcedureKit/pull/834)]: Adds `BatchProcedure`\n    \n    `BatchProcedure` is a `GroupProcedure` subclass which can be used to batch process a homogeneous array of objects, so that we get `[T] -> [V]` via a procedure which does `T -> V`. We already have `MapProcedure` which does this via a closure, and so is synchronous, and useful for simple data transforms. `BatchProcedure` allows asynchronous processing via a custom procedure. This is actually a pretty common situation in production apps. For example, consider an API response for a gallery of images, we can use `BatchProcedure` to get all the images in the gallery.\n\n4. [[#838](https://github.com/ProcedureKit/ProcedureKit/pull/838)]: Adds `IgnoreErrorsProcedure`\n    \n    `IgnoreErrorsProcedure` will safely wrap another procedure to execute it and suppress any errors. This can be useful for _fire, forget and ignore_ type behavior.\n\n5. [[#843](https://github.com/ProcedureKit/ProcedureKit/pull/843), [#844](https://github.com/ProcedureKit/ProcedureKit/pull/844), [#847](https://github.com/ProcedureKit/ProcedureKit/pull/847), [#849](https://github.com/ProcedureKit/ProcedureKit/pull/849)]: Adds _ProcedureKitCoreData_.\n\n    - [x] `LoadCoreDataProcedure` - intended to be subclassed by framework consumers for their project, see the docs.\n    - [x] `MakeFetchedResultControllerProcedure`\n    - [x] `SaveManagedObjectContext`\n    - [x] `InsertManagedObjectsProcedure`\n    - [x] `MakesBackgroundManagedObjectContext` - a protocol to allow mixed usage of `NSPersistentContainer`, `NSManagedObjectContext` and `NSPersistentStoreCoordinator`.\n\n6. [[#840](https://github.com/ProcedureKit/ProcedureKit/pull/840), [#858](https://github.com/ProcedureKit/ProcedureKit/pull/858), [#868](https://github.com/ProcedureKit/ProcedureKit/pull/868)]: Adds `UIBlockProcedure`\n\n    `UIBlockProcedure` replaces `UIProcedure`, and it essentially is a block which will always run on the main queue. It is the basis for other UI procedures.\n\n7. [[#841](https://github.com/ProcedureKit/ProcedureKit/pull/841), [#873](https://github.com/ProcedureKit/ProcedureKit/pull/873), [#874](https://github.com/ProcedureKit/ProcedureKit/pull/874)]: Adds `UIViewController` containment procedures\n\n    - [x] `AddChildViewControllerProcedure`\n    - [x] `RemoveChildViewControllerProcedure`\n    - [x] `SetChildViewControllerProcedure`\n    \n    All of these procedures provide configurable auto-layout options. By default the child view controller's view is \"pinned\" to the bounds of the parent view. However, it is possible to use custom auto-layout behaviour.\n\n## Notes\n\nThanks to everyone who has contributed to _ProcedureKit_ - v5 has been quite a while in development. There is still quite a bit left to do on the documentation effort - but that will be ongoing for evermore.\n\n\n# 4.5.0\n\n## Swift 4.0\n\n1. [#816](https://github.com/ProcedureKit/ProcedureKit/pull/816) Updates for Xcode 9.2 and Swift 4.0. Thanks to [@jshier](https://github.com/jshier) for making the updates. Included here are updates to the Travis config too.\n\n## Improvements\n1. [#781](https://github.com/ProcedureKit/ProcedureKit/pull/781) Some significant performance and reliability improvements for `BackgroundObserver` by [@swiftlyfalling](https://github.com/swiftlyfalling).\n\n## Deprecations\n1. [#818](https://github.com/ProcedureKit/ProcedureKit/pull/818) `UserIntent` property on `Procedure` has been deprecated. Suggestion is to set the underlying queue priority. \n\n\n# 4.4.0\n\n## Breaking Change\n1. [#787](https://github.com/ProcedureKit/ProcedureKit/pull/787) Updates to a minimum version of watchOS 3. Technically, this is a breaking change, but, realistically, anyone building for  Watch will be at least on watchOS 3 now. \n\n## Others\n1. [#802](https://github.com/ProcedureKit/ProcedureKit/pull/802) Updates iOS Simulators to iOS 11 in Fastlane\n2. [#801](https://github.com/ProcedureKit/ProcedureKit/pull/801) Removes SwiftLint\n3. [#795](https://github.com/ProcedureKit/ProcedureKit/pull/795) Fixes an issue with Conditions and suspended ProcedureQueues\n\n\n\n# 4.3.2\n\n1. [#790](https://github.com/ProcedureKit/ProcedureKit/issues/790),[#791](https://github.com/ProcedureKit/ProcedureKit/pull/791) Fixes a mistake which hid the initialiser of `ReverseGeocodeUserLocation` which renders it un-usable 🙄. Thanks to [Anatoliy](https://github.com/eastsss) for raising the issue. There really aught to be some way of having autogenerated tests for this type of bug.\n2. [#793](https://github.com/ProcedureKit/ProcedureKit/pull/793) Migrates _ProcedureKit_'s CI to a complementary account on [BuildKite](http://buildkite.com/procedurekit). You will still need an account to view this, however, it means that open source contributors can be added to the BK account without cost. Please get in touch if you want an invite. Thanks to [@keithpitt](https://github.com/keithpitt) and [@ticky](https://github.com/ticky) for migrating our pipeline & history between orgs.\n\n    In addition to this, I have setup a Mac in MacStadium, in addition to my own build server. This means that we should have effectively got _constant_ uptime of agents to build CI.\n    \n    In light of these changes, I've disabled the Travis service, which has proved to be slow and un-reliable. The `travis.yml` will stay and remain working for anyone who maintains their own fork. \n\n# 4.3.1\n\n1. [#785](https://github.com/ProcedureKit/ProcedureKit/pull/785) To get round an error with Xcode 9 betas archiving applications. \n\n# 4.3.0\n\n## Documentation\n\n1. [#750](https://github.com/ProcedureKit/ProcedureKit/pull/750), [#762](https://github.com/ProcedureKit/ProcedureKit/pull/762), [#763](https://github.com/ProcedureKit/ProcedureKit/pull/763), [#751](https://github.com/ProcedureKit/ProcedureKit/pull/751), [#766](https://github.com/ProcedureKit/ProcedureKit/pull/766), [#767](https://github.com/ProcedureKit/ProcedureKit/pull/767), [#768](https://github.com/ProcedureKit/ProcedureKit/pull/768), [#771](https://github.com/ProcedureKit/ProcedureKit/pull/771), [#772](https://github.com/ProcedureKit/ProcedureKit/pull/772), [#773](https://github.com/ProcedureKit/ProcedureKit/pull/773), [#775](https://github.com/ProcedureKit/ProcedureKit/pull/775), [#779](https://github.com/ProcedureKit/ProcedureKit/pull/779) Numerous improvements to project documentation.\n2. Docs are a combination of source code documentation and a programming guide. It is built as the code changes as part of the CI system, and published on [procedure.kit.run](http://procedure.kit.run) with a path matching the branch. Therefore, the most up-to-date documentation is: [procedure.kit.run/development](http://procedure.kit.run/development).\n3. The programming guide is written in Markdown, and stored in the repo under `Documentation/Guides`\n4. Documentation is generated using [jazzy](http://github.com/realm/jazzy) and organised via `.jazzy.json` file. It can be generated locally by running `jazzy --config .jazzy.json` from the project root.\n5. Because documentation is built as part of CI, it should evolve with the code, and the documentation for WIP branches can be built, published and viewed.\n6. Eventually the documentation site will allow framework consumers to browse versions of the programming guide.\n7. Current documentation coverage is 53%. This is reported in a shield on the project page.\n    \n## Other Improvements\n\n1. [#757](https://github.com/ProcedureKit/ProcedureKit/pull/757) Improves the `QualityOfService` tests.\n2. [#756](https://github.com/ProcedureKit/ProcedureKit/pull/756) Fixes a rare race condition involving `Condition`.\n3. [#752](https://github.com/ProcedureKit/ProcedureKit/pull/752), [#754](https://github.com/ProcedureKit/ProcedureKit/pull/754) Resolves `ProcedureObserver` errors in Xcode 9 Beta 3 onwards.\n4. [#769](https://github.com/ProcedureKit/ProcedureKit/pull/769) Fixes a race condition in `TestProcedure`.\n5. [#770](https://github.com/ProcedureKit/ProcedureKit/pull/770), [#774](https://github.com/ProcedureKit/ProcedureKit/pull/774) Fixes unstable tests related to producing operations.\n6. [#777](https://github.com/ProcedureKit/ProcedureKit/pull/777) Simplifies `Procedure.ConditionEvaluator` state management.\n\n## Other Notes\n\n- I ([@danthorpe](https://github.com/danthorpe)) changed the _code of conduct_ to comply with GitHub's notion of what a code of conduct is. Quite frankly, this is annoying, please feel free to contact me if you find the [changes](https://github.com/ProcedureKit/ProcedureKit/commit/6a15f80da6fdf6ffaf918a8f21f984212502e0e1) disagreeable.\n\n# 4.2.0\n\n## Breaking Changes\n1. [#717](https://github.com/ProcedureKit/ProcedureKit/pull/717) Termination status & termination reason provided to handler (full details in PR).\n2. [#737](https://github.com/ProcedureKit/ProcedureKit/pull/737) Simplifies `GroupProcedure` child error handling, so that it is now centralised in a single, better named method: `child(_:willFinishWithErrors:)`\n\n## Swift 4\n1. [@swiftlyfalling](https://github.com/swiftlyfalling) has gone through the entire project and fixes Swift 4 released issues so that _ProcedureKit_ will work in Xcode 9 beta without issue. Critically, we have not yet changed the build settings for Swift 4 - but this is the last release for Swift 3.\n2. [#739](https://github.com/ProcedureKit/ProcedureKit/pull/739) Fixes complication of `ProcedureEventQueue` in Xcode 9, when in Swift 3 mode.\n\n## Tweaks & Improvements\n1. [#715](https://github.com/ProcedureKit/ProcedureKit/pull/715) Improves the `.then { }` API so that _all_ operations in the receiver are added as dependents of the argument.\n2. [#717](https://github.com/ProcedureKit/ProcedureKit/pull/717) Improves `ProcessProcedure` so that can be used with result injection and dispatches using its internal queue.\n3. [#738](https://github.com/ProcedureKit/ProcedureKit/pull/738) Adds `transformChildErrorsBlock` to `GroupProcedure`. This will enable customisation of the errors with `GroupProcedure` without subclassing.\n\n\n## Stability & Bug Fixes\n1. [#710](https://github.com/ProcedureKit/ProcedureKit/pull/710), [#711](https://github.com/ProcedureKit/ProcedureKit/pull/711), [#712](https://github.com/ProcedureKit/ProcedureKit/pull/712) Lots of robustness fixes for tests.\n2. [#714](https://github.com/ProcedureKit/ProcedureKit/pull/714) Fixes a (rare) data race in DelayProcedure.\n3. [#721](https://github.com/ProcedureKit/ProcedureKit/pull/721) Adds missing `tearDown` overrides to `CloudKitProcedure` tests.\n4. [#722](https://github.com/ProcedureKit/ProcedureKit/pull/722) Fixes a memory cycle in `makeFinishingProcedure` in the testing framework helpers.\n5. [#724](https://github.com/ProcedureKit/ProcedureKit/pull/724) Reduces dependencies on BuildKite agents by adding Travis CI.  \n\n# 4.1.0\n\n1. Swift 3.1 fixes for Xcode 8.3\n\n# 4.0.1\n\nSame as Beta 7 😀\n\n# 4.0.0 Beta 7\n\n## Breaking Changes\n1. [#668](https://github.com/ProcedureKit/ProcedureKit/pull/668) Adds Procedure event queue. Procedure now utilises an internal serial FIFO queue which dispatched user \"events\". Procedure events include anything that calls user code, like overridden methods, observer callbacks, injecting results from a dependency. See the PR for more details, there are some breaking changes here, which is very well documented in the PR description.\n2. [#681](https://github.com/ProcedureKit/ProcedureKit/pull/681) [@swiftlyfalling](https://github.com/swiftlyfalling) Refactors how Condition is implemented. There are breaking changes here which are well documented in PR description.\n\n## New APIs & Enhancements\n1. [#662](https://github.com/ProcedureKit/ProcedureKit/pull/662), [#673](https://github.com/ProcedureKit/ProcedureKit/pull/673) Improves the TimeoutObserver implementation by utilising a registrar to handle the lifetime of timers. By [@swiftlyfalling](https://github.com/swiftlyfalling).\n2. [#658](https://github.com/ProcedureKit/ProcedureKit/issues/658), [#659](https://github.com/ProcedureKit/ProcedureKit/pull/659) Adds Repeatable type.\n3. [#663](https://github.com/ProcedureKit/ProcedureKit/pull/663) Fixes building when using Swift Package Manager.\n4. [#664](https://github.com/ProcedureKit/ProcedureKit/pull/664) Improves Swift 3 URLError handling in Network procedures.\n5. [#690](https://github.com/ProcedureKit/ProcedureKit/pull/690) Adds `UserConfirmationCondition` as in _Operations_.\n6. [#676](https://github.com/ProcedureKit/ProcedureKit/pull/676) Enhances `AnyProcedure` to allow for `AnyOutputProcedure`. Thanks to [@sviatoslav](https://github.com/sviatoslav).\n\n## Bug Fixes\n1. [#660](https://github.com/ProcedureKit/ProcedureKit/issues/660), [#661](https://github.com/ProcedureKit/ProcedureKit/pull/661) Fixes a string conversion memory leak, which is actually a bug in Swift itself.\n2. [#666](https://github.com/ProcedureKit/ProcedureKit/pull/666) Fixes code signing issues that prevents compiling release configuration builds.\n3. [#669](https://github.com/ProcedureKit/ProcedureKit/pull/669) Fixes a type to Dan's GitHub profile.\n4. [#677](https://github.com/ProcedureKit/ProcedureKit/pull/677) Restricts `RetryProcedure` to only allow `Procedure` subclasses.\n5. [#679](https://github.com/ProcedureKit/ProcedureKit/pull/679) `AuthorizedFor` condition now ensures that the produced `AuthorizedCapabilityProcedure` is mutually exclusive, rather than the procedure it gets attached to.\n6. [#689](https://github.com/ProcedureKit/ProcedureKit/pull/689) Updates SwiftLint ruleset.\n7. [#687](https://github.com/ProcedureKit/ProcedureKit/pull/687) Uses `dependencyCancelledWithErrors` error context.\n\n# 4.0.0 Beta 6\n_ProcedureKit_ is nearing a final v4 release. Beta 6 sees all functionality that will be added for v4 in place. Some breaking changes around cancellation are currently being discussed, and will come in the next (and hopefully last) beta.\n\nIn this release, [@swiftlyfalling](https://github.com/swiftlyfalling) has been doing amazing work finding, fixing and adding tests for race-conditions, memory leaks, general thread-safety and cancellation. It really has been fantastic. Currently, over 83% for all components on average. \n\n## New APIs\n1. [#631](https://github.com/ProcedureKit/ProcedureKit/issues/631), [#632](https://github.com/ProcedureKit/ProcedureKit/pull/632) Result injection is now supported for `NetworkDataProcedure` et. al. This API is called `injectPayload(fromNetwork:)` and will support functionality like this:\n    ```swift\n    // Procedure to get a network request\n    let getRequest = GetRequest()\n    // Procedure to get the Data payload\n    let network = NetworkDataProcedure()\n        // Inject the URLRequest\n        .injectResult(from: getRequest)\n    // Procedure to decode the data payload\n    let decode = DecodeNetworkPayload()\n        // Inject the network payload\n        .injectPayload(fromNetwork: network)\n    ```\n    Thanks to [@robfeldmann](https://github.com/robfeldmann) for raising the initial issue.\n2. [#592](https://github.com/ProcedureKit/ProcedureKit/pull/592) Adds `UIProcedure` and `AlertProcedure` as part of _ProcedureKitMobile_ framework. Usage is like this:\n    ```swift\n    let alert = AlertProcedure(presentAlertFrom: self)\n    alert.add(actionWithTitle: \"Sweet\") { alert, action in\n        alert.log.info(message: \"Running the handler!\")\n    }\n    alert.title = \"Hello World\"\n    alert.message = \"This is a message in an alert\"\n    queue.add(operation: alert)\n    ```\n\n1. [#623](https://github.com/ProcedureKit/ProcedureKit/issues/623) Adds `ProcedureKit/All` CocoaPod sub-spec which corresponds to all the cross platform components.\n2. [#625](https://github.com/ProcedureKit/ProcedureKit/issues/625) Tweaks for _TestingProcedureKit_ imports.\n3. [#626](https://github.com/ProcedureKit/ProcedureKit/issues/626),  [#627](https://github.com/ProcedureKit/ProcedureKit/issues/627),[#640](https://github.com/ProcedureKit/ProcedureKit/pull/640), [#646](https://github.com/ProcedureKit/ProcedureKit/pull/646) Tweaks Network procedures so that cancellation is thread safe, avoids a potential race condition, and testing enhancements.\n4. [#624](https://github.com/ProcedureKit/ProcedureKit/issues/624) Some minor fixes after a through investigation with the visual memory debugger - which can produce erroneous leak indicators.\n6. [#630](https://github.com/ProcedureKit/ProcedureKit/issues/630) Adds a build step to CI to perform integration testing using CocoaPods works with the current changes on a feature branch. Currently this does not work for 3rd party contributions.\n7. [#634](https://github.com/ProcedureKit/ProcedureKit/issues/634) Fixes some copy/paste typos from a merge conflict.\n8. [#635](https://github.com/ProcedureKit/ProcedureKit/pull/635) Removes the fatal override of `waitUntilFinished()`.\n9. [#639](https://github.com/ProcedureKit/ProcedureKit/pull/639) Thread safety improvements to `ProcedureProcedure` in _ProcedureKitMac_.\n10. [#643](https://github.com/ProcedureKit/ProcedureKit/pull/643) Further testing of `DidExecute` observers. Adds `checkAfterDidExecute` API to `ProcedureKitTestCase`.\n11. [#649](https://github.com/ProcedureKit/ProcedureKit/pull/649) Removes all code signing settings.\n12. [#644](https://github.com/ProcedureKit/ProcedureKit/pull/644) Fixes issues for _ProcedureKitCloud_ in Xcode 8.2 - as they've changed some APIs here.\n13. [#647](https://github.com/ProcedureKit/ProcedureKit/pull/647) Marks non-open properties/methods as `final`.\n14. [#650](https://github.com/ProcedureKit/ProcedureKit/pull/650) Adds more tests for cancelling `Condition` subclasses.\n15. [#655](https://github.com/ProcedureKit/ProcedureKit/pull/655) Removes the beta tag from the internal framework versioning.\n\n# 4.0.0 Beta 5\nBeta 5 is primarily about refinements and bug fixes.\n\n## Breaking API Changes\n1. [#574](https://github.com/ProcedureKit/ProcedureKit/issues/574), [#583](https://github.com/ProcedureKit/ProcedureKit/pull/583) Removal of `GroupObserverProtocol`\n    This protocol was to allow observer to be attached to a group, and be informed when children are added to the group. Instead, this functionality has been rolled into `ProcedureObserver`.\n2. [#601](https://github.com/ProcedureKit/ProcedureKit/pull/601), [#605](https://github.com/ProcedureKit/ProcedureKit/pull/605) Refactor of `ResultInjection`.\n    The `ResultInjection` protocol has been overhauled, again. The major changes here, are:\n    - Change to a pair of protocols, `InputProcedure` and  `OutputProcedure`, with associated type `Input` and `Output` respectively. This change is to avoid overloading the \"result\" concept.\n    - Renames `PendingValue<T>` to just `Pending`. Both protocols have properties which are `Pending`, which in turn maintains  the `.pending` and `.ready` cases.\n    - `ProcedureResult<T>` which is an _either_ enum type, which is either `.success(value)` or `.failure(error)`. The error is not an associated type - so any `Error` will do.\n    - `OutputProcedure`'s `output` property is `Pending<ProcedureResult<Output>>` which means that it can now capture the procedure finishing with an error instead of just a value.\n\n    In addition, `Procedure` subclasses which conform to `OutputProcedure` can use the following API:\n    \n    ```swift\n    /// Finish the procedure with a successful result.\n    finish(withResult: .success(outputValue))\n\n    /// Finish the procedure with an error.\n    finish(withResult: .failure(anError))    \n    ``` \n    \n    To support `OutputProcedure` with a `Void` output value, there is also a public constant called `success` which represents `.success(())`.\n    \n    All other APIs have been changed to reflect this change, e.g. `injectResult(from: dependency)` works as before if your receiver is updated to conform to `OutputProcedure`.\n3. [#561](https://github.com/ProcedureKit/ProcedureKit/pull/561) Rename & refactor of `ResilientNetworkProcedure`\n    `NetworkProcedure` now performs the functionality of network resiliency, in addition to automatic handling of client reachability errors.\n\n\n## New Features\n1. [#565](https://github.com/ProcedureKit/ProcedureKit/pull/565) `NetworkDownloadProcedure`\n    Thanks to [@yageek](https://github.com/yageek) for adding support for network file downloads.\n2. [#567](https://github.com/ProcedureKit/ProcedureKit/pull/567) `NetworkUploadProcedure`\n    Thanks to [@yageek](https://github.com/yageek) for adding support for network file uploads.\n3. [#570](https://github.com/ProcedureKit/ProcedureKit/pull/570) `ProcessProcedure`\n    Thanks to [@yageek](https://github.com/yageek) for adding support for wrapping `Process` (previously `NSTask`) to _ProcedureKitMac_.\n4. [#542](https://github.com/ProcedureKit/ProcedureKit/pull/542), [#599](https://github.com/ProcedureKit/ProcedureKit/pull/599) `CloudKitProcedure`\n    This is a wrapper class for running Apple's `CKOperation` subclasses.\n5. [#587](https://github.com/ProcedureKit/ProcedureKit/pull/587) Mutual Exclusion categories\n    Mutually exclusive conditions now support arbitrary category names, which means that a condition can be used to add mutual exclusion to any number of disparate procedures.\n6. [#563](https://github.com/ProcedureKit/ProcedureKit/pull/563) `NetworkProcedure` (called `NetworkReachableProcedure` here)\n    `NetworkProcedure` is a wrapper procedure for executing network procedures. It has full support for handling client reachability issues, and resilient handling of client and server errors.  \n7. [#569](https://github.com/ProcedureKit/ProcedureKit/issues/569) `Profiler`\n    Thanks to [@yageek](https://github.com/yageek) for implementing the `Profiler` which is a `ProcedureObserver` and can be used to report timing profiles of procedures.\n8. [#593](https://github.com/ProcedureKit/ProcedureKit/pull/593) Supports the merging of collections of `Procedure` subclasses which all conform to `ResultInjection`.\n    These APIs `flatMap`, `reduce` and `gathered()` each return another procedure which will depend on all other procedures in the collection, and then perform synchronous processing of the results. For example, either just gather the results into a single array, or flat map the resultant array into an array of different types, or reduce the resultant array into a single type.\n9. [#606](https://github.com/ProcedureKit/ProcedureKit/pull/606), [#607](https://github.com/ProcedureKit/ProcedureKit/pull/607) `AsyncResultProcedure` etc.\n    `AsyncResultProcedure`, `AsyncBlockProcedure` and `AsyncTransformProcedure` support asynchronous blocks. Each procedure's initialiser receives a _finishWithResult_ closure, which must be called to finish the procedure. For example:\n    \n    ```swift\n    let procedure = AsyncBlockProcedure { finishWithResult in\n        asyncTask {\n            finishWithResult(success)\n        }\n    }\n    ```\n\n\n\n## Bug Fixes etc\n1. [#562](https://github.com/ProcedureKit/ProcedureKit/pull/562) Fixes a typo in `LocationServicesRegistrarProtocol`\n2. [#566](https://github.com/ProcedureKit/ProcedureKit/pull/566) Fixes `Condition` so that it can support result injection.\n3. [#575](https://github.com/ProcedureKit/ProcedureKit/pull/575) Improves the performance of `add(observer: )`.\n4. [#568](https://github.com/ProcedureKit/ProcedureKit/pull/578) Opens up `add(operation: Operation)` for overriding by subclasses. Thanks to [@bizz84](https://github.com/bizz84).\n6. [#579](https://github.com/ProcedureKit/ProcedureKit/pull/579) Adds more test coverage to `GroupProcedure`.\n7. [#586](https://github.com/ProcedureKit/ProcedureKit/issues/586) Fixes `HTTPRequirement` initializers. Thanks to [@yageek](https://github.com/yageek) for this one.\n8. [#588](https://github.com/ProcedureKit/ProcedureKit/pull/588) Fixes bug where using the `produce(operation:)` from a `GroupProcedure` subclass was failing. This was actually introduced by other changes since Beta 4.\n9. [#591](https://github.com/ProcedureKit/ProcedureKit/pull/591) Adds some missing equality checks in `ProcedureKitError.Context`.\n10. [#600](https://github.com/ProcedureKit/ProcedureKit/pull/600) Minor changes to remove @testable imports.\n11. [#602](https://github.com/ProcedureKit/ProcedureKit/pull/602) Adds stress tests for cancelling `RepeatProcedure`.\n12. [#603](https://github.com/ProcedureKit/ProcedureKit/pull/603) Adds more `GroupProcedure` tests.\n13. [#608](https://github.com/ProcedureKit/ProcedureKit/pull/608) Uses the internal queue for the `DispatchAfter` delayed functionality in `NetworkActivityController` instead of the main queue.\n14. [#611](https://github.com/ProcedureKit/ProcedureKit/pull/611) Restores `import Foundation` etc where needed in all classes, which makes Xcode 8 a little happier - although not strictly necessary.\n15. [#615](https://github.com/ProcedureKit/ProcedureKit/pull/615) Fixes issues where `BackgroundObserver` was not removing notification observers.\n16. [#619](https://github.com/ProcedureKit/ProcedureKit/pull/619) Fixes some issues with location related procedures.\n\n## Thread Safety bug fixes\nRecently, [@swiftlyfalling](https://github.com/swiftlyfalling) has been fixing a number of thread safety issues highlighted either from our own stress tests, or from the Thread Sanitizer. \n1. `NetworkObserver` - [#577](https://github.com/ProcedureKit/ProcedureKit/pull/577)\n2. `StressTestCase` - [#596](https://github.com/ProcedureKit/ProcedureKit/pull/596) \n3. `RepeatProcedure` - [#597](https://github.com/ProcedureKit/ProcedureKit/pull/597)\n4. `Procedure` - [#598](https://github.com/ProcedureKit/ProcedureKit/pull/598)\n5. `NetworkDataProcedure` etc - [#609](https://github.com/ProcedureKit/ProcedureKit/pull/609)\n6. `BackgroundObserver` - [#614](https://github.com/ProcedureKit/ProcedureKit/pull/614)\n7. `DelayProcedure` - [#616](https://github.com/ProcedureKit/ProcedureKit/pull/616)\n\n# 4.0.0 Beta 4\nBeta 4 is a significant maturation over Beta 3. There are a couple of breaking changes here which I will call out explicitly. Overall however, the APIs have been refined, adjusted and extended, bugs have been fixed, and tests have been stabilised.\n\nAdditionally, Beta 4 now supports integration via Carthage _and CocoaPods_ including full support for _TestingProcedureKit_ and CocoaPod subspecs.\n\n## Breaking API Changes\n1. [#519](https://github.com/ProcedureKit/ProcedureKit/pull/519) Renames \n    - `AuthorizationStatusProtocol` to `AuthorizationStatus`. \n    Thanks to [@martnst](https://github.com/martnst).\n2. [#520](https://github.com/ProcedureKit/ProcedureKit/pull/520) Renames:\n    - `GetAuthorizationStatus` to `GetAuthorizationStatusProcedure`, \n    - `Authorize` to `AuthorizeCapabilityProcedure`\n    Thanks to [@martnst](https://github.com/martnst) again.\n3. [#527](https://github.com/ProcedureKit/ProcedureKit/pull/527), [#528](https://github.com/ProcedureKit/ProcedureKit/pull/528), [#541](https://github.com/ProcedureKit/ProcedureKit/pull/541), [#546](https://github.com/ProcedureKit/ProcedureKit/pull/546) ResultInjection \n\n    ResultInjection, which is what we call the methodology of automatically injecting the result from one procedure as the requirement of a dependency, has been revamped in Beta 4.\n    - It is now an extension on `ProcedureProctocol`.\n    - The API now support injection via a transform block. For example, lets assume that we are using `NetworkDataProcedure` which requires a `URLRequest`, and we have a procedure which results in a `URL`, we might do this:\n        ```swift\n        download.injectResult(from: getURL) { url in\n            return URLRequest(url: $0) \n        }\n        ```\n    - Refactors `ResultInjection` protocol to use `PendingValue<T>`. Now the `requirement` and `result` properties are `PendingValue<Requrement>` and `PendingValue<Result>` respectively. This avoids the need to use explicitly unwrapped optionals for the `Requirement`. For example:\n        ```swift\n        class MyProcedure: Procedure, ResultInjection {\n            var requirement: PendingValue<Foo> = .pending\n            var result: PendingValue<Bar> = .pending\n        }\n        ```\n    - Extension APIs automatically unwrap optionals. This means that where a `Result? == Requirement` the result will be automatically unwrapped. \n\n## New Features\n1. [#516](https://github.com/ProcedureKit/ProcedureKit/pull/516), [#534](https://github.com/ProcedureKit/ProcedureKit/pull/534): `AnyProcedure` \n\n    This is a new procedure which supports composition of any `Procedure` subclass conforming to `ResultInjection` APIs with complete type erasure. This makes the following usage possible: \n    - Inject / store generic `Procedure` subclasses into other types.\n    - Store many different types of `Procedure` subclasses in a homogenous storage container, so long as they have the same sub-type `Requirement` and `Result`.\n\n    An example of where this is useful would be with a strategy design pattern, where each strategies likely has a different `Procedure` subclass, but the `Requirement` (i.e. input) and `Result` (i.e. output) of each is the same. Given this, any strategy can be injected into a `GroupProcedure` or other structure type-erased using `AnyProcedure<Requirement,Result>`.\n2. [#523](https://github.com/ProcedureKit/ProcedureKit/pull/523) _ProcedureKitCloud_\n\n    Added a _ProcedureKitCloud_ framework, which currently just\nincludes `Capability.CloudKit`. Unfortunately the full `CloudKitProcedure` class did not get finished in time for this beta. However, it is very close to being finished, see PR: [#542](https://github.com/ProcedureKit/ProcedureKit/pull/542).\n3. [#524](https://github.com/ProcedureKit/ProcedureKit/pull/524), [#525](https://github.com/ProcedureKit/ProcedureKit/pull/525), [#526](https://github.com/ProcedureKit/ProcedureKit/pull/526), [#538](https://github.com/ProcedureKit/ProcedureKit/pull/538),[#547](https://github.com/ProcedureKit/ProcedureKit/pull/547) _ProcedureKitNetwork_\n    \n    _ProcedureKitNetwork_ is a framework which offers a very simple wrapper around `URLSession` **completion based** APIs. Currently only for `NetworkDataProcedure` which uses the `URLSessionDataTask` based APIs. If you need to use the delegate based APIs you cannot use this `Procedure` subclass.\n    \n    Additionally, there is full support in _TestingProcedureKit_ for using `TestableURLSession` which allows framework consumers to check that the session receives the correct request etc.\n4. [#536](https://github.com/ProcedureKit/ProcedureKit/pull/536) `.then { }` API\n\n    Added an alternative way of adding dependencies on `Operation` in a chain. For example:\n    ```swift\n    let operations = foo.then(do: bar).then { Baz() }\n    ```\n    Thanks to [@jshier](https://github.com/jshier) for initial idea and suggestion - sorry it took so long to get done!\n5. [#508](https://github.com/ProcedureKit/ProcedureKit/pull/508), [#553](https://github.com/ProcedureKit/ProcedureKit/pull/553) CocoaPods\n\n    Note here that the standard pod is just the core framework. This is Extension API compatible with support for all 4 platforms. To get iOS related classes, such as `BackgroundObserver` which are not Extension API compatible use `ProcedureKit/Mobile`, likewise for `ProcedureKit/Location`, `ProcedureKit/Network`, `ProcedureKit/Cloud` etc.\n    _TestingProcedureKit_, has its own podspec.\n6. [#537](https://github.com/ProcedureKit/ProcedureKit/pull/537) `ResilientNetworkProcedure` Beta\n\n    This is a `RetryProcedure` subclass which is designed to add network resiliency around network request based `Procedure` subclasses. This procedure works by providing a value which corresponds to `ResilientNetworkBehavior` protocol, and a closure which returns a new network request procedure. The protocol allows the framework consumer to decide how to interpret status/error codes, and trigger retries.\n7. [#550](https://github.com/ProcedureKit/ProcedureKit/pull/550) `ConcurrencyTestCase`\n\n    This is a new `ProcedureKitTestCase` subclass in _TestingProcedureKit_ which has methods to help test concurrency issues in _ProcedureKit_ itself, but also in your applications. Thanks to [@swiftlyfalling](https://github.com/swiftlyfalling) for adding it.\n8. [#552](https://github.com/ProcedureKit/ProcedureKit/pull/552) `wait(forAll: [Procedure])` API \n\n    This is added to `ProcedureKitTestCase`. Thanks to [@swiftlyfalling](https://github.com/swiftlyfalling) for adding this.\n9. [#554](https://github.com/ProcedureKit/ProcedureKit/pull/554) Adds `did(execute: Procedure)` observer callback.\n\n    Use this with great caution, as it may not always do what you expect depending on the behavior of the `execute` method of the procedure. From the discussion:\n    > all that's currently guaranteed is that didExecuteObservers will be called after execute() returns. The rest is up to the specifics of the Procedure subclass implementation.\n    This will likely be improved before 4.0.0 is final. \n    \n## Bug Fixes etc\n1. [#518](https://github.com/ProcedureKit/ProcedureKit/pull/518) Fixes failing release build regression.\n2. [#531](https://github.com/ProcedureKit/ProcedureKit/pull/531) Adds default empty implementation to some of the Queue Delegate methods. Feedback welcome here!\n3. [#533](https://github.com/ProcedureKit/ProcedureKit/pull/533) Adds an area in the repo for talks and presentations which have been given about _Operations_ or _ProcedureKit_. Watch out for [@jshier](https://github.com/jshier) who will be speaking at [Swift Summit](https://www.swiftsummit.com) _ProcedureKit and you_ on Nov 7th. 😀😀😀\n4. [#532](https://github.com/ProcedureKit/ProcedureKit/pull/532) Fixes a bug where `GroupProcedure` would collect errors from its children after it had been cancelled. This is a bit annoying, if  a group is cancelled, it will cancel all of its children with an error (`ProcedureKitError.parentDidCancel(error)`), but it would then receive in its delegate all of those errors from the children.\n5. [#539](https://github.com/ProcedureKit/ProcedureKit/pull/539) Tweaks to cancel `BlockProcedure` stress tests.\n6. [#540](https://github.com/ProcedureKit/ProcedureKit/pull/540) Moves `import ProcedureKit` into umbrella headers.\n7. [#544](https://github.com/ProcedureKit/ProcedureKit/pull/544) Fixes `BlockProcedure` stress tests - thanks to [@swiftlyfalling](https://github.com/swiftlyfalling).\n8. [#545](https://github.com/ProcedureKit/ProcedureKit/pull/545) Fixes a bug where `ExclusivityManager` was not thread safe. Thanks to [@myexec](https://github.com/myexec) for reporting the bug, and [@swiftlyfalling](https://github.com/swiftlyfalling) for fixing it.\n9. [#549](https://github.com/ProcedureKit/ProcedureKit/pull/549) Fixes random crashed in `QueueTestDelegate` - thanks to [@swiftlyfalling](https://github.com/swiftlyfalling) for fixing this, and generally being awesome at identifying where code paths are not thread safe 💚.\n10. [#557](https://github.com/ProcedureKit/ProcedureKit/pull/557) Fixes some CI errors in Fastfile.\n11. [#558](https://github.com/ProcedureKit/ProcedureKit/pull/558) [#559](https://github.com/ProcedureKit/ProcedureKit/pull/559) Fixes issue with Xcode 8.1 release builds, thanks so much to [@pomozoff](https://github.com/pomozoff) for figuring out the issue here!\n12. [#556](https://github.com/ProcedureKit/ProcedureKit/pull/556) Adds group concurrency tests using the new `ConcurrencyTestCase`. Thanks to [@swiftlyfalling](https://github.com/swiftlyfalling) for their awesome contributions!\n\n# 4.0.0 Beta 3\n\nBeta 3 adds _ProcedureKitMobile_, _ProcedureKitLocation_ and _TestingProcedureKit_ frameworks. The mobile framework is suitable for use in iOS applications, although it does not yet have `AlertProcedure` which will come in a future beta.\n\nTo integrate these frameworks, use:\n```swift\nimport ProcedureKit\n```\nwhich can be done anywhere, such as internal frameworks and extensions, and on any platform.\n\n```swift\nimport ProcedureKitMobile\n```\nwhich can only be done in an iOS application target, as it’s not extension compatible.\n\n```swift\nimport ProcedureKitLocation\n```\nwhich can be used on any platform.\n\n_TestingProcedureKit_ is a framework is for adding to test bundle targets. It links with XCTest, so cannot be added to an application target. While documentation is sorely lacking here, this is very useful for writing unit tests for `Procedure` subclasses. It has APIs to support waiting for procedures to run, and asserting their end state.\n\n## New Features\n\n1. [#476](https://github.com/ProcedureKit/ProcedureKit/pull/476) Adds `BackgroundObserver`\n2. [#496](https://github.com/ProcedureKit/ProcedureKit/pull/496) Adds `FilterProcedure`\n3. [#497](https://github.com/ProcedureKit/ProcedureKit/pull/497) Adds `ReduceProcedure`\n4. [#498](https://github.com/ProcedureKit/ProcedureKit/pull/498) Adds `NetworkObserver`\n5. [#499](https://github.com/ProcedureKit/ProcedureKit/pull/499) Adds `Capability.Location`\n6. [#500](https://github.com/ProcedureKit/ProcedureKit/pull/500) Adds `UserLocationProcedure`\n7. [#502](https://github.com/ProcedureKit/ProcedureKit/pull/502) Adds `ReverseGeocodeUserLocationProcedure`\n8. [#503](https://github.com/ProcedureKit/ProcedureKit/pull/503) Adds `ReverseGeocodeUserLocationProcedure`\n\n## Bug fixes etc\n\n9. [#503](https://github.com/ProcedureKit/ProcedureKit/pull/503) Fixes an issue where the minimum deployment target was incorrect for iOS.\n10. [#510](https://github.com/ProcedureKit/ProcedureKit/pull/510) Makes procedures which were `public` and therefore not override-able by a framework consumer `open`. Got to watch out for these.\n11. [#511](https://github.com/ProcedureKit/ProcedureKit/pull/511) Refactors `BlockProcedure` to no longer be a subclass of `TransformProcedure`. I did like the simplicity of this, however, I want to be able to automatically throw an error if the requirement of `TransformProcedure` is not set.\n\n# 4.0.0 Beta 2\n\nBeta 2 is all about rounding out the majority of the missing functionality from _ProcedureKit_, and additionally fixing integration issues.\n\n1. [#471](https://github.com/ProcedureKit/ProcedureKit/pull/471) NegatedCondition\n2. [#472](https://github.com/ProcedureKit/ProcedureKit/pull/472) SilentCondition \n3. [#474](https://github.com/ProcedureKit/ProcedureKit/pull/471) Fixes for how Procedure finishes - thanks [@swiftlyfalling](https://github.com/swiftlyfalling)\n4. [#473](https://github.com/ProcedureKit/ProcedureKit/pull/471) BlockCondition\n5. [#470](https://github.com/ProcedureKit/ProcedureKit/pull/471) NoFailedDependenciesCondition\n6. [#475](https://github.com/ProcedureKit/ProcedureKit/pull/471) TimeoutObserver\n7. [#478](https://github.com/ProcedureKit/ProcedureKit/pull/471) Procedure name and identity\n8. [#480](https://github.com/ProcedureKit/ProcedureKit/pull/471) BlockObserver - thanks to [@jshier](https://github.com/jshier) for his input on this.\n9. [#487](https://github.com/ProcedureKit/ProcedureKit/pull/471) Adds ComposedProcedure & GatedProcedure\n10. [#488](https://github.com/ProcedureKit/ProcedureKit/pull/471) RepeatProcedure\n11. [#491](https://github.com/ProcedureKit/ProcedureKit/pull/471) RetryProcedure\n12. [#492](https://github.com/ProcedureKit/ProcedureKit/pull/492) Capabilities\n\nIn addition to the above additions, fixes have been made to fix Release builds correctly compile, despite some Swift 3 compiler bugs in Xcode 8 and 8.1. See the release notes for more instructions.\n\n# 4.0.0 Beta 1\n\nWell, it’s time to say goodbye to _Operations_ and hello to _ProcedureKit_. _ProcedureKit_ is a complete re-write of _Operations_ in Swift 3.0, and has the following key changes.\n\n1. _ProcedureKit_\n    _Operations_ has been lucky to have many contributors, and for _ProcedureKit_ I wanted to be able to recognise the fantastic contributions of this little community properly. So the repository has been transferred into an organization. At the moment, the only additional member is [@swiftlyfalling](https://github.com/swiftlyfalling) however I hope that more will join soon. In addition to moving to an org, there are now contribution guidelines and code of conduct documents.\n    \n2. Naming changes\n    Because Swift 3.0 has dropped the `NS` prefix from many classes, including `NSOperation`, `NSOperationQueue` and `NSBlockOperation`, _Operations_ had some pretty significant issues in Swift 3.0. At WWDC this year, I was able to discuss _Operations_ with Dave DeLong and Philippe Hausler. We brainstormed some alternatives, and came up with “Procedure”, which I’ve sort of grown accustomed to now. The name changes are  widespread, and essentially, what was once `Operation` is now `Procedure`.\n    \n3. Project structure\n    For a long time, we’ve had an issue where some classes are not extension API compatible. This has resulted in having two projects in the repository, which in turn leads to problems with Carthage not being able to build desired frameworks. With ProcedureKit, this problem is entirely resolved. The core framework, which is the focus of this beta, is entirely extension API compatible. It should be imported like this:\n    ```swift\n    import ProcedureKit\n    ```\n    \n    Functionality which depends on UIKit, such as `AlertProcedure` will be exposed in a framework called `ProcedureKitMobile`, and imported like this:\n    ```swift\n    import ProcedureKit\n    import ProcedureKitMobile\n    ```\n    \n    Similarly for other non-core functionality like CloudKit wrappers etc.\n    \n    In addition to types which should be used in applications, I wanted to expose types to aid writing unit tests. This is called `TestingProcedureKit`, which itself links against `XCTest`. *It can only be used inside test bundle targets*. This framework includes `ProcedureKitTestCase` and `StressTestCase` which are suitable for subclassing. The former then exposes simple APIs to wait for procedures to run using `XCTestExpectation`. Additionally, there are `XCTAssertProcedure*` style macros which can assert that a `Procedure` ran as expected. To use it in your own application’s unit test target:\n    ```swift\n    import ProcedureKit\n    import TestingProcedureKit\n    @testable import MyApplication\n    ```    \n4. Beta 1 Functionality\n    This beta is focused on the minimum. It has `Procedure`, `ProcedureQueue`, `GroupProcedure`, `MapProcedure`, `BlockProcedure` and `DelayProcedure`. In addition, there is support for the following features:\n    1. Attaching conditions which may support mutual exclusion\n    2. Adding observers - see notes below.\n    3. Result injection has been simplified to a single protocol.\n    4. Full logging support\n    5. Errors are consolidated into a single `ProcedureKitError` type.\n\n5. Observers\n    An annoying element of the observers in _Operations_ is that the received `Operation` does not retain full type fidelity. It’s just `Operation`, not `MyOperationSubclass`. With `ProcedureKit` this has been fixed as now the underlying protocol `ProcedureObserver` is generic over the `Procedure` which is possible as there is now a `ProcedureProtocol`. This means, that the block observers are now generic too. Additionally, an extension on `ProcedureProtocol` provides convenience methods for adding block observers. This means that adding block observers should now be done like this:    \n    ```swift \n    let foo = FooProcedure()\n    foo.addDidFinishBlockObserver { foo, errors in\n        // No need to cast argument to FooProcedure\n        foo.doFooMethod()\n    }\n    ```\n6. `BlockProcedure`\n    The API for `BlockProcedure` has changed somewhat. The block type is now `() throws -> Void`. In some regards this is a reduction in capability over `BlockOperation` from _Operations_ which received a finishing block. The finishing block meant that the block could have an asynchronous callback to it.\n    \n    While this functionality might return, I think that it is far better to have a simple abstraction around synchronous work which will be enqueued and can throw errors. For asynchronous work, it would be best to make a proper `Procedure` subclass.\n    \n    Having said that, potentially we will add `AsyncBlockProcedure` to support this use case. Please raise an issue if this is something you care about!\n    \nAnyway, I think that is about it - thanks to all the contributors who have supported _Operations_ and _ProcedureKit_ while this has been written. Stay tuned for Beta 2 in a week or so.\n\n# 3.4.0\n\nThis is a release suitable for submission for iOS 10, but built using Swift 2.3 & Xcode 8.\n\n# 3.3.0\nThis is a release suitable for submission for iOS 10, but built using Swift 2.2 & Xcode 7.\n\n1. [OPR-452](https://github.com/ProcedureKit/ProcedureKit/pull/452)  Resolves the warning related to CFErrorRef.\n2. [OPR-453](https://github.com/ProcedureKit/ProcedureKit/issues/453), [OPR-454](https://github.com/ProcedureKit/ProcedureKit/pull/454) Fixes an issue where the Mac OS X deployment target was incorrect.\n3. [OPR-456](https://github.com/ProcedureKit/ProcedureKit/pull/456)  Modifies the podspec to remove Calendar, Passbook, Photos, CloudKit, Location, AddressBook etc from the standard spec. This  is to prevent linking/importing OS frameworks which consumers might not have explanations in their info.plist. This is following reports that  are being more restrictive for iOS 10 submissions.\n\n# 3.2.0\nThis is a pretty special release! All the important changes have been provided by contributors! 🚀😀💚\n\nAdditionally, [@swiftlyfalling](https://github.com/swiftlyfalling) has become a _ProcedureKit_ core contributor 😀 \n\n1. [OPR-416](https://github.com/ProcedureKit/ProcedureKit/issues/416), [OPR-417](https://github.com/ProcedureKit/ProcedureKit/issues/417) Thanks to [@pomozoff](https://github.com/pomozoff) for reporting and fixing a bug which could cause a crash in an edge case where operation with conditions is previously cancelled. Thanks to [@swiftlyfalling](https://github.com/swiftlyfalling).\n2. [OPR-420](https://github.com/ProcedureKit/ProcedureKit/pull/420) Thanks to [@swiftlyfalling](https://github.com/swiftlyfalling) for replacing an assertion failure, and adding some more stress tests in `Condition`’s `execute` method.\n3. [OPR-344](https://github.com/ProcedureKit/ProcedureKit/issues/344), [OPR-344](https://github.com/ProcedureKit/ProcedureKit/pull/421) Thanks to [@ryanjm](https://github.com/ryanjm) for reporting (_a while ago_, sorry!) a bug in `NetworkObserver`, and thanks to [@swiftlyfalling](https://github.com/swiftlyfalling) for fixing the bug!\n4. [OPR-422](https://github.com/ProcedureKit/ProcedureKit/pull/422)  Thanks to [@swiftlyfalling](https://github.com/swiftlyfalling) for adding some robustness to `NetworkObserver` and its tests.\n5. [OPR-419](https://github.com/ProcedureKit/ProcedureKit/pull/419) Thanks to [@swiftlyfalling](https://github.com/swiftlyfalling) for fixing a bug which improves the performance of a whole number of tests. Mostly the changes here are to ensure that `XCTestExpectation`s get their `fulfill()` methods called on the main queue.\n6. [OPR-423](https://github.com/ProcedureKit/ProcedureKit/pull/423) Thanks to [@swiftlyfalling](https://github.com/swiftlyfalling) for fixing a bug where `cancelWithError()` could result in an assertion due to an illegal state transition. They even added some stress tests around this 💚\n7. [OPR-425](https://github.com/ProcedureKit/ProcedureKit/pull/425)  Thanks to [@swiftlyfalling](https://github.com/swiftlyfalling) for refactoring some unit tests to use a dispatch group instead of multiple `XCTestExpectation` instances.\n8. [OPR-427](https://github.com/ProcedureKit/ProcedureKit/pull/427) I made some changes to the CI pipeline for Swift 2.2 branch so that [@swiftlyfalling](https://github.com/swiftlyfalling) didn’t have to wait too long to merge their pull requests.\n9. [OPR-434](https://github.com/ProcedureKit/ProcedureKit/pull/434) Thanks to [@pomozoff](https://github.com/pomozoff) for raising a configuration issue where a file was added to the Xcode project twice, causing a warning when running Carthage.\n10. [OPR-435](https://github.com/ProcedureKit/ProcedureKit/pull/435) Thanks to [@swiftlyfalling](https://github.com/swiftlyfalling) for making some improvements to avoid a Swift 2.2 bug which causes a memory leak when using string interpolation.\n\n# 3.1.1\n\n1. [OPR-410](https://github.com/danthorpe/Operations/pull/410) Thanks to [@paulpires](https://github.com/paulpires) for fixing a bug in the `ReachabilityManager`.\n2. [OPR-412](https://github.com/danthorpe/Operations/pull/412) Makes the `condition` property of `Operation` publicly accessible.\n\n# 3.1.0\n\n## Improvements to Result Injection\n\nI’ve made some changes to make working with _result injection_ easier.\n\n1. [OPR-362](https://github.com/danthorpe/Operations/pull/362), [OPR-363](https://github.com/danthorpe/Operations/pull/363), [OPR-378](https://github.com/danthorpe/Operations/pull/378)\n    These changes simplify the core implementation of how result injection works, no longer using any closure capture. Additionally, if the `Requirement` is equal to `Result?`, the framework provides a new API, for _requiring_ that the result is available. For example:\n    \n    ```swift\n    class Foo: Operation, ResultOperationType {\n        var result: String?\n        // etc\n    }\n    \n    class Bar: Operation, AutomaticInjectionOperationType {\n        var requirement: String = “default value”\n        // etc\n    }\n    \n    let foo = Foo()\n    let bar = Bar()\n    bar.requireResultFromDependency(foo)\n    ```\n    \n    Now, if `foo` finishes with a nil `result` value, `bar` will be automatically cancelled with an `AutomaticInjectionError.RequirementNotSatisfied` error. And it’s no longer necessary to `guard let` unwrap the requirement in the `execute()` method.\n    \n    This works well in situations where the `requirement` property is not an optional, but can be set with a default value.\n   \n## Improvements to Conditions\n\nI’ve made some changes to improve working with `Condition`s. The focus here has been to support more subtle/complex dependency graphs, and suppressing errors resulting from failed conditions. \n\n2. [OPR-379](https://github.com/danthorpe/Operations/pull/379), [OPR-386](https://github.com/danthorpe/Operations/pull/386) Fixes some unexpected behaviour where indirect dependencies (i.e. dependencies of a condition) which are also direct dependencies got added to the queue more than once. This was fixed more generally to avoid adding operations which are already enqueued.\n3. [OPR-385](https://github.com/danthorpe/Operations/pull/385), [OPR-390](https://github.com/danthorpe/Operations/pull/390), [OPR-397](https://github.com/danthorpe/Operations/pull/397) Adds support for ignoring condition failures\n\n    In some situations, it can be beneficial for an operation to not collect an error if an attached condition fails. To support this, `ConditionResult` now has an `.Ignored` case, which can be used to just cancel the attached `Operation` but without an error.\n    \n    To make this easier, a new condition, `IgnoredCondition` is provided which composes another condition. It will ignore any failures of the composed condition.\n    \n    In addition, `NoFailedDependenciesCondition` now supports an initialiser where it will ignore any dependencies which are also ignored, rather than failing for cancelations. This can be used like this:\n    \n    ```swift\n    dependency.addCondition(IgnoredCondition(myCondition))\n    operation.addDependency(dependency)\n    operation.addCondition(NoFailedDependenciesCondition(ignoreCancellations: true))\n    ``` \n    \n    Note that the `ignoreCancellations` argument defaults to false to maintain previous behaviour. Thanks to [@aurelcobb](https://github.com/aurelcobb) for raising this issue.\n\n## API Changes\n\n2. [OPR-361](https://github.com/danthorpe/Operations/pull/361) `GroupOperation`’s queue is now private.\n\n    Given the way that `GroupOperation` works, critically that it acts as its queue’s delegate, this change restricts the ability for that contract to be broken. Specifically, the queue is now private, but its properties are exposed via properties of the group.\n\n    Additionally, the default initialiser of `GroupOperation` now takes an optional `dispatch_queue_t` argument. This dispatch queue is set as the `NSOperationQueue`’s `underlyingQueue` property, and effectively allows the class user to set a target dispatch queue. By default this is `nil`.\n\n    This change will require changes to subclasses which override the default initialiser.\n\n    Thanks to [@swiftlyfalling](https://github.com/swiftlyfalling) for these changes.\n\t\n   \n## Bug Fixes\n\n3. [OPR-377](https://github.com/danthorpe/Operations/pull/377) GatedOperation will now cancel its composed operation if the gate is closed.\n4. [OPR-365](https://github.com/danthorpe/Operations/pull/365) Fixes a log message error. Thanks to [@DeFrenZ](https://github.com/DeFrenZ) for this one.\n5. [OPR-382](https://github.com/danthorpe/Operations/pull/382) Fixes an issue where `TaskOperation` was included in non-macOS platforms via CocoaPods.\n\n\n# 3.0.0\n\n🚀🙌 After a significant period of testing, Version 3.0.0 is finally here! Checkout the details below:\n\n## Conditions\nThe protocol `OperationCondition` is not deprecated. Instead, conditions should be refactored as subclasses of `Condition` or `ComposedCondition`. Condition itself is an `Operation` subclass, and there is now support in `Operation` for adding conditions like this. Internally `Operation` manages a group operation which is added as a dependency. This group evaluates all of the conditions.\n\n1. [[OPR-286](https://github.com/danthorpe/Operations/pull/286)]: Conditions are now subclasses of `Condition` and `Operation` subclass.\n2. [[OPR-309](https://github.com/danthorpe/Operations/pull/309)]: Fixes a bug with `ComposedCondition`.\n\n## Operation & OperationQueue\n\n3. [[OPR-293](https://github.com/danthorpe/Operations/pull/293)]: Adds `WillCancelObserver` - use will/did cancel observer to handle cancellation.\n4. [[OPR-319](https://github.com/danthorpe/Operations/pull/319)]: Improvements to invoking observers in `Operation`.\n5. [[OPR-353](https://github.com/danthorpe/Operations/pull/353)]: Fixes a bug with Swift 2.* where weak properties are not thread safe when reading. [@swiftlyfalling](https://github.com/swiftlyfalling) for fixing this one!\n6. [[OPR-330](https://github.com/danthorpe/Operations/pull/330)]: Ensures that `NSOperationQueue.mainQueue()` returns an `OperationQueue` instance. Thanks to [@gtchance](https://github.com/gtchance) for this - great spot!\n7. [[OPR-359](https://github.com/danthorpe/Operations/pull/359)]: `Operation.cancel()` is now final, which means that it cannot be overridden. To support effective cancelling in `Operation` subclasses, attach `WillCancelObserver` and `DidCancelObserver` observers to the operation before it is added to a queue. Thanks to [@swiftlyfalling](https://github.com/swiftlyfalling) for adding this.\n8. [[OPR-358](https://github.com/danthorpe/Operations/pull/358)]: [@swiftlyfalling](https://github.com/swiftlyfalling) has done a fantastic job fixing an assortment of thread safety issues in `Operation` and `GroupOperation`. Now cancellation, finishing, logs, and adding operations to groups is a lot safer.\n\n## Features\n9. [[OPR-305](https://github.com/danthorpe/Operations/pull/305), [OPR-306](https://github.com/danthorpe/Operations/pull/306)]: Fixes a bug where `CLLocationManager` would respond with a status of not determined prematurely in some cases. Thanks to [@J-Swift](https://github.com/J-Swift) for the fix!\n10. [[OPR-321](https://github.com/danthorpe/Operations/pull/321)]: Adds support for checking if the current queue is the main queue, without using `NSThread.isMainThread()` API. This technique is used to ensure that `CLLocationManager` is always created on the main queue, regardless of the calling queue. This allows for location operations to be run inside `GroupOperation`s for example. Thanks again to [@J-Swift](https://github.com/J-Swift) for reporting this one!\n11. [[OPR-304](https://github.com/danthorpe/Operations/pull/304)]: Vastly improved support for CloudKit errors. Each `CKOperation` defines its own CloudKit error type which provides direct support for managing its subtypes. For example, `CKMarkNotificationsReadOperation` uses an `ErrorType` of `MarkNotificationsReadError<NotificationID>` which stores the marked notification IDs. These error types allow framework consumers to provide effective error handling for `CKPartialError` for example.\n12. [[OPR-327](https://github.com/danthorpe/Operations/pull/327)]: Removes reachability from `CLoudKitOperation`, now, network reachability will be handled as recommended by Apple, which is to retry using the error information provided. This is in contrast to waiting for the network to be reachable.\n13. [[OPR-312](https://github.com/danthorpe/Operations/pull/312)]: Supports the `enterReaderIfAvailable` configuration of `SFSafariViewController` with `WebpageOperation`. This defaults to false. Thanks to [@blg-andreasbraun](https://github.com/blg-andreasbraun) for adding this!\n14. [[OPR-315](https://github.com/danthorpe/Operations/pull/315)]: Refactors `WebpageOperation` to subclass `ComposedOperation`. Thanks to [@blg-andreasbraun](https://github.com/blg-andreasbraun) for tidying this up!\n15. [[OPR-317](https://github.com/danthorpe/Operations/pull/317)]: Adds an `OpenInSafariOperation`. Thanks to [@blg-andreasbraun](https://github.com/blg-andreasbraun) for adding this!\n16. [[OPR-334](https://github.com/danthorpe/Operations/pull/334), [OPR-351](https://github.com/danthorpe/Operations/pull/351)]: Updates `AlertController` to support action sheets with `UIAletController`. Thanks, again, to [@blg-andreasbraun](https://github.com/blg-andreasbraun), for fixing this!\n17. [[OPR-329](https://github.com/danthorpe/Operations/pull/326)]: Added support for `GroupOperation` subclasses to recover from errors. Thanks to [@gsimmons](https://github.com/gsimmons) for reporting this issue!\n18. [[OPR-348](https://github.com/danthorpe/Operations/pull/348)]: Added the ability for `RepeatedOperation` to reset its configuration block.\n19. [[OPR-294](https://github.com/danthorpe/Operations/pull/294)]: Adds very simplistic support to `CloudKitOperation` to handle `CKLimitExceeded`. Framework consumers should bear in mind however, that this is quite simplistic, and if your object graph uses many (or any) `CKReferences` be careful here. It is generally advised to update `CKReferences` first.\n\n## Miscellaneous issues & bug fixes\n20. [[OPR-302](https://github.com/danthorpe/Operations/pull/302)]: Fixes a incorrect Fix-It hint\n21. [[OPR-303](https://github.com/danthorpe/Operations/pull/303)]: Fixes `.Notice` severity logs.\n22. [[OPR-310](https://github.com/danthorpe/Operations/pull/310)]: Removes an unnecessary `let` statement. Thanks to [@pomozoff](https://github.com/pomozoff) for this one!\n23. [[OPR-324](https://github.com/danthorpe/Operations/pull/324)]: Exposes the `LogSeverity` value to Objective-C. Thanks to [@J-Swift](https://github.com/J-Swift) for this one!\n24. [[OPR-341](https://github.com/danthorpe/Operations/pull/341)]: Makes `UserIntent` accessible from Objective-C. Thanks [@ryanjm](https://github.com/ryanjm) for this one!\n25. [[OPR-338](https://github.com/danthorpe/Operations/pull/338)]: Thanks to [@ryanjm](https://github.com/ryanjm) for fixing an issue which caused the `NetworkObserver` to flicker.\n26. [[OPR-350](https://github.com/danthorpe/Operations/pull/350)]: Turns on Whole Module Optimization for Release configuration builds. Whoops! Sorry!\n\nThis is a pretty big release. Thanks so much to all the contributors. I promise that 3.1 will not be too far behind.\n\n# 2.10.1\n\n1. [[OPR-305](https://github.com/danthorpe/Operations/pull/305)]: Resolves an issue where `Capability.Location` can finish early. This can happen on subsequent permission challenges if the app is closed while the permission alert is on screen. It appears to be some slightly unexpected behavior of `CLLocationManager` informing its delegate immediately that the status is `.NotDetermined`. Lots of thanks to [J-Swift](https://github.com/J-Swift) for finding, explaining to me, and providing a fix for this issue!  \n\n# 2.10.0\n\n1. [[OPR-256](https://github.com/danthorpe/Operations/pull/256)]: When a `GroupOperation` is cancelled with errors, the child operations in the group are also cancelled with those errors wrapped inside an `OperationError.ParentOperationCancelledWithErrors` error. Thanks to [@felix-dumit](https://github.com/felix-dumit) and [@jshier](https://github.com/jshier) for contributing.\n2. [[OPR-257, OPR-259](https://github.com/danthorpe/Operations/pull/259)]: Improves the README to give much clearer documentation regarding the need for an `OperationQueue` instance, instead of just a regular `NSOperationQueue`. Thanks to [@DavidNix](https://github.com/DavidNix) for raising the initial issue.\n3. [[OPR-265](https://github.com/danthorpe/Operations/pull/265)]: Defines `Operation.UserIntent`. This is a simple type which can be used express the intent of the operation. It allows for explicit user action (`.Initiated`), a side effect of user actions (`.SideEffect`), and `.None` for anything else, which is the default. `Operation` will use this value to set the quality of service (QoS) of the operation. The reason for separating `UserIntent` from the QoS, is that it is not possible to accurately determine the intent from the QoS because an `NSOperation`'s QoS can be modified when it is added to a queue which has a different QoS, or even if it is already on a queue, which has another `NSOperation` with a different QoS added to the same queue. See [the documentation on Quality of Service classes](https://developer.apple.com/library/ios/documentation/Performance/Conceptual/EnergyGuide-iOS/PrioritizeWorkWithQoS.html).\n4. [[OPR-266](https://github.com/danthorpe/Operations/pull/266/commits/dc19369828d5bf555ab9eee4603e73c2b6eedb6b)]: Thanks for [@estromlund](https://github.com/estromlund) for fixing this bug - now network errors are passed into the errors of the network operation.\n5. [[OPR-273](https://github.com/danthorpe/Operations/pull/273)]: `AlertOperation` can now be customized to display action sheet style alerts. Thanks to [@felix-dumit](https://github.com/felix-dumit) for writing this one!\n6. [[OPR-281](https://github.com/danthorpe/Operations/pull/281)]: `BlockOperation` now supports blocks which throw errors. The errors are caught and processed by `Operation` correctly. Thanks to [@ryanjm](https://github.com/ryanjm) for reporting and contributing!\n7. [[OPR-292](https://github.com/danthorpe/Operations/pull/282)]: Fixes a bug accessing `PHPhotoLibrary`. Thanks to [@ffittschen](https://github.com/ffittschen) for reporting this bug!\n8. [[OPR-285](https://github.com/danthorpe/Operations/pull/285)]: Fixes the watchOS target which had CloudKit references in it. Thanks to [@vibrazy](https://github.com/vibrazy) and the ASOS team for this one!\n9. [[OPR-290](https://github.com/danthorpe/Operations/pull/289)]: Fixes a typo - thanks [@waywalker](https://github.com/waywalker)!\n10. [[OPR-296](https://github.com/danthorpe/Operations/pull/296)]: Updates the `.gitignore` for Swift Package Manager. Thanks to [@abizern](https://github.com/abizern) for contributing.\n11. [[OPR-269](https://github.com/danthorpe/Operations/pull/269)]: Fixes a bug with `NSURLSessionTaskOperation` where it could crash if it is not safely finished. Please report any bugs with this class, as at the moment it is not very well tested.\n\nThis is an interim release before some significant breaking changes get merged, for version 3.0.\n\nThanks a lot for everyone who has contributed!\n\n# 2.9.1\n\n1. [[OPR-282](https://github.com/danthorpe/Operations/pull/282)]: Fixes a bug accessing `PHPhotoLibrary` through `Capability.Photos`.\n2. [[OPR-285](https://github.com/danthorpe/Operations/pull/285)]: Removes CloudKit files from the watchOS target.\n\nThis is a patch release to get these fixes released.\n\n# 2.9.0\n\n1. [[OPR-241](https://github.com/danthorpe/Operations/pull/241)]: Makes change for Xcode 7.3 and Swift 2.2.\n2. [[OPR-251](https://github.com/danthorpe/Operations/pull/252)]: Refactors how Capabilities work with their generic registrars.\n\nGot there in the end! Thanks everyone for helping out during the change to Swift 2.2 - by the time Swift 3.0 comes around, I’ll hopefully have a fully automated CI system in place for switching up toolchains/build.\n\n# 2.8.2\n\n1. [[OPR-250](https://github.com/danthorpe/Operations/pull/250)]: Thanks to [@felix-dumit](https://github.com/felix-dumit) for making the cancellation of `GroupOperation` more sensible and consistent. Essentially now the group will cancel after all of its children have cancelled.\n\nThis should be the last bug release before v2.9.0 and Swift 2.2 is released.\n\nAlso, before v2.10 is released, if you happen to use Operations framework in your app or team, and would agree to having a logo displayed in the README - please [get in touch](https://github.com/danthorpe/Operations/issues/new)!\n\n# 2.8.1\n\n1. [[OPR-245](https://github.com/danthorpe/Operations/pull/247)]: Thanks to [@difujia](https://github.com/difujia) for spotting and fixing a really clear retain cycle in `ComposedOperation`. Good tip - is to remember that an operation will retain its observers, meaning that if an operation owns another operation, *and* acts as its observer, then it will create a retain cycle. The easy fix is to use block based observers, with a capture list of `[unowned self]`.\n2. [[OPR-246](https://github.com/danthorpe/Operations/pull/248)]: Another bug fix from [@difujia](https://github.com/difujia) for a race condition when adding operation which have mutual exclusive dependencies. My bad! Thanks Frank!\n\nJust a quick note - these bug fixes are both being released now as 2.8.1 for Swift 2.1 & Xcode 7.2. The same fixes will be pulled into the `development` branch which is shortly going to become Swift 2.2, although it isn't yet. Bear with me - as that should happen over the weekend. \n\n# 2.8.0\n🚀 This will be the last minor release for Swift 2.1.1. From here on development of new features will be in Swift 2.2 😀.\n\nYet again, this release features more contributors - thanks a lot to [@estromlund](https://github.com/estromlund), [@itsthejb](https://github.com/itsthejb), [@MrAlek](https://github.com/MrAlek) and [@felix-dumit](https://github.com/felix-dumit) for finding bugs and fixing them!\n\nAlso, I’m pretty happy to report that adoption and usage of this framework has been seeing somewhat of an uptick! According to the stats on CocoaPods, we’re seeing almost 2,500 downloads/week and over used by over 120 applications 🎉! The support from the Swift community on this has been pretty amazing so far - thanks everyone 😀🙌!\n\n1. [[OPR-233](https://github.com/danthorpe/Operations/pull/223)]: Thanks to [@estromlund](https://github.com/estromlund) & [@itsthejb](https://github.com/itsthejb) for fixing a bug which would have caused retain cycles when using result injection.\n2. [[OPR-225](https://github.com/danthorpe/Operations/pull/225)]: Adds a unit test to check that `Operation` calls `finished()`. This was a bit of a followup to the fixes in 2.7.1.\n3. [[OPR-208,OPR-209](https://github.com/danthorpe/Operations/pull/209)]: Thanks to [@itsthejb](https://github.com/itsthejb) who remove the `HostReachabilityType` from the arguments of `ReachabilityCondition` which allows it to be more easily consumed. It’s now access via a property in unit tests.\n4. [[OPR-210](https://github.com/danthorpe/Operations/pull/210)]: Thanks to [@itsthejb](https://github.com/itsthejb) (again!) for improving the logic for ReachabilityCondition.\n5. [[OPR-226](https://github.com/danthorpe/Operations/pull/226)]: Some improvements to the unit tests to fix some failures on development.\n6. [[OPR-224](https://github.com/danthorpe/Operations/pull/224)]: Use `.Warning` log severity when logging errors in `Operation`. Thanks again to [@itsthejb](https://github.com/itsthejb) for this one.\n7. [[OPR-227](https://github.com/danthorpe/Operations/pull/227)]: Sets the log severity to `.Fatal` for the unit tests.\n8. [[OPR-229](https://github.com/danthorpe/Operations/pull/229)]: Thanks to [@estromlund](https://github.com/estromlund) for fixing a bug from 2.7.0 where the automatic result injection was done using a `DidFinishObserver` instead of `WillFinishObserver` which was causing some race conditions.\n9. [[OPR-231](https://github.com/danthorpe/Operations/pull/231)]: Removes `self` from the default operation name - which due to the `@autoclosure` nature of the log message could cause locking issues.\n10. [[OPR-234](https://github.com/danthorpe/Operations/pull/234)]: Thanks to [@MrAlek](https://github.com/MrAlek) for fixing a bug (causing a race condition) when cancelling a `GroupOperation`.\n11. [[OPR-236](https://github.com/danthorpe/Operations/pull/236)]: Thanks to [@felix-dumit](https://github.com/felix-dumit) for fixing a bug where an `AlertOperation` would finish before its handler is called.\n12. [[OPR-239](https://github.com/danthorpe/Operations/pull/239)]: Adds `GroupOperationWillAddChildObserver` observer protocol. This is only used by `GroupOperation` and can be use to observer when child operations are about to be added to the group’s queue.\n13. [[OPR-235](https://github.com/danthorpe/Operations/pull/235)]: New Observer: `OperationProfiler`.\n\n    An `OperationProfiler` can be added as an observer to an `Operation` instance. It will report a profile result which contains the timings for the lifecycle events of the operation, from created through attached, started to cancelled or finished.\n    \n    By default, a logging reporter is added, which will print the profile information to the `LogManager`’s logger. This is done like this:\n    \n    ```swift\n    let operation = MyBigNumberCrunchingOperation()\n    operation.addObserver(OperationProfiler())\n    queue.addOperation(operation)\n    ```\n    \n    However, for customized reporting and analysis of profile results, create the profiler with an array of reporters, which are types conforming to the `OperationProfilerReporter` protocol.\n    \n    **In most cases doing any kind of profiling of applications in production is unnecessary and should be avoided.**\n    \n    However, in some circumstances, especially with applications which have very high active global users, it is necessary to gain a holistic view of an applications performance. Typically these measurements should be tied to networking operations and profiling in back end systems. The `OperationProfiler` has deliberately designed with a view of using custom reporters. The built in logging reporter should only really be used as debugging tool during development.\n    \n    In addition to profiling regular “basic” `Operation` instances. The profiler will also measure spawned operations, and keep track of them from the parent operation’s profiler. Operations can be spawned by calling `produceOperation()` or by using a `GroupOperation`. Regardless, the profiler’s results will reference both as “children” in the same way.\n    \n    WARNING: Use this feature carefully. *If you have not* written a custom reporter class, **there is no need** to add profilers to operations in production.\n\n# 2.7.1\n\n1. [[OPR-219](https://github.com/danthorpe/Operations/issues/220)]: Fixes an issue after refactoring Operation which would prevent subclasses from overriding `finished(errors: [ErrorType])`.\n\n# 2.7.0\n🚀 This release continues the refinement of the framework. Thanks again to everyone who has contributed!\n\n1. [[OPR-152](https://github.com/danthorpe/Operations/issues/152), [OPR-193](https://github.com/danthorpe/Operations/pull/193), [OPR-195](https://github.com/danthorpe/Operations/pull/195), [OPR-201](https://github.com/danthorpe/Operations/pull/201)]: This is a breaking change which significantly improves Operation observers.\n    1. Observers can be safely added to an Operation at any point in its lifecycle.\n    2. Observers can implement a callback which is executed when there are attached to the operation.\n    3. All the block based observers have labels on their arguments.\n\n    Thanks to [@jshier](https://github.com/jshier) for reporting this one.\n2. [[OPR-193](https://github.com/danthorpe/Operations/pull/196)]: Thanks to [@seancatkinson](https://github.com/seancatkinson) who made improvements to `UIOperation` making it possible to specify whether the controller should be wrapped in a `UINavigationController`.\n3. [[OPR-199](https://github.com/danthorpe/Operations/pull/203)]: Refactored the initializers of `RepeatedOperation` to make it far easier for framework consumers to subclass it - thanks [@jshier](https://github.com/jshier) for reporting this one.\n4. [[OPR-197](https://github.com/danthorpe/Operations/pull/198)]: Fixes a bug where errors from nested `GroupOperation`s were not propagating correctly - thanks to [@bastianschilbe](https://github.com/bastianschilbe) for reporting this one.\n5. [[OPR-204](https://github.com/danthorpe/Operations/pull/204)]: Fixes a typo in the README - thanks to [@Augustyniak](https://github.com/Augustyniak).\n6. [[OPR-214](https://github.com/danthorpe/Operations/pull/214)]: Moves code coverage reporting from Codecov.io to [Coveralls](https://coveralls.io/github/danthorpe/Operations).\n7. [[OPR-164](https://github.com/danthorpe/Operations/pull/164)]: Adds initial support for Swift Package Manager - no idea if this actually works yet though.\n8. [[OPR-212](https://github.com/danthorpe/Operations/pull/212)]: Removes the example projects from the repo. They are now in the [@danthorpe/Examples](https://github.com/danthorpe/Examples) repo. This was done as a safer/better fix for the issue which was resolved in v2.6.1. Essentially because Carthage now builds *all* Xcode projects that it can finds, it will attempt to build any example projects in the repo, and because Carthage does not have the concept of “local dependencies” these example projects are setup using CocoaPods. And I really don’t like to include the `Pods` folder of dependencies in repositories as it just take longer to checkout. So, this was causing Carthage to exit because it couldn’t build these exampled. So, I’ve moved them to a new repo.\n9. [[OPR-216](https://github.com/danthorpe/Operations/pull/216)]: Adds SwiftLint to the project & CI, including fixes for all the issues which were warnings or errors.\n10. [[OPR-192](https://github.com/danthorpe/Operations/pull/192)]: Updates the `.podspec` to have more granular dependencies. For users of `CloudKitOperation` this is a breaking change, and you will need to update your `Podfile`:\n\n    ```ruby\n    pod ‘Operations/+CloudKit’\n    ```\n\n    Thanks to [@itsthejb](https://github.com/itsthejb) for this one.\n\n\n# 2.6.1\n\n1. [[OPR-205, OPR-206](https://github.com/danthorpe/Operations/pull/206)]: Fixes a mistake where the Cloud Capability was not available on tvOS platform.\n\n2. Temporary work around for an issue with Carthage versions 0.12 and later. In this version, Carthage now builds all Xcode projects it can find, which in this case is 4 projects because there are two examples. Those example projects use CocoaPods to setup their dependency on the Operations framework, using the \"development pod\" technique. I would prefer to not include their `Pods/` folder in the repo, however, without it, it becomes necessary to run `pod update` before building - which Carthage (reasonably) does not do. Therefore they fail to build and Carthage exits.\n\n# 2.6.0\n\n🚀 This release contains quite a few changes, with over 230 commits with input from 11 contributors! Thanks! 😀🎉\n\nA note on quality: test coverage has increased from 64% in v2.5 to 76%. The code which remains untested is either untestable (`fatalError` etc) or is due for deletion or deprecation such as `AddressBookCondition` etc.\n\n### New Operations\n\n1. [[OPR-150](https://github.com/danthorpe/Operations/pull/150)]: `MapOperation`, `FilterOperation` and `ReduceOperation` *For advanced usage*. \n\n\tThese operations should be used in conjunction with `ResultOperationType` which was introduced in v2.5.0. Essentially, given an receiving operation, conforming to `ResultOperationType`, the result of mapping, filtering, or reducing the receiver’s `result` can be returned as the `result` of another operation, which also conforms to `ResultOperationType`. This means that it can be trivial to map the results of one operation inside another.\n\n\tIt is suggested that this is considered for advanced users only as it’s pretty subtle behavior.\n\n2. [[OPR-154](https://github.com/danthorpe/Operations/pull/154), [OPR-168](https://github.com/danthorpe/Operations/pull/168)]: `RepeatedOperation`\n\n\tThe `RepeatedOperation` is a `GroupOperation` subclass which can be used in conjunction with a generator to schedule `NSOperation` instances. It is useful to remember that `NSOperation` is a “one time only” class, meaning that once an instance finishes, it cannot be re-executed. Therefore, it is necessary to construct repeatable operations using a closure or generator.\n \n\tThis is useful directly for periodically running idempotent operations. It also forms the basis for operation types which can be retried.\n \n\tThe operations may optionally be scheduled after a delay has passed, or a date in the future has been reached.\n \n\tAt the lowest level, which offers the most flexibility, `RepeatedOperation` is initialized with a generator. The generator (something conforming to `GeneratorType`) element type is `(Delay?, T)`, where `T` is a `NSOperation` subclass, and `Delay` is an enum used in conjunction with `DelayOperation`.\n \n\t`RepeatedOperation` can also be initialized with a simple `() -> T?` closure and `WaitStrategy`. The strategy offers standardized delays such as `.Random` and `.ExpoentialBackoff`, and will automatically create the appropriate `Delay`. \n\n\t`RepeatedOperation` can be stopped by returning `nil` in the generator, or after a maximum count of operations, or by calling `cancel()`.\n\n\tAdditionally, a `RepeatableOperation` has been included, which composes an `Operation` type, and adds convenience methods to support whether or not another instance should be scheduled based on the previous instance.\n\n2. [[OPR-154](https://github.com/danthorpe/Operations/pull/154), [OPR-161](https://github.com/danthorpe/Operations/pull/161), [OPR-168](https://github.com/danthorpe/Operations/pull/168)]: `RetryOperation`\n\n\t`RetryOperation` is a subclass of `RepeatedOperation`, except that instead of repeating irrespective of the finishing state of the previous instance, `RetryOperation` only repeats if the previous instance finished with errors.\n\n\tAdditionally, `RetryOperation` is initialized with an “error recovery” block. This block receives various info including the errors from the previous instance, the aggregate errors so far, a `LoggerType` value, plus the *suggested* `(Delay, T?)` tuple. This tuple is the what the `RetryOperation` would execute again without any intervention. The error block allows the consumer to adjust this, either by returning `.None` to not retry at all, or by modifying the return value.\n\n3. [[OPR-160](https://github.com/danthorpe/Operations/pull/160), [OPR-165](https://github.com/danthorpe/Operations/pull/165), [OPR-167](https://github.com/danthorpe/Operations/pull/167)]: `CloudKitOperation` 2.0\n\n\tTechnically, this work is a refactor of `CloudKitOperation`, however, because it’s a major overhaul it is best viewed as completely new.\n\n\t`CloudKitOperation` is a subclass of `RetryOperation`, which composes the `CKOperation` subclass inside a `ReachableOperation`.\n\t\n\t`CloudKitOperation` can be used to schedule `CKOperation` subclasses. It supports configuration of the underlying `CKOperation` instance “through” the outer `CloudKitOperation`, where the configuration applied is stored and re-applied on new instances in the event of retrying. For example, below\n\t\n\t```swift\n    // Modify CloudKit Records\n    let operation = CloudKitOperation { CKModifyRecordsOperation() }\n    \n    // The user must be logged into iCloud \n    operation.addCondition(AuthorizedFor(Capability.Cloud()))\n    \n    // Configure the container & database\n    operation.container = container\n    operation.database = container.privateCloudDatabase\n    \n    // Set the records to save\n    operation.recordsToSave = [ recordOne, recordTwo ]\n    \n    // Set the policy\n    operation.savePolicy = .ChangedKeys\n    \n    // Set the completion\n    operation.setModifyRecordsCompletionBlock { saved, deleted in\n        // Only need to manage the happy path here\n    }\n\t```\n\t\n\tIn the above example, all the properties set on `operation` are saved into an internal configuration block. This is so that it in the case of retrying after an error, the same configuration is applied to the new `CKOperation` instance returned from the generator. The same could also be achieved by setting these properties inside the initial block, however the completion block above must be called to setup the `CloudKitOperation` correctly. \n\t\n\tThanks to `RetryOperation`, `CloudKitOperation` supports some standardized error handling for common errors. For example, if Apple’s CloudKit service is unavailable, your operation will be automatically re-tried with the correct delay. Error handling can be set for individual `CKErrorCode` values, which can replace the default handlers if desired. \n\t\n\t`CKOperation` subclasses also all have completion blocks which receives the result and an optional error. As discussed briefly above, `CloudKitOperation` provides this completion block automatically when the consumer sets the “happy path” completion block. The format of this function is always `set<Name of the CKOperation completion block>()` This means, that it is only necessary to set a block which is executed in the case of no error being received.\n\t\n\t`BatchedCloudKitOperation` is a `RepeatedOperation` subclass which composed `CloutKitOperation` instances. It can only be used with `CKOperation` subclasses which have the notion of batched results.\n\t\n\tSee the class header, example projects, blog posts and (updated) guide for more documentation. This is significant change to the existing class, and should really be viewed as entirely new. Please get in touch if you were previously using `CloudKitOperation` prior to this version, and are now unsure how to proceed. I’m still working on improving the documentation & examples for this class. \n\n### Examples & Documentation\n\n1. [[OPR-169](https://github.com/danthorpe/Operations/pull/172)]: Last Opened example project\n\n\tLast Opened, is the start of an iOS application which will demonstrate how to use the new `CloudKitOperation`. At the moment, it is not exactly complete, but it does show some example. However, the application does not compile until the correct development team & bundle id is set. \n\n2. [[OPR-171](https://github.com/danthorpe/Operations/pull/171)]: `CloudKitOperation` documentation\n\n\tThere is now quite a bit of public interface documentation. Still working on updating the programming guide right now.\n\n### Operation Changes\n\n1. [[OPR-152](https://github.com/danthorpe/Operations/pull/156)]: Adding Conditions & Observers\n\n\tWhen adding conditions and observers, we sanity check the state of the operation as appropriate. For adding a Condition, the operation must not have started executing. For adding an Observer, it now depends on the kind, for example, it is possible to add a `OperationDidFinishObserver` right up until the operation enters its `.Finishing` state.\n\n2. [[OPR-147](https://github.com/danthorpe/Operations/pull/157)]: Scheduling of Operations from Conditions\n\n\tWhen an Operation has dependencies and also has Conditions attached which also have dependencies, the scheduling of these dependencies is now well defined. Dependencies from Conditions are referred to as *indirect dependencies* versus *direct* for dependencies added normally.\n\n\tThe *indirect dependencies* are now scheduled __after__ *all* the direct dependencies finish. See [original issue](https://github.com/danthorpe/Operations/pull/147) and the [pull request](https://github.com/danthorpe/Operations/pull/157) for further explanation including a diagram of the queue.\n\n3. [[OPR-129](https://github.com/danthorpe/Operations/pull/159)]: Dependencies of mutually exclusive Conditions.\n\n\tIf a Condition is mutually exclusive, the `OperationQueue` essentially adds a lock on the associated `Operation`. However, this previously would lead to unexpected scheduling of that condition had a dependency operation. Now, the “lock” is placed on the dependency of the condition instead of the associated operation, but only if it’s not nil. Otherwise, standard behavior is maintained.\n\n4. [[OPR-162](https://github.com/danthorpe/Operations/pull/162)]: Refactor of `ComposedOperation` and `GatedOperation`\n\n\tPreviously, the hierarchy of these two classes was all mixed up. `ComposedOperation` has been re-written to support both `Operation` subclasses and `NSOperation` subclasses. When a `NSOperation` (but not `Operation`) subclass is composed, it is scheduled inside its own `GroupOperation`. However, if composing an `Operation` subclass, instead we “produce” it and use observers to finish the `ComposedOperation` correctly.\n\n\tNow, `GatedOperation` is a subclass of `ComposedOperation` with the appropriate logic.\n\n5. [[OPR-163](https://github.com/danthorpe/Operations/pull/163), [OPR-171](https://github.com/danthorpe/Operations/pull/171), [OPR-179](https://github.com/danthorpe/Operations/pull/179)]: Refactor of `ReachableOperation`\n\n\t`ReachableOperation` now subclasses `ComposedOperation`, and uses `SCNetworkReachablity` callbacks correctly. \n\n6. [[OPR-187](https://github.com/danthorpe/Operations/pull/187)]: Sanity check `produceOperation()`. Thanks to [@bastianschilbe](https://github.com/bastianschilbe) for this fix. Now the `Operation` must at least have passed the `.Initialized` state before `produceOperation()` can be called.\n\n### Project Configurations\n\n1. [[OPR-182](https://github.com/danthorpe/Operations/pull/184)]: Extension Compatible\n\n\tUpdates the extension compatible Xcode project. Sorry this got out of sync for anyone who was trying to get it to work!\n\n### Bug Fixes!\n\n1. [[OPR-186](https://github.com/danthorpe/Operations/pull/186), [OPR-188](https://github.com/danthorpe/Operations/pull/188)]: Ensures `UIOperation` finishes correctly.\n\n2. [[OPR-180](https://github.com/danthorpe/Operations/pull/180)]: Completion Blocks.\n\n\tChanges in this pull request improved the stability of working with `OperationCondition`s attached to `Operation` instances. However, there is still a bug which is potentially an issue with KVO.\n\t\n\tCurrently it is suggested that the `completionBlock` associated with `NSOperation` is avoid. Other frameworks expressly forbid its usage, and there is even a Radar from Dave De Long recommending it be deprecated.\n\t\n\tThe original issue, [#175](https://github.com/danthorpe/Operations/issue/180) is still being tracked.\n\n3. [[OPR-181](https://github.com/danthorpe/Operations/pull/189)]: Fixes a bug in `GroupOperation` where many child operations which failed could cause a crash. Now access to the `aggregateErrors` property is thread safe, and this issue is tested with a tight loop of 10,000 child operations which all fail. Thanks to [@ansf](https://github.com/ansf) for reporting this one.\n\t\n### Thanks!\n\n I want to say a *huge thank you* to everyone who has contributed to this project so far. Whether you use the framework in your apps (~ 90 apps, 6k+ downloads via CocoaPods metrics), or you’ve submitted issues, or even sent me pull requests - thanks!  \n \n I don’t think I’d be able to find anywhere near the number of edge cases without all the help. The suggestions and questions from everyone keeps me learning new stuff. \n\nCheers,\nDan\n\n### What’s next?\n\nI’ve not got anything too major planned right now, except improving the example projects. So the next big thing will probably be Swift 3.0 support, and possibly ditching `NSOperation`.\n\n\n\n# 2.5.1\n1. [[OPR-151](https://github.com/danthorpe/Operations/pull/151), [OPR-155](https://github.com/danthorpe/Operations/pull/155)]: Fixes a bug where `UserLocationOperation` could crash when the LocationManager returns subsequent locations after the operation has finished.\n\n# 2.5.0\n\nThis is a relatively large number of changes with some breaking changes from 2.4.*.\n\n### Breaking changes\n\n1. [[OPR-140](https://github.com/danthorpe/Operations/pull/140)]: `OperationObserver` has been refactored to refine four different protocols each with a single function, instead of defining four functions itself. \n\n    The four protocols are for observing the following events: *did start*, *did cancel*, *did produce operation* and *did finish*. There are now specialized block observers, one for each event.\n\n    This change is to reflect that observers are generally focused on a single event, which is more in keeping with the single responsibility principle. I feel this is better than a single type which typically has either three no-op functions or consists entirely of optional closures.\n\n    To observe multiple events using blocks: add multiple observers. Alternatively, create a bespoke type to observe multiple events with the same type.\n\n    `BlockObserver` itself still exists, however its usage is discouraged and it will be removed at a later time. It may also be necessary to make syntactic changes to existing code, in which case, I recommend replacing its usage entirely with one or more of `StartedObserver`, `CancelledObserver`, `ProducedOperationObserver` or `FinishedObserver`, all of which accept a non-optional block.\n\n2. [[OPR-139](https://github.com/danthorpe/Operations/pull/139)]: Removed `Capabiltiy.Health`. Because this capability imports HealthKit, it is flagged by the app review team, and an application may be rejecting for not providing guidance on its usage of HealthKit. Therefore, as the majority of apps probably do not use this capability, I have removed it from the standard application framework. It is available as a subspec through Cocoapods:\n\n    ```ruby\n    pod 'Operations/+Health'\n    ```\n\n### Improvements\n\n1. [[OPR-121](https://github.com/danthorpe/Operations/issues/121),[OPR-122](https://github.com/danthorpe/Operations/pull/122), [OPR-126](https://github.com/danthorpe/Operations/pull/126), [OPR-138](https://github.com/danthorpe/Operations/pull/138)]: Improves the built in logger. So that now:\n\n    1. the message is enclosed in an  `@autoclosure`. \n    2. there is a default/global severity threshold\n    3. there is a global enabled setting.\n\n    Thanks to Jon ([@jshier](https://github.com/jshier)) for raising the initial issue on this one.\n\n2. [[OPR-128](https://github.com/danthorpe/Operations/pull/128)]: Improves how code coverage is generated.\n\n    Thanks to Steve ([@stevepeak](https://github.com/stevepeak)) from [Codecov.io](https://codecov.io) for helping with this.\n\n3. [[OPR-133](https://github.com/danthorpe/Operations/issues/133), [OPR-134](https://github.com/danthorpe/Operations/pull/134)]: `DelayOperation` and `BlockOperation` have improved response to being cancelled.\n\n    Thanks to Jon ([@jshier](https://github.com/jshier)) for raising the initial issue on this one.\n\n4. [[OPR-132](https://github.com/danthorpe/Operations/pull/132)]: `BlockObserver` now supports a cancellation handler. However see the notes regarding changes to `OperationObserver` and `BlockObserver` above under breaking changes.\n\n5. [[OPR-135](https://github.com/danthorpe/Operations/issues/135),[OPR-137](https://github.com/danthorpe/Operations/pull/137)]: Result Injection.\n\n    It is now possible to inject the results from one operation into another operation as its requirements before it executes. This can be performed with a provided block, or automatically in the one-to-one, result-to-requirement case. See the [programming guide](https://operations.readme.io/docs/injecting-results) for more information.\n\n    Thanks very much to Frank ([@difujia](https://github.com/difujia)) for the inspiration on this, and Jon ([@jshier](https://github.com/jshier)) for contributing to the discussion.\n\n6. [[OPR-141](https://github.com/danthorpe/Operations/pull/141)]: `Operation` now uses `precondition` to check the expectations of public APIs. These are called out in the function’s documentation. Thanks to the Swift evolution mailing list & Chris Lattner on this one.\n\n7. [[OPR-144](https://github.com/danthorpe/Operations/issues/144), [OPR-145](https://github.com/danthorpe/Operations/pull/145)]: Supports adapting the internal logger to use 3rd party logging frameworks. The example project uses [SwiftyBeaver](https://github.com/SwiftyBeaver/SwiftyBeaver) as a logger. \n\n    Thanks to Steven ([@shsteven](https://github.com/shsteven)) for raising the issue on this one!\n\n8. [[OPR-148](https://github.com/danthorpe/Operations/pull/148)]: Location operations now conform to `ResultOperationType` which means their result (`CLLocation`, `CLPlacemark`) can be injected automatically into appropriate consuming operations.\n\n### Bug Fixes\n\n1. [[OPR-124](https://github.com/danthorpe/Operations/pull/124)]: Fixes a bug where notification names conflicted. \n\n    Thanks to Frank ([@difujia](https://github.com/difujia)) for this one.\n\n2. [[OPR-123](https://github.com/danthorpe/Operations/issues/123),[OPR-125](https://github.com/danthorpe/Operations/pull/125), [OPR-130](https://github.com/danthorpe/Operations/pull/130)]: Fixes a bug where a completion block would be executed twice. \n\n    Thanks again to Frank ([@difujia](https://github.com/difujia)) for raising the issue.\n\n3. [[OPR-127](https://github.com/danthorpe/Operations/issues/127), [OPR-131](https://github.com/danthorpe/Operations/pull/131)]: Fixes a bug where an operation could fail to start due to a race condition. Now, if an operation has no conditions, rather than entering a `.EvaluatingConditions` state, it will immediately (i.e. synchronously) become `.Ready`. \n\n    Thanks to Kevin ([@kevinbrewster](https://github.com/kevinbrewster)) for raising this issue.\n\n4. [[OPR-142](https://github.com/danthorpe/Operations/pull/142)]: `Operation` now checks the current state in comparison to `.Ready` before adding conditions or operations. This is unlikely to be a breaking change, as it is not a significant difference.\n\n    Thanks to Frank ([@difujia](https://github.com/difujia)) for this one.\n\n5. [[OPR-146](https://github.com/danthorpe/Operations/pull/146)]: Fixes a subtle issue where assessing the readiness could trigger state changes.\n\n\nThanks to [@difujia](https://github.com/difujia), [@jshier](https://github.com/jshier), [@kevinbrewster](https://github.com/kevinbrewster), [@shsteven](https://github.com/shsteven) and [@stevepeak](https://github.com/stevepeak) for contributing to this version. :)\n\n\n# 2.4.1\n1. [[OPR-113](https://github.com/danthorpe/Operations/pull/113)]: Fixes an issue where building against iOS 9 using Carthage would unleash a tidal wave of warnings related to ABAddressBook. Thanks to [@JaimeWhite](https://github.com/JamieWhite) for bringing this to my attention!\n2. [[OPR-114](https://github.com/danthorpe/Operations/pull/114)]: Reorganized the repository into two project files. One create standard frameworks for applications, for iOS, watchOS, tvOS, and OS X. The other creates Extension API compatible frameworks for iOS, tvOS and OS X. At the moment, if you wish to use an API extension compatible framework with Carthage - this is a problem, as Carthage only builds one project, however the is a Pull Request which will fix this. The issue previously was that the `Operations.framework` products would overwrite each other. I’ve tried everything I can think of to make Xcode produce a product which has a different name to its module - but it won’t let me. So.. the best thing to do in this case is use CocoaPods and the Extension subspec.\n3. [[OPR-115](https://github.com/danthorpe/Operations/pull/115)]: Fixes an issue with code coverage after project reorganization.\n4. [[OPR-116](https://github.com/danthorpe/Operations/pull/116)]: Fixes a mistake where `aggregateErrors` was not publicly accessible in `GroupOperation`. Thanks to [@JaimeWhite](https://github.com/JamieWhite) for this.\n\nThanks a lot to [@JaimeWhite](https://github.com/JamieWhite) for helping me find and squash some bugs with this release. Greatly appreciated!  \n\n# 2.4.0\n1. [[OPR-108](https://github.com/danthorpe/Operations/pull/108)]: Adds an internal logging mechanism to `Operation`. Output log information using the `log` property  of the operation. This property exposes simple log functions. E.g.\n\n   ```swift\n   let operation = MyOperation() // etc\n   operation.log.info(“This is a info message.”)\n   ```\nTo use a custom logger, create a type conforming to `LoggerType` and add an instance property to your `Operation` subclass. Then override `getLogger()` and `setLogger(: LoggerType)` to get/set your custom property.\n\nThe global severity is set to `.Warning`, however individual operation loggers can override to set it lower, e.g. \n\n    ```swift\n    operation.log.verbose(“This verbose message will not be logged, as the severity threshold is .Warning”)\n    operation.log.severity = .Verbose\n    operation.log.verbose(“Now it will be logged.”)\n    ```\n2. [[OPR-109](https://github.com/danthorpe/Operations/pull/109)]: Added documentation to all of the Capability (device permissions etc) functionality. Also now uses Jazzy categories configuration to make the generated documentation more easily navigable. Documentation is hosted on here: [docs.danthorpe.me/operations](http://docs.danthorpe.me/operations/2.4.0/index.html).\n\n\n# 2.3.0\n1. [[OPR-89](https://github.com/danthorpe/Operations/pull/89)]: Adds support (via subspecs) for watchOS 2 and tvOS apps.\n2. [[OPR-101](https://github.com/danthorpe/Operations/pull/101)]: Fixes a bug where `ReachableOperation` may fail to start in some scenarios.\n3. [[OPR-102](https://github.com/danthorpe/Operations/pull/102)]: Adds more documentation to the finish method of Operation. If it’s possible for an Operation to be cancelled before it’s started, then do not call finish. This is mostly likely a possibility when writing network operations and cancelling groups.\n4. [[OPR-103](https://github.com/danthorpe/Operations/pull/103)]: Adds % of code covered by tests to the README. Service performed by CodeCov.\n5. [[OPR-104](https://github.com/danthorpe/Operations/pull/104)]: Maintenance work on the CI scripts, which have now moved to using a build pipeline which is uploaded to BuildKite and executed all on the same physical box. See [post on danthorpe.me](http://danthorpe.me/posts/uploading-build-pipelines.html).\n6. [[OPR-105](https://github.com/danthorpe/Operations/pull/105)]: Improves the testability and test coverage of the Reachability object.\n7. [[OPR-106](https://github.com/danthorpe/Operations/pull/106)]: Adds more tests to the AddressBook swift wrapper, increases coverage of `Operation`, `NegatedCondition` & `UIOperation`.\n\n# 2.2.1\n1. [[OPR-100](https://github.com/danthorpe/Operations/pull/100)]: Adds documentation to all “Core” elements of the framework. Increases documentation coverage from 8% to 22%. Still pretty bad, but will get there eventually.\n\n# 2.2.0\n1. [[OPR-91](https://github.com/danthorpe/Operations/pull/91), [OPR-92](https://github.com/danthorpe/Operations/pull/92)]: Fixes a bug in AddressBook when building against iOS 9, where `Unmanaged<T>` could be unwrapped incorrectly.\n2. [[OPR-93](https://github.com/danthorpe/Operations/pull/93), [OPR-95](https://github.com/danthorpe/Operations/pull/95)]: Adds support for Contacts.framework including `ContactsCondition` plus operations for `GetContacts`, `GetContactsGroup`, `RemoveContactsGroup`, `AddContactsToGroup` and `RemoveContactsFromGroup` in addition to a base contacts operation class. Also included are UI operations `DisplayContactViewController` and `DisplayCreateContactViewController`.\n3. [[OPR-97](https://github.com/danthorpe/Operations/pull/97), [OPR-98](https://github.com/danthorpe/Operations/pull/98)]: Refactors how device authorization permissions are checked and requested. Introduces the concept of a `CapabilityType` to govern authorization status and requests. This works in tandem with new operations `GetAuthorizationStatus<Capability>` and `Authorize<Capability>` with an operation condition `AuthorizedFor<Capability>`. The following conditions are now deprecated: `CalendarCondition`, `CloudContainerCondition`, `HealthCondition`, `LocationCondition`, `PassbookCondition`, `PhotosCondition` in favor of `Capability.Calendar`, `Capability.Cloud`, `Capability.Heath`, `Capability.Location`, `Capability.Passbook`, `Capability.Photos` respectively. Replace your condition code like this example:\n\n```swift\noperation.addCondition(AuthorizedFor(Capability.Location(.WhenInUse)))\n```\n\n# 2.1.0\n1. [[OPR-90](https://github.com/danthorpe/Operations/pull/90)]: Multi-platform support. Adds new framework targets to the project for iOS Extension only API framework. This doesn’t have support for BackgroundObserver, or NetworkObserver for example. Use `pod ‘Operations/Extension’` to use it in a Podfile for your iOS Extension target. Also, we have Mac OS X support (no special pod required). And watchOS support - use `pod ‘Operations/watchOS’`.\n\n# 2.0.2\n1. [[OPR-87](https://github.com/danthorpe/Operations/pull/87)]: Improves the reliability of the reverse geocoder unit tests.\n\n# 2.0.1\n1. [[OPR-62, OPR-86](https://github.com/danthorpe/Operations/pull/86)]: Fixes a bug in Swift 2.0 where two identical conditions would cause a deadlock. Thanks to @mblsha.\n2. [[OPR-85](https://github.com/danthorpe/Operations/pull/85)]: Fixes up the Permissions example project for Swift 2.0. Note that YapDatabase currently has a problem because it has some weak links, which doesn’t work with Bitcode enabled, which is default in Xcode 7. This PR just turned off Bitcode, but if you re-run the Pods, then that change will be over-ridden. What you can do instead, if YapDatabase is still not fixed is to use my fork which has a fix on the `YAP-180` branch.\n\n# 2.0.0\nThis is the Swift 2.0 compatible version.\n\n# 1.0.0\n1. [[OPR-79](https://github.com/danthorpe/Operations/pull/79)]: Adds more documentation to the types.\n2. [[OPR-83](https://github.com/danthorpe/Operations/pull/83)]: Adds some convenience functions to `NSOperation` and `GroupOperation` for adding multiple dependencies at once, and multiple operations to a group before it is added to a queue.\n\nThis is a release for Swift 1.2 compatible codebases.\n\n# 0.12.1\n1. [[OPR-74](https://github.com/danthorpe/Operations/pull/74)]: Work in progress on AddressBook external change request. *Warning* so not use this, as I cannot actually get this working yet.\n2. [[OPR-75](https://github.com/danthorpe/Operations/pull/75)]: Fixes a serious bug where attempting to create an ABAddressBook after previously denying access executed a fatalError.\n\n# 0.12.0\n1. [[OPR-63](https://github.com/danthorpe/Operations/pull/63)]: Speeds up the test suite by 40 seconds.\n2. [[OPR-65](https://github.com/danthorpe/Operations/pull/65)]: Adds a generic `UIOperation` class. Can be used to show view controllers, either present modally, show or show detail presentations. It is used as the basis for `AlertOperation`, and the `AddressBookDisplayPersonController`, `AddressBookDisplayNewPersonController` operations.\n3. [[OPR-67](https://github.com/danthorpe/Operations/pull/67)]: Adds reverse geocode operations. Supply a `CLLocation` to `ReverseGeocodeOperation` directly. Or use `ReverseGeocodeUserLocationOperation` to reverse geocode the user’s current location. Additionally, `LocationOperation` has been renamed to `UserLocationOperation`.\n4. [[OPR-68](https://github.com/danthorpe/Operations/pull/68)]: General improvements to the `AddressBook` APIs including a `createPerson` function, plus addition of missing person properties & labels. Additionally, fixes a bug in setting multi-value string properties.\n5. [[OPR-71](https://github.com/danthorpe/Operations/pull/71)]: Updates the unit test scripts to use Fastlane, same as Swift 2.0 branch.\n\n# 0.11.0\n1. [[OPR-45](https://github.com/danthorpe/Operations/pull/45), [OPR-46](https://github.com/danthorpe/Operations/pull/46), [OPR-47](https://github.com/danthorpe/Operations/pull/47), [OPR-48](https://github.com/danthorpe/Operations/pull/48), [OPR-49](https://github.com/danthorpe/Operations/pull/49), [OPR-54](https://github.com/danthorpe/Operations/pull/54)]:\n\nRefactor of AddressBook.framework related functionality. The `AddressBookOperation` is no longer block based, but instead keeps a reference to the address book as a property. This allows for superior composition. Additionally there is now an `AddressBookGetResource` operation, which will access the address book, and then exposes methods to read people, and if set, an individual person record and group record.\n\nAdditionally, there is now operations for adding/removing a person to a group. Add/Remove groups. And map all the people records into your own type.\n\nInternally, these operations are supported by a Swift wrapper of the AddressBook types, e.g. `AddressBookPerson` etc. This wrapper is heavily inspired by the Gulliver. If you want more powerful AddressBook features, I suggest you checkout that project, and then either subclass the operations to expose Gulliver types, or write a simple protocol extension to get Gulliver types from `AddressBookPersonType` etc etc.\n\n2. [[OPR-57](https://github.com/danthorpe/Operations/pull/57)]: The CloudKitOperation is no longer a GroupOperation, just a standard Operation, which enqueues the `CKDatabaseOperation` onto the database’s queue directly.\n3. [[OPR-58](https://github.com/danthorpe/Operations/pull/58)]: Added `ComposedOperation` which is a specialized `GatedOperation` which always succeeds. This is handy if you want to add conditions or observers to an `NSOperation`.\n4. [[OPR-60](https://github.com/danthorpe/Operations/pull/60)]: Renamed `NoCancellationsCondition` to `NoFailedDependenciesCondition` which encompasses the same logic, but will also fail if any of the operation’s dependencies are `Operation` subclasses which have failed. In addition, `Operation` now exposes all it’s errors via the `errors` public property.\n\n# 0.10.0\n1. [[OPR-14](https://github.com/danthorpe/Operations/pull/14)]: Supports Photos library permission condition.\n2. [[OPR-16](https://github.com/danthorpe/Operations/pull/16)]: Supports Health Kit permission condition.\n\n# 0.9.0\n1. [[OPR-11](https://github.com/danthorpe/Operations/pull/11)]: Supports Passbook condition.\n2. [[OPR-13](https://github.com/danthorpe/Operations/pull/13)]: Supports a EventKit permission condition.\n3. [[OPR-17](https://github.com/danthorpe/Operations/pull/17)]: Supports remote notification permission condition.\n4. [[OPR-18](https://github.com/danthorpe/Operations/pull/18)]: Supports user notification settings condition.\n5. [[OPR-38](https://github.com/danthorpe/Operations/pull/38)]: Adds a `LocationOperation` demo to Permissions.app\n6. [[OPR-39](https://github.com/danthorpe/Operations/pull/39)]: Adds a user confirmation alert condition.\n\n\n# 0.8.0\n1. [[OPR-37](https://github.com/danthorpe/Operations/pull/37)]: Creates an example app called Permissions. This is a simple catalogue style application which will be used to demonstrate functionality of the Operations framework.\n\nAt the moment, it only shows Address Book related functionality. Including using combinations of `SilentCondition`, `NegatedCondition` and `AddressBookCondition` to determine if the app has already got authorization, requesting authorization and performing a simple ABAddressBook related operation.\n\nAdditionally, after discussions with Dave DeLong, I’ve introduced changes to the underlying Operation’s state machine.\n\nLastly, the structure of `BlockOperation` has been modified slightly to allow the task execution block to pass an error (`ErrorType`) into the continuation block. Because closures cannot have default arguments, this currently means that it is required, e.g. `continueWithError(error: nil)` upon success. \n \n\n# 0.7.0\n1. [[OPR-7](https://github.com/danthorpe/Operations/pull/7)]: Supports a condition which requires all of an operation’s dependencies to succeed.\n2. [[OPR-12](https://github.com/danthorpe/Operations/pull/12)]: Adds `LocationOperation` and `LocationCondition`. This allows for accessing the user’s location, requesting “WhenInUse” authorization.\n3. [[OPR-36](https://github.com/danthorpe/Operations/pull/36)]: Adds `AddressBookOperation` which allows for access to the user’s address book inside of a handler block (similar to a `BlockOperation`). As part of this, `AddressBookCondition` is also available, which allows us to condition other operation types.\n\n\n# 0.6.0\n1. [[OPR-5](https://github.com/danthorpe/Operations/pull/5)]: Supports silent conditions. This means that if a condition would normally produce an operation (say, to request access to a resource) as a dependency, composing it inside a `SilentCondition` will suppress that dependent operation.\n2. [[OPR-6](https://github.com/danthorpe/Operations/pull/r)]: Supports negating condition.\n3. [[OPR-30](https://github.com/danthorpe/Operations/pull/30)]: Adds a `LoggingObserver` to log operation lifecycle events.\n4. [[OPR-33](https://github.com/danthorpe/Operations/pull/33)]: Adds `GatedOperation` which will only execute the composed operation if the supplied block evaluates true - i.e. opens the gate.\n5. [[OPR-34](https://github.com/danthorpe/Operations/pull/34)] & [[OPR-35](https://github.com/danthorpe/Operations/pull/35)]: Adds a `ReachableOperation`. Composing an operation inside a `ReachableOperation` will ensure that it runs after the device regains network reachability. If the network is reachable, the operation will execute immediately, if not, it will register a Reachability observer to execute the operation when the network is available. Unlike the `ReachabilityCondition` which will fail if a host is not available, use `ReachableOperation` to perform network related tasks which must be executed regardless.\n\n\n# 0.5.0\n1. [[OPR-22](https://github.com/danthorpe/Operations/pull/22)]: Supports displaying a `UIAlertController` as a `AlertOperation`.\n2. [[OPR-26](https://github.com/danthorpe/Operations/pull/26)]: Adds a Block Condition. This allows an operation to only execute if a block evaluates true.\n3. [[OPR-27](https://github.com/danthorpe/Operations/pull/27)]: Fixes a bug where the `produceOperation` function was not publicly accessible. Thanks - @MattKiazyk\n4. [[OPR-28](https://github.com/danthorpe/Operations/pull/28)]: Supports a generic `Operation` subclass which wraps a `CKDatabaseOperation` setting the provided `CKDatabase`.\n5. [[OPR-29](https://github.com/danthorpe/Operations/pull/29)]: Improves the `CloudCondition.Error` to include `.NotAuthenticated` for when the user is not signed into iCloud.\n\n\n# 0.4.2 - Initial Release of Operations.\nBase `Operation` and `OperationQueue` classes, with the following features.\n\nThe project has been developed using Xcode 7 and Swift 2.0, with  unit testing (~ 75% test coverage). It has now been back-ported to Swift 1.2 for version 1.0 of the framework. Version 2.0 will support Swift 2.0 features, including iOS 9 technologies such as Contacts framework etc.\n\n1. Operation types:\n1.1. `BlockOperation`: run a block inside an operation, taking advantage of Operation features.\n1.2. `GroupOperation`: compose one more operations into a group.\n1.3. `DelayOperation`: delay execution of operations on the queue.\n\n2. Conditions\nConditions can be attached to `Operation`s, and optionally introduce new `NSOperation` instances to overcome the condition requirements. E.g. presenting a permission dialog. The following conditions are currently supported:\n2.1. `MutuallyExclusive`: for exclusivity of a given kind, e.g. to prevent system alerts presenting at the same time.\n2.2. `ReachabilityCondition`: only execute tasks when the device is online.\n2.3. `CloudCondition`: authorised access to a CloudKit container. \n\n3. Observers\nObservers can be attached to `Operation`s, and respond to events such as the operation starting, finishing etc. Currently observer types are:\n3.1. `BackgroundObserver`: when the app enters the background, a background task will automatically be started, and ended when the operation ends.\n3.2. `BlockObserver`: run arbitrary blocks when events occur on the observed operation.\n3.3. `NetworkObserver`: updates the status of the network indicator.\n3.4. `TimeoutObserver`: trigger functionality if the operation does not complete within a given time interval.\n\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment include:\n\n* Using welcoming and inclusive language\n* Being respectful of differing viewpoints and experiences\n* Gracefully accepting constructive criticism\n* Focusing on what is best for the community\n* Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n* The use of sexualized language or imagery and unwelcome sexual attention or advances\n* Trolling, insulting/derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or electronic address, without explicit permission\n* Other conduct which could reasonably be considered inappropriate in a professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at hello@procedure.kit.run. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]\n\n[homepage]: http://contributor-covenant.org\n[version]: http://contributor-covenant.org/version/1/4/\n"
  },
  {
    "path": "Documentation/Guides/Advanced Topics/Advanced Result Injection.md",
    "content": "# Advanced Result Injection\n\n- Remark: Functional state transformation\n\nIn [Result Injection](result-injection.html) we introduced the basic concept of _transforming state_ by chaining procedures together. Each link in the chain received an input, and is responsible for settings its output. The `injectResult(from:)` API then glues everything together. \n\nThis works very nicely at a simple level, however it is a bit restrictive when it comes to real world usage. While we firmly advocate writing small single purpose procedures, chaining these together can result in code which is a little _ungaily_. What to do...\n\n## Binding\n\nTypically, the scenario described above would be encapsulated in a [`GroupProcedure`](Classes\\/GroupProcedure.html). However, the initial `Input` property, and final `Output` property should then be exposed at the group level. This requires the group's `input` property to be set on the first child procedure, and to observe the last procedure in the chain to extract it's `output` property.\n\nThis can be quite frustrating to write more than once, but luckily there are helper APIs for this called `bind(to:)` and `bind(from:)`.\n\n```swift\nclass MyGroup: TestGroupProcedure, InputProcedure, OutputProcedure {\n\n    var input: Pending<Foo> = .pending\n    \n    var output: Pending<ProcedureResult<Bar>> = .pending\n\n    init() {\n\n        let stage1 = TransformProcedure<Foo,Baz> { /* etc */ }\n\n\t\tlet stage2 = TransformProcedure<Baz,Bat> { /* etc */ }\n\t\t    .injectResult(from: stage1)\n\n\t\tlet stage3 = TransformProcedure<Bat,Bar> { /* etc */ }\n\t\t    .injectResult(from: stage2)\n\n\t\tsuper.init(operations: [stage1, stage2, stage3])\n\n\t\t// Bind the group's input property to the first procedure\n\t\tbind(to: stage1)\n\n\t\t// Bind the group's output property from the last procedure\t\t\n\t\tbind(from: stage3)\n\t}\n}\n```\n\nThese two APIs will automatically add appropriate observers to the procedures to ensure that the `input` property is set when the receiver's `input` property is set via the `injectResult(from:)` API.\n\nNote that if the `input` property is set manually, the observers will not fire and so the binding will not work. Consider the above class:\n\n```swift\nlet foo = ResultProcedure { Foo() } // This is a procedure which creates a Foo output\n\nlet myGroup = MyGroup() // This expects to be injected with a Foo value\n\nmyGroup.injectResult(from: foo) // This does the injection, and triggers the binding.\n\nqueue.add(operations: foo, myGroup)\n\nmyGroup.addDidFinishBlockObserver { (group, _, _) in \n    // group output will now be set\n}\n```\n\n\n"
  },
  {
    "path": "Documentation/Guides/Advanced Topics/Mutual Exclusion.md",
    "content": "# Mutual Exclusion\n\n- Remark: Makes Procedures exclusive\n\n\nA [`Condition`](Classes\\/Condition.html) can assert whether its Procedure should be evaluated exclusively with respect to other Procedures. This can be very handy for preventing Procedures from executing at the same time.\n\nFor example, if our application presents a modal alert, by adding a mutually exclusive condition, it will prevent any other modal alert from being presented at the same time. Given the nature of event based applications this would otherwise be quite tricky. We would write this:\n\n```swift\nimport ProcedureKitMobile\n\nlet alert = AlertProcedure(presentAlertFrom: viewController)\nalert.title = NSLocalizedString(\"Hello World\", comment: \"Hello World\")\nqueue.addOperation(alert)\n```\n\n`AlertProcedure` adds a mutually exclusive condition to itself during its initializer.\n\n- Note: Mutual exclusion does not stop subsequent Procedures from ever running. The Procedure will run once the mutually-exclusive blocking Procedure in front of it finishes.\n\n## Implementation\n\nTo add mutual exclusion to an operation, we attach a [`MutuallyExclusive<T>()`](Classes\\/MutuallyExclusive.html) condition, in the case of `AlertProcedure` it is implemented like this:\n\n```swift\nprocedure.add(condition: MutuallyExclusive<UIAlertController>())\n```\n\nwhich means that any subsequent procedure which is also mutually exclusive with `UIAlertController` will wait until the current one has finished.\n\nThis generic type, let call it the _mutual exclusion type_ has no constraints: it can be anything.\n\n### How to choose the mutual exclusion type?\n\nIf it is only necessary to restrict the same type of Procedure from executing then use the Procedure's own class, or parent class, as the type.\n\nTo share mutual exclusion between a number of different Procedure, either create an empty `enum` which will be used to define the mutual exclusion. Name it based on the category of procedure, for example:\n\n```swift\npublic enum CoreDataWork { }\n```\n\nThen in the procedure, add a condition for mutual exclusion:\n\n```swift\nprocedure.add(condition: MutuallyExclusive<CoreDataWork>())\n```\n\n## Using the `category` string\n\nThe _mutual exclusion type_ is a convenience to add some strong typing to `MutualExclusion`. However if using `String` categories names is easier, that works too:\n\n```swift\nprocedure.add(condition: MutuallyExclusive<Void>(category: \"mutually exclusive key\")\n```\n\nobviously we would recommend using static constants for these, or `String` backed `enum` types.\n"
  },
  {
    "path": "Documentation/Guides/Basic Features/Conditions.md",
    "content": "# Conditions\n\n- Remark: Conditions (can) prevent procedures from starting\n\n\nConditions are types which can be attached to a [Procedure](Classes\\/Procedure.html), and multiple conditions can be attached to the same Procedure. Before the Procedure executes, it asynchronously _evaluates_ all of its conditions. If any condition fails, the procedure is canceled with an error instead of executing.\n\nThis is very useful as it allows us to abstract the control logic of whether a procedure should be executed or not into a decoupled unit. This is a key idea behind _ProcedureKit_: that procedures are units of work, and conditions are the business logic which executes them or not.\n\nAdding a condition is easy:\n\n```swift\nprocedure.add(condition: BlockCondition {\n    // procedure will cancel instead of executing if this is false\n    return trueOrFalse\n})\n```\n\n## Scheduling\n\nConditions are evaluated after all of the procedure's direct dependencies have finished. What does this mean? Consider the following code:\n\n```swift\n// Create some simple procedures\nlet global = BlockProcedure { print(\" World\") }\nlet local = BlockProcedure { print(\" Dan\") }\n\n// Add a dependency\nlet greeting = BlockProcedure { print(\"Hello\") }\n\n// Add a dependency directly to the procedure\nglobal.add(dependency: greeting)\nlocal.add(dependency: greeting)\n\n// Add some conditions\nglobal.add(condition: BlockCondition { showGlobalGreeting }) // assume we have a Bool\nlocal.add(condition: BlockCondition { !showGlobalGreeting })\n\nqueue.add(operations: global, local, greeting)\n```\n\nIf we forgive the contrived nature of the example, if the variable `showGlobalGreeting` is true, we'll have this output:\n\n> Hello World\n\nand for a false value:\n\n> Hello Dan\n\nThe key point is that the greeting procedure, which is added a dependency executes first, and then the condition (and all other conditions) is evaluated.\n\n_ProcedureKit_ has several built-in Conditions, like `BlockCondition` and [`MutuallyExclusive<T>`](Classes\\/MutuallyExclusive.html). It is also easy to implement your own.\n\n## Implementing a custom Condition\n\nFirst, subclass [`Condition`](Classes\\/Condition.html). Then, override `evaluate(procedure:completion:)`. Here is a simple example of [`FalseCondition`](Classes\\/FalseCondition.html) which is part of the framework:\n\n```swift\nclass FalseCondition: Condition {\n     override func evaluate(procedure: Procedure, completion: @escaping (ConditionResult) -> Void) {\n        completion(.failure(ProcedureKitError.FalseCondition()))\n     }\n}\n```\n\nThis method receives the procedure instance which the condition has been attached to, and should called the (escaping) completion handler with the result. This means that it is possible to evaluate the condition asynchronously. The result of the evaluation is a [`ConditionResult`](Other%20Typealiases.html#\\/s:12ProcedureKit15ConditionResult), which is a typealias for `ProcedureResult<Bool>`.\n\n### Calling the completion block\n\n- Important:\nYour `evaluate(procedure:completion:)` override **must** eventually call the completion block with a [`ConditionResult`](Other%20Typealiases.html#\\/s:12ProcedureKit15ConditionResult). (Although it may, of course, be called asynchronously.)\n\n[`ConditionResult`](Other%20Typealiases.html#\\/s:12ProcedureKit15ConditionResult) encompasses 3 states:\n1. `.success(true)`, the \"successful\" result\n2. `.failure(let error: Error)`, the \"failure\" result\n3. `.success(false)`, an \"ignored\" result\n\n\nGenerally:\n - If a Condition *succeeds*, return `.success(true)`.\n - If a Condition *fails*, return `.failure(error)` with a unique error defined for your Condition.\n\n In some situations, it can be beneficial for a Procedure to not collect an\n error if an attached condition fails. You can use [`IgnoredCondition`](Classes\\/IgnoredCondition.html) to\n suppress the error associated with any Condition. This is generally\n preferred (greater utility, flexibility) to returning `.success(false)` directly.\n\n## Indirect Dependencies\n\n[`Condition`](Classes\\/Condition.html), while not an `Operation` or `Procedure` subclass, supports the concept of producing dependencies using the API: `produce(dependency:)`. This should be called during the initializer of the condition. These dependencies can be `Operation` instances. They allow conditions to create an operation which runs _after_ the procedure's direct dependencies, but before the conditions are evaluated. We'll cover this topic more in [Advanced Conditions](Advanced-Conditions.html) and [Capabilities](Capabilities.html).\n"
  },
  {
    "path": "Documentation/Guides/Basic Features/Groups.md",
    "content": "# Groups\n\n- Remark: Groups encapsulate Procedures into a single logic unit\n\n\n_ProcedureKit_ makes it easy to decompose significant work into smaller chunks of work which can be combined together. This is always a good architectural practice, as it will reduce the impact of each component and increase their re-use and testability. However, it can be unwieldy and diminish code readability.\n\nTherefore we can create more abstract notions of _work_ by using a [`GroupProcedure`](Classes\\/GroupProcedure.html).\n\n## Direct usage\n\n[`GroupProcedure`](Classes\\/GroupProcedure.html) can be used directly.\n\n```swift\nlet group = GroupProcedure(operations: opOne, opTwo, opThree)\ngroup.addDidFinishBlockObserver { (group, errors)  in\n    // The group has finished, meaning all child operations \n    // have finished. From here you can access them.\n    print(\"children: \\(group.children)\")\n}\nqueue.add(operation: group)\n```\n\nThere are a couple of key points here.\n\n1. Child operations need only be [`Foundation.Operation`](https://developer.apple.com/documentation/foundation/operation) instances, not necessarily [`Procedure`](Classes\\/Procedure.html) subclasses. So, a group can be used with Apple's `Operation` subclasses or from elsewhere.\n\n2. The operation instances added to the group are referred to as its children, and can be accessed via its [`.children`](Classes\\/GroupProcedure.html#\\/s:vC12ProcedureKit14GroupProcedure8childrenGSaCSo9Operation_) property.\n\n3. A [`GroupProcedure`](Classes\\/GroupProcedure.html) runs until its last child finishes. This means, that it is possible to add additional children while it is running.\n    ```swift\n    group.add(child: opFour)\n    group.add(children: [opFive, opSix])\n    ```\n    This is also a crucial detail, and is used for a host of features which `GroupProcedure` enables.\n\n## Custom `GroupProcedure`\n\nWhile using a [`GroupProcedure`](Classes\\/GroupProcedure.html) directly is convenient, it doesn't really help to create a larger abstraction of work around the children. For example, consider authenticating a user with a webservice - it is likely that we will need: network requests, possibly some data parsing and mapping, and possibly writing to disks or caches. All of these tasks should be [`Procedure`](Classes\\/Procedure.html) subclasses, but when encapsulated together, its just a `LoginProcedure`. The group _hides_ all the detail. Therefore, most of the time, we want to subclass [`GroupProcedure`](Classes\\/GroupProcedure.html), which is the focus of this guide.  \n\n## The initialiser\n\nIf all the child operations are known at compile time they can be configured during initialization. Configuration would be things such as setting dependencies, observers, conditions.\n\n```swift\nclass LoginProcedure: GroupProcedure {\n\n    // Nested class definitions to help componentize Login\n    class PersistLoginInfo: Operation { /* etc */ }\n    class LoginSessionTask: NSURLSessionTask { /* etc */ }\n    \n    init(credentials: Credentials /* etc, inject known dependencies */) {\n\n        // Create the child operations\n        let persist = PersistLoginInfo(credentials)\n        let login = URLSessionTaskOperation(task: LoginSessionTask(credentials))\n        \n        // Do any configuration or setup\n        persist.addDependency(login)\n        \n        // Call the super initializer with the operations\n        super.init(operations: [persist, login])\n        \n        // Configure any properties, such as name.\n        name = \"Login\"\n        \n        // Add observers, conditions etc to the group\n        add(observer: NetworkObserver())\n        add(condition: MutualExclusive<LoginProcedure>())\n    }\n}\n```\n\nThe initialization strategy shown above is relatively simple but shows some good practices. Creating and configuring child operations before calling the `LoginProcedure` initialiser reduces the complexity and increases the readability of the class. Adding observers and conditions to the group inside its initialiser sets the default and expected behaviour which makes using the class easier. Remember that these can always be nullified by using [`ComposedProcedure`](Classes\\/ComposedProcedure.html).\n\n## Adding child operations later\n\nIn some cases, the results of one child are needed by a subsequent child. We cover techniques to achieve this in [Result Injection](result-injection.html) which still applies here. However, this doesn't cover a critical scenario which is branching. A common usage might be to perform either operation `Bar` or `Baz` depending on `Foo`, which cannot be setup during initialisation.\n\n```swift\nclass FooBarBazProcedure: GroupProcedure {\n    /* etc */\n\n    override func child(_ child: Procedure, willFinishWithErrors errors: [ErrorType]) {\n        super.child(child: willFinishWithErrors: errors)    \n        guard !isCancelled else { return }\n        if errors.isEmpty, let foo = child as? FooProcedure {\n           if foo.doBaz {\n              add(child: BazProcedure())\n           }\n           else {\n              add(child: BarProcedure())\n           }\n        }\n    }\n}\n```\n\nThe above function exists primarily to allow subclasses to perform actions when each child operation finishes.  Therefore a standard operation should:\n\n1. Call the `super` implementation.\n2. Check that the group has not been cancelled\n3. Inspect and handle any errors\n4. Test the received operation to check that it is the expected instance. For example, optionally cast it to the expected type, and if possible check if it is equal to a stored property of the group.\n5. Call `add(child:)` or `add(children:)` to add more operations to the queue.\n\nUsing this technique the group will keep executing and only finish until all children, including ones added after the group started, have finished.\n\n## Cancelling\n\n[`GroupProcedure`](Classes\\/GroupProcedure.html) itself already responds to cancellation correctly: Its behaviour is to call `cancel()` on all of its children and wait for them to finish before it finishes.\n\nHowever, sometimes additional behavior is warranted. Consider operations that are injected into a [`GroupProcedure`](Classes\\/GroupProcedure.html). By definition, these are exposed outside the group, and in some scenarios may be cancelled by external factors. For example, a network procedure that is injected may be cancelled by the user or system. In a scenario such as this, it often makes sense for a cancelled child to result in the entire group being cancelled.\n\nTherefore, a good practice when subclassing [`GroupProcedure`](Classes\\/GroupProcedure.html) is to add *DidCancel* observers to injected operations. Lets modify our `LoginProcedure` to inject the network session task:\n\n```swift\n// Lets assume we have a network procedure\nclass LoginSessionTask: MyNetworkingProcedure { /* etc */ }\n\nclass LoginProcedure: GroupProcedure {\n\n    class PersistLoginInfo: Procedure { /* etc */ }\n    \n    let task: MyNetworkingProcedure\n    \n    init(credentials: Credentials, task: MyNetworkingProcedure) {\n        self.task = task\n        \n        // Create the child operations\n        let persist = PersistLoginInfo(credentials)\n\n        // Do any configuration or setup\n        persist.add(dependency: task)\n\n        // Call the super initializer with the operations\n        super.init(operations: [persist, login])\n        \n        // Configure any properties, such as name.\n        name = \"Login\"\n        \n        // Add observers, conditions etc to the group\n        add(observer: NetworkObserver())\n        add(condition: MutualExclusive<LoginProcedure>())\n \n        // Add cancellation observer to injected procedures\n        task.addDidCancelBlockObserver { [weak self] (task, errors) in \n            self?.cancel()\n        }\n    }       \n}\n``` \n\n- Important:\nSometimes it is necessary to perform such configuration (which references `self`) after the initializer has finished. For these situations, override `execute` but *always* call `super.execute()`. This is because the [`GroupProcedure`](Classes\\/GroupProcedure.html) has critical functionality in its `execute` implementation (such as starting the queue).\n\nWe will cover move advanced usage of [`GroupProcedure`](Classes\\/GroupProcedure.html) in [Advanced Groups](advanced-groups.html). Also, see [`ComposedProcedure`](Classes\\/ComposedProcedure.html) on how to wrap an `Operation` class, to be able to add observers.\n"
  },
  {
    "path": "Documentation/Guides/Basic Features/Observers.md",
    "content": "# Observers\n\n- Remark: Observers watch procedures, and handle events\n\n\nWhen a [Procedure](Classes\\/Procedure.html) is added to a [queue](Classes\\/ProcedureQueue.html), it moves through its own internal state, as discussed in [Scheduling](Classes\\Scheduling.html). Key transitions between these states are referred to as events, and each state transition can be observed.\n\nObservers are attached to the procedure. When an event occurs, the method equivalent to the state transition will be invoked. The [ProcedureObserver protocol](Protocols\\/ProcedureObserver.html) defines all the methods, and there are empty default implementations provided. This is because typically an observer is only for a particular transition, such as the procedure cancelling or finishing.\n\n## Possible Observers\n\n| Method   | Event Description |\n|----------------|:--------------------------:|\n| `didAttach(to:)` | When the observer is attached to a procedure. |\n| `did(execute:)`  | After the procedure calls its `execute` method. |\n| `did(cancel:withErrors:)`  | After the procedure cancels. |\n| `procedure(_:willAdd:)`  | When the procedure will spawn a new `Operation`. |\n| `procedure(_:didAdd:)`  | After the procedure did spawn a new `Operation`. |\n| `will(finish:withErrors:pendingFinish:)`  | When the procedure will finish. |\n| `did(finish:withErrors:)`  | After the procedure did finish. |\n\n\n## \"Will\" vs. \"Did\" Observers:\n\nIt is important to understand the purpose of both common observer prefixes, and the guarantees that the ProcedureKit framework makes:\n\n- Will(X) observers are called **before an event occurs**.\n\n> Examples:\n\n> All \"WillFinish\" observers are called before the Procedure's internal state transitions to finished.\n\n- Did(X) observers are called **at some point after an event occurs**.\n\n> Example:\n\n> All \"DidExecute\" observers are called after the Procedure's `execute()` function returns.\n\n> However, other observers may be called *prior* to the \"DidExecute\" observer (depending on the order that events occur).\n\n### Observers and Thread-safety:\n\n- Important: An observer will never be called concurrently with other Procedure events (or observers) generated by a Procedure.\n\nIf you register multiple observers (for example: a DidExecute observer and a DidFinish observer) on a Procedure, they will not be called concurrently.\n\n**However**, no such guarantee is made between Procedures. Hence, if you register an observer on `ProcedureA` and an observer on `ProcedureB`, both observers access/modify the same data, and both Procedures may execute concurrently, you should ensure that those accesses are thread-safe or support concurrency. (Or in other words, avoid shared state without the appropriate locking mechanisms)"
  },
  {
    "path": "Documentation/Guides/Basic Features/Result Injection.md",
    "content": "# Result Injection\n\n- Remark: Transforming state through procedures\n\nUp until now procedures have been discussed as isolated units of work, albeit with scheduling thanks to dependencies. In practice, this is rather limiting. If a procedure has a dependency, then it's likely the result of the dependency is needed for the waiting procedure.\n\nIn software engineering this is known as [dependency injection](https://en.wikipedia.org/wiki/Dependency_injection), but we wish to avoid this term to avoid confusion the operational dependencies.\n\n## Synchronous & literal requirements\n\nIf the requirement for a procedure is available synchronously, or perhaps as a literal value, then it can be inject into the procedure's initialiser. This is following best practices for object orientated programming.\n\n## Asynchronous input\n\nWhen the requirements needed for a procedure are not available when the instance is created, it must be injected sometime later - but _before the procedure executes_.\n\nConsider a `DataProcessing` procedure class. Its job is to process `Data`, which we refer to as its _input_. However, lets assume that the data in question must be retrieved from storage, or the network. For this, there is a `DataFetch` procedure. In this context, the `Data` is its _output_.\n\nLets look at some code:\n\n```swift\nclass DataFetch: Procedure, OutputProcedure {\n\n    private(set) var output: Pending<ProcedureResult<Data>> = .pending\n    \n    override func execute() {\n        fetchDataAsynchronouslyFromTheNetwork { data in \n            output = .ready(.success(data))\n            finish()\n        }\n    }\n}\n```\n\nAbove is a `DataFetch` example. It conforms to the `OutputProcedure` protocol, which requires the `output` property. This is a generic property with no contraint on `Output`, its associatedtype. \n\n## Asynchronous output\n\nFor a data processing class example:\n\n```swift\nclass DataProcessing: Procedure, InputProcedure, OutputProcedure {\n\n    var input: Pending<Data> = .pending\n    var ouptut: Pending<ProcedureResult<Data>> = .pending\n    \n    override func execute() {\n        guard let data = input.value else { return }\n        process(data: data) { processed in \n            output = .ready(.success(processed))\n            finish()\n        }\n    }\n}\n```\n\nThe above shows a `DataProcessing` class. Here it conforms to `InputProcedure` which defines its `input` property, which is also a generic property with no constraints. In this case, it also conforms to `OutputProcedure`.\n\n## Transforming state through procedures\n\nPutting these ideas together allows us to chain procedures together, essentially mutating state through the procedures. Something like this:\n\n```swift\nlet fetch = DataFetch()\nlet processing = DataProcessing()\nprocessing.injectResult(from: fetch)\n``` \n\nFirstly, the `injectResult(from:)` API is defined in a public extension on `InputProcedure`. But, what does it do?\n\n1. The data fetch procedure is automatically added as a dependency of the processing procedure.\n2. A _will finish_ block observer is added to the dependency to take its output, and set it as the processing procedure's input. This happens before the data fetch procedure finishes, and therefore before the processing procedure becomes ready.\n\n- Note:\nThere is a constraint on `injectResult(from:)` where the dependency, which conforms to `OutputProcedure`, has an `Output` type which is equal to the `InputProcedure`'s `Input` type. Essentially, input has to equal output.\n\n## What about errors?\n\nIf the dependency (the `DataFetch` procedure in this example) is cancelled with an error, the _dependent_ procedure (`DataProcessing` in this example) is automatically cancelled with a `ProcedureKitError`.\n\nIf the dependency finishes with errors, likewise, the dependent is cancelled with an appropriate error.\n\nIf the dependency finishes without a `.ready` output value, the dependent is cancelled with an appropriate error.\n\nif the dependency finishes with an error, the dependency is cancelled with an appropriate error.\n\n"
  },
  {
    "path": "Documentation/Guides/Cancellation/Handling Cancellation.md",
    "content": "# Understanding Cancellation\n\n- Remark: When and how do we respond to cancellation\n\n\nIn _ProcedureKit_, [`Procedure`](Classes/Procedure.html) follows the policy of cancellation that Apple use in Foundation for [`Operation`](https://developer.apple.com/documentation/foundation/operation). There is a [`cancel()`](Classes/Procedure.html#/s:FC12ProcedureKit9Procedure6cancelFT_T_) method which sets [`isCancelled`](Classes/Procedure.html#/s:vC12ProcedureKit9Procedure11isCancelledSb) to be `true`. That is all.\n\nBefore we get into the details of cancellation, it is helpful to clarify some assumptions about usage.\n\n## Who calls `cancel()`?\n\nIn general, [`Procedure`](Classes/Procedure.html) instances should not call [`cancel()`](Classes/Procedure.html#/s:FC12ProcedureKit9Procedure6cancelFT_T_) on themselves. Instead, other code will cancel a procedure. Lets think of some examples:\n\n1. The user taps \"Cancel\" on a button.\n    In this scenario, a controller will likely respond or react to that button press, and invoke `cancel()` on the procedure doing any work, such as a network request or data processing.\n    \n2. An iOS application is sent to the background.\n    Potentially here, the app delegate may signal to any running procedures to `cancel()`.\n    \n3. A [`Procedure`](Classes/Procedure.html)'s dependency finishes with errors.\n    In this scenario, a procedure is waiting for the results of another procedure. However, if the dependency finishes unsuccessfully, the waiting procedure aught to be cancelled. This is likely done from within a *DidCancelObserver* which will call [`cancel(withError:)`](Classes/Procedure.html#/s:FC12ProcedureKit9Procedure6cancelFT10withErrorsGSaPs5Error___T_) on the waiting procedure. The framework does this automatically with the [`injectResult(from:)`](Protocols/InputProcedure.html) APIs.\n    \nIn all of these example, `cancel()` is invoked on the procedure from outside. In all situations, the [`Procedure`](Classes/Procedure.html) needs to ensure that it _handles_ cancellation correctly.\n\n## Handling Cancellation\n\nOnce a procedure is cancelled, it must move to the finished state. \n\n- Important:\nIt is the responsibility of the [`Procedure`](Classes/Procedure.html) subclass to cancel its work and move to the finished state as soon as is practical once cancelled.\n\nWe call handling cancellation and moving to the finished state quickly once cancelled being *responsive to cancellation*.\n\nBuilt-in [`Procedure`](Classes/Procedure.html) subclasses in the framework are already responsive. For example:\n\n1. [`GroupProcedure`](Classes/GroupProcedure.html) will cancel its children. It finishes after all of its children have finished. It also prevents new children from being added after cancelled.\n2. [`DelayProcedure`](Classes/DelayProcedure.html) immediately finishes when cancelled.\n\nIf you want your custom [`Procedure`](Classes/Procedure.html) subclass to response to cancellation (i.e. finish early when it is cancelled) you *must* do some additional work.\n\n### When _ProcedureKit_ handles cancellation for you\n\n- When using built-in procedures, such as [`GroupProcedure`](Classes/GroupProcedure.html).\n- By default, when a custom [`Procedure`](Classes/Procedure.html) subclass is cancelled _before it has begun executing_ (i.e. before your `execute()` method is called).\n\n### When you need to handle Cancellation\n\n- When you need to take any additional steps to properly cancel the underlying work of your procedure. For example, if wrapping another asynchronous task in a [`Procedure`](Classes/Procedure.html).\n- Inside your `execute()` method. Periodically, if possible, check to see if the procedure has been cancelled. How?\n\n    ```swift  \n    override func execute() {\n\n\t\t// Just an example\n        doStepOne()\n\n\t\t// You probably wouldn't ever do this really\n        doStepTwo()\n        \n        finish()\n    }\n    \n    private func doStepOne() {\n        guard !isCancelled else { return }    \n        \n        // etc\n    }\n    \n    private func doStepTwo() {\n        guard !isCancelled else { return }    \n        \n        // etc\n    }\n    \n    ````\n\n## Sequence of events during Cancellation\n\nWhen a [`Procedure`](Classes/Procedure.html) is cancelled, the following order of events happen:\n\n1. *[`isCancelled`](Classes/Procedure.html#/s:vC12ProcedureKit9Procedure11isCancelledSb)* is set to *`true`*\n\n2. *[`procedureDidCancel(withErrors:)`](Classes/Procedure.html#/s:FC12ProcedureKit9Procedure18procedureDidCancelFT10withErrorsGSaPs5Error___T_)* is called (can be overridden)\n\n3. *[`DidCancelObserver`](Structs/DidCancelObserver.html)* instances are called.\n\n## You can handle cancellation by any combination of:\n\n1. Checking [`isCancelled`](Classes/Procedure.html#/s:vC12ProcedureKit9Procedure11isCancelledSb) as in the example above.\n\n2. Override [`procedureDidCancel(withErrors:)`](Classes/Procedure.html#/s:FC12ProcedureKit9Procedure18procedureDidCancelFT10withErrorsGSaPs5Error___T_).\n    While the [`Procedure`](Classes/Procedure.html) implementation of this method is empty, it is best practice to call `super.procedureDidCancel(withErrors:)` at the beginning of your override.\n    \n3. Attach [`DidCancelObserver`](Structs/DidCancelObserver.html) instances. This is the only mechanism to observe cancellation from outside the instance. For example:\n    ```swift\n    let procedure = MyProcedure() // etc\n    \n    procedure.addDidCancelBlockObserver { (procedure, errors) in\n        // inspect the errors possibly.\n    }\n    ````\n    \nGenerally, the method you choose will depend on the type of [`Procedure`](Classes/Procedure.html), and what is required if a procedure is cancelled.\n\n## Next steps\n\n- [Synchronous Procedures](cancelling-in-synchronous-procedures.html)\n- [Asynchronous Procedures](cancelling-in-asynchronous-procedures.html)\n"
  },
  {
    "path": "Documentation/Guides/Cancellation/In Asynchronous Procedures.md",
    "content": "# Handling Cancellation in Asynchronous Procedures\n\n\nAn *Asynchronous* [`Procedure`](Classes/Procedure.html) may return from its `execute()` method without _finishing_, and then call `finish()` some time later. Typically this happens in a completion block of another asynchronous API.\n\nFor example, consider this simplified version of [`DelayProcedure`](Classes/DelayProcedure.html) from the framework:\n\n```swift\n// NOTE: Do not use this code. It is not responsive to cancellation. It is\n// intended as an example of what not-to-do. Use DelayProcedure if you need\n// a delay.\n\nclass BadOneMinuteDelay: Procedure {\n\n    var timer: DispatchSourceTimer? = nil\n    \n    over func execute() {\n        timer = DispatchSource.makeTimerSource(flags: [], queue: .default)\n        timer?.setEventHandler { [weak self] in \n            guard let strongSelf = self else { return }\n            strongSelf.finish()\n        }\n        timer?.scheduleOneshot(deadline: now() + .seconds(60))\n        timer?.resume()\n    }\n}\n```\n\nA `BadOneMinuteDelay` instance will wait for 60 seconds and then finishes, by calling `finish()` from inside the event handler block of a dispatch source timer.\n\n- Note:\nThe event handle code above shows the best-practice of capturing self as a `weak` reference. It is not necessarily guaranteed that the `Procedure` will not have been deallocated when the closure is invoked, so it is recommended to use `weak` instead of `unowned` in this situation.\n\nThe `BadOneMinuteDelay` can be cancelled, but it does not *_respond_* to cancellation. If it is cancelled after it has begun executing, it will only finish when the timer fires.\n\nTo respond to cancellation, we need to do two things:\n\n1. Intercept the *DidCancel* event.\n2. Cancel the timer and finish the procedure.\n\nTo intercept the *DidCancel* event in an asynchronous procedure we can either override the  *`procedureDidCancel(withErrors:)`* method, or add an observer which is shown below.\n\n```swift\n// NOTE: This is a limited example of handling cancellation.\n// Use `DelayProcedure` if you need a delay.\nclass BetterOneMinuteDelay: Procedure {\n\n    var timer: DispatchSourceTimer? = nil\n    \n    override init() {\n        super.init()\n        addDidCancelBlockObserver { procedure, _ in\n            procedure.timer?.cancel()\n            // since cancelling the timer prevents it from calling its event handler\n            // this will prevent the Procedure from finishing\n            // thus, we must call finish() after we've cancelled the timer\n            // to ensure that the Procedure always finishes\n            procedure.finish()\n        }\n    }\n\n    over func execute() {\n        timer = DispatchSource.makeTimerSource(flags: [], queue: .default)\n        timer?.setEventHandler { [weak self] in \n            guard let strongSelf = self else { return }\n            strongSelf.finish()\n        }\n        timer?.scheduleOneshot(deadline: now() + .seconds(60))\n        timer?.resume()\n    }\n}\n```\n\nThe `BetterOneMinuteDelay` class adds a block based observer for *DidCancel* event to be invoked when it is cancelled. In the block, it:\n\n1. Cancels the procedure's own timer.\n2. Explicitly calls `finish()` (since we've cancelled the timer)\n\nNote also that the observer block is provided with an instance of the procedure - we don't need to capture `self` here.\n\n### Add an observer vs override `procedureDidCancel(withErrors:)`?\n\nThe main differences between these two options are..\n\n1. A `Procedure` can have multiple did cancel observers.\n2. Observers are added to specific instances (vs behaviour for an entire class)\n3. A slight difference in the order they are called. The `procedureDidCancel(withErrors:)` method is always invoked before all of the observers.\n4. Observers cannot be removed / overridden / usurped by a subclass.\n\nIt is that last point, which is primarily why observers are used throughout this framework, and for open classes, we recommend choosing to use an observer. However, for final classes, it is more efficient to implement an override of `procedureDidCancel(withErrors:)`.\n"
  },
  {
    "path": "Documentation/Guides/Cancellation/In Synchronous Procedures.md",
    "content": "# Handling Cancellation in Synchronous Procedures\n\n\nA _synchronous_ [`Procedure`](Classes/Procedure.html) performs all its work as part of its [`execute()`](Classes/Procedure.html#/s:FC12ProcedureKit9Procedure7executeFT_T_) method, and calls [`finish()`](Classes/Procedure.html#/s:FC12ProcedureKit9Procedure6finishFT10withErrorsGSaPs5Error___T_) before returning.\n\n- Note: 💡 Synchronous procedures are great candidates for the use of occasional [`!isCancelled`](Classes/Procedure.html#/s:vC12ProcedureKit9Procedure11isCancelledSb) checks.\n\nFor example, consider the following example `BadFibonacci`, which shows an *anti-pattern* which generates a sequence and feeds them to a block:\n\n```swift\n// NOTE: Do not use this code. It is not responsive to cancellation.\n\nclass BadFibonacci: Procedure {\n\n    let count: Int\n    let block: (Int) -> Void\n    \n    init(count: Int = 10, block: @escaping (Int) -> Void) {\n        self.count = count\n        self.block = block\n        super.init()\n        name = \"Bad Fibonacci\"\n    }\n    \n    override func execute() {\n        guard count > 0 else { finish(); return }\n        block(0)\n        var result = 0\n        var prevResult = 1\n        for _ in 1..<count {\n            let nextResult = prevResult + result\n            prevResult = result\n            result = nextResult\n            block(nextResult)\n        }\n        finish()\n    }\n}\n``` \n\nAn instance of `BadFibonacci` can be cancelled, but it does not *_respond_* to cancellation. It will have no impact if cancelled while running. To make it respond, we need to modify the loop to periodically check [`isCancelled`](Classes/Procedure.html#/s:vC12ProcedureKit9Procedure11isCancelledSb).\n\n```swift\nclass BetterFibonacci: Procedure {\n\n    let count: Int\n    let block: (Int) -> Void\n    \n    init(count: Int = 10, block: @escaping (Int) -> Void) {\n        self.count = count\n        self.block = block\n        super.init()\n        name = \"Bad Fibonacci\"\n    }\n\n    override func execute() {\n        guard count > 0 else { finish(); return }\n        block(0)\n        var result = 0\n        var prevResult = 1\n        for i in 1..<count {\n            if i % 2 == 0 { // no need to check `isCancelled` every time in this loop\n                guard !isCancelled else {\n                    // handle cancellation by finishing and returning immediately\n                    finish()\n                    return\n                }\n            }\n            let nextResult = prevResult + result\n            prevResult = result\n            result = nextResult\n            block(nextResult)\n        }\n        finish()\n    }\n}\n```\n\nThe `BetterFibonacci` class checks whether it has been cancelled every 2 values in the sequence. If it has, then it finishes and returns immediately.\n\n- Important:\n  You may want to consider how frequently [`isCancelled`](Classes/Procedure.html#/s:vC12ProcedureKit9Procedure11isCancelledSb) is checked, and potentially use a throttle as shown above. Consider that each check to [`isCancelled`](Classes/Procedure.html#/s:vC12ProcedureKit9Procedure11isCancelledSb) requires a lock which can impact performance.\n  \n  For tight loops, say 1000 iterations in 50ms, do not check [`isCancelled`](Classes/Procedure.html#/s:vC12ProcedureKit9Procedure11isCancelledSb) more frequently than every 1000 or even 10,000 iterations. Try to determine how quickly you want the procedure to respond to cancellation, to calibrate how frequently you check for cancellation.\n\n"
  },
  {
    "path": "Documentation/Guides/Getting Started/Dependencies.md",
    "content": "# Dependencies\n\n`Foundation.Operation` supports the concept of operations which depend on other operations finishing first. Additionally, an operation can have multiple dependencies across different queues.\n\n```swift\nlet greet = Greeter(name: \"Daniel\")\nlet welcome = ShowWelcome()\ngreet.addDependency(welcome)\nqueue.add(operations: greet, welcome)\n```\n\n### Set dependencies before adding operations to queues\n\nA great aspect of this features is that the dependency can be setup between operations in different queues. However, we recommend that if possible all operations involved in a dependency graph are added to the same queue at the same time, and that dependencies are set before operations are added to any queues.\n\n## Handling Failure\n\n`Procedure` has the concept of finishing (or cancelling) with errors, whereas `Foundation.Operation` does not, they just complete. If a procedure finishes with an error, and it is the dependency of another operation, *that operation will still execute despite this failure*. This is pretty subtle behavior, and it may change in future versions. However, there are helper methods to catch cancellations, errors and ensure dependencies succeeded which we'll get into later. But consider that before your `Procedure` subclass executes its work it is a best practice to validate assumptions using `assert` or `precondition`."
  },
  {
    "path": "Documentation/Guides/Getting Started/Installing ProcedureKit.md",
    "content": "# Installing _ProcedureKit_\n\n_ProcedureKit_ is a \"multi-module\" framework (don't bother Googling that, I just made it up). What we mean by this, is that the Xcode project has multiple targets/products each of which produces a Swift module. Some of these modules are cross-platform, others are dedicated, e.g. `ProcedureKitNetwork` vs `ProcedureKitMobile`.\n\nYou can add _ProcedureKit_ to your project, by following [Apple's guidelines](https://www.google.com/search?q=apple+docs,+add+framework+to+xcode+project) (dragging the `.xcodeproj` file into your project). Alternatively, you can use package managers as described below.\n\n## CocoaPods\n\nProcedureKit is available through [CocoaPods](https://cocoapods.org/pods/ProcedureKit). To install\nit, include it in your Podfile. Here is a full example of a cross platform application with unit test support. In this case, _ProcedureKit_ has been included via submodules.\n\n```ruby\ntarget 'MyApp' do\n  platform :osx, '10.11'\n\n  use_frameworks!\n\n  # This subspec includes all the cross-platform modules\n  # including networking, location & cloudkit\n  pod 'ProcedureKit/All', :path => 'submodules/ProcedureKit'\n\n  target 'TryProcedureKitTests' do\n    inherit! :search_paths\n    # This pod provides test harnesses and mechanism to help\n    # write unit tests for your Procedures\n    pod 'TestingProcedureKit', :path => 'submodules/ProcedureKit'\n  end\nend\n\ntarget 'MyApp iOS' do\n  platform :ios, '10'\n  use_frameworks!\n\n  pod 'ProcedureKit/All', :path => 'submodules/ProcedureKit'\n  # This subspec is the iOS only UIKit related stuff\n  pod 'ProcedureKit/Mobile', :path => 'submodules/ProcedureKit'  \n\n  target 'TryProcedureKit iOSTests' do\n    inherit! :search_paths\n    pod 'TestingProcedureKit', :path => 'submodules/ProcedureKit'\n  end\nend\n```\n\nNow, due to the way that CocoaPods works, all code from the _ProcedureKit_ is made available under a single module name, `ProcedureKit`. This is because CocoaPods creates its own Xcode targets to add the files defined in the spec. So, your Swift files will only need to add `import ProcedureKit` even if you want to use functionality from other modules, such as  _ProcedureKitMobile_. We appreciate that this can be a bit confusing!\n\n## Carthage\n\nAdd the following line to your Cartfile:\n\n```ruby\ngithub 'ProcedureKit/ProcedureKit'\n```\n\nThen update your `Carthage` directory by running on the command line:\n\n```bash\n$ carthage bootstrap\n```\nThis will go off and build everything. It'll take a short while, definitely time for a cup of tea. When it's complete, you can drag the built frameworks to your project and embed them in the binary.\n\nWhen using Carthage, each module is separated out. So, if you want to use the networking APIs, you would add the following to your Swift file:\n\n```swift\nimport ProcedureKit\nimport ProcedureKitNetwork\n```\n\n## Swift Package Manager\n_ProcedureKit_ totally supports SPM, it's basically just like Carthage.\n"
  },
  {
    "path": "Documentation/Guides/Getting Started/MyFirstProcedure.md",
    "content": "# Creating MyFirstProcedure\n\n[`Procedure`](Classes/Procedure.html) is a [`Foundation.Operation`](https://developer.apple.com/documentation/foundation/operation) subclass. It is also an abstract class which *must* be subclassed.\n\nHere is a simple example:\n\n```swift\nimport ProcedureKit\n\nclass MyFirstProcedure: Procedure {\n    override func execute() {\n        print(\"Hello World\")\n        finish()\n    }\n}\n```\n\n## Executing\n\nTo use the procedure, we need to add it to a [`ProcedureQueue`](Classes/ProcedureQueue.html).\n\n```swift\nlet queue = ProcedureQueue()\nlet myProcedure = MyFirstProcedure()\nqueue.add(procedure: myProcedure)\n```\n\nThis is a contrived example, but the important points are:\n\n1. Subclass [`Procedure`](Classes/Procedure.html)\n2. Override `execute()`, but **do not** call `super.execute()`.\n3. Always call [`finish()`](Classes\\/Procedure.html#\\/s:FC12ProcedureKit9Procedure6finishFT10withErrorsGSaPs5Error___T_) when the work is complete. This could be done asynchronously.\n4. Add operations to instances of [`ProcedureQueue`](Classes/ProcedureQueue.html).\n\nIf the queue is not suspended, procedures will be executed as soon as they become ready and the queue has capacity.\n\n### Finishing\n\n- Important: Every Procedure **must** eventually call [`finish`](Classes\\/Procedure.html#\\/s:FC12ProcedureKit9Procedure6finishFT10withErrorsGSaPs5Error___T_).\n\nIf the procedure does not call [`finish()`](Classes\\/Procedure.html#\\/s:FC12ProcedureKit9Procedure6finishFT10withErrorsGSaPs5Error___T_) or [`finish(withErrors:)`](Classes\\/Procedure.html#\\/s:FC12ProcedureKit9Procedure6finishFT10withErrorsGSaPs5Error___T_) it will never complete. This might block a queue from executing subsequent operations. Any operations which are waiting on the stuck operation will not start.\n\n## Best Practices\n\n[`Procedure`](Classes/Procedure.html) is a class, so object orientated programming best practices apply. For example pass known dependencies into the initialiser:\n\n```swift\nclass Greeter: Procedure {\n\n    let personName: String\n    \n    init(name: String) {\n        self.personName = name\n        super.init()\n        name = \"Greeter Operation\"\n    }\n    \n    override func execute() {\n        print(\"Hello \\(personName)\")\n        finish()\n    }\n}\n```\n\n### Set the name\n\n[`Foundation.Operation`](https://developer.apple.com/documentation/foundation/operation) has a [`name`](https://developer.apple.com/documentation/foundation/operation/1416089-name) property. It can be handy to set this for debugging purposes.\n\n### Cancelling\n\n[`Procedure`](Classes/Procedure.html) will check that it has not been cancelled before it invokes `execute()`. However, depending on the *work* being done, the subclass should periodically check if it has been cancelled, and then finish accordingly. See the [Cancellation] for more guidance on how to handle cancellation.\n\n"
  },
  {
    "path": "Documentation/Guides/Getting Started/What is ProcedureKit?.md",
    "content": "# What is ProcedureKit?\n\n*ProcedureKit* is a framework which provides advanced features to [`Foundation.Operation`](https://developer.apple.com/reference/foundation/operation) and [`Foundation.OperationQueue`](https://developer.apple.com/reference/foundation/operationqueue). \n\n[`Procedure`](Classes/Procedure.html) is a subclass of `Foundation.Operation` and is used to perform *work* on an instance of `ProcedureQueue` which is a subclass of `Foundation.OperationQueue`. `Procedure` itself however is an abstract class and should always be subclassed to specialize the *work*.\n\nWhat do we mean by *work*? This is anything (programmatic), for example number crunching, data processing, parsing or retrieval, view controller presentation, seriously - anything.\n\n## What does the ProcedureKit framework provide?\n\nThe framework provides the core elements of `Procedure` and `ProcedureQueue` types. It also has abstract types for core functionality like the `Condition` class and `Observer` protocol.  \n\nAdditionally, there are helper types, which are \"building blocks\" which when used together with `Procedure ` subclasses allow for advanced usage. On top of this there are a number of feature procedures. These are `Procedure ` subclasses which can be used directly to perform common yet specialist functionality, like `UserLocationProcedure`."
  },
  {
    "path": "Documentation/Guides/Migration/From NSOperation.md",
    "content": "# Migrating from _Foundation.Operation_\n\n![ProcedureKit 4.0+](https://img.shields.io/badge/ProcedureKit-4.0⁺-blue.svg)\n\n_ProcedureKit_ makes it simple to use `Procedure`s alongside existing `Foundation.Operation` (`NSOperation`) subclasses.\n\nConcepts from `Foundation.Operation` map closely to (differently-named) _ProcedureKit_ classes.\n\n# Comparisons\n\nA cheat-sheet for the _ProcedureKit_ replacements for _Foundation.Operation_ concepts:\n\n| Foundation     | ProcedureKit   |             |\n|----------------|----------------|:--------------------------:|\n| Operation      | Procedure      | [Compare](#operation--procedure)  |\n| OperationQueue | ProcedureQueue | [Compare](#operationqueue--procedurequeue) |\n| BlockOperation | BlockProcedure | [Compare](#blockoperation--blockprocedure) |\n\n### Operation → [Procedure](Classes/Procedure.html)\n\n#### Core Differences:\n- A `Procedure` **must** be added to a `ProcedureQueue`. It cannot be started manually.\n- A `Procedure`'s code goes in its `execute()` override. (Instead of `start()` or `main()`.)\n- A `Procedure` cannot override `cancel()` or several other `Operation` methods - safer alternatives (like Observers) are provided.\n\n#### Core Additional Functionality:\n- A `Procedure` supports [Observers](Classes/Observers.html) for executing code in response to `Procedure` events, which have numerous advantages over KVO on `Operation`.\n- A `Procedure` supports [Conditions](Classes/Conditions.html). Before a `Procedure` is ready to execute it will asynchronously evaluate all of its conditions. If any condition fails, it finishes with an error instead of executing.\n- `Procedure` has its own internal logging functionality that can be easily customized to [[support third-party logging frameworks or custom logging|Custom-Logging]] for easy debugging.\n- `Procedures` can support the property of [Mutual Exclusion](Classes/MutualExclusion.html).\n\n### OperationQueue → [ProcedureQueue](Classes/ProcedureQueue.html)\n\nA `ProcedureQueue` can be a drop-in replacement for an `OperationQueue`, and supports the same API and functionality as `OperationQueue`.\n\n#### Core Additional Functionality:\n- Full `Procedure` support.\n- Supports a `ProcedureQueueDelegate` to receive asynchronous callbacks when events (like adding a new `Operation` / `Procedure`) occur.\n\n### BlockOperation → [BlockProcedure](Classes/BlockProcedure.html)\n\nIn essentially all cases, `BlockProcedure` can be a drop-in replacement for `BlockOperation`, but provides all the additional functionality of a `Procedure` ([see above](#operation--procedure)).\n\n# Core Additional Features\n\n- Dependency Injection\n- GroupProcedure\n\n## [Dependency Injection](dependency-injection.html)\n\nOften, `Procedure`s will need dependencies in order to execute. As is typical with asynchronous / event-based applications, these dependencies might not be known at creation time. Instead they must be injected after the `Procedure` is initialised, but before it is executed.\n\n_ProcedureKit_ supports this via a set of [protocols and types which work together](Dependency-Injection.html). We think this pattern is great, as it encourages the composition of small single purpose procedures. These are easier to test and potentially enable greater re-use. You will find dependency injection used and encouraged throughout this framework.\n\n## [GroupProcedure](Classes/GroupProcedure.html)\n\nA `GroupProcedure` can be used to create a logical grouping of \"child\" `Operations` / `Procedures` that run on its own (private) queue.\n\nThis is a very powerful class, and underpins a lot of other built-in `Procedure`s provided by the framework. It is probably the second most commonly used after `BlockProcedure`.\n\nInstead of a maze of dependencies, allow `GroupProcedure` to help you break up `Operations` / `Procedures` into many reusable chunks that join into larger logical building blocks.\n"
  },
  {
    "path": "Documentation/Guides/Migration/From PSOperations.md",
    "content": "# Migrating from _PSOperations_\n\n![ProcedureKit 4.0+](https://img.shields.io/badge/ProcedureKit-4.0⁺-blue.svg)\n\nConcepts from _PSOperations_ map closely to (differently-named) _ProcedureKit_ classes.\n\n## Comparisons\n\nA cheat-sheet for the _ProcedureKit_ replacements for _PSOperations_ classes:\n\n| PSOperations   | ProcedureKit   |             |\n|----------------|----------------|:--------------------------:|\n| Operation      | Procedure      | [Compare](#-psoperationsoperation--procedure)  |\n| OperationQueue | ProcedureQueue | [Compare](#-psoperationsoperationqueue--procedurequeue) |\n| BlockOperation | BlockProcedure | [Compare](#-psoperationsblockoperation--blockprocedure) |\n| GroupOperation | GroupProcedure | [Compare](#-psoperationsgroupoperation--groupprocedure) |\n| DelayOperation | DelayProcedure | [Compare](#-psoperationsdelayoperation--delayprocedure) |\n| URLSessionTaskOperation | NetworkDataProcedure / NetworkDownloadProcedure / NetworkUploadProcedure | [Compare](#-psoperationsurlsessiontaskoperation--networkprocedures) |\n| MutuallyExclusive | MutuallyExclusive | [Compare](#-psoperationsmutuallyexclusive--mutuallyexclusive-condition) |\n\n\n## PSOperations.Operation → [Procedure](Classes\\Procedure.html)\n\n### Usage Differences:\n- A `Procedure` must be added to a `ProcedureQueue`.\n- A `Procedure` cannot override `cancel()` or several other `Foundation.Operation` methods - safer alternatives (like Observers) are provided.\n- `Procedure.cancel()` does not automatically call `finish()` once the `Procedure` has been started. See our guide on [[how to handle cancellation in your Procedure subclasses|Handling-Cancellation]].\n\n#### Advantages:\n- `Procedure` provides enhanced thread-safety and fixes for race conditions.\n- `Procedure` fixes a bug where [Operations occasionally get stuck ready, but never execute or properly finish](https://github.com/ProcedureKit/ProcedureKit/issues/175#issuecomment-208004960) (due to overriding `isReady`).\n- `Procedure` executes user code and events on a serial [[EventQueue]], helping avoid common classes of concurrency issues with subclass overrides, Observers, and more.\n- `Procedure`'s internals (and methods) are asynchronous, preventing several classes of deadlock issues.\n- `Procedure` does not use recursive locks.\n- `Procedure` is aggressively stress-tested with [a massive Stress-Testing suite](https://github.com/ProcedureKit/ProcedureKit/tree/development/Tests/ProcedureKitStressTests).\n- `Procedure` incorporates numerous performance-improvements, such as short-circuit evaluation of Conditions and minimizing lock contention and use.\n- `Procedure` provides numerous helpers for adopting proper asynchronous patterns and scheduling blocks / Observers on specific queues, or before / after certain `Procedure` lifecycle events.\n- `Procedure` internal checks and asserts help you catch logical mistakes in your code.\n- `Procedure` provides verbose, [[customizable|Custom-Logging]] logging that makes it easier to debug complex graphs of `Procedures`.\n\n## PSOperations.OperationQueue → [ProcedureQueue](Classes\\ProcedureQueue.html)\n\nA `ProcedureQueue` can be a nearly drop-in replacement for a `PSOperations.OperationQueue`, and supports the same API and functionality as `OperationQueue`.\n\n### Key Exception:\n- `ProcedureQueue` supports `ProcedureQueueDelegate` which has naming changes and additional functionality over `PSOperations.OperationQueueDelegate`.\n\n## PSOperations.BlockOperation → [BlockProcedure](Classes\\BlockProcedure.html)\n\nIn essentially all cases, `BlockProcedure` can be a drop-in replacement for `PSOperations.BlockOperation`, but provides all the additional functionality and advantages of a `Procedure` ([see above](#-psoperationsoperation--procedure)).\n\n## PSOperations.GroupOperation → [GroupProcedure](Classes\\GroupProcedure.html)\n\nIn essentially all cases, `GroupProcedure` can be a drop-in replacement for `PSOperations.GroupOperation`, but provides all the additional functionality and advantages of a `Procedure` ([see above](#-psoperationsoperation--procedure)).\n\n### Additional Advantages:\n\n- `GroupProcedure` provides enhanced thread-safety and fixes for race conditions, including:\n    - `GroupOperation` has race conditions and other issues impacting cancellation, which can result in a cancelled `GroupOperation` finishing without the cancelled flag ever being set.\n    - `GroupOperation` has race conditions impacting error aggregation from children, which can result in crashes or other unexpected behavior.\n- `GroupProcedure` supports customization of the `underlyingQueue` used for its children, the `qualityOfService`, etc.\n- `GroupProcedure` supports suspend / resume.\n- `GroupProcedure` provides overrides to support customizing error handling behavior and customizing added `Operations`.\n- `GroupProcedure` provides numerous helpers for adopting proper asynchronous patterns and scheduling blocks / Observers on specific queues, or before / after certain `Procedure` lifecycle events.\n- `GroupProcedure` internal checks and asserts help you catch logical mistakes in your code.\n\n## PSOperations.DelayOperation → [DelayProcedure](Classes\\DelayProcedure.html)\n\nIn essentially all cases, `DelayProcedure` can be a drop-in replacement for `PSOperations.DelayOperation`, but provides all the additional functionality and advantages of a `Procedure` ([see above](#-psoperationsoperation--procedure)).\n\n## PSOperations.URLSessionTaskOperation → Network*Procedures\n\n_ProcedureKitNetwork_ provides three classes that split up the duties of `PSOperation`'s `URLSessionTaskOperation`:\n\n1. `NetworkDataProcedure` is a simple procedure which will perform a data task using URLSession based APIs.\n2. `NetworkDownloadProcedure` is a simple procedure which will perform a download task using URLSession based APIs.\n3. `NetworkUploadProcedure` is a simple procedure which will perform an upload task using URLSession based APIs.\n\n#### Core Differences:\n\n- 3 classes versus 1\n- `Network*Procedure` only supports the completion block style URLSession API, therefore do not use these procedures if you wish to use delegate based APIs on URLSession.\n\n#### Advantages:\n\n- `Network*Procedures` can utilize dependency injection to have their \"input\" (the request, etc) provided post-initialization.\n- `Network*Procedures` do not utilize KVO on `URLSessionTask`, which [can cause crashes](https://github.com/ProcedureKit/ProcedureKit/issues/320).\n\n## · PSOperations.MutuallyExclusive → [[MutuallyExclusive (Condition)]]\n\nIn essentially all cases, `MutuallyExclusive` can be a drop-in replacement for `PSOperations.MutuallyExclusive`.\n\n#### Additional Advantages:\n\n- Mutual Exclusivity is now evaluated post-dependencies and condition evaluation (i.e. immediately before execute).\n    - This resolves **several deadlock and unexpected dependency scenarios**, while still ensuring that only one `Procedure` with each mutual exclusivity category is running simultaneously.\n    - It also **improves performance** by only acquiring locks in a single request, and only when the `Procedure` is otherwise ready to execute.\n\n# Additional Features\n\n**ProcedureKit** also provides a number of new features, when migrating from `PSOperations`:\n\n- Dependency Injection\n- RepeatProcedure\n- RetryProcedure\n\n## · [[Dependency Injection]]\n\nOften, `Procedures` will need dependencies in order to execute. As is typical with asynchronous / event-based applications, these dependencies might not be known at creation time. Instead they must be injected after the `Procedure` is initialised, but before it is executed.\n\n**ProcedureKit** supports this via a set of [[protocols and types which work together|Dependency-Injection]]. We think this pattern is great, as it encourages the composition of small single purpose procedures. These can be easier to test and potentially enable greater re-use. You will find dependency injection used and encouraged throughout this framework.\n\n# Additional Built-in Procedures\n\n- CloudKitProcedure\n- AlertProcedure `(iOS)`\n- UIProcedure `(iOS)`\n- ProcessProcedure `(macOS)`\n- Location Procedures"
  },
  {
    "path": "Documentation/Guides/Migration/From WWDC2015.md",
    "content": "# Migrating from _Advanced Operations_, WWDC 2015\n\n![ProcedureKit 4.0+](https://img.shields.io/badge/ProcedureKit-4.0⁺-blue.svg)\n\nConcepts from the WWDC 2015 \"Advanced NSOperations\" sample framework map closely to (differently-named) _ProcedureKit_ classes. This guide will walk you through the differences, and reasons to make the move. Trust us.\n\n## Why switch to _ProcedureKit_\n\nMigrating to _ProcedureKit_ will provide immediate improvements over the \"Advanced NSOperations\" code, including:\n\n- Fixes for various thread-safety issues and race conditions in the \"Advanced NSOperations\" code.\n- Fixes for [operations occasionally get stuck ready, but never execute or properly finish](https://github.com/ProcedureKit/ProcedureKit/issues/175#issuecomment-208004960) (most commonly seen when using Conditions with the \"Advanced NSOperations\" code).\n- Swift 3+ compatibility.\n- Asserts to catch programmer errors.\n- Logging to help debug `Procedure` execution.\n- Support for more platforms: macOS, iOS, tvOS, watchOS.\n\nIn addition, _ProcedureKit_ is aggressively unit-tested, integration tested and actively developed and improved.\n\n## Comparisons\n\nA cheat-sheet for the `ProcedureKit` replacements for \"Advanced NSOperations\" classes:\n\n| Advanced NSOperations   | ProcedureKit   |             |\n|----------------|----------------|:--------------------------:|\n| Operation      | Procedure      | [Compare](#-advanced-nsoperationsoperation--procedure)  |\n| OperationQueue | ProcedureQueue | [Compare](#-advanced-nsoperationsoperationqueue--procedurequeue) |\n| BlockOperation | BlockProcedure | [Compare](#-advanced-nsoperationsblockoperation--blockprocedure) |\n| GroupOperation | GroupProcedure | [Compare](#-advanced-nsoperationsgroupoperation--groupprocedure) |\n| DelayOperation | DelayProcedure | [Compare](#-advanced-nsoperationsdelayoperation--delayprocedure) |\n| URLSessionTaskOperation | NetworkDataProcedure / NetworkDownloadProcedure / NetworkUploadProcedure | [Compare](#-advanced-nsoperationsurlsessiontaskoperation--networkprocedures) |\n| MutuallyExclusive | MutuallyExclusive | [Compare](#-advanced-nsoperationsmutuallyexclusive--mutuallyexclusive-condition) |\n\n\n### \"Advanced NSOperations\".Operation → [Procedure](Classes/Procedure.html)\n\n#### Usage Differences:\n- A `Procedure` must be added to a `ProcedureQueue`.\n- A `Procedure` cannot override `cancel()` or several other `Foundation.Operation` methods - safer alternatives (like Observers) are provided.\n- `Procedure.cancel()` will (by default) automatically `finish()` a Procedure (bypassing `execute()`) if it is called before the `Procedure` is started. See our guide on [how to handle cancellation in your Procedure subclasses](Handling-Cancellation.html).\n\n#### Advantages:\n- `Procedure` provides enhanced thread-safety and fixes for race conditions.\n- `Procedure` fixes a bug where [Operations occasionally get stuck ready, but never execute or properly finish](https://github.com/ProcedureKit/ProcedureKit/issues/175#issuecomment-208004960) (due to overriding `isReady`).\n- `Procedure` executes user code and events on a serial [EventQueue](Classes/EventQueue.html), helping avoid common classes of concurrency issues with subclass overrides, Observers, and more.\n- `Procedure`'s internals (and methods) are asynchronous, preventing several classes of deadlock issues.\n- `Procedure` Observers support many more events.\n- `Procedure` is aggressively unit-tested with [an extensive unit test suite](https://github.com/ProcedureKit/ProcedureKit/tree/development/Tests) across all supported platforms.\n- `Procedure` is aggressively stress-tested with [an extensive stress test suite](https://github.com/ProcedureKit/ProcedureKit/tree/development/Tests/ProcedureKitStressTests).\n- `Procedure` incorporates numerous performance-improvements, such as short-circuit evaluation of Conditions and minimizing lock contention and use.\n- `Procedure` provides numerous helpers for adopting proper asynchronous patterns and scheduling blocks / Observers on specific queues, or before / after certain `Procedure` lifecycle events.\n- `Procedure` internal checks and asserts help you catch logical mistakes in your code.\n- `Procedure` provides verbose, [customizable](Custom-Logging.html) logging that makes it easier to debug complex graphs of `Procedure`.\n\n### \"Advanced NSOperations\".OperationQueue → [ProcedureQueue](Classes/ProcedureQueue.html)\n\nA `ProcedureQueue` can be a nearly drop-in replacement for Advanced NSOperations' `OperationQueue`, and supports the same API and functionality as `OperationQueue`.\n\n#### Key Exception:\n- `ProcedureQueue` supports `ProcedureQueueDelegate` which has naming changes and additional functionality over `OperationQueueDelegate`.\n\n## \"Advanced NSOperations\".BlockOperation → [BlockProcedure](Classes/BlockProcedure.html)\n\nIn essentially all cases, `BlockProcedure` can be a drop-in replacement for Advanced NSOperations' `BlockOperation`, but provides all the additional functionality and advantages of a `Procedure` ([see above](#-advanced-nsoperationsoperation--procedure)).\n\n#### Key Difference:\n- `BlockProcedure` does not provide the `convenience init(mainQueueBlock: dispatch_block_t)`.\n\n### \"Advanced NSOperations\".GroupOperation → [GroupProcedure](Classes/GroupProcedure.html)\n\nIn essentially all cases, `GroupProcedure` can be a drop-in replacement for Advanced NSOperations' `GroupOperation`, but provides all the additional functionality and advantages of a `Procedure` ([see above](#-advanced-nsoperationsoperation--procedure)).\n\n#### Additional Advantages:\n\n- `GroupProcedure` provides enhanced thread-safety and fixes for race conditions / concurrency issues, including:\n    - `GroupOperation` has race conditions and other issues impacting cancellation, which can result in a cancelled `GroupOperation` finishing without the cancelled flag ever being set.\n    - `GroupOperation` has race conditions impacting error aggregation from children, which can result in crashes or other unexpected behavior.\n- `GroupProcedure` supports customization of the `underlyingQueue` used for its children, the `qualityOfService`, etc.\n- `GroupProcedure` supports suspend / resume.\n- `GroupProcedure` provides overrides to support customizing error handling behavior and customizing added `Operations`.\n- `GroupProcedure` provides numerous helpers for adopting proper asynchronous patterns and scheduling blocks / Observers on specific queues, or before / after certain `Procedure` lifecycle events.\n- `GroupProcedure` internal checks and asserts help you catch logical mistakes in your code.\n\n### \"Advanced NSOperations\".DelayOperation → [DelayProcedure](Classes/DelayProcedure.html)\n\nIn essentially all cases, `DelayProcedure` can be a drop-in replacement for Advanced NSOperations' `DelayOperation`, but provides all the additional functionality and advantages of a `Procedure` ([see above](#-advanced-nsoperationsoperation--procedure)).\n\n### \"Advanced NSOperations\".URLSessionTaskOperation → Network*Procedures\n\n_ProcedureKitNetwork_ provides three classes that split up the duties of Advanced NSOperations' `URLSessionTaskOperation`:\n\n1. `NetworkDataProcedure` is a simple procedure which will perform a data task using URLSession based APIs.\n2. `NetworkDownloadProcedure` is a simple procedure which will perform a download task using URLSession based APIs.\n3. `NetworkUploadProcedure` is a simple procedure which will perform an upload task using URLSession based APIs.\n\n#### Core Differences:\n\n- 3 classes versus 1\n- `Network*Procedure` only supports the completion block style URLSession API, therefore do not use these procedures if you wish to use delegate based APIs on URLSession.\n\n#### Advantages:\n\n- `Network*Procedures` can utilize dependency injection to have their \"input\" (the request, etc) provided post-initialization.\n- `Network*Procedures` do not utilize KVO on `URLSessionTask`, which [can cause crashes](https://github.com/ProcedureKit/ProcedureKit/issues/320).\n\n### \"Advanced NSOperations\".MutuallyExclusive → [MutuallyExclusive (Condition)](Classes/MutualExclusive.html)\n\nIn essentially all cases, `MutuallyExclusive` can be a drop-in replacement for Advanced NSOperations' `MutuallyExclusive`.\n\n#### Additional Advantages:\n\n- Mutual Exclusivity is now evaluated post-dependencies and condition evaluation (i.e. immediately before execute).\n    - This resolves **several deadlock and unexpected dependency scenarios**, while still ensuring that only one `Procedure` with each mutual exclusivity category is running simultaneously.\n    - It also **improves performance** by only acquiring locks in a single request, and only when the `Procedure` is otherwise ready to execute.\n\n# Additional Features\n\n_ProcedureKit_ also provides a number of new features, when migrating from \"Advanced NSOperations\":\n\n- Dependency Injection\n\n### [Dependency Injection](dependency-injection.html)\n\nOften, `Procedures` will need dependencies in order to execute. As is typical with asynchronous / event-based applications, these dependencies might not be known at creation time. Instead they must be injected after the `Procedure` is initialised, but before it is executed.\n\n_ProcedureKit_ supports this via a set of [protocols and types which work together](dependency-injection.html). We think this pattern is great, as it encourages the composition of small single purpose procedures. These can be easier to test and potentially enable greater re-use. You will find dependency injection used and encouraged throughout this framework.\n\n# Additional Built-in Procedures\n\n- CloudKitProcedure\n- AlertProcedure `(iOS)`\n- UIProcedure `(iOS)`\n- ProcessProcedure `(macOS)`\n- Location Procedures\n\n\n\n\n"
  },
  {
    "path": "Documentation/Guides/Migration/From v3 Operations.md",
    "content": "# Migrating from Operations, a.k.a. ProcedureKit v3\n\n![ProcedureKit 4.0+](https://img.shields.io/badge/ProcedureKit-4.0⁺-blue.svg)\n\n> ## 🚧 Work-In-Progress 🚧\n> This document is incomplete.\n\nThe journey from _Operations v3_ to _ProcedureKit v4_ included some ground-breaking re-thinks of how things work internally.\n\nMigrating your code from _Operations v3_ to _ProcedureKit v4_ will net you:\n- Numerous bug fixes, thread-safety improvements, and fixes for rare bugs, edge cases, and race conditions.\n- A rock-solid, asynchronous core, with a massively expanded library of tests to back it up.\n- New methods to minimise the code you have to write.\n- New asserts and logging to help catch programmer error and debug issues with your code.\n- Swift 3 support and naming.\n\nHowever, because of some of these improvements, and the concurrent transition to Swift 3, some class and method names have changed.\n\n(With Swift 3.x, Foundation's \"NSOperation\" became \"Operation\", so renaming this framework's \"Operation\" class - and the framework itself - became a part of the major new release.)\n\n## Comparisons\n\nA cheat-sheet for the `ProcedureKit` replacements for `Operations 3.x` classes:\n\n| Operations 3.x | ProcedureKit 4.x  |             |\n|----------------|----------------|:--------------------------:|\n| Operation      | Procedure      | [Compare](#-operation--procedure)  |\n| OperationQueue | ProcedureQueue | [Compare](#-operationqueue--procedurequeue) |\n| BlockOperation | BlockProcedure | [Compare](#-blockoperation--blockprocedure) |\n| GroupOperation | GroupProcedure | [Compare](#-groupoperation--groupprocedure) |\n| DelayOperation | DelayProcedure | [Compare](#-delayoperation--delayprocedure) |\n| URLSessionTaskOperation | NetworkDataProcedure / NetworkDownloadProcedure / NetworkUploadProcedure | [Compare](#-urlsessiontaskoperation--networkprocedures) |\n| MutuallyExclusive | MutuallyExclusive | [Compare](#-mutuallyexclusive--mutuallyexclusive-condition) |\n| RepeatOperation | RepeatProcedure |\n| RetryOperation | RetryProcedure |\n| CloudKitOperation | CloudKitProcedure |\n\n\n### Operation → [Procedure](Classes\\Procedure.html)\n\n#### Usage Differences:\n- A `Procedure` must be added to a `ProcedureQueue`.\n- A `Procedure` cannot override `cancel()` or several other `Foundation.Operation` methods - safer alternatives (like Observers) are provided.\n- `Procedure.cancel()` does not automatically call `finish()` once the `Procedure` has been started. See our guide on [[how to handle cancellation in your Procedure subclasses|Handling-Cancellation]].\n\n#### Improvements:\n- `Procedure` provides enhanced thread-safety and fixes for race conditions.\n- `Procedure` executes user code and events on a serial [EventQueue](Classes\\EventQueue.html), helping avoid common classes of concurrency issues with subclass overrides, Observers, and more.\n- `Procedure`'s internals (and methods) are asynchronous, preventing several classes of deadlock issues.\n- `Procedure` does not use recursive locks.\n- `Procedure` incorporates numerous performance-improvements, such as short-circuit evaluation of Conditions and minimizing lock contention and use.\n- `Procedure` provides numerous helpers for adopting proper asynchronous patterns and scheduling blocks / Observers on specific queues, or before / after certain `Procedure` lifecycle events.\n- Additional internal checks and asserts help you catch logical mistakes in your code.\n- Additional verbose, [[customizable|Custom-Logging]] logging that makes it easier to debug complex graphs of `Procedures`.\n\n### OperationQueue → [ProcedureQueue](Classes\\ProcedureQueue.html)\n\nA `ProcedureQueue` can be a nearly drop-in replacement for an Operations' `OperationQueue`, and supports the same API and functionality as `OperationQueue`.\n\n#### Key Exception:\n- `ProcedureQueue` supports `ProcedureQueueDelegate` which has naming changes and additional functionality over `OperationQueueDelegate`. If you are using a delegate, review `ProcedureQueueDelegate` for the new interface.\n\n### BlockOperation → [BlockProcedure](Classes\\BlockProcedure.html)\n\nOperations 3.x had `BlockOperation`.\n\nProcedureKit 4.x has `BlockProcedure` and `AsyncBlockProcedure`, and the interface is slightly different.\n\n#### Operations 3.x - Example 1\n\nIf you previously initialized a `BlockOperation` with a block that takes a continuation as input, like this:\n```swift\n// NOTE: The following does not do any asynchronous calls within the block.\nlet operation = BlockOperation { (continuation: BlockOperation.ContinuationBlockType) in\n    doSomeWork()\n    continuation(error: nil)\n}\n```\n\n#### ProcedureKit 4.x - Example 1\n\nYou can replace your use of `BlockOperation` with **`BlockProcedure`** as follows:\n```swift\nlet procedure = BlockProcedure {\n    doSomeWork()\n    // optionally throw the error, if one occurs\n}\n```\n\n#### Operations 3.x - Example 2\n\nHowever, if you had an asynchronous call and require the completion handler, like so:\n```swift\nlet operation = BlockOperation { (continuation: BlockOperation.ContinuationBlockType) in\n    dispatch_async(Queue.Default.queue) {\n        doSomeWork()\n        continuation(error: nil)\n    }\n}\n```\n\n#### ProcedureKit 4.x - Example 2\n\nReplace your use of `BlockOperation` with **`AsyncBlockProcedure`**:\n```swift\nlet procedure = AsyncBlockProcedure { finishWithResult in\n    DispatchQueue.global().async {\n        doSomeWork()\n        // if an error occurs, call `finishWithResult(.failure(error))`\n        // else, call `finishWithResult(success)`\n        finishWithResult(success)\n    }\n}\n```\n\n### GroupOperation → [GroupProcedure](Classes\\GroupProcedure.html)\n\nIn essentially all cases, `GroupProcedure` can be a drop-in replacement for `GroupOperation`.\n\n### DelayOperation → [DelayProcedure](Classes\\DelayProcedure.html)\n\nIn essentially all cases, `DelayProcedure` can be a drop-in replacement for `DelayOperation`.\n\n### URLSessionTaskOperation → Network*Procedures\n\n_ProcedureKitNetwork_ provides three classes that split up the duties of `URLSessionTaskOperation`:\n\n1. `NetworkDataProcedure` is a simple procedure which will perform a data task using URLSession based APIs.\n2. `NetworkDownloadProcedure` is a simple procedure which will perform a download task using URLSession based APIs.\n3. `NetworkUploadProcedure` is a simple procedure which will perform an upload task using URLSession based APIs.\n\n#### Core Differences:\n\n- 3 classes versus 1\n- `Network*Procedure` only supports the completion block style URLSession API, therefore do not use these procedures if you wish to use delegate based APIs on URLSession.\n- `Network*Procedure` is now initialized with the session, completion handler, and (optionally) the request (and data, in the case of upload) - *not* the URLSessionTask. The `Network*Procedure` is responsible for internally creating the URLSessionTask based on the input parameters.\n\n#### Advantages:\n\n- `Network*Procedures` can utilize dependency injection to have their \"input\" (the request, etc) provided post-initialization.\n- `Network*Procedures` do not utilize KVO on `URLSessionTask`, which [can cause crashes](https://github.com/ProcedureKit/ProcedureKit/issues/320).\n\n### MutuallyExclusive → [MutuallyExclusive (Condition)](Classes\\MutuallyExclusive.html)\n\nIn essentially all cases, `MutuallyExclusive` can be a drop-in replacement for Operations' `MutuallyExclusive`.\n\n#### Additional Advantages:\n\n- Mutual Exclusivity is now evaluated post-dependencies and condition evaluation (i.e. immediately before execute).\n    - This resolves **several deadlock and unexpected dependency scenarios**, while still ensuring that only one `Procedure` with each mutual exclusivity category is running simultaneously.\n    - It also **improves performance** by only acquiring locks in a single request, and only when the `Procedure` is otherwise ready to execute.\n"
  },
  {
    "path": "Documentation/Themes/fullwidth_pk/assets/css/highlight.css.scss",
    "content": "/* Credit to https://gist.github.com/wataru420/2048287 */\n\n.highlight {\n  .c { color: #999988; font-style: italic } /* Comment */\n  .err { color: #a61717; background-color: #e3d2d2 } /* Error */\n  .k { color: #000000; font-weight: bold } /* Keyword */\n  .o { color: #000000; font-weight: bold } /* Operator */\n  .cm { color: #999988; font-style: italic } /* Comment.Multiline */\n  .cp { color: #999999; font-weight: bold } /* Comment.Preproc */\n  .c1 { color: #999988; font-style: italic } /* Comment.Single */\n  .cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */\n  .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */\n  .gd .x { color: #000000; background-color: #ffaaaa } /* Generic.Deleted.Specific */\n  .ge { color: #000000; font-style: italic } /* Generic.Emph */\n  .gr { color: #aa0000 } /* Generic.Error */\n  .gh { color: #999999 } /* Generic.Heading */\n  .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */\n  .gi .x { color: #000000; background-color: #aaffaa } /* Generic.Inserted.Specific */\n  .go { color: #888888 } /* Generic.Output */\n  .gp { color: #555555 } /* Generic.Prompt */\n  .gs { font-weight: bold } /* Generic.Strong */\n  .gu { color: #aaaaaa } /* Generic.Subheading */\n  .gt { color: #aa0000 } /* Generic.Traceback */\n  .kc { color: #000000; font-weight: bold } /* Keyword.Constant */\n  .kd { color: #000000; font-weight: bold } /* Keyword.Declaration */\n  .kp { color: #000000; font-weight: bold } /* Keyword.Pseudo */\n  .kr { color: #000000; font-weight: bold } /* Keyword.Reserved */\n  .kt { color: #445588; } /* Keyword.Type */\n  .m { color: #009999 } /* Literal.Number */\n  .s { color: #d14 } /* Literal.String */\n  .na { color: #008080 } /* Name.Attribute */\n  .nb { color: #0086B3 } /* Name.Builtin */\n  .nc { color: #445588; font-weight: bold } /* Name.Class */\n  .no { color: #008080 } /* Name.Constant */\n  .ni { color: #800080 } /* Name.Entity */\n  .ne { color: #990000; font-weight: bold } /* Name.Exception */\n  .nf { color: #990000; } /* Name.Function */\n  .nn { color: #555555 } /* Name.Namespace */\n  .nt { color: #000080 } /* Name.Tag */\n  .nv { color: #008080 } /* Name.Variable */\n  .ow { color: #000000; font-weight: bold } /* Operator.Word */\n  .w { color: #bbbbbb } /* Text.Whitespace */\n  .mf { color: #009999 } /* Literal.Number.Float */\n  .mh { color: #009999 } /* Literal.Number.Hex */\n  .mi { color: #009999 } /* Literal.Number.Integer */\n  .mo { color: #009999 } /* Literal.Number.Oct */\n  .sb { color: #d14 } /* Literal.String.Backtick */\n  .sc { color: #d14 } /* Literal.String.Char */\n  .sd { color: #d14 } /* Literal.String.Doc */\n  .s2 { color: #d14 } /* Literal.String.Double */\n  .se { color: #d14 } /* Literal.String.Escape */\n  .sh { color: #d14 } /* Literal.String.Heredoc */\n  .si { color: #d14 } /* Literal.String.Interpol */\n  .sx { color: #d14 } /* Literal.String.Other */\n  .sr { color: #009926 } /* Literal.String.Regex */\n  .s1 { color: #d14 } /* Literal.String.Single */\n  .ss { color: #990073 } /* Literal.String.Symbol */\n  .bp { color: #999999 } /* Name.Builtin.Pseudo */\n  .vc { color: #008080 } /* Name.Variable.Class */\n  .vg { color: #008080 } /* Name.Variable.Global */\n  .vi { color: #008080 } /* Name.Variable.Instance */\n  .il { color: #009999 } /* Literal.Number.Integer.Long */\n}\n"
  },
  {
    "path": "Documentation/Themes/fullwidth_pk/assets/css/jazzy.css.scss",
    "content": "// ===========================================================================\n//\n//  Variables\n//\n// ===========================================================================\n\n$body_background: #fff;\n$body_font: 16px/1.7 'Helvetica Neue', Helvetica, Arial, sans-serif;\n$text_color: #333;\n$gray_border: 1px solid #ddd;\n\n$heading_weight: 700;\n$light_heading_color: #777;\n\n$quote_color: #858585;\n$quote_border: 4px solid #e5e5e5;\n\n$link_color: #4183c4;\n\n$table_alt_row_color: #fbfbfb;\n$table_border_color: #ddd;\n\n$code_bg_color: #f7f7f7;\n$code_font: Consolas, \"Liberation Mono\", Menlo, Courier, monospace;\n\n\n// ----- Layout\n\n$gutter: 16px;\n$navigation_max_width: 300px;\n\n\n// ----- Header\n\n$header_bg_color: #444;\n$header_link_color: #fff;\n$doc_coverage_color: #999;\n\n\n// ----- Breadcrumbs\n\n$breadcrumbs_bg_color: #fbfbfb;\n$breadcrumbs_border_color: #ddd;\n\n\n// ----- Navigation\n\n$navigation_max_width: 300px;\n$navigation_bg_color: #fbfbfb;\n$navigation_border_color: #ddd;\n$navigation_title_color: #333;\n$navigation_task_color: #808080;\n\n// ----- Content\n\n$declaration_title_language_color: #4183c4;\n$declaration_language_border: 5px solid #cde9f4;\n$declaration_bg_color: #fff;\n$declaration_border_color: #ddd;\n\n$aside_color: #777;\n$aside_background_color: #fafafa;\n$aside_border: 5px solid #ccc;\n$aside_warning_color: #ff6666;\n$aside_warning_background: #ffe7e8;\n$aside_warning_border: 5px solid $aside_warning_color;\n$aside_warning_title_color: #ae272f;\n$aside_important_background: #fbf8e8;\n$aside_important_border: 5px solid #fee450;\n$aside_important_title_color: #776a25;\n\n// ----- Footer\n\n$footer_bg_color: #444;\n$footer_text_color: #ddd;\n$footer_link_color: #fff;\n\n\n// ===========================================================================\n//\n//  Base\n//\n// ===========================================================================\n\n*, *:before, *:after {\n  box-sizing: inherit;\n}\n\nbody {\n  margin: 0;\n  background: $body_background;\n  color: $text_color;\n  font: $body_font;\n  letter-spacing: .2px;\n  -webkit-font-smoothing: antialiased;\n  box-sizing: border-box;\n}\n\n// ----- Block elements\n\n@mixin heading($font-size: 1rem, $margin: 1.275em 0 0.85em) {\n  font-size: $font-size;\n  font-weight: $heading_weight;\n  margin: $margin;\n}\n\nh1 {\n  @include heading(2rem, 1.275em 0 0.6em);\n}\n\nh2 {\n  @include heading(1.75rem, 1.275em 0 0.3em);\n}\n\nh3 {\n  @include heading(1.5rem, 1em 0 0.3em);\n}\n\nh4 {\n  @include heading(1.25rem);\n}\n\nh5 {\n  @include heading;\n}\n\nh6 {\n  @include heading;\n  color: $light_heading_color;\n}\n\np {\n  margin: 0 0 1em;\n}\n\nul, ol {\n  padding: 0 0 0 2em;\n  margin: 0 0 0.85em;\n}\n\nblockquote {\n  margin: 0 0 0.85em;\n  padding: 0 15px;\n  color: $quote_color;\n  border-left: $quote_border;\n}\n\n\n// ----- Inline elements\n\nimg {\n  max-width: 100%;\n}\n\na {\n  color: $link_color;\n  text-decoration: none;\n\n  &:hover, &:focus {\n    outline: 0;\n    text-decoration: underline;\n  }\n}\n\n\n// ----- Tables\n\ntable {\n  background: $body_background;\n  width: 100%;\n  border-collapse: collapse;\n  border-spacing: 0;\n  overflow: auto;\n  margin: 0 0 0.85em;\n}\n\ntr {\n  &:nth-child(2n) {\n    background-color: $table_alt_row_color;\n  }\n}\n\nth, td {\n  padding: 6px 13px;\n  border: 1px solid $table_border_color;\n}\n\n\n// ----- Code\n\npre {\n  margin: 0 0 1.275em;\n  padding: .85em 1em;\n  overflow: auto;\n  background: $code_bg_color;\n  font-size: .85em;\n  font-family: $code_font;\n}\n\ncode {\n  font-family: $code_font;\n}\n\np, li {\n  > code {\n    background: $code_bg_color;\n    padding: .2em;\n    &:before, &:after {\n      letter-spacing: -.2em;\n      content: \"\\00a0\";\n    }\n  }\n}\n\npre code {\n  padding: 0;\n  white-space: pre;\n}\n\n\n// ===========================================================================\n//\n//  Layout\n//\n// ===========================================================================\n\n.content-wrapper {\n  display: flex;\n  flex-direction: column;\n  @media (min-width: 768px) {\n    flex-direction: row;\n  }\n}\n\n\n// ===========================================================================\n//\n//  Header\n//\n// ===========================================================================\n\n.header {\n  display: flex;\n  padding: $gutter/2;\n  font-size: 0.875em;\n  background: $header_bg_color;\n  color: $doc_coverage_color;\n}\n\n.header-col {\n  margin: 0;\n  padding: 0 $gutter/2\n}\n\n.header-col--primary {\n  flex: 1;\n}\n\n.header-link {\n  color: $header_link_color;\n}\n\n.header-icon {\n  padding-right: 6px;\n  vertical-align: -4px;\n  height: 16px;\n}\n\n\n\n// ===========================================================================\n//\n//  Breadcrumbs\n//\n// ===========================================================================\n\n.breadcrumbs {\n  font-size: 0.875em;\n  padding: $gutter / 2 $gutter;\n  margin: 0;\n  background: $breadcrumbs_bg_color;\n  border-bottom: 1px solid $breadcrumbs_border_color;\n}\n\n.carat {\n  height: 10px;\n  margin: 0 5px;\n}\n\n\n// ===========================================================================\n//\n//  Navigation\n//\n// ===========================================================================\n\n.navigation {\n  order: 2;\n\n  @media (min-width: 768px) {\n    order: 1;\n    width: 25%;\n    max-width: $navigation_max_width;\n    padding-bottom: $gutter*4;\n    overflow: hidden;\n    word-wrap: normal;\n    background: $navigation_bg_color;\n    border-right: 1px solid $navigation_border_color;\n  }\n  @media print {\n    display: none;\n  }\n}\n\n.nav-groups {\n  list-style-type: none;\n  padding-left: 0;\n}\n\n.nav-group-name {\n  border-bottom: 1px solid $navigation_border_color;\n  padding: $gutter/2 0 $gutter/2 $gutter;\n}\n\n.nav-group-name-link {\n  color: $navigation_title_color;\n}\n\n.nav-group-tasks {\n  margin: $gutter/2 0;\n  padding: 0 0 0 $gutter/2;\n}\n\n.nav-group-task {\n  font-size: 1em;\n  list-style-type: none;\n  white-space: nowrap;\n}\n\n.nav-group-task-link {\n  color: $navigation_task_color;\n}\n\n// ===========================================================================\n//\n//  Content\n//\n// ===========================================================================\n\n.main-content {\n  order: 1;\n  @media (min-width: 768px) {\n    order: 2;\n    flex: 1;\n    padding-bottom: 60px;\n  }\n}\n\n.section {\n  padding: 0 $gutter * 2;\n  border-bottom: 1px solid $navigation_border_color;\n}\n\n.section-content {\n  max-width: 834px;\n  margin: 0 auto;\n  padding: $gutter 0;\n}\n\n.section-name {\n  color: #666;\n  display: block;\n}\n\n.declaration .highlight {\n  overflow-x: initial; // This allows the scrollbar to show up inside declarations\n  padding: $gutter/2 0;\n  margin: 0;\n  background-color: transparent;\n  border: none;\n}\n\n.task-group-section {\n  border-top: $gray_border;\n}\n\n.task-group {\n  padding-top: 0px;\n}\n\n.task-name-container {\n  a[name] {\n    &:before {\n      content: \"\";\n      display: block;\n    }\n  }\n}\n\n.item-container {\n  padding: 0;\n}\n\n.item {\n  padding-top: 8px;\n  width: 100%;\n  list-style-type: none;\n\n  a[name] {\n    &:before {\n      content: \"\";\n      display: block;\n    }\n  }\n\n  .token {\n    padding-left: 3px;\n    margin-left: 0px;\n    font-size: 1rem;\n  }\n\n  .declaration-note {\n    font-size: .85em;\n    color: #808080;\n    font-style: italic;\n  }\n}\n\n.pointer-container {\n  border-bottom: $gray_border;\n  left: -23px;\n  padding-bottom: 13px;\n  position: relative;\n  width: 110%;\n}\n\n.pointer {\n  left: 21px;\n  top: 7px;\n  display: block;\n  position: absolute;\n  width: 12px;\n  height: 12px;\n  border-left: 1px solid $declaration_border_color;\n  border-top: 1px solid $declaration_border_color;\n  background: $declaration_bg_color;\n  transform: rotate(45deg);\n}\n\n.height-container {\n  display: none;\n  position: relative;\n  width: 100%;\n  overflow: hidden;\n  .section {\n    background: $declaration_bg_color;\n    border: $gray_border;\n    border-top-width: 0;\n    padding-top: 10px;\n    padding-bottom: 5px;\n    padding: $gutter / 2 $gutter;\n  }\n}\n\n.aside, .language {\n  padding: 6px 12px;\n  padding-bottom: 14px;\n  margin: 12px 0;\n  border-left: $aside_border;\n  overflow-y: hidden;\n  background-color: $aside_background_color;\n  .aside-title {\n    font-size: 9px;\n    letter-spacing: 2px;\n    text-transform: uppercase;\n    padding-bottom: 0;\n    margin: 0;\n    color: $aside_color;\n    -webkit-user-select: none;\n  }\n  p:last-child {\n    margin-bottom: 0;\n  }\n}\n\n.aside {\n  .aside-title {\n    font-weight: 400;\n    padding-bottom: 8px;\n  }\n}\n\n.language {\n  padding: 6px 12px;\n  border-left: $declaration_language_border;\n  .aside-title {\n    color: $declaration_title_language_color;\n  }\n  p:last-child {\n    padding-bottom: 0;\n  }\n}\n\n.aside-warning {\n  background-color: $aside_warning_background;\n  border-left: $aside_warning_border;\n  .aside-title {\n    color: $aside_warning_title_color;\n  }\n}\n\n.aside-important {\n  background-color: $aside_important_background;\n  border-left: $aside_important_border;\n  .aside-title {\n    color: $aside_important_title_color;\n  }\n}\n\n.aside-precondition {\n  background-color: $aside_important_background;\n  border-left: $aside_important_border;\n  .aside-title {\n    color: $aside_important_title_color;\n  }\n}\n\n.graybox {\n  border-collapse: collapse;\n  width: 100%;\n  p {\n    margin: 0;\n    word-break: break-word;\n    min-width: 50px;\n  }\n  td {\n    border: $gray_border;\n    padding: 5px 25px 5px 10px;\n    vertical-align: middle;\n  }\n  tr td:first-of-type {\n    text-align: right;\n    padding: 7px;\n    vertical-align: top;\n    word-break: normal;\n    width: 40px;\n  }\n}\n\n.slightly-smaller {\n  font-size: 0.9em;\n}\n\n\n// ===========================================================================\n//\n//  Footer\n//\n// ===========================================================================\n\n.footer {\n  padding: $gutter/2 $gutter;\n  background: $footer_bg_color;\n  color: $footer_text_color;\n  font-size: 0.8em;\n\n  p {\n    margin: $gutter/2 0;\n  }\n\n  a {\n    color: $footer_link_color;\n  }\n}\n\n\n// ===========================================================================\n//\n//  Dash\n//\n// ===========================================================================\n\nhtml.dash {\n\n  .header, .breadcrumbs, .navigation {\n    display: none;\n  }\n\n  .height-container {\n    display: block;\n  }\n}\n\n// ===========================================================================\n//\n//  Search\n//\n// ===========================================================================\nform[role=search] {\n  input {\n    font: $body_font;\n    font-size: 14px;\n    line-height: 24px;\n    padding: 0 10px;\n    margin: 0;\n    border: none;\n    border-radius: 1em;\n    .loading & {\n      background: white url(../img/spinner.gif) center right 4px no-repeat;\n    }\n  }\n\n  // Typeahead elements\n\n  .tt-menu {\n    margin: 0;\n    min-width: 300px;\n    background: $navigation_bg_color;\n    color: $text_color;\n    border: 1px solid $navigation_border_color;\n  }\n\n  .tt-highlight {\n    font-weight: bold;\n  }\n\n  .tt-suggestion {\n    font: $body_font;\n    padding: 0 $gutter/2;\n    span {\n      display: table-cell;\n      white-space: nowrap;\n    }\n    .doc-parent-name {\n      width: 100%;\n      text-align: right;\n      font-weight: normal;\n      font-size: 0.9em;\n      padding-left: $gutter;\n    }\n  }\n\n  .tt-suggestion:hover,\n  .tt-suggestion.tt-cursor {\n    cursor: pointer;\n    background-color: $link_color;\n    color: #fff;\n  }\n\n  .tt-suggestion:hover .doc-parent-name,\n  .tt-suggestion.tt-cursor .doc-parent-name {\n    color: #fff;\n  }\n}"
  },
  {
    "path": "Documentation/Themes/fullwidth_pk/assets/js/jazzy.js",
    "content": "window.jazzy = {'docset': false}\nif (typeof window.dash != 'undefined') {\n  document.documentElement.className += ' dash'\n  window.jazzy.docset = true\n}\nif (navigator.userAgent.match(/xcode/i)) {\n  document.documentElement.className += ' xcode'\n  window.jazzy.docset = true\n}\n\n// On doc load, toggle the URL hash discussion if present\n$(document).ready(function() {\n  if (!window.jazzy.docset) {\n    var linkToHash = $('a[href=\"' + window.location.hash +'\"]');\n    linkToHash.trigger(\"click\");\n  }\n});\n\n// On token click, toggle its discussion and animate token.marginLeft\n$(\".token\").click(function(event) {\n  if (window.jazzy.docset) {\n    return;\n  }\n  var link = $(this);\n  var animationDuration = 300;\n  $content = link.parent().parent().next();\n  $content.slideToggle(animationDuration);\n\n  // Keeps the document from jumping to the hash.\n  var href = $(this).attr('href');\n  if (history.pushState) {\n    history.pushState({}, '', href);\n  } else {\n    location.hash = href;\n  }\n  event.preventDefault();\n});\n\n// Dumb down quotes within code blocks that delimit strings instead of quotations\n// https://github.com/realm/jazzy/issues/714\n$(\"code q\").replaceWith(function () {\n  return [\"\\\"\", $(this).contents(), \"\\\"\"];\n});\n"
  },
  {
    "path": "Documentation/Themes/fullwidth_pk/assets/js/jazzy.search.js",
    "content": "$(function(){\n  var searchIndex = lunr(function() {\n    this.ref('url');\n    this.field('name');\n  });\n\n  var $typeahead = $('[data-typeahead]');\n  var $form = $typeahead.parents('form');\n  var searchURL = $form.attr('action');\n\n  function displayTemplate(result) {\n    return result.name;\n  }\n\n  function suggestionTemplate(result) {\n    var t = '<div class=\"list-group-item clearfix\">';\n    t += '<span class=\"doc-name\">' + result.name + '</span>';\n    if (result.parent_name) {\n     t += '<span class=\"doc-parent-name label\">' + result.parent_name + '</span>';\n    }\n    t += '</div>';\n    return t;\n  }\n\n  $typeahead.one('focus', function() {\n    $form.addClass('loading');\n\n    $.getJSON(searchURL).then(function(searchData) {\n      $.each(searchData, function (url, doc) {\n        searchIndex.add({url: url, name: doc.name});\n      });\n\n      $typeahead.typeahead(\n        {\n          highlight: true,\n          minLength: 3\n        },\n        {\n          limit: 10,\n          display: displayTemplate,\n          templates: { suggestion: suggestionTemplate },\n          source: function(query, sync) {\n            var results = searchIndex.search(query).map(function(result) {\n              var doc = searchData[result.ref];\n              doc.url = result.ref;\n              return doc;\n            });\n            sync(results);\n          }\n        }\n      );\n      $form.removeClass('loading');\n      $typeahead.trigger('focus');\n    });\n  });\n\n  var baseURL = searchURL.slice(0, -\"search.json\".length);\n\n  $typeahead.on('typeahead:select', function(e, result) {\n    window.location = baseURL + result.url;\n  });\n});\n"
  },
  {
    "path": "Documentation/Themes/fullwidth_pk/assets/js/typeahead.jquery.js",
    "content": "/*!\n * typeahead.js 0.11.1\n * https://github.com/twitter/typeahead.js\n * Copyright 2013-2015 Twitter, Inc. and other contributors; Licensed MIT\n */\n\n(function(root, factory) {\n    if (typeof define === \"function\" && define.amd) {\n        define(\"typeahead.js\", [ \"jquery\" ], function(a0) {\n            return factory(a0);\n        });\n    } else if (typeof exports === \"object\") {\n        module.exports = factory(require(\"jquery\"));\n    } else {\n        factory(jQuery);\n    }\n})(this, function($) {\n    var _ = function() {\n        \"use strict\";\n        return {\n            isMsie: function() {\n                return /(msie|trident)/i.test(navigator.userAgent) ? navigator.userAgent.match(/(msie |rv:)(\\d+(.\\d+)?)/i)[2] : false;\n            },\n            isBlankString: function(str) {\n                return !str || /^\\s*$/.test(str);\n            },\n            escapeRegExChars: function(str) {\n                return str.replace(/[\\-\\[\\]\\/\\{\\}\\(\\)\\*\\+\\?\\.\\\\\\^\\$\\|]/g, \"\\\\$&\");\n            },\n            isString: function(obj) {\n                return typeof obj === \"string\";\n            },\n            isNumber: function(obj) {\n                return typeof obj === \"number\";\n            },\n            isArray: $.isArray,\n            isFunction: $.isFunction,\n            isObject: $.isPlainObject,\n            isUndefined: function(obj) {\n                return typeof obj === \"undefined\";\n            },\n            isElement: function(obj) {\n                return !!(obj && obj.nodeType === 1);\n            },\n            isJQuery: function(obj) {\n                return obj instanceof $;\n            },\n            toStr: function toStr(s) {\n                return _.isUndefined(s) || s === null ? \"\" : s + \"\";\n            },\n            bind: $.proxy,\n            each: function(collection, cb) {\n                $.each(collection, reverseArgs);\n                function reverseArgs(index, value) {\n                    return cb(value, index);\n                }\n            },\n            map: $.map,\n            filter: $.grep,\n            every: function(obj, test) {\n                var result = true;\n                if (!obj) {\n                    return result;\n                }\n                $.each(obj, function(key, val) {\n                    if (!(result = test.call(null, val, key, obj))) {\n                        return false;\n                    }\n                });\n                return !!result;\n            },\n            some: function(obj, test) {\n                var result = false;\n                if (!obj) {\n                    return result;\n                }\n                $.each(obj, function(key, val) {\n                    if (result = test.call(null, val, key, obj)) {\n                        return false;\n                    }\n                });\n                return !!result;\n            },\n            mixin: $.extend,\n            identity: function(x) {\n                return x;\n            },\n            clone: function(obj) {\n                return $.extend(true, {}, obj);\n            },\n            getIdGenerator: function() {\n                var counter = 0;\n                return function() {\n                    return counter++;\n                };\n            },\n            templatify: function templatify(obj) {\n                return $.isFunction(obj) ? obj : template;\n                function template() {\n                    return String(obj);\n                }\n            },\n            defer: function(fn) {\n                setTimeout(fn, 0);\n            },\n            debounce: function(func, wait, immediate) {\n                var timeout, result;\n                return function() {\n                    var context = this, args = arguments, later, callNow;\n                    later = function() {\n                        timeout = null;\n                        if (!immediate) {\n                            result = func.apply(context, args);\n                        }\n                    };\n                    callNow = immediate && !timeout;\n                    clearTimeout(timeout);\n                    timeout = setTimeout(later, wait);\n                    if (callNow) {\n                        result = func.apply(context, args);\n                    }\n                    return result;\n                };\n            },\n            throttle: function(func, wait) {\n                var context, args, timeout, result, previous, later;\n                previous = 0;\n                later = function() {\n                    previous = new Date();\n                    timeout = null;\n                    result = func.apply(context, args);\n                };\n                return function() {\n                    var now = new Date(), remaining = wait - (now - previous);\n                    context = this;\n                    args = arguments;\n                    if (remaining <= 0) {\n                        clearTimeout(timeout);\n                        timeout = null;\n                        previous = now;\n                        result = func.apply(context, args);\n                    } else if (!timeout) {\n                        timeout = setTimeout(later, remaining);\n                    }\n                    return result;\n                };\n            },\n            stringify: function(val) {\n                return _.isString(val) ? val : JSON.stringify(val);\n            },\n            noop: function() {}\n        };\n    }();\n    var WWW = function() {\n        \"use strict\";\n        var defaultClassNames = {\n            wrapper: \"twitter-typeahead\",\n            input: \"tt-input\",\n            hint: \"tt-hint\",\n            menu: \"tt-menu\",\n            dataset: \"tt-dataset\",\n            suggestion: \"tt-suggestion\",\n            selectable: \"tt-selectable\",\n            empty: \"tt-empty\",\n            open: \"tt-open\",\n            cursor: \"tt-cursor\",\n            highlight: \"tt-highlight\"\n        };\n        return build;\n        function build(o) {\n            var www, classes;\n            classes = _.mixin({}, defaultClassNames, o);\n            www = {\n                css: buildCss(),\n                classes: classes,\n                html: buildHtml(classes),\n                selectors: buildSelectors(classes)\n            };\n            return {\n                css: www.css,\n                html: www.html,\n                classes: www.classes,\n                selectors: www.selectors,\n                mixin: function(o) {\n                    _.mixin(o, www);\n                }\n            };\n        }\n        function buildHtml(c) {\n            return {\n                wrapper: '<span class=\"' + c.wrapper + '\"></span>',\n                menu: '<div class=\"' + c.menu + '\"></div>'\n            };\n        }\n        function buildSelectors(classes) {\n            var selectors = {};\n            _.each(classes, function(v, k) {\n                selectors[k] = \".\" + v;\n            });\n            return selectors;\n        }\n        function buildCss() {\n            var css = {\n                wrapper: {\n                    position: \"relative\",\n                    display: \"inline-block\"\n                },\n                hint: {\n                    position: \"absolute\",\n                    top: \"0\",\n                    left: \"0\",\n                    borderColor: \"transparent\",\n                    boxShadow: \"none\",\n                    opacity: \"1\"\n                },\n                input: {\n                    position: \"relative\",\n                    verticalAlign: \"top\",\n                    backgroundColor: \"transparent\"\n                },\n                inputWithNoHint: {\n                    position: \"relative\",\n                    verticalAlign: \"top\"\n                },\n                menu: {\n                    position: \"absolute\",\n                    top: \"100%\",\n                    left: \"0\",\n                    zIndex: \"100\",\n                    display: \"none\"\n                },\n                ltr: {\n                    left: \"0\",\n                    right: \"auto\"\n                },\n                rtl: {\n                    left: \"auto\",\n                    right: \" 0\"\n                }\n            };\n            if (_.isMsie()) {\n                _.mixin(css.input, {\n                    backgroundImage: \"url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)\"\n                });\n            }\n            return css;\n        }\n    }();\n    var EventBus = function() {\n        \"use strict\";\n        var namespace, deprecationMap;\n        namespace = \"typeahead:\";\n        deprecationMap = {\n            render: \"rendered\",\n            cursorchange: \"cursorchanged\",\n            select: \"selected\",\n            autocomplete: \"autocompleted\"\n        };\n        function EventBus(o) {\n            if (!o || !o.el) {\n                $.error(\"EventBus initialized without el\");\n            }\n            this.$el = $(o.el);\n        }\n        _.mixin(EventBus.prototype, {\n            _trigger: function(type, args) {\n                var $e;\n                $e = $.Event(namespace + type);\n                (args = args || []).unshift($e);\n                this.$el.trigger.apply(this.$el, args);\n                return $e;\n            },\n            before: function(type) {\n                var args, $e;\n                args = [].slice.call(arguments, 1);\n                $e = this._trigger(\"before\" + type, args);\n                return $e.isDefaultPrevented();\n            },\n            trigger: function(type) {\n                var deprecatedType;\n                this._trigger(type, [].slice.call(arguments, 1));\n                if (deprecatedType = deprecationMap[type]) {\n                    this._trigger(deprecatedType, [].slice.call(arguments, 1));\n                }\n            }\n        });\n        return EventBus;\n    }();\n    var EventEmitter = function() {\n        \"use strict\";\n        var splitter = /\\s+/, nextTick = getNextTick();\n        return {\n            onSync: onSync,\n            onAsync: onAsync,\n            off: off,\n            trigger: trigger\n        };\n        function on(method, types, cb, context) {\n            var type;\n            if (!cb) {\n                return this;\n            }\n            types = types.split(splitter);\n            cb = context ? bindContext(cb, context) : cb;\n            this._callbacks = this._callbacks || {};\n            while (type = types.shift()) {\n                this._callbacks[type] = this._callbacks[type] || {\n                    sync: [],\n                    async: []\n                };\n                this._callbacks[type][method].push(cb);\n            }\n            return this;\n        }\n        function onAsync(types, cb, context) {\n            return on.call(this, \"async\", types, cb, context);\n        }\n        function onSync(types, cb, context) {\n            return on.call(this, \"sync\", types, cb, context);\n        }\n        function off(types) {\n            var type;\n            if (!this._callbacks) {\n                return this;\n            }\n            types = types.split(splitter);\n            while (type = types.shift()) {\n                delete this._callbacks[type];\n            }\n            return this;\n        }\n        function trigger(types) {\n            var type, callbacks, args, syncFlush, asyncFlush;\n            if (!this._callbacks) {\n                return this;\n            }\n            types = types.split(splitter);\n            args = [].slice.call(arguments, 1);\n            while ((type = types.shift()) && (callbacks = this._callbacks[type])) {\n                syncFlush = getFlush(callbacks.sync, this, [ type ].concat(args));\n                asyncFlush = getFlush(callbacks.async, this, [ type ].concat(args));\n                syncFlush() && nextTick(asyncFlush);\n            }\n            return this;\n        }\n        function getFlush(callbacks, context, args) {\n            return flush;\n            function flush() {\n                var cancelled;\n                for (var i = 0, len = callbacks.length; !cancelled && i < len; i += 1) {\n                    cancelled = callbacks[i].apply(context, args) === false;\n                }\n                return !cancelled;\n            }\n        }\n        function getNextTick() {\n            var nextTickFn;\n            if (window.setImmediate) {\n                nextTickFn = function nextTickSetImmediate(fn) {\n                    setImmediate(function() {\n                        fn();\n                    });\n                };\n            } else {\n                nextTickFn = function nextTickSetTimeout(fn) {\n                    setTimeout(function() {\n                        fn();\n                    }, 0);\n                };\n            }\n            return nextTickFn;\n        }\n        function bindContext(fn, context) {\n            return fn.bind ? fn.bind(context) : function() {\n                fn.apply(context, [].slice.call(arguments, 0));\n            };\n        }\n    }();\n    var highlight = function(doc) {\n        \"use strict\";\n        var defaults = {\n            node: null,\n            pattern: null,\n            tagName: \"strong\",\n            className: null,\n            wordsOnly: false,\n            caseSensitive: false\n        };\n        return function hightlight(o) {\n            var regex;\n            o = _.mixin({}, defaults, o);\n            if (!o.node || !o.pattern) {\n                return;\n            }\n            o.pattern = _.isArray(o.pattern) ? o.pattern : [ o.pattern ];\n            regex = getRegex(o.pattern, o.caseSensitive, o.wordsOnly);\n            traverse(o.node, hightlightTextNode);\n            function hightlightTextNode(textNode) {\n                var match, patternNode, wrapperNode;\n                if (match = regex.exec(textNode.data)) {\n                    wrapperNode = doc.createElement(o.tagName);\n                    o.className && (wrapperNode.className = o.className);\n                    patternNode = textNode.splitText(match.index);\n                    patternNode.splitText(match[0].length);\n                    wrapperNode.appendChild(patternNode.cloneNode(true));\n                    textNode.parentNode.replaceChild(wrapperNode, patternNode);\n                }\n                return !!match;\n            }\n            function traverse(el, hightlightTextNode) {\n                var childNode, TEXT_NODE_TYPE = 3;\n                for (var i = 0; i < el.childNodes.length; i++) {\n                    childNode = el.childNodes[i];\n                    if (childNode.nodeType === TEXT_NODE_TYPE) {\n                        i += hightlightTextNode(childNode) ? 1 : 0;\n                    } else {\n                        traverse(childNode, hightlightTextNode);\n                    }\n                }\n            }\n        };\n        function getRegex(patterns, caseSensitive, wordsOnly) {\n            var escapedPatterns = [], regexStr;\n            for (var i = 0, len = patterns.length; i < len; i++) {\n                escapedPatterns.push(_.escapeRegExChars(patterns[i]));\n            }\n            regexStr = wordsOnly ? \"\\\\b(\" + escapedPatterns.join(\"|\") + \")\\\\b\" : \"(\" + escapedPatterns.join(\"|\") + \")\";\n            return caseSensitive ? new RegExp(regexStr) : new RegExp(regexStr, \"i\");\n        }\n    }(window.document);\n    var Input = function() {\n        \"use strict\";\n        var specialKeyCodeMap;\n        specialKeyCodeMap = {\n            9: \"tab\",\n            27: \"esc\",\n            37: \"left\",\n            39: \"right\",\n            13: \"enter\",\n            38: \"up\",\n            40: \"down\"\n        };\n        function Input(o, www) {\n            o = o || {};\n            if (!o.input) {\n                $.error(\"input is missing\");\n            }\n            www.mixin(this);\n            this.$hint = $(o.hint);\n            this.$input = $(o.input);\n            this.query = this.$input.val();\n            this.queryWhenFocused = this.hasFocus() ? this.query : null;\n            this.$overflowHelper = buildOverflowHelper(this.$input);\n            this._checkLanguageDirection();\n            if (this.$hint.length === 0) {\n                this.setHint = this.getHint = this.clearHint = this.clearHintIfInvalid = _.noop;\n            }\n        }\n        Input.normalizeQuery = function(str) {\n            return _.toStr(str).replace(/^\\s*/g, \"\").replace(/\\s{2,}/g, \" \");\n        };\n        _.mixin(Input.prototype, EventEmitter, {\n            _onBlur: function onBlur() {\n                this.resetInputValue();\n                this.trigger(\"blurred\");\n            },\n            _onFocus: function onFocus() {\n                this.queryWhenFocused = this.query;\n                this.trigger(\"focused\");\n            },\n            _onKeydown: function onKeydown($e) {\n                var keyName = specialKeyCodeMap[$e.which || $e.keyCode];\n                this._managePreventDefault(keyName, $e);\n                if (keyName && this._shouldTrigger(keyName, $e)) {\n                    this.trigger(keyName + \"Keyed\", $e);\n                }\n            },\n            _onInput: function onInput() {\n                this._setQuery(this.getInputValue());\n                this.clearHintIfInvalid();\n                this._checkLanguageDirection();\n            },\n            _managePreventDefault: function managePreventDefault(keyName, $e) {\n                var preventDefault;\n                switch (keyName) {\n                  case \"up\":\n                  case \"down\":\n                    preventDefault = !withModifier($e);\n                    break;\n\n                  default:\n                    preventDefault = false;\n                }\n                preventDefault && $e.preventDefault();\n            },\n            _shouldTrigger: function shouldTrigger(keyName, $e) {\n                var trigger;\n                switch (keyName) {\n                  case \"tab\":\n                    trigger = !withModifier($e);\n                    break;\n\n                  default:\n                    trigger = true;\n                }\n                return trigger;\n            },\n            _checkLanguageDirection: function checkLanguageDirection() {\n                var dir = (this.$input.css(\"direction\") || \"ltr\").toLowerCase();\n                if (this.dir !== dir) {\n                    this.dir = dir;\n                    this.$hint.attr(\"dir\", dir);\n                    this.trigger(\"langDirChanged\", dir);\n                }\n            },\n            _setQuery: function setQuery(val, silent) {\n                var areEquivalent, hasDifferentWhitespace;\n                areEquivalent = areQueriesEquivalent(val, this.query);\n                hasDifferentWhitespace = areEquivalent ? this.query.length !== val.length : false;\n                this.query = val;\n                if (!silent && !areEquivalent) {\n                    this.trigger(\"queryChanged\", this.query);\n                } else if (!silent && hasDifferentWhitespace) {\n                    this.trigger(\"whitespaceChanged\", this.query);\n                }\n            },\n            bind: function() {\n                var that = this, onBlur, onFocus, onKeydown, onInput;\n                onBlur = _.bind(this._onBlur, this);\n                onFocus = _.bind(this._onFocus, this);\n                onKeydown = _.bind(this._onKeydown, this);\n                onInput = _.bind(this._onInput, this);\n                this.$input.on(\"blur.tt\", onBlur).on(\"focus.tt\", onFocus).on(\"keydown.tt\", onKeydown);\n                if (!_.isMsie() || _.isMsie() > 9) {\n                    this.$input.on(\"input.tt\", onInput);\n                } else {\n                    this.$input.on(\"keydown.tt keypress.tt cut.tt paste.tt\", function($e) {\n                        if (specialKeyCodeMap[$e.which || $e.keyCode]) {\n                            return;\n                        }\n                        _.defer(_.bind(that._onInput, that, $e));\n                    });\n                }\n                return this;\n            },\n            focus: function focus() {\n                this.$input.focus();\n            },\n            blur: function blur() {\n                this.$input.blur();\n            },\n            getLangDir: function getLangDir() {\n                return this.dir;\n            },\n            getQuery: function getQuery() {\n                return this.query || \"\";\n            },\n            setQuery: function setQuery(val, silent) {\n                this.setInputValue(val);\n                this._setQuery(val, silent);\n            },\n            hasQueryChangedSinceLastFocus: function hasQueryChangedSinceLastFocus() {\n                return this.query !== this.queryWhenFocused;\n            },\n            getInputValue: function getInputValue() {\n                return this.$input.val();\n            },\n            setInputValue: function setInputValue(value) {\n                this.$input.val(value);\n                this.clearHintIfInvalid();\n                this._checkLanguageDirection();\n            },\n            resetInputValue: function resetInputValue() {\n                this.setInputValue(this.query);\n            },\n            getHint: function getHint() {\n                return this.$hint.val();\n            },\n            setHint: function setHint(value) {\n                this.$hint.val(value);\n            },\n            clearHint: function clearHint() {\n                this.setHint(\"\");\n            },\n            clearHintIfInvalid: function clearHintIfInvalid() {\n                var val, hint, valIsPrefixOfHint, isValid;\n                val = this.getInputValue();\n                hint = this.getHint();\n                valIsPrefixOfHint = val !== hint && hint.indexOf(val) === 0;\n                isValid = val !== \"\" && valIsPrefixOfHint && !this.hasOverflow();\n                !isValid && this.clearHint();\n            },\n            hasFocus: function hasFocus() {\n                return this.$input.is(\":focus\");\n            },\n            hasOverflow: function hasOverflow() {\n                var constraint = this.$input.width() - 2;\n                this.$overflowHelper.text(this.getInputValue());\n                return this.$overflowHelper.width() >= constraint;\n            },\n            isCursorAtEnd: function() {\n                var valueLength, selectionStart, range;\n                valueLength = this.$input.val().length;\n                selectionStart = this.$input[0].selectionStart;\n                if (_.isNumber(selectionStart)) {\n                    return selectionStart === valueLength;\n                } else if (document.selection) {\n                    range = document.selection.createRange();\n                    range.moveStart(\"character\", -valueLength);\n                    return valueLength === range.text.length;\n                }\n                return true;\n            },\n            destroy: function destroy() {\n                this.$hint.off(\".tt\");\n                this.$input.off(\".tt\");\n                this.$overflowHelper.remove();\n                this.$hint = this.$input = this.$overflowHelper = $(\"<div>\");\n            }\n        });\n        return Input;\n        function buildOverflowHelper($input) {\n            return $('<pre aria-hidden=\"true\"></pre>').css({\n                position: \"absolute\",\n                visibility: \"hidden\",\n                whiteSpace: \"pre\",\n                fontFamily: $input.css(\"font-family\"),\n                fontSize: $input.css(\"font-size\"),\n                fontStyle: $input.css(\"font-style\"),\n                fontVariant: $input.css(\"font-variant\"),\n                fontWeight: $input.css(\"font-weight\"),\n                wordSpacing: $input.css(\"word-spacing\"),\n                letterSpacing: $input.css(\"letter-spacing\"),\n                textIndent: $input.css(\"text-indent\"),\n                textRendering: $input.css(\"text-rendering\"),\n                textTransform: $input.css(\"text-transform\")\n            }).insertAfter($input);\n        }\n        function areQueriesEquivalent(a, b) {\n            return Input.normalizeQuery(a) === Input.normalizeQuery(b);\n        }\n        function withModifier($e) {\n            return $e.altKey || $e.ctrlKey || $e.metaKey || $e.shiftKey;\n        }\n    }();\n    var Dataset = function() {\n        \"use strict\";\n        var keys, nameGenerator;\n        keys = {\n            val: \"tt-selectable-display\",\n            obj: \"tt-selectable-object\"\n        };\n        nameGenerator = _.getIdGenerator();\n        function Dataset(o, www) {\n            o = o || {};\n            o.templates = o.templates || {};\n            o.templates.notFound = o.templates.notFound || o.templates.empty;\n            if (!o.source) {\n                $.error(\"missing source\");\n            }\n            if (!o.node) {\n                $.error(\"missing node\");\n            }\n            if (o.name && !isValidName(o.name)) {\n                $.error(\"invalid dataset name: \" + o.name);\n            }\n            www.mixin(this);\n            this.highlight = !!o.highlight;\n            this.name = o.name || nameGenerator();\n            this.limit = o.limit || 5;\n            this.displayFn = getDisplayFn(o.display || o.displayKey);\n            this.templates = getTemplates(o.templates, this.displayFn);\n            this.source = o.source.__ttAdapter ? o.source.__ttAdapter() : o.source;\n            this.async = _.isUndefined(o.async) ? this.source.length > 2 : !!o.async;\n            this._resetLastSuggestion();\n            this.$el = $(o.node).addClass(this.classes.dataset).addClass(this.classes.dataset + \"-\" + this.name);\n        }\n        Dataset.extractData = function extractData(el) {\n            var $el = $(el);\n            if ($el.data(keys.obj)) {\n                return {\n                    val: $el.data(keys.val) || \"\",\n                    obj: $el.data(keys.obj) || null\n                };\n            }\n            return null;\n        };\n        _.mixin(Dataset.prototype, EventEmitter, {\n            _overwrite: function overwrite(query, suggestions) {\n                suggestions = suggestions || [];\n                if (suggestions.length) {\n                    this._renderSuggestions(query, suggestions);\n                } else if (this.async && this.templates.pending) {\n                    this._renderPending(query);\n                } else if (!this.async && this.templates.notFound) {\n                    this._renderNotFound(query);\n                } else {\n                    this._empty();\n                }\n                this.trigger(\"rendered\", this.name, suggestions, false);\n            },\n            _append: function append(query, suggestions) {\n                suggestions = suggestions || [];\n                if (suggestions.length && this.$lastSuggestion.length) {\n                    this._appendSuggestions(query, suggestions);\n                } else if (suggestions.length) {\n                    this._renderSuggestions(query, suggestions);\n                } else if (!this.$lastSuggestion.length && this.templates.notFound) {\n                    this._renderNotFound(query);\n                }\n                this.trigger(\"rendered\", this.name, suggestions, true);\n            },\n            _renderSuggestions: function renderSuggestions(query, suggestions) {\n                var $fragment;\n                $fragment = this._getSuggestionsFragment(query, suggestions);\n                this.$lastSuggestion = $fragment.children().last();\n                this.$el.html($fragment).prepend(this._getHeader(query, suggestions)).append(this._getFooter(query, suggestions));\n            },\n            _appendSuggestions: function appendSuggestions(query, suggestions) {\n                var $fragment, $lastSuggestion;\n                $fragment = this._getSuggestionsFragment(query, suggestions);\n                $lastSuggestion = $fragment.children().last();\n                this.$lastSuggestion.after($fragment);\n                this.$lastSuggestion = $lastSuggestion;\n            },\n            _renderPending: function renderPending(query) {\n                var template = this.templates.pending;\n                this._resetLastSuggestion();\n                template && this.$el.html(template({\n                    query: query,\n                    dataset: this.name\n                }));\n            },\n            _renderNotFound: function renderNotFound(query) {\n                var template = this.templates.notFound;\n                this._resetLastSuggestion();\n                template && this.$el.html(template({\n                    query: query,\n                    dataset: this.name\n                }));\n            },\n            _empty: function empty() {\n                this.$el.empty();\n                this._resetLastSuggestion();\n            },\n            _getSuggestionsFragment: function getSuggestionsFragment(query, suggestions) {\n                var that = this, fragment;\n                fragment = document.createDocumentFragment();\n                _.each(suggestions, function getSuggestionNode(suggestion) {\n                    var $el, context;\n                    context = that._injectQuery(query, suggestion);\n                    $el = $(that.templates.suggestion(context)).data(keys.obj, suggestion).data(keys.val, that.displayFn(suggestion)).addClass(that.classes.suggestion + \" \" + that.classes.selectable);\n                    fragment.appendChild($el[0]);\n                });\n                this.highlight && highlight({\n                    className: this.classes.highlight,\n                    node: fragment,\n                    pattern: query\n                });\n                return $(fragment);\n            },\n            _getFooter: function getFooter(query, suggestions) {\n                return this.templates.footer ? this.templates.footer({\n                    query: query,\n                    suggestions: suggestions,\n                    dataset: this.name\n                }) : null;\n            },\n            _getHeader: function getHeader(query, suggestions) {\n                return this.templates.header ? this.templates.header({\n                    query: query,\n                    suggestions: suggestions,\n                    dataset: this.name\n                }) : null;\n            },\n            _resetLastSuggestion: function resetLastSuggestion() {\n                this.$lastSuggestion = $();\n            },\n            _injectQuery: function injectQuery(query, obj) {\n                return _.isObject(obj) ? _.mixin({\n                    _query: query\n                }, obj) : obj;\n            },\n            update: function update(query) {\n                var that = this, canceled = false, syncCalled = false, rendered = 0;\n                this.cancel();\n                this.cancel = function cancel() {\n                    canceled = true;\n                    that.cancel = $.noop;\n                    that.async && that.trigger(\"asyncCanceled\", query);\n                };\n                this.source(query, sync, async);\n                !syncCalled && sync([]);\n                function sync(suggestions) {\n                    if (syncCalled) {\n                        return;\n                    }\n                    syncCalled = true;\n                    suggestions = (suggestions || []).slice(0, that.limit);\n                    rendered = suggestions.length;\n                    that._overwrite(query, suggestions);\n                    if (rendered < that.limit && that.async) {\n                        that.trigger(\"asyncRequested\", query);\n                    }\n                }\n                function async(suggestions) {\n                    suggestions = suggestions || [];\n                    if (!canceled && rendered < that.limit) {\n                        that.cancel = $.noop;\n                        rendered += suggestions.length;\n                        that._append(query, suggestions.slice(0, that.limit - rendered));\n                        that.async && that.trigger(\"asyncReceived\", query);\n                    }\n                }\n            },\n            cancel: $.noop,\n            clear: function clear() {\n                this._empty();\n                this.cancel();\n                this.trigger(\"cleared\");\n            },\n            isEmpty: function isEmpty() {\n                return this.$el.is(\":empty\");\n            },\n            destroy: function destroy() {\n                this.$el = $(\"<div>\");\n            }\n        });\n        return Dataset;\n        function getDisplayFn(display) {\n            display = display || _.stringify;\n            return _.isFunction(display) ? display : displayFn;\n            function displayFn(obj) {\n                return obj[display];\n            }\n        }\n        function getTemplates(templates, displayFn) {\n            return {\n                notFound: templates.notFound && _.templatify(templates.notFound),\n                pending: templates.pending && _.templatify(templates.pending),\n                header: templates.header && _.templatify(templates.header),\n                footer: templates.footer && _.templatify(templates.footer),\n                suggestion: templates.suggestion || suggestionTemplate\n            };\n            function suggestionTemplate(context) {\n                return $(\"<div>\").text(displayFn(context));\n            }\n        }\n        function isValidName(str) {\n            return /^[_a-zA-Z0-9-]+$/.test(str);\n        }\n    }();\n    var Menu = function() {\n        \"use strict\";\n        function Menu(o, www) {\n            var that = this;\n            o = o || {};\n            if (!o.node) {\n                $.error(\"node is required\");\n            }\n            www.mixin(this);\n            this.$node = $(o.node);\n            this.query = null;\n            this.datasets = _.map(o.datasets, initializeDataset);\n            function initializeDataset(oDataset) {\n                var node = that.$node.find(oDataset.node).first();\n                oDataset.node = node.length ? node : $(\"<div>\").appendTo(that.$node);\n                return new Dataset(oDataset, www);\n            }\n        }\n        _.mixin(Menu.prototype, EventEmitter, {\n            _onSelectableClick: function onSelectableClick($e) {\n                this.trigger(\"selectableClicked\", $($e.currentTarget));\n            },\n            _onRendered: function onRendered(type, dataset, suggestions, async) {\n                this.$node.toggleClass(this.classes.empty, this._allDatasetsEmpty());\n                this.trigger(\"datasetRendered\", dataset, suggestions, async);\n            },\n            _onCleared: function onCleared() {\n                this.$node.toggleClass(this.classes.empty, this._allDatasetsEmpty());\n                this.trigger(\"datasetCleared\");\n            },\n            _propagate: function propagate() {\n                this.trigger.apply(this, arguments);\n            },\n            _allDatasetsEmpty: function allDatasetsEmpty() {\n                return _.every(this.datasets, isDatasetEmpty);\n                function isDatasetEmpty(dataset) {\n                    return dataset.isEmpty();\n                }\n            },\n            _getSelectables: function getSelectables() {\n                return this.$node.find(this.selectors.selectable);\n            },\n            _removeCursor: function _removeCursor() {\n                var $selectable = this.getActiveSelectable();\n                $selectable && $selectable.removeClass(this.classes.cursor);\n            },\n            _ensureVisible: function ensureVisible($el) {\n                var elTop, elBottom, nodeScrollTop, nodeHeight;\n                elTop = $el.position().top;\n                elBottom = elTop + $el.outerHeight(true);\n                nodeScrollTop = this.$node.scrollTop();\n                nodeHeight = this.$node.height() + parseInt(this.$node.css(\"paddingTop\"), 10) + parseInt(this.$node.css(\"paddingBottom\"), 10);\n                if (elTop < 0) {\n                    this.$node.scrollTop(nodeScrollTop + elTop);\n                } else if (nodeHeight < elBottom) {\n                    this.$node.scrollTop(nodeScrollTop + (elBottom - nodeHeight));\n                }\n            },\n            bind: function() {\n                var that = this, onSelectableClick;\n                onSelectableClick = _.bind(this._onSelectableClick, this);\n                this.$node.on(\"click.tt\", this.selectors.selectable, onSelectableClick);\n                _.each(this.datasets, function(dataset) {\n                    dataset.onSync(\"asyncRequested\", that._propagate, that).onSync(\"asyncCanceled\", that._propagate, that).onSync(\"asyncReceived\", that._propagate, that).onSync(\"rendered\", that._onRendered, that).onSync(\"cleared\", that._onCleared, that);\n                });\n                return this;\n            },\n            isOpen: function isOpen() {\n                return this.$node.hasClass(this.classes.open);\n            },\n            open: function open() {\n                this.$node.addClass(this.classes.open);\n            },\n            close: function close() {\n                this.$node.removeClass(this.classes.open);\n                this._removeCursor();\n            },\n            setLanguageDirection: function setLanguageDirection(dir) {\n                this.$node.attr(\"dir\", dir);\n            },\n            selectableRelativeToCursor: function selectableRelativeToCursor(delta) {\n                var $selectables, $oldCursor, oldIndex, newIndex;\n                $oldCursor = this.getActiveSelectable();\n                $selectables = this._getSelectables();\n                oldIndex = $oldCursor ? $selectables.index($oldCursor) : -1;\n                newIndex = oldIndex + delta;\n                newIndex = (newIndex + 1) % ($selectables.length + 1) - 1;\n                newIndex = newIndex < -1 ? $selectables.length - 1 : newIndex;\n                return newIndex === -1 ? null : $selectables.eq(newIndex);\n            },\n            setCursor: function setCursor($selectable) {\n                this._removeCursor();\n                if ($selectable = $selectable && $selectable.first()) {\n                    $selectable.addClass(this.classes.cursor);\n                    this._ensureVisible($selectable);\n                }\n            },\n            getSelectableData: function getSelectableData($el) {\n                return $el && $el.length ? Dataset.extractData($el) : null;\n            },\n            getActiveSelectable: function getActiveSelectable() {\n                var $selectable = this._getSelectables().filter(this.selectors.cursor).first();\n                return $selectable.length ? $selectable : null;\n            },\n            getTopSelectable: function getTopSelectable() {\n                var $selectable = this._getSelectables().first();\n                return $selectable.length ? $selectable : null;\n            },\n            update: function update(query) {\n                var isValidUpdate = query !== this.query;\n                if (isValidUpdate) {\n                    this.query = query;\n                    _.each(this.datasets, updateDataset);\n                }\n                return isValidUpdate;\n                function updateDataset(dataset) {\n                    dataset.update(query);\n                }\n            },\n            empty: function empty() {\n                _.each(this.datasets, clearDataset);\n                this.query = null;\n                this.$node.addClass(this.classes.empty);\n                function clearDataset(dataset) {\n                    dataset.clear();\n                }\n            },\n            destroy: function destroy() {\n                this.$node.off(\".tt\");\n                this.$node = $(\"<div>\");\n                _.each(this.datasets, destroyDataset);\n                function destroyDataset(dataset) {\n                    dataset.destroy();\n                }\n            }\n        });\n        return Menu;\n    }();\n    var DefaultMenu = function() {\n        \"use strict\";\n        var s = Menu.prototype;\n        function DefaultMenu() {\n            Menu.apply(this, [].slice.call(arguments, 0));\n        }\n        _.mixin(DefaultMenu.prototype, Menu.prototype, {\n            open: function open() {\n                !this._allDatasetsEmpty() && this._show();\n                return s.open.apply(this, [].slice.call(arguments, 0));\n            },\n            close: function close() {\n                this._hide();\n                return s.close.apply(this, [].slice.call(arguments, 0));\n            },\n            _onRendered: function onRendered() {\n                if (this._allDatasetsEmpty()) {\n                    this._hide();\n                } else {\n                    this.isOpen() && this._show();\n                }\n                return s._onRendered.apply(this, [].slice.call(arguments, 0));\n            },\n            _onCleared: function onCleared() {\n                if (this._allDatasetsEmpty()) {\n                    this._hide();\n                } else {\n                    this.isOpen() && this._show();\n                }\n                return s._onCleared.apply(this, [].slice.call(arguments, 0));\n            },\n            setLanguageDirection: function setLanguageDirection(dir) {\n                this.$node.css(dir === \"ltr\" ? this.css.ltr : this.css.rtl);\n                return s.setLanguageDirection.apply(this, [].slice.call(arguments, 0));\n            },\n            _hide: function hide() {\n                this.$node.hide();\n            },\n            _show: function show() {\n                this.$node.css(\"display\", \"block\");\n            }\n        });\n        return DefaultMenu;\n    }();\n    var Typeahead = function() {\n        \"use strict\";\n        function Typeahead(o, www) {\n            var onFocused, onBlurred, onEnterKeyed, onTabKeyed, onEscKeyed, onUpKeyed, onDownKeyed, onLeftKeyed, onRightKeyed, onQueryChanged, onWhitespaceChanged;\n            o = o || {};\n            if (!o.input) {\n                $.error(\"missing input\");\n            }\n            if (!o.menu) {\n                $.error(\"missing menu\");\n            }\n            if (!o.eventBus) {\n                $.error(\"missing event bus\");\n            }\n            www.mixin(this);\n            this.eventBus = o.eventBus;\n            this.minLength = _.isNumber(o.minLength) ? o.minLength : 1;\n            this.input = o.input;\n            this.menu = o.menu;\n            this.enabled = true;\n            this.active = false;\n            this.input.hasFocus() && this.activate();\n            this.dir = this.input.getLangDir();\n            this._hacks();\n            this.menu.bind().onSync(\"selectableClicked\", this._onSelectableClicked, this).onSync(\"asyncRequested\", this._onAsyncRequested, this).onSync(\"asyncCanceled\", this._onAsyncCanceled, this).onSync(\"asyncReceived\", this._onAsyncReceived, this).onSync(\"datasetRendered\", this._onDatasetRendered, this).onSync(\"datasetCleared\", this._onDatasetCleared, this);\n            onFocused = c(this, \"activate\", \"open\", \"_onFocused\");\n            onBlurred = c(this, \"deactivate\", \"_onBlurred\");\n            onEnterKeyed = c(this, \"isActive\", \"isOpen\", \"_onEnterKeyed\");\n            onTabKeyed = c(this, \"isActive\", \"isOpen\", \"_onTabKeyed\");\n            onEscKeyed = c(this, \"isActive\", \"_onEscKeyed\");\n            onUpKeyed = c(this, \"isActive\", \"open\", \"_onUpKeyed\");\n            onDownKeyed = c(this, \"isActive\", \"open\", \"_onDownKeyed\");\n            onLeftKeyed = c(this, \"isActive\", \"isOpen\", \"_onLeftKeyed\");\n            onRightKeyed = c(this, \"isActive\", \"isOpen\", \"_onRightKeyed\");\n            onQueryChanged = c(this, \"_openIfActive\", \"_onQueryChanged\");\n            onWhitespaceChanged = c(this, \"_openIfActive\", \"_onWhitespaceChanged\");\n            this.input.bind().onSync(\"focused\", onFocused, this).onSync(\"blurred\", onBlurred, this).onSync(\"enterKeyed\", onEnterKeyed, this).onSync(\"tabKeyed\", onTabKeyed, this).onSync(\"escKeyed\", onEscKeyed, this).onSync(\"upKeyed\", onUpKeyed, this).onSync(\"downKeyed\", onDownKeyed, this).onSync(\"leftKeyed\", onLeftKeyed, this).onSync(\"rightKeyed\", onRightKeyed, this).onSync(\"queryChanged\", onQueryChanged, this).onSync(\"whitespaceChanged\", onWhitespaceChanged, this).onSync(\"langDirChanged\", this._onLangDirChanged, this);\n        }\n        _.mixin(Typeahead.prototype, {\n            _hacks: function hacks() {\n                var $input, $menu;\n                $input = this.input.$input || $(\"<div>\");\n                $menu = this.menu.$node || $(\"<div>\");\n                $input.on(\"blur.tt\", function($e) {\n                    var active, isActive, hasActive;\n                    active = document.activeElement;\n                    isActive = $menu.is(active);\n                    hasActive = $menu.has(active).length > 0;\n                    if (_.isMsie() && (isActive || hasActive)) {\n                        $e.preventDefault();\n                        $e.stopImmediatePropagation();\n                        _.defer(function() {\n                            $input.focus();\n                        });\n                    }\n                });\n                $menu.on(\"mousedown.tt\", function($e) {\n                    $e.preventDefault();\n                });\n            },\n            _onSelectableClicked: function onSelectableClicked(type, $el) {\n                this.select($el);\n            },\n            _onDatasetCleared: function onDatasetCleared() {\n                this._updateHint();\n            },\n            _onDatasetRendered: function onDatasetRendered(type, dataset, suggestions, async) {\n                this._updateHint();\n                this.eventBus.trigger(\"render\", suggestions, async, dataset);\n            },\n            _onAsyncRequested: function onAsyncRequested(type, dataset, query) {\n                this.eventBus.trigger(\"asyncrequest\", query, dataset);\n            },\n            _onAsyncCanceled: function onAsyncCanceled(type, dataset, query) {\n                this.eventBus.trigger(\"asynccancel\", query, dataset);\n            },\n            _onAsyncReceived: function onAsyncReceived(type, dataset, query) {\n                this.eventBus.trigger(\"asyncreceive\", query, dataset);\n            },\n            _onFocused: function onFocused() {\n                this._minLengthMet() && this.menu.update(this.input.getQuery());\n            },\n            _onBlurred: function onBlurred() {\n                if (this.input.hasQueryChangedSinceLastFocus()) {\n                    this.eventBus.trigger(\"change\", this.input.getQuery());\n                }\n            },\n            _onEnterKeyed: function onEnterKeyed(type, $e) {\n                var $selectable;\n                if ($selectable = this.menu.getActiveSelectable()) {\n                    this.select($selectable) && $e.preventDefault();\n                }\n            },\n            _onTabKeyed: function onTabKeyed(type, $e) {\n                var $selectable;\n                if ($selectable = this.menu.getActiveSelectable()) {\n                    this.select($selectable) && $e.preventDefault();\n                } else if ($selectable = this.menu.getTopSelectable()) {\n                    this.autocomplete($selectable) && $e.preventDefault();\n                }\n            },\n            _onEscKeyed: function onEscKeyed() {\n                this.close();\n            },\n            _onUpKeyed: function onUpKeyed() {\n                this.moveCursor(-1);\n            },\n            _onDownKeyed: function onDownKeyed() {\n                this.moveCursor(+1);\n            },\n            _onLeftKeyed: function onLeftKeyed() {\n                if (this.dir === \"rtl\" && this.input.isCursorAtEnd()) {\n                    this.autocomplete(this.menu.getTopSelectable());\n                }\n            },\n            _onRightKeyed: function onRightKeyed() {\n                if (this.dir === \"ltr\" && this.input.isCursorAtEnd()) {\n                    this.autocomplete(this.menu.getTopSelectable());\n                }\n            },\n            _onQueryChanged: function onQueryChanged(e, query) {\n                this._minLengthMet(query) ? this.menu.update(query) : this.menu.empty();\n            },\n            _onWhitespaceChanged: function onWhitespaceChanged() {\n                this._updateHint();\n            },\n            _onLangDirChanged: function onLangDirChanged(e, dir) {\n                if (this.dir !== dir) {\n                    this.dir = dir;\n                    this.menu.setLanguageDirection(dir);\n                }\n            },\n            _openIfActive: function openIfActive() {\n                this.isActive() && this.open();\n            },\n            _minLengthMet: function minLengthMet(query) {\n                query = _.isString(query) ? query : this.input.getQuery() || \"\";\n                return query.length >= this.minLength;\n            },\n            _updateHint: function updateHint() {\n                var $selectable, data, val, query, escapedQuery, frontMatchRegEx, match;\n                $selectable = this.menu.getTopSelectable();\n                data = this.menu.getSelectableData($selectable);\n                val = this.input.getInputValue();\n                if (data && !_.isBlankString(val) && !this.input.hasOverflow()) {\n                    query = Input.normalizeQuery(val);\n                    escapedQuery = _.escapeRegExChars(query);\n                    frontMatchRegEx = new RegExp(\"^(?:\" + escapedQuery + \")(.+$)\", \"i\");\n                    match = frontMatchRegEx.exec(data.val);\n                    match && this.input.setHint(val + match[1]);\n                } else {\n                    this.input.clearHint();\n                }\n            },\n            isEnabled: function isEnabled() {\n                return this.enabled;\n            },\n            enable: function enable() {\n                this.enabled = true;\n            },\n            disable: function disable() {\n                this.enabled = false;\n            },\n            isActive: function isActive() {\n                return this.active;\n            },\n            activate: function activate() {\n                if (this.isActive()) {\n                    return true;\n                } else if (!this.isEnabled() || this.eventBus.before(\"active\")) {\n                    return false;\n                } else {\n                    this.active = true;\n                    this.eventBus.trigger(\"active\");\n                    return true;\n                }\n            },\n            deactivate: function deactivate() {\n                if (!this.isActive()) {\n                    return true;\n                } else if (this.eventBus.before(\"idle\")) {\n                    return false;\n                } else {\n                    this.active = false;\n                    this.close();\n                    this.eventBus.trigger(\"idle\");\n                    return true;\n                }\n            },\n            isOpen: function isOpen() {\n                return this.menu.isOpen();\n            },\n            open: function open() {\n                if (!this.isOpen() && !this.eventBus.before(\"open\")) {\n                    this.menu.open();\n                    this._updateHint();\n                    this.eventBus.trigger(\"open\");\n                }\n                return this.isOpen();\n            },\n            close: function close() {\n                if (this.isOpen() && !this.eventBus.before(\"close\")) {\n                    this.menu.close();\n                    this.input.clearHint();\n                    this.input.resetInputValue();\n                    this.eventBus.trigger(\"close\");\n                }\n                return !this.isOpen();\n            },\n            setVal: function setVal(val) {\n                this.input.setQuery(_.toStr(val));\n            },\n            getVal: function getVal() {\n                return this.input.getQuery();\n            },\n            select: function select($selectable) {\n                var data = this.menu.getSelectableData($selectable);\n                if (data && !this.eventBus.before(\"select\", data.obj)) {\n                    this.input.setQuery(data.val, true);\n                    this.eventBus.trigger(\"select\", data.obj);\n                    this.close();\n                    return true;\n                }\n                return false;\n            },\n            autocomplete: function autocomplete($selectable) {\n                var query, data, isValid;\n                query = this.input.getQuery();\n                data = this.menu.getSelectableData($selectable);\n                isValid = data && query !== data.val;\n                if (isValid && !this.eventBus.before(\"autocomplete\", data.obj)) {\n                    this.input.setQuery(data.val);\n                    this.eventBus.trigger(\"autocomplete\", data.obj);\n                    return true;\n                }\n                return false;\n            },\n            moveCursor: function moveCursor(delta) {\n                var query, $candidate, data, payload, cancelMove;\n                query = this.input.getQuery();\n                $candidate = this.menu.selectableRelativeToCursor(delta);\n                data = this.menu.getSelectableData($candidate);\n                payload = data ? data.obj : null;\n                cancelMove = this._minLengthMet() && this.menu.update(query);\n                if (!cancelMove && !this.eventBus.before(\"cursorchange\", payload)) {\n                    this.menu.setCursor($candidate);\n                    if (data) {\n                        this.input.setInputValue(data.val);\n                    } else {\n                        this.input.resetInputValue();\n                        this._updateHint();\n                    }\n                    this.eventBus.trigger(\"cursorchange\", payload);\n                    return true;\n                }\n                return false;\n            },\n            destroy: function destroy() {\n                this.input.destroy();\n                this.menu.destroy();\n            }\n        });\n        return Typeahead;\n        function c(ctx) {\n            var methods = [].slice.call(arguments, 1);\n            return function() {\n                var args = [].slice.call(arguments);\n                _.each(methods, function(method) {\n                    return ctx[method].apply(ctx, args);\n                });\n            };\n        }\n    }();\n    (function() {\n        \"use strict\";\n        var old, keys, methods;\n        old = $.fn.typeahead;\n        keys = {\n            www: \"tt-www\",\n            attrs: \"tt-attrs\",\n            typeahead: \"tt-typeahead\"\n        };\n        methods = {\n            initialize: function initialize(o, datasets) {\n                var www;\n                datasets = _.isArray(datasets) ? datasets : [].slice.call(arguments, 1);\n                o = o || {};\n                www = WWW(o.classNames);\n                return this.each(attach);\n                function attach() {\n                    var $input, $wrapper, $hint, $menu, defaultHint, defaultMenu, eventBus, input, menu, typeahead, MenuConstructor;\n                    _.each(datasets, function(d) {\n                        d.highlight = !!o.highlight;\n                    });\n                    $input = $(this);\n                    $wrapper = $(www.html.wrapper);\n                    $hint = $elOrNull(o.hint);\n                    $menu = $elOrNull(o.menu);\n                    defaultHint = o.hint !== false && !$hint;\n                    defaultMenu = o.menu !== false && !$menu;\n                    defaultHint && ($hint = buildHintFromInput($input, www));\n                    defaultMenu && ($menu = $(www.html.menu).css(www.css.menu));\n                    $hint && $hint.val(\"\");\n                    $input = prepInput($input, www);\n                    if (defaultHint || defaultMenu) {\n                        $wrapper.css(www.css.wrapper);\n                        $input.css(defaultHint ? www.css.input : www.css.inputWithNoHint);\n                        $input.wrap($wrapper).parent().prepend(defaultHint ? $hint : null).append(defaultMenu ? $menu : null);\n                    }\n                    MenuConstructor = defaultMenu ? DefaultMenu : Menu;\n                    eventBus = new EventBus({\n                        el: $input\n                    });\n                    input = new Input({\n                        hint: $hint,\n                        input: $input\n                    }, www);\n                    menu = new MenuConstructor({\n                        node: $menu,\n                        datasets: datasets\n                    }, www);\n                    typeahead = new Typeahead({\n                        input: input,\n                        menu: menu,\n                        eventBus: eventBus,\n                        minLength: o.minLength\n                    }, www);\n                    $input.data(keys.www, www);\n                    $input.data(keys.typeahead, typeahead);\n                }\n            },\n            isEnabled: function isEnabled() {\n                var enabled;\n                ttEach(this.first(), function(t) {\n                    enabled = t.isEnabled();\n                });\n                return enabled;\n            },\n            enable: function enable() {\n                ttEach(this, function(t) {\n                    t.enable();\n                });\n                return this;\n            },\n            disable: function disable() {\n                ttEach(this, function(t) {\n                    t.disable();\n                });\n                return this;\n            },\n            isActive: function isActive() {\n                var active;\n                ttEach(this.first(), function(t) {\n                    active = t.isActive();\n                });\n                return active;\n            },\n            activate: function activate() {\n                ttEach(this, function(t) {\n                    t.activate();\n                });\n                return this;\n            },\n            deactivate: function deactivate() {\n                ttEach(this, function(t) {\n                    t.deactivate();\n                });\n                return this;\n            },\n            isOpen: function isOpen() {\n                var open;\n                ttEach(this.first(), function(t) {\n                    open = t.isOpen();\n                });\n                return open;\n            },\n            open: function open() {\n                ttEach(this, function(t) {\n                    t.open();\n                });\n                return this;\n            },\n            close: function close() {\n                ttEach(this, function(t) {\n                    t.close();\n                });\n                return this;\n            },\n            select: function select(el) {\n                var success = false, $el = $(el);\n                ttEach(this.first(), function(t) {\n                    success = t.select($el);\n                });\n                return success;\n            },\n            autocomplete: function autocomplete(el) {\n                var success = false, $el = $(el);\n                ttEach(this.first(), function(t) {\n                    success = t.autocomplete($el);\n                });\n                return success;\n            },\n            moveCursor: function moveCursoe(delta) {\n                var success = false;\n                ttEach(this.first(), function(t) {\n                    success = t.moveCursor(delta);\n                });\n                return success;\n            },\n            val: function val(newVal) {\n                var query;\n                if (!arguments.length) {\n                    ttEach(this.first(), function(t) {\n                        query = t.getVal();\n                    });\n                    return query;\n                } else {\n                    ttEach(this, function(t) {\n                        t.setVal(newVal);\n                    });\n                    return this;\n                }\n            },\n            destroy: function destroy() {\n                ttEach(this, function(typeahead, $input) {\n                    revert($input);\n                    typeahead.destroy();\n                });\n                return this;\n            }\n        };\n        $.fn.typeahead = function(method) {\n            if (methods[method]) {\n                return methods[method].apply(this, [].slice.call(arguments, 1));\n            } else {\n                return methods.initialize.apply(this, arguments);\n            }\n        };\n        $.fn.typeahead.noConflict = function noConflict() {\n            $.fn.typeahead = old;\n            return this;\n        };\n        function ttEach($els, fn) {\n            $els.each(function() {\n                var $input = $(this), typeahead;\n                (typeahead = $input.data(keys.typeahead)) && fn(typeahead, $input);\n            });\n        }\n        function buildHintFromInput($input, www) {\n            return $input.clone().addClass(www.classes.hint).removeData().css(www.css.hint).css(getBackgroundStyles($input)).prop(\"readonly\", true).removeAttr(\"id name placeholder required\").attr({\n                autocomplete: \"off\",\n                spellcheck: \"false\",\n                tabindex: -1\n            });\n        }\n        function prepInput($input, www) {\n            $input.data(keys.attrs, {\n                dir: $input.attr(\"dir\"),\n                autocomplete: $input.attr(\"autocomplete\"),\n                spellcheck: $input.attr(\"spellcheck\"),\n                style: $input.attr(\"style\")\n            });\n            $input.addClass(www.classes.input).attr({\n                autocomplete: \"off\",\n                spellcheck: false\n            });\n            try {\n                !$input.attr(\"dir\") && $input.attr(\"dir\", \"auto\");\n            } catch (e) {}\n            return $input;\n        }\n        function getBackgroundStyles($el) {\n            return {\n                backgroundAttachment: $el.css(\"background-attachment\"),\n                backgroundClip: $el.css(\"background-clip\"),\n                backgroundColor: $el.css(\"background-color\"),\n                backgroundImage: $el.css(\"background-image\"),\n                backgroundOrigin: $el.css(\"background-origin\"),\n                backgroundPosition: $el.css(\"background-position\"),\n                backgroundRepeat: $el.css(\"background-repeat\"),\n                backgroundSize: $el.css(\"background-size\")\n            };\n        }\n        function revert($input) {\n            var www, $wrapper;\n            www = $input.data(keys.www);\n            $wrapper = $input.parent().filter(www.selectors.wrapper);\n            _.each($input.data(keys.attrs), function(val, key) {\n                _.isUndefined(val) ? $input.removeAttr(key) : $input.attr(key, val);\n            });\n            $input.removeData(keys.typeahead).removeData(keys.www).removeData(keys.attr).removeClass(www.classes.input);\n            if ($wrapper.length) {\n                $input.detach().insertAfter($wrapper);\n                $wrapper.remove();\n            }\n        }\n        function $elOrNull(obj) {\n            var isValid, $el;\n            isValid = _.isJQuery(obj) || _.isElement(obj);\n            $el = isValid ? $(obj).first() : [];\n            return $el.length ? $el : null;\n        }\n    })();\n});"
  },
  {
    "path": "Documentation/Themes/fullwidth_pk/templates/doc.mustache",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <title>{{name}} {{kind}} Reference</title>\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"{{path_to_root}}css/jazzy.css\" />\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"{{path_to_root}}css/highlight.css\" />\n    <meta charset=\"utf-8\">\n    <script src=\"{{path_to_root}}js/jquery.min.js\" defer></script>\n    <script src=\"{{path_to_root}}js/jazzy.js\" defer></script>\n    {{{custom_head}}}\n    {{^disable_search}}\n    <script src=\"{{path_to_root}}js/lunr.min.js\" defer></script>\n    <script src=\"{{path_to_root}}js/typeahead.jquery.js\" defer></script>\n    <script src=\"{{path_to_root}}js/jazzy.search.js\" defer></script>\n    {{/disable_search}}\n  </head>\n  <body>\n\n    {{#dash_type}}\n    <a name=\"//apple_ref/{{language_stub}}/{{dash_type}}/{{name}}\" class=\"dashAnchor\"></a>\n    {{/dash_type}}\n\n    <a title=\"{{name}} {{kind}} Reference\"></a>\n\n    {{> header}}\n\n    <p class=\"breadcrumbs\">\n      <a class=\"breadcrumb\" href=\"{{path_to_root}}index.html\">{{module_name}} Reference</a>\n      <img class=\"carat\" src=\"{{path_to_root}}img/carat.png\" />\n      {{name}} {{kind}} Reference\n    </p>\n\n    <div class=\"content-wrapper\">\n      {{> nav}}\n      <article class=\"main-content\">\n\n        <section class=\"section\">\n          <div class=\"section-content\">\n            {{^hide_name}}<h1>{{name}}</h1>{{/hide_name}}\n            {{#declaration}}\n              <div class=\"declaration\">\n                <div class=\"language\">\n                  {{{declaration}}}\n                </div>\n              </div>\n            {{/declaration}}\n            {{{overview}}}\n          </div>\n        </section>\n\n        {{> tasks}}\n\n      </article>\n    </div>\n    {{> footer}}\n  </body>\n</div>\n</html>\n"
  },
  {
    "path": "Documentation/Themes/fullwidth_pk/templates/footer.mustache",
    "content": "<section class=\"footer\">\n  {{{copyright}}}\n  <p>Generated by <a class=\"link\" href=\"https://github.com/realm/jazzy\" target=\"_blank\" rel=\"external\">jazzy ♪♫ v{{jazzy_version}}</a>, a <a class=\"link\" href=\"http://realm.io\" target=\"_blank\" rel=\"external\">Realm</a> project.</p>\n</section>\n"
  },
  {
    "path": "Documentation/Themes/fullwidth_pk/templates/header.mustache",
    "content": "<header class=\"header\">\n  <p class=\"header-col header-col--primary\">\n    <a class=\"header-link\" href=\"{{path_to_root}}index.html\">\n      {{module_name}} Docs\n    </a>\n    {{#doc_coverage}} ({{doc_coverage}}% documented){{/doc_coverage}}\n  </p>\n\n  {{^disable_search}}\n  <p class=\"header-col--secondary\">\n    <form role=\"search\" action=\"{{path_to_root}}search.json\">\n      <input type=\"text\" placeholder=\"Search documentation\" data-typeahead>\n    </form>\n  </p>\n  {{/disable_search}}\n\n  {{#github_url}}\n    <p class=\"header-col header-col--secondary\">\n      <a class=\"header-link\" href=\"{{github_url}}\">\n        <img class=\"header-icon\" src=\"{{path_to_root}}img/gh.png\"/>\n        View on GitHub\n      </a>\n    </p>\n  {{/github_url}}\n\n  {{#dash_url}}\n    <p class=\"header-col header-col--secondary\">\n      <a class=\"header-link\" href=\"{{dash_url}}\">\n        <img class=\"header-icon\" src=\"{{path_to_root}}img/dash.png\"/>\n        Install in Dash\n      </a>\n    </p>\n  {{/dash_url}}\n</header>\n"
  },
  {
    "path": "Documentation/Themes/fullwidth_pk/templates/nav.mustache",
    "content": "<nav class=\"navigation\">\n  <ul class=\"nav-groups\">\n    {{#structure}}\n    <li class=\"nav-group-name\">\n      <a class=\"nav-group-name-link\" href=\"{{path_to_root}}{{section}}.html\">{{section}}</a>\n      <ul class=\"nav-group-tasks\">\n        {{#children}}\n        <li class=\"nav-group-task\">\n          <a class=\"nav-group-task-link\" href=\"{{path_to_root}}{{url}}\">{{name}}</a>\n        </li>\n        {{/children}}\n      </ul>\n    </li>\n    {{/structure}}\n  </ul>\n</nav>\n"
  },
  {
    "path": "Documentation/Themes/fullwidth_pk/templates/parameter.mustache",
    "content": "<tr>\n  <td>\n    <code>\n    <em>{{name}}</em>\n    </code>\n  </td>\n  <td>\n    <div>\n      {{{discussion}}}\n    </div>\n  </td>\n</tr>\n"
  },
  {
    "path": "Documentation/Themes/fullwidth_pk/templates/task.mustache",
    "content": "<div class=\"task-group\">\n  {{#name}}\n  <div class=\"task-name-container\">\n    <a name=\"/{{uid}}\"></a>\n    <a name=\"//apple_ref/{{language_stub}}/Section/{{name}}\" class=\"dashAnchor\"></a>\n    <a href=\"#/{{uid}}\">\n      <h3 class=\"section-name\">{{name}}</h3>\n    </a>\n  </div>\n  {{/name}}\n  <ul class=\"item-container\">\n    {{#items}}\n    <li class=\"item\">\n      <div>\n        <code>\n        <a name=\"/{{usr}}\"></a>\n        <a name=\"//apple_ref/{{language_stub}}/{{dash_type}}/{{name}}\" class=\"dashAnchor\"></a>\n        <a class=\"token\" href=\"#/{{usr}}\">{{name}}</a>\n        </code>\n        {{#default_impl_abstract}}\n          <span class=\"declaration-note\">\n            Default implementation\n          </span>\n        {{/default_impl_abstract}}\n        {{#from_protocol_extension}}\n          <span class=\"declaration-note\">\n            Extension method\n          </span>\n        {{/from_protocol_extension}}\n      </div>\n      <div class=\"height-container\">\n        <div class=\"pointer-container\"></div>\n        <section class=\"section\">\n          <div class=\"pointer\"></div>\n          {{#abstract}}\n          <div class=\"abstract\">\n            {{{abstract}}}\n            {{#url}}\n            <a href=\"{{{path_to_root}}}{{{url}}}\" class=\"slightly-smaller\">See more</a>\n            {{/url}}\n          </div>\n          {{/abstract}}\n          {{#default_impl_abstract}}\n          <h4>Default Implementation</h4>\n          <div class=\"default_impl abstract\">\n            {{{default_impl_abstract}}}\n          </div>\n          {{/default_impl_abstract}}\n          {{#declaration}}\n          <div class=\"declaration\">\n            <h4>Declaration</h4>\n            <div class=\"language\">\n              <p class=\"aside-title\">{{language}}</p>\n              {{{declaration}}}\n            </div>\n            {{#other_language_declaration}}\n            <div class=\"language\">\n              <p class=\"aside-title\">Swift</p>\n              {{{other_language_declaration}}}\n            </div>\n            {{/other_language_declaration}}\n          </div>\n          {{/declaration}}\n          {{#parameters.count}}\n          <div>\n            <h4>Parameters</h4>\n            <table class=\"graybox\">\n              <tbody>\n                {{#parameters}}\n                {{> parameter}}\n                {{/parameters}}\n              </tbody>\n            </table>\n          </div>\n          {{/parameters.count}}\n          {{#return}}\n          <div>\n            <h4>Return Value</h4>\n            {{{return}}}\n          </div>\n          {{/return}}\n          {{#github_token_url}}\n          <div class=\"slightly-smaller\">\n            <a href=\"{{{github_token_url}}}\">Show on GitHub</a>\n          </div>\n          {{/github_token_url}}\n        </section>\n      </div>\n    </li>\n    {{/items}}\n  </ul>\n</div>\n"
  },
  {
    "path": "Documentation/Themes/fullwidth_pk/templates/tasks.mustache",
    "content": "{{#tasks.count}}\n<section class=\"section\">\n  <div class=\"section-content\">\n    {{#tasks}}\n    {{> task}}\n    {{/tasks}}\n  </div>\n</section>\n{{/tasks.count}}\n"
  },
  {
    "path": "Gemfile",
    "content": "source \"https://rubygems.org\"\n\ngem \"cocoapods\"\ngem \"xcpretty\"\ngem \"jazzy\"\n"
  },
  {
    "path": "Integrations/CocoaPods/Podfile",
    "content": "target 'TryProcedureKit' do\n  platform :osx, '10.11'\n\n  use_frameworks!\n\n  pod 'ProcedureKit/All', :path => '../..'\n\n  target 'TryProcedureKitTests' do\n    inherit! :search_paths\n    pod 'TestingProcedureKit', :path => '../..'\n  end\nend\n\ntarget 'TryProcedureKit iOS' do\n  platform :ios, '10.0'\n  use_frameworks!\n\n  pod 'ProcedureKit/All', :path => '../..'\n  pod 'ProcedureKit/Mobile', :path => '../..'  \n\n  target 'TryProcedureKit iOSTests' do\n    inherit! :search_paths\n    pod 'TestingProcedureKit', :path => '../..'\n  end\nend\n"
  },
  {
    "path": "Integrations/CocoaPods/TryProcedureKit/AppDelegate.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2016 ProcedureKit. All rights reserved.\n//\n\nimport Cocoa\n\n@NSApplicationMain\nclass AppDelegate: NSObject, NSApplicationDelegate { }\n\n"
  },
  {
    "path": "Integrations/CocoaPods/TryProcedureKit/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"16x16\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"16x16\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"32x32\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"32x32\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"128x128\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"128x128\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"256x256\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"256x256\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"512x512\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"mac\",\n      \"size\" : \"512x512\",\n      \"scale\" : \"2x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Integrations/CocoaPods/TryProcedureKit/Base.lproj/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"11134\" systemVersion=\"15F34\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" initialViewController=\"B8D-0N-5wS\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"11134\"/>\n    </dependencies>\n    <scenes>\n        <!--Application-->\n        <scene sceneID=\"JPo-4y-FX3\">\n            <objects>\n                <application id=\"hnw-xV-0zn\" sceneMemberID=\"viewController\">\n                    <menu key=\"mainMenu\" title=\"Main Menu\" systemMenu=\"main\" id=\"AYu-sK-qS6\">\n                        <items>\n                            <menuItem title=\"TryProcedureKit\" id=\"1Xt-HY-uBw\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"TryProcedureKit\" systemMenu=\"apple\" id=\"uQy-DD-JDr\">\n                                    <items>\n                                        <menuItem title=\"About TryProcedureKit\" id=\"5kV-Vb-QxS\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"orderFrontStandardAboutPanel:\" target=\"Ady-hI-5gd\" id=\"Exp-CZ-Vem\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"VOq-y0-SEH\"/>\n                                        <menuItem title=\"Preferences…\" keyEquivalent=\",\" id=\"BOF-NM-1cW\"/>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"wFC-TO-SCJ\"/>\n                                        <menuItem title=\"Services\" id=\"NMo-om-nkz\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Services\" systemMenu=\"services\" id=\"hz9-B4-Xy5\"/>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"4je-JR-u6R\"/>\n                                        <menuItem title=\"Hide TryProcedureKit\" keyEquivalent=\"h\" id=\"Olw-nP-bQN\">\n                                            <connections>\n                                                <action selector=\"hide:\" target=\"Ady-hI-5gd\" id=\"PnN-Uc-m68\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Hide Others\" keyEquivalent=\"h\" id=\"Vdr-fp-XzO\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"hideOtherApplications:\" target=\"Ady-hI-5gd\" id=\"VT4-aY-XCT\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Show All\" id=\"Kd2-mp-pUS\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"unhideAllApplications:\" target=\"Ady-hI-5gd\" id=\"Dhg-Le-xox\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"kCx-OE-vgT\"/>\n                                        <menuItem title=\"Quit TryProcedureKit\" keyEquivalent=\"q\" id=\"4sb-4s-VLi\">\n                                            <connections>\n                                                <action selector=\"terminate:\" target=\"Ady-hI-5gd\" id=\"Te7-pn-YzF\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"File\" id=\"dMs-cI-mzQ\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"File\" id=\"bib-Uj-vzu\">\n                                    <items>\n                                        <menuItem title=\"New\" keyEquivalent=\"n\" id=\"Was-JA-tGl\">\n                                            <connections>\n                                                <action selector=\"newDocument:\" target=\"Ady-hI-5gd\" id=\"4Si-XN-c54\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Open…\" keyEquivalent=\"o\" id=\"IAo-SY-fd9\">\n                                            <connections>\n                                                <action selector=\"openDocument:\" target=\"Ady-hI-5gd\" id=\"bVn-NM-KNZ\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Open Recent\" id=\"tXI-mr-wws\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Open Recent\" systemMenu=\"recentDocuments\" id=\"oas-Oc-fiZ\">\n                                                <items>\n                                                    <menuItem title=\"Clear Menu\" id=\"vNY-rz-j42\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"clearRecentDocuments:\" target=\"Ady-hI-5gd\" id=\"Daa-9d-B3U\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"m54-Is-iLE\"/>\n                                        <menuItem title=\"Close\" keyEquivalent=\"w\" id=\"DVo-aG-piG\">\n                                            <connections>\n                                                <action selector=\"performClose:\" target=\"Ady-hI-5gd\" id=\"HmO-Ls-i7Q\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Save…\" keyEquivalent=\"s\" id=\"pxx-59-PXV\">\n                                            <connections>\n                                                <action selector=\"saveDocument:\" target=\"Ady-hI-5gd\" id=\"teZ-XB-qJY\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Save As…\" keyEquivalent=\"S\" id=\"Bw7-FT-i3A\">\n                                            <connections>\n                                                <action selector=\"saveDocumentAs:\" target=\"Ady-hI-5gd\" id=\"mDf-zr-I0C\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Revert to Saved\" keyEquivalent=\"r\" id=\"KaW-ft-85H\">\n                                            <connections>\n                                                <action selector=\"revertDocumentToSaved:\" target=\"Ady-hI-5gd\" id=\"iJ3-Pv-kwq\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"aJh-i4-bef\"/>\n                                        <menuItem title=\"Page Setup…\" keyEquivalent=\"P\" id=\"qIS-W8-SiK\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" shift=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"runPageLayout:\" target=\"Ady-hI-5gd\" id=\"Din-rz-gC5\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Print…\" keyEquivalent=\"p\" id=\"aTl-1u-JFS\">\n                                            <connections>\n                                                <action selector=\"print:\" target=\"Ady-hI-5gd\" id=\"qaZ-4w-aoO\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Edit\" id=\"5QF-Oa-p0T\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Edit\" id=\"W48-6f-4Dl\">\n                                    <items>\n                                        <menuItem title=\"Undo\" keyEquivalent=\"z\" id=\"dRJ-4n-Yzg\">\n                                            <connections>\n                                                <action selector=\"undo:\" target=\"Ady-hI-5gd\" id=\"M6e-cu-g7V\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Redo\" keyEquivalent=\"Z\" id=\"6dh-zS-Vam\">\n                                            <connections>\n                                                <action selector=\"redo:\" target=\"Ady-hI-5gd\" id=\"oIA-Rs-6OD\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"WRV-NI-Exz\"/>\n                                        <menuItem title=\"Cut\" keyEquivalent=\"x\" id=\"uRl-iY-unG\">\n                                            <connections>\n                                                <action selector=\"cut:\" target=\"Ady-hI-5gd\" id=\"YJe-68-I9s\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Copy\" keyEquivalent=\"c\" id=\"x3v-GG-iWU\">\n                                            <connections>\n                                                <action selector=\"copy:\" target=\"Ady-hI-5gd\" id=\"G1f-GL-Joy\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Paste\" keyEquivalent=\"v\" id=\"gVA-U4-sdL\">\n                                            <connections>\n                                                <action selector=\"paste:\" target=\"Ady-hI-5gd\" id=\"UvS-8e-Qdg\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Paste and Match Style\" keyEquivalent=\"V\" id=\"WeT-3V-zwk\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"pasteAsPlainText:\" target=\"Ady-hI-5gd\" id=\"cEh-KX-wJQ\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Delete\" id=\"pa3-QI-u2k\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"delete:\" target=\"Ady-hI-5gd\" id=\"0Mk-Ml-PaM\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Select All\" keyEquivalent=\"a\" id=\"Ruw-6m-B2m\">\n                                            <connections>\n                                                <action selector=\"selectAll:\" target=\"Ady-hI-5gd\" id=\"VNm-Mi-diN\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"uyl-h8-XO2\"/>\n                                        <menuItem title=\"Find\" id=\"4EN-yA-p0u\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Find\" id=\"1b7-l0-nxx\">\n                                                <items>\n                                                    <menuItem title=\"Find…\" tag=\"1\" keyEquivalent=\"f\" id=\"Xz5-n4-O0W\">\n                                                        <connections>\n                                                            <action selector=\"performFindPanelAction:\" target=\"Ady-hI-5gd\" id=\"cD7-Qs-BN4\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Find and Replace…\" tag=\"12\" keyEquivalent=\"f\" id=\"YEy-JH-Tfz\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                                        <connections>\n                                                            <action selector=\"performFindPanelAction:\" target=\"Ady-hI-5gd\" id=\"WD3-Gg-5AJ\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Find Next\" tag=\"2\" keyEquivalent=\"g\" id=\"q09-fT-Sye\">\n                                                        <connections>\n                                                            <action selector=\"performFindPanelAction:\" target=\"Ady-hI-5gd\" id=\"NDo-RZ-v9R\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Find Previous\" tag=\"3\" keyEquivalent=\"G\" id=\"OwM-mh-QMV\">\n                                                        <connections>\n                                                            <action selector=\"performFindPanelAction:\" target=\"Ady-hI-5gd\" id=\"HOh-sY-3ay\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Use Selection for Find\" tag=\"7\" keyEquivalent=\"e\" id=\"buJ-ug-pKt\">\n                                                        <connections>\n                                                            <action selector=\"performFindPanelAction:\" target=\"Ady-hI-5gd\" id=\"U76-nv-p5D\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Jump to Selection\" keyEquivalent=\"j\" id=\"S0p-oC-mLd\">\n                                                        <connections>\n                                                            <action selector=\"centerSelectionInVisibleArea:\" target=\"Ady-hI-5gd\" id=\"IOG-6D-g5B\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem title=\"Spelling and Grammar\" id=\"Dv1-io-Yv7\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Spelling\" id=\"3IN-sU-3Bg\">\n                                                <items>\n                                                    <menuItem title=\"Show Spelling and Grammar\" keyEquivalent=\":\" id=\"HFo-cy-zxI\">\n                                                        <connections>\n                                                            <action selector=\"showGuessPanel:\" target=\"Ady-hI-5gd\" id=\"vFj-Ks-hy3\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Check Document Now\" keyEquivalent=\";\" id=\"hz2-CU-CR7\">\n                                                        <connections>\n                                                            <action selector=\"checkSpelling:\" target=\"Ady-hI-5gd\" id=\"fz7-VC-reM\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"bNw-od-mp5\"/>\n                                                    <menuItem title=\"Check Spelling While Typing\" id=\"rbD-Rh-wIN\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleContinuousSpellChecking:\" target=\"Ady-hI-5gd\" id=\"7w6-Qz-0kB\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Check Grammar With Spelling\" id=\"mK6-2p-4JG\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleGrammarChecking:\" target=\"Ady-hI-5gd\" id=\"muD-Qn-j4w\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Correct Spelling Automatically\" id=\"78Y-hA-62v\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleAutomaticSpellingCorrection:\" target=\"Ady-hI-5gd\" id=\"2lM-Qi-WAP\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem title=\"Substitutions\" id=\"9ic-FL-obx\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Substitutions\" id=\"FeM-D8-WVr\">\n                                                <items>\n                                                    <menuItem title=\"Show Substitutions\" id=\"z6F-FW-3nz\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"orderFrontSubstitutionsPanel:\" target=\"Ady-hI-5gd\" id=\"oku-mr-iSq\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"gPx-C9-uUO\"/>\n                                                    <menuItem title=\"Smart Copy/Paste\" id=\"9yt-4B-nSM\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleSmartInsertDelete:\" target=\"Ady-hI-5gd\" id=\"3IJ-Se-DZD\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Smart Quotes\" id=\"hQb-2v-fYv\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleAutomaticQuoteSubstitution:\" target=\"Ady-hI-5gd\" id=\"ptq-xd-QOA\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Smart Dashes\" id=\"rgM-f4-ycn\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleAutomaticDashSubstitution:\" target=\"Ady-hI-5gd\" id=\"oCt-pO-9gS\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Smart Links\" id=\"cwL-P1-jid\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleAutomaticLinkDetection:\" target=\"Ady-hI-5gd\" id=\"Gip-E3-Fov\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Data Detectors\" id=\"tRr-pd-1PS\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleAutomaticDataDetection:\" target=\"Ady-hI-5gd\" id=\"R1I-Nq-Kbl\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Text Replacement\" id=\"HFQ-gK-NFA\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleAutomaticTextReplacement:\" target=\"Ady-hI-5gd\" id=\"DvP-Fe-Py6\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem title=\"Transformations\" id=\"2oI-Rn-ZJC\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Transformations\" id=\"c8a-y6-VQd\">\n                                                <items>\n                                                    <menuItem title=\"Make Upper Case\" id=\"vmV-6d-7jI\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"uppercaseWord:\" target=\"Ady-hI-5gd\" id=\"sPh-Tk-edu\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Make Lower Case\" id=\"d9M-CD-aMd\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"lowercaseWord:\" target=\"Ady-hI-5gd\" id=\"iUZ-b5-hil\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Capitalize\" id=\"UEZ-Bs-lqG\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"capitalizeWord:\" target=\"Ady-hI-5gd\" id=\"26H-TL-nsh\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem title=\"Speech\" id=\"xrE-MZ-jX0\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Speech\" id=\"3rS-ZA-NoH\">\n                                                <items>\n                                                    <menuItem title=\"Start Speaking\" id=\"Ynk-f8-cLZ\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"startSpeaking:\" target=\"Ady-hI-5gd\" id=\"654-Ng-kyl\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Stop Speaking\" id=\"Oyz-dy-DGm\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"stopSpeaking:\" target=\"Ady-hI-5gd\" id=\"dX8-6p-jy9\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Format\" id=\"jxT-CU-nIS\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Format\" id=\"GEO-Iw-cKr\">\n                                    <items>\n                                        <menuItem title=\"Font\" id=\"Gi5-1S-RQB\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Font\" systemMenu=\"font\" id=\"aXa-aM-Jaq\">\n                                                <items>\n                                                    <menuItem title=\"Show Fonts\" keyEquivalent=\"t\" id=\"Q5e-8K-NDq\"/>\n                                                    <menuItem title=\"Bold\" tag=\"2\" keyEquivalent=\"b\" id=\"GB9-OM-e27\"/>\n                                                    <menuItem title=\"Italic\" tag=\"1\" keyEquivalent=\"i\" id=\"Vjx-xi-njq\"/>\n                                                    <menuItem title=\"Underline\" keyEquivalent=\"u\" id=\"WRG-CD-K1S\">\n                                                        <connections>\n                                                            <action selector=\"underline:\" target=\"Ady-hI-5gd\" id=\"FYS-2b-JAY\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"5gT-KC-WSO\"/>\n                                                    <menuItem title=\"Bigger\" tag=\"3\" keyEquivalent=\"+\" id=\"Ptp-SP-VEL\"/>\n                                                    <menuItem title=\"Smaller\" tag=\"4\" keyEquivalent=\"-\" id=\"i1d-Er-qST\"/>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"kx3-Dk-x3B\"/>\n                                                    <menuItem title=\"Kern\" id=\"jBQ-r6-VK2\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <menu key=\"submenu\" title=\"Kern\" id=\"tlD-Oa-oAM\">\n                                                            <items>\n                                                                <menuItem title=\"Use Default\" id=\"GUa-eO-cwY\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"useStandardKerning:\" target=\"Ady-hI-5gd\" id=\"6dk-9l-Ckg\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Use None\" id=\"cDB-IK-hbR\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"turnOffKerning:\" target=\"Ady-hI-5gd\" id=\"U8a-gz-Maa\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Tighten\" id=\"46P-cB-AYj\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"tightenKerning:\" target=\"Ady-hI-5gd\" id=\"hr7-Nz-8ro\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Loosen\" id=\"ogc-rX-tC1\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"loosenKerning:\" target=\"Ady-hI-5gd\" id=\"8i4-f9-FKE\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                            </items>\n                                                        </menu>\n                                                    </menuItem>\n                                                    <menuItem title=\"Ligatures\" id=\"o6e-r0-MWq\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <menu key=\"submenu\" title=\"Ligatures\" id=\"w0m-vy-SC9\">\n                                                            <items>\n                                                                <menuItem title=\"Use Default\" id=\"agt-UL-0e3\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"useStandardLigatures:\" target=\"Ady-hI-5gd\" id=\"7uR-wd-Dx6\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Use None\" id=\"J7y-lM-qPV\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"turnOffLigatures:\" target=\"Ady-hI-5gd\" id=\"iX2-gA-Ilz\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Use All\" id=\"xQD-1f-W4t\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"useAllLigatures:\" target=\"Ady-hI-5gd\" id=\"KcB-kA-TuK\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                            </items>\n                                                        </menu>\n                                                    </menuItem>\n                                                    <menuItem title=\"Baseline\" id=\"OaQ-X3-Vso\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <menu key=\"submenu\" title=\"Baseline\" id=\"ijk-EB-dga\">\n                                                            <items>\n                                                                <menuItem title=\"Use Default\" id=\"3Om-Ey-2VK\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"unscript:\" target=\"Ady-hI-5gd\" id=\"0vZ-95-Ywn\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Superscript\" id=\"Rqc-34-cIF\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"superscript:\" target=\"Ady-hI-5gd\" id=\"3qV-fo-wpU\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Subscript\" id=\"I0S-gh-46l\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"subscript:\" target=\"Ady-hI-5gd\" id=\"Q6W-4W-IGz\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Raise\" id=\"2h7-ER-AoG\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"raiseBaseline:\" target=\"Ady-hI-5gd\" id=\"4sk-31-7Q9\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem title=\"Lower\" id=\"1tx-W0-xDw\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"lowerBaseline:\" target=\"Ady-hI-5gd\" id=\"OF1-bc-KW4\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                            </items>\n                                                        </menu>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"Ndw-q3-faq\"/>\n                                                    <menuItem title=\"Show Colors\" keyEquivalent=\"C\" id=\"bgn-CT-cEk\">\n                                                        <connections>\n                                                            <action selector=\"orderFrontColorPanel:\" target=\"Ady-hI-5gd\" id=\"mSX-Xz-DV3\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"iMs-zA-UFJ\"/>\n                                                    <menuItem title=\"Copy Style\" keyEquivalent=\"c\" id=\"5Vv-lz-BsD\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                                        <connections>\n                                                            <action selector=\"copyFont:\" target=\"Ady-hI-5gd\" id=\"GJO-xA-L4q\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Paste Style\" keyEquivalent=\"v\" id=\"vKC-jM-MkH\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                                        <connections>\n                                                            <action selector=\"pasteFont:\" target=\"Ady-hI-5gd\" id=\"JfD-CL-leO\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                        <menuItem title=\"Text\" id=\"Fal-I4-PZk\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <menu key=\"submenu\" title=\"Text\" id=\"d9c-me-L2H\">\n                                                <items>\n                                                    <menuItem title=\"Align Left\" keyEquivalent=\"{\" id=\"ZM1-6Q-yy1\">\n                                                        <connections>\n                                                            <action selector=\"alignLeft:\" target=\"Ady-hI-5gd\" id=\"zUv-R1-uAa\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Center\" keyEquivalent=\"|\" id=\"VIY-Ag-zcb\">\n                                                        <connections>\n                                                            <action selector=\"alignCenter:\" target=\"Ady-hI-5gd\" id=\"spX-mk-kcS\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Justify\" id=\"J5U-5w-g23\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"alignJustified:\" target=\"Ady-hI-5gd\" id=\"ljL-7U-jND\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Align Right\" keyEquivalent=\"}\" id=\"wb2-vD-lq4\">\n                                                        <connections>\n                                                            <action selector=\"alignRight:\" target=\"Ady-hI-5gd\" id=\"r48-bG-YeY\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"4s2-GY-VfK\"/>\n                                                    <menuItem title=\"Writing Direction\" id=\"H1b-Si-o9J\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <menu key=\"submenu\" title=\"Writing Direction\" id=\"8mr-sm-Yjd\">\n                                                            <items>\n                                                                <menuItem title=\"Paragraph\" enabled=\"NO\" id=\"ZvO-Gk-QUH\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                </menuItem>\n                                                                <menuItem id=\"YGs-j5-SAR\">\n                                                                    <string key=\"title\">\tDefault</string>\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"makeBaseWritingDirectionNatural:\" target=\"Ady-hI-5gd\" id=\"qtV-5e-UBP\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem id=\"Lbh-J2-qVU\">\n                                                                    <string key=\"title\">\tLeft to Right</string>\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"makeBaseWritingDirectionLeftToRight:\" target=\"Ady-hI-5gd\" id=\"S0X-9S-QSf\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem id=\"jFq-tB-4Kx\">\n                                                                    <string key=\"title\">\tRight to Left</string>\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"makeBaseWritingDirectionRightToLeft:\" target=\"Ady-hI-5gd\" id=\"5fk-qB-AqJ\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem isSeparatorItem=\"YES\" id=\"swp-gr-a21\"/>\n                                                                <menuItem title=\"Selection\" enabled=\"NO\" id=\"cqv-fj-IhA\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                </menuItem>\n                                                                <menuItem id=\"Nop-cj-93Q\">\n                                                                    <string key=\"title\">\tDefault</string>\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"makeTextWritingDirectionNatural:\" target=\"Ady-hI-5gd\" id=\"lPI-Se-ZHp\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem id=\"BgM-ve-c93\">\n                                                                    <string key=\"title\">\tLeft to Right</string>\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"makeTextWritingDirectionLeftToRight:\" target=\"Ady-hI-5gd\" id=\"caW-Bv-w94\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                                <menuItem id=\"RB4-Sm-HuC\">\n                                                                    <string key=\"title\">\tRight to Left</string>\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                    <connections>\n                                                                        <action selector=\"makeTextWritingDirectionRightToLeft:\" target=\"Ady-hI-5gd\" id=\"EXD-6r-ZUu\"/>\n                                                                    </connections>\n                                                                </menuItem>\n                                                            </items>\n                                                        </menu>\n                                                    </menuItem>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"fKy-g9-1gm\"/>\n                                                    <menuItem title=\"Show Ruler\" id=\"vLm-3I-IUL\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                        <connections>\n                                                            <action selector=\"toggleRuler:\" target=\"Ady-hI-5gd\" id=\"FOx-HJ-KwY\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Copy Ruler\" keyEquivalent=\"c\" id=\"MkV-Pr-PK5\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                                                        <connections>\n                                                            <action selector=\"copyRuler:\" target=\"Ady-hI-5gd\" id=\"71i-fW-3W2\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                    <menuItem title=\"Paste Ruler\" keyEquivalent=\"v\" id=\"LVM-kO-fVI\">\n                                                        <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                                                        <connections>\n                                                            <action selector=\"pasteRuler:\" target=\"Ady-hI-5gd\" id=\"cSh-wd-qM2\"/>\n                                                        </connections>\n                                                    </menuItem>\n                                                </items>\n                                            </menu>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"View\" id=\"H8h-7b-M4v\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"View\" id=\"HyV-fh-RgO\">\n                                    <items>\n                                        <menuItem title=\"Show Toolbar\" keyEquivalent=\"t\" id=\"snW-S8-Cw5\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"toggleToolbarShown:\" target=\"Ady-hI-5gd\" id=\"BXY-wc-z0C\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Customize Toolbar…\" id=\"1UK-8n-QPP\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"runToolbarCustomizationPalette:\" target=\"Ady-hI-5gd\" id=\"pQI-g3-MTW\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"hB3-LF-h0Y\"/>\n                                        <menuItem title=\"Show Sidebar\" keyEquivalent=\"s\" id=\"kIP-vf-haE\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"toggleSourceList:\" target=\"Ady-hI-5gd\" id=\"iwa-gc-5KM\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Enter Full Screen\" keyEquivalent=\"f\" id=\"4J7-dP-txa\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"toggleFullScreen:\" target=\"Ady-hI-5gd\" id=\"dU3-MA-1Rq\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Window\" id=\"aUF-d1-5bR\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Window\" systemMenu=\"window\" id=\"Td7-aD-5lo\">\n                                    <items>\n                                        <menuItem title=\"Minimize\" keyEquivalent=\"m\" id=\"OY7-WF-poV\">\n                                            <connections>\n                                                <action selector=\"performMiniaturize:\" target=\"Ady-hI-5gd\" id=\"VwT-WD-YPe\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Zoom\" id=\"R4o-n2-Eq4\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"performZoom:\" target=\"Ady-hI-5gd\" id=\"DIl-cC-cCs\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"eu3-7i-yIM\"/>\n                                        <menuItem title=\"Bring All to Front\" id=\"LE2-aR-0XJ\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"arrangeInFront:\" target=\"Ady-hI-5gd\" id=\"DRN-fu-gQh\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Help\" id=\"wpr-3q-Mcd\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Help\" systemMenu=\"help\" id=\"F2S-fz-NVQ\">\n                                    <items>\n                                        <menuItem title=\"TryProcedureKit Help\" keyEquivalent=\"?\" id=\"FKE-Sm-Kum\">\n                                            <connections>\n                                                <action selector=\"showHelp:\" target=\"Ady-hI-5gd\" id=\"y7X-2Q-9no\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                        </items>\n                    </menu>\n                    <connections>\n                        <outlet property=\"delegate\" destination=\"Voe-Tx-rLC\" id=\"PrD-fu-P6m\"/>\n                    </connections>\n                </application>\n                <customObject id=\"Voe-Tx-rLC\" customClass=\"AppDelegate\" customModuleProvider=\"target\"/>\n                <customObject id=\"Ady-hI-5gd\" userLabel=\"First Responder\" customClass=\"NSResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"75\" y=\"0.0\"/>\n        </scene>\n        <!--Window Controller-->\n        <scene sceneID=\"R2V-B0-nI4\">\n            <objects>\n                <windowController id=\"B8D-0N-5wS\" sceneMemberID=\"viewController\">\n                    <window key=\"window\" title=\"Window\" allowsToolTipsWhenApplicationIsInactive=\"NO\" autorecalculatesKeyViewLoop=\"NO\" oneShot=\"NO\" releasedWhenClosed=\"NO\" showsToolbarButton=\"NO\" visibleAtLaunch=\"NO\" animationBehavior=\"default\" id=\"IQv-IB-iLA\">\n                        <windowStyleMask key=\"styleMask\" titled=\"YES\" closable=\"YES\" miniaturizable=\"YES\" resizable=\"YES\"/>\n                        <windowPositionMask key=\"initialPositionMask\" leftStrut=\"YES\" rightStrut=\"YES\" topStrut=\"YES\" bottomStrut=\"YES\"/>\n                        <rect key=\"contentRect\" x=\"196\" y=\"240\" width=\"480\" height=\"270\"/>\n                        <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"1680\" height=\"1027\"/>\n                    </window>\n                    <connections>\n                        <segue destination=\"XfG-lQ-9wD\" kind=\"relationship\" relationship=\"window.shadowedContentViewController\" id=\"cq2-FE-JQM\"/>\n                    </connections>\n                </windowController>\n                <customObject id=\"Oky-zY-oP4\" userLabel=\"First Responder\" customClass=\"NSResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"75\" y=\"250\"/>\n        </scene>\n        <!--View Controller-->\n        <scene sceneID=\"hIz-AP-VOD\">\n            <objects>\n                <viewController id=\"XfG-lQ-9wD\" customClass=\"ViewController\" customModuleProvider=\"target\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" wantsLayer=\"YES\" id=\"m2S-Jp-Qdl\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"480\" height=\"270\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </view>\n                </viewController>\n                <customObject id=\"rPt-NT-nkU\" userLabel=\"First Responder\" customClass=\"NSResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"75\" y=\"655\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "Integrations/CocoaPods/TryProcedureKit/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIconFile</key>\n\t<string></string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSMinimumSystemVersion</key>\n\t<string>$(MACOSX_DEPLOYMENT_TARGET)</string>\n\t<key>NSHumanReadableCopyright</key>\n\t<string>Copyright © 2016 ProcedureKit. All rights reserved.</string>\n\t<key>NSMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>NSPrincipalClass</key>\n\t<string>NSApplication</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Integrations/CocoaPods/TryProcedureKit/ViewController.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2016 ProcedureKit. All rights reserved.\n//\n\nimport Cocoa\nimport ProcedureKit\n\nclass ViewController: NSViewController {\n\n    lazy var queue = ProcedureQueue()\n\n    override func viewDidLoad() {\n        super.viewDidLoad()\n\n        queue.addOperation(AsyncBlockProcedure { finishWithResult in\n            DispatchQueue.default.async {\n                print(\"Hello world\")\n                finishWithResult(success)\n            }\n        })\n\n        getNetworkResource()\n    }\n\n    func getNetworkResource() {\n\n        let procedure = NetworkProcedure { NetworkDataProcedure(session: URLSession.shared, request: URLRequest(url: \"http://www.apple.com\")) }\n        procedure.log.severity = .info\n        procedure.addDidFinishBlockObserver { procedure, error in\n            guard let result = procedure.output.success else { return }\n            procedure.log.info.message(\"Received: \\(result.response)\")\n        }\n        queue.addOperation(procedure)\n    }\n}\n"
  },
  {
    "path": "Integrations/CocoaPods/TryProcedureKit iOS/AppDelegate.swift",
    "content": "//\n//  AppDelegate.swift\n//  TryProcedureKit iOS\n//\n//  Created by Daniel Thorpe on 05/12/2016.\n//  Copyright © 2016 ProcedureKit. All rights reserved.\n//\n\nimport UIKit\n\n@UIApplicationMain\nclass AppDelegate: UIResponder, UIApplicationDelegate {\n\n    var window: UIWindow?\n\n\n    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {\n        // Override point for customization after application launch.\n        return true\n    }\n\n    func applicationWillResignActive(_ application: UIApplication) {\n        // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.\n        // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.\n    }\n\n    func applicationDidEnterBackground(_ application: UIApplication) {\n        // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.\n        // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.\n    }\n\n    func applicationWillEnterForeground(_ application: UIApplication) {\n        // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.\n    }\n\n    func applicationDidBecomeActive(_ application: UIApplication) {\n        // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.\n    }\n\n    func applicationWillTerminate(_ application: UIApplication) {\n        // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.\n    }\n\n\n}\n\n"
  },
  {
    "path": "Integrations/CocoaPods/TryProcedureKit iOS/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Integrations/CocoaPods/TryProcedureKit iOS/Base.lproj/LaunchScreen.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"11134\" systemVersion=\"15F34\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" useTraitCollections=\"YES\" colorMatched=\"YES\" initialViewController=\"01J-lp-oVM\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"11106\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"EHf-IW-A2E\">\n            <objects>\n                <viewController id=\"01J-lp-oVM\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"Llm-lL-Icb\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"xb3-aO-Qok\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"Ze5-6b-2t3\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"iYj-Kq-Ea1\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"53\" y=\"375\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "Integrations/CocoaPods/TryProcedureKit iOS/Base.lproj/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"11542\" systemVersion=\"16B2555\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" colorMatched=\"YES\" initialViewController=\"Dli-x0-utA\">\n    <device id=\"retina4_7\" orientation=\"portrait\">\n        <adaptation id=\"fullscreen\"/>\n    </device>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"11524\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"tne-QT-ifu\">\n            <objects>\n                <viewController id=\"BYZ-38-t0r\" customClass=\"ViewController\" customModule=\"TryProcedureKit_iOS\" customModuleProvider=\"target\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"y3c-jy-aDJ\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"wfy-db-euE\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"8bC-Xf-vdC\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"n6s-6t-1Wl\">\n                                <rect key=\"frame\" x=\"172\" y=\"318\" width=\"30\" height=\"30\"/>\n                                <state key=\"normal\" title=\"Go\"/>\n                                <connections>\n                                    <action selector=\"go:\" destination=\"BYZ-38-t0r\" eventType=\"touchUpInside\" id=\"Cqm-k5-PH9\"/>\n                                </connections>\n                            </button>\n                            <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"aoN-oX-7KT\">\n                                <rect key=\"frame\" x=\"171\" y=\"356\" width=\"33\" height=\"30\"/>\n                                <state key=\"normal\" title=\"Alert\"/>\n                                <connections>\n                                    <action selector=\"alert:\" destination=\"BYZ-38-t0r\" eventType=\"touchUpInside\" id=\"Kdr-70-mat\"/>\n                                </connections>\n                            </button>\n                        </subviews>\n                        <color key=\"backgroundColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                        <constraints>\n                            <constraint firstItem=\"n6s-6t-1Wl\" firstAttribute=\"centerX\" secondItem=\"8bC-Xf-vdC\" secondAttribute=\"centerX\" id=\"5WW-5m-Pc8\"/>\n                            <constraint firstItem=\"aoN-oX-7KT\" firstAttribute=\"top\" secondItem=\"n6s-6t-1Wl\" secondAttribute=\"bottom\" constant=\"8\" id=\"HLu-bt-voI\"/>\n                            <constraint firstItem=\"aoN-oX-7KT\" firstAttribute=\"centerX\" secondItem=\"8bC-Xf-vdC\" secondAttribute=\"centerX\" id=\"KqS-Kl-89p\"/>\n                            <constraint firstItem=\"n6s-6t-1Wl\" firstAttribute=\"centerY\" secondItem=\"8bC-Xf-vdC\" secondAttribute=\"centerY\" id=\"Sc7-0H-msG\"/>\n                        </constraints>\n                    </view>\n                    <navigationItem key=\"navigationItem\" id=\"3j6-6V-5PI\"/>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"dkx-z0-nzr\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"462\" y=\"-635\"/>\n        </scene>\n        <!--Another View Controller-->\n        <scene sceneID=\"7Rn-XB-hwV\">\n            <objects>\n                <viewController storyboardIdentifier=\"another\" id=\"Nja-sH-6E4\" customClass=\"AnotherViewController\" customModule=\"TryProcedureKit_iOS\" customModuleProvider=\"target\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"IZf-ac-ZFY\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"Bzf-uN-Wbc\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"HgZ-QP-NdB\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Hello World\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"81z-6Y-cyM\">\n                                <rect key=\"frame\" x=\"143\" y=\"323\" width=\"89\" height=\"21\"/>\n                                <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                                <nil key=\"textColor\"/>\n                                <nil key=\"highlightedColor\"/>\n                            </label>\n                        </subviews>\n                        <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                        <constraints>\n                            <constraint firstItem=\"81z-6Y-cyM\" firstAttribute=\"centerY\" secondItem=\"HgZ-QP-NdB\" secondAttribute=\"centerY\" id=\"Fca-Ps-tqD\"/>\n                            <constraint firstItem=\"81z-6Y-cyM\" firstAttribute=\"centerX\" secondItem=\"HgZ-QP-NdB\" secondAttribute=\"centerX\" id=\"xeF-dG-hwN\"/>\n                        </constraints>\n                    </view>\n                    <toolbarItems/>\n                    <simulatedNavigationBarMetrics key=\"simulatedTopBarMetrics\" prompted=\"NO\"/>\n                    <connections>\n                        <outlet property=\"label\" destination=\"81z-6Y-cyM\" id=\"fj3-3c-OFx\"/>\n                    </connections>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"Uag-wx-EDq\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"1290\" y=\"-636\"/>\n        </scene>\n        <!--Navigation Controller-->\n        <scene sceneID=\"LJj-1g-Pb2\">\n            <objects>\n                <navigationController automaticallyAdjustsScrollViewInsets=\"NO\" id=\"Dli-x0-utA\" sceneMemberID=\"viewController\">\n                    <toolbarItems/>\n                    <navigationBar key=\"navigationBar\" contentMode=\"scaleToFill\" id=\"aBu-ae-Puj\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"44\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </navigationBar>\n                    <nil name=\"viewControllers\"/>\n                    <connections>\n                        <segue destination=\"BYZ-38-t0r\" kind=\"relationship\" relationship=\"rootViewController\" id=\"8xl-i2-Y4h\"/>\n                    </connections>\n                </navigationController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"mR1-Ln-btD\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"-335\" y=\"-634\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "Integrations/CocoaPods/TryProcedureKit iOS/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</string>\n\t<key>UIMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>UIRequiredDeviceCapabilities</key>\n\t<array>\n\t\t<string>armv7</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "Integrations/CocoaPods/TryProcedureKit iOS/ViewController.swift",
    "content": "//\n//  ViewController.swift\n//  TryProcedureKit iOS\n//\n//  Created by Daniel Thorpe on 05/12/2016.\n//  Copyright © 2016 ProcedureKit. All rights reserved.\n//\n\nimport UIKit\nimport ProcedureKit\n\nclass AnotherViewController: UIViewController, DismissingViewController {\n\n    @IBOutlet weak var label: UILabel!\n    var didDismissViewControllerBlock: () -> Void = { }\n\n    override func viewDidLoad() {\n        super.viewDidLoad()\n        view.backgroundColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)\n        navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(cancel(_:)))\n    }\n\n    @IBAction func cancel(_ sender: UIButton) {\n        dismiss(animated: true, completion: didDismissViewControllerBlock)\n    }\n}\n\nclass ViewController: UIViewController {\n\n    lazy var queue = ProcedureQueue()\n\n    override func viewDidLoad() {\n        super.viewDidLoad()\n\n        let block = BlockProcedure { this in\n            DispatchQueue.default.async {\n                this.log.debug.message(\"Hello ProcedureKit\")\n                this.finish()\n            }\n        }\n        block.addCondition(UserConfirmationCondition(from: self))\n        queue.addOperation(block)\n    }\n\n    override func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) {\n        print(\"\\(type(of: self)) \\(#function)\")\n        super.dismiss(animated: flag, completion: completion)\n    }\n\n    @IBAction func go(_ sender: UIButton) {\n        guard\n            let storyboard = storyboard,\n            let another = storyboard.instantiateViewController(withIdentifier: \"another\") as? AnotherViewController\n        else { return }\n        let presentation = UIProcedure(present: another, from: self, withStyle: .present, waitForDismissal: true)\n        presentation.log.severity = .info\n        queue.addOperation(presentation)\n    }\n\n    @IBAction func alert(_ sender: UIButton) {\n\n        let alert = AlertProcedure(title: \"Hello World\", from: self)\n        alert.message = \"This is a message in an alert\"\n        alert.add(actionWithTitle: \"Sweet\") { (procedure, action) in\n            procedure.log.debug.message(\"Running the \\(action) handler!\")\n        }\n        queue.addOperation(alert)\n    }\n}\n"
  },
  {
    "path": "Integrations/CocoaPods/TryProcedureKit iOSTests/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>BNDL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Integrations/CocoaPods/TryProcedureKit iOSTests/TryProcedureKit_iOSTests.swift",
    "content": "//\n//  TryProcedureKit_iOSTests.swift\n//  TryProcedureKit iOSTests\n//\n//  Created by Daniel Thorpe on 05/12/2016.\n//  Copyright © 2016 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\n@testable import TryProcedureKit_iOS\n\nclass TryProcedureKit_iOSTests: XCTestCase {\n    \n    override func setUp() {\n        super.setUp()\n        // Put setup code here. This method is called before the invocation of each test method in the class.\n    }\n    \n    override func tearDown() {\n        // Put teardown code here. This method is called after the invocation of each test method in the class.\n        super.tearDown()\n    }\n    \n    func testExample() {\n        // This is an example of a functional test case.\n        // Use XCTAssert and related functions to verify your tests produce the correct results.\n    }\n    \n    func testPerformanceExample() {\n        // This is an example of a performance test case.\n        self.measure {\n            // Put the code you want to measure the time of here.\n        }\n    }\n    \n}\n"
  },
  {
    "path": "Integrations/CocoaPods/TryProcedureKit.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t2C5D53E08E5AE0F233961E68 /* Pods_TryProcedureKitTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A01E9CD09C0388F209F3BFEB /* Pods_TryProcedureKitTests.framework */; };\n\t\t3833776426F4F231C0D71DF9 /* Pods_TryProcedureKit_iOSTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C945E52D1FE103F80AC10B19 /* Pods_TryProcedureKit_iOSTests.framework */; };\n\t\t65987D621DEDCB6D00868688 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65987D611DEDCB6D00868688 /* AppDelegate.swift */; };\n\t\t65987D641DEDCB6D00868688 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65987D631DEDCB6D00868688 /* ViewController.swift */; };\n\t\t65987D661DEDCB6D00868688 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 65987D651DEDCB6D00868688 /* Assets.xcassets */; };\n\t\t65987D691DEDCB6D00868688 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 65987D671DEDCB6D00868688 /* Main.storyboard */; };\n\t\t65987D741DEDCB6D00868688 /* TryProcedureKitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65987D731DEDCB6D00868688 /* TryProcedureKitTests.swift */; };\n\t\t65C540221DF5DA1500DCB059 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65C540211DF5DA1500DCB059 /* AppDelegate.swift */; };\n\t\t65C540241DF5DA1500DCB059 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65C540231DF5DA1500DCB059 /* ViewController.swift */; };\n\t\t65C540271DF5DA1500DCB059 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 65C540251DF5DA1500DCB059 /* Main.storyboard */; };\n\t\t65C540291DF5DA1500DCB059 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 65C540281DF5DA1500DCB059 /* Assets.xcassets */; };\n\t\t65C5402C1DF5DA1500DCB059 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 65C5402A1DF5DA1500DCB059 /* LaunchScreen.storyboard */; };\n\t\t65C540371DF5DA1500DCB059 /* TryProcedureKit_iOSTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65C540361DF5DA1500DCB059 /* TryProcedureKit_iOSTests.swift */; };\n\t\tD9172DF90FED58818048C5EA /* Pods_TryProcedureKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D3711ECF3ED2EEF87B754C60 /* Pods_TryProcedureKit.framework */; };\n\t\tDE732B581EF976A594D792D5 /* Pods_TryProcedureKit_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3E651D3358ADB59E3AC6FE61 /* Pods_TryProcedureKit_iOS.framework */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXContainerItemProxy section */\n\t\t65987D701DEDCB6D00868688 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 65987D561DEDCB6D00868688 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 65987D5D1DEDCB6D00868688;\n\t\t\tremoteInfo = TryProcedureKit;\n\t\t};\n\t\t65C540331DF5DA1500DCB059 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 65987D561DEDCB6D00868688 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 65C5401E1DF5DA1500DCB059;\n\t\t\tremoteInfo = \"TryProcedureKit iOS\";\n\t\t};\n/* End PBXContainerItemProxy section */\n\n/* Begin PBXFileReference section */\n\t\t20BA1F62FDB673FAF14C8FD0 /* Pods-TryProcedureKit iOSTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-TryProcedureKit iOSTests.debug.xcconfig\"; path = \"Pods/Target Support Files/Pods-TryProcedureKit iOSTests/Pods-TryProcedureKit iOSTests.debug.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t22D696D4AB45191E7B56C3F8 /* Pods-TryProcedureKit iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-TryProcedureKit iOS.debug.xcconfig\"; path = \"Pods/Target Support Files/Pods-TryProcedureKit iOS/Pods-TryProcedureKit iOS.debug.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t3E651D3358ADB59E3AC6FE61 /* Pods_TryProcedureKit_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_TryProcedureKit_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t4C75AB65DA9F459E58F44D20 /* Pods-TryProcedureKitTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-TryProcedureKitTests.release.xcconfig\"; path = \"Pods/Target Support Files/Pods-TryProcedureKitTests/Pods-TryProcedureKitTests.release.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t566864A4B9D3236BD0492C34 /* Pods-TryProcedureKit iOSTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-TryProcedureKit iOSTests.release.xcconfig\"; path = \"Pods/Target Support Files/Pods-TryProcedureKit iOSTests/Pods-TryProcedureKit iOSTests.release.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t64E1871A3A35473F2C6303A9 /* Pods-TryProcedureKitTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-TryProcedureKitTests.debug.xcconfig\"; path = \"Pods/Target Support Files/Pods-TryProcedureKitTests/Pods-TryProcedureKitTests.debug.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t65987D5E1DEDCB6D00868688 /* TryProcedureKit.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TryProcedureKit.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t65987D611DEDCB6D00868688 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = \"<group>\"; };\n\t\t65987D631DEDCB6D00868688 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = \"<group>\"; };\n\t\t65987D651DEDCB6D00868688 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\t65987D681DEDCB6D00868688 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = \"<group>\"; };\n\t\t65987D6A1DEDCB6D00868688 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t65987D6F1DEDCB6D00868688 /* TryProcedureKitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TryProcedureKitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t65987D731DEDCB6D00868688 /* TryProcedureKitTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TryProcedureKitTests.swift; sourceTree = \"<group>\"; };\n\t\t65987D751DEDCB6D00868688 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t65C5401F1DF5DA1500DCB059 /* TryProcedureKit iOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = \"TryProcedureKit iOS.app\"; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t65C540211DF5DA1500DCB059 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = \"<group>\"; };\n\t\t65C540231DF5DA1500DCB059 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = \"<group>\"; };\n\t\t65C540261DF5DA1500DCB059 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = \"<group>\"; };\n\t\t65C540281DF5DA1500DCB059 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\t65C5402B1DF5DA1500DCB059 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = \"<group>\"; };\n\t\t65C5402D1DF5DA1500DCB059 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t65C540321DF5DA1500DCB059 /* TryProcedureKit iOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = \"TryProcedureKit iOSTests.xctest\"; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t65C540361DF5DA1500DCB059 /* TryProcedureKit_iOSTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TryProcedureKit_iOSTests.swift; sourceTree = \"<group>\"; };\n\t\t65C540381DF5DA1500DCB059 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\tA01E9CD09C0388F209F3BFEB /* Pods_TryProcedureKitTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_TryProcedureKitTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tA80C8A224A4D10648271BF7F /* Pods-TryProcedureKit iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-TryProcedureKit iOS.release.xcconfig\"; path = \"Pods/Target Support Files/Pods-TryProcedureKit iOS/Pods-TryProcedureKit iOS.release.xcconfig\"; sourceTree = \"<group>\"; };\n\t\tC43DCAAEFE574A655166C29E /* Pods-TryProcedureKit.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-TryProcedureKit.release.xcconfig\"; path = \"Pods/Target Support Files/Pods-TryProcedureKit/Pods-TryProcedureKit.release.xcconfig\"; sourceTree = \"<group>\"; };\n\t\tC945E52D1FE103F80AC10B19 /* Pods_TryProcedureKit_iOSTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_TryProcedureKit_iOSTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tD3711ECF3ED2EEF87B754C60 /* Pods_TryProcedureKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_TryProcedureKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tDDEBF5EF4F1774FBA52EE748 /* Pods-TryProcedureKit.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-TryProcedureKit.debug.xcconfig\"; path = \"Pods/Target Support Files/Pods-TryProcedureKit/Pods-TryProcedureKit.debug.xcconfig\"; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t65987D5B1DEDCB6D00868688 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tD9172DF90FED58818048C5EA /* Pods_TryProcedureKit.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t65987D6C1DEDCB6D00868688 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2C5D53E08E5AE0F233961E68 /* Pods_TryProcedureKitTests.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t65C5401C1DF5DA1500DCB059 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tDE732B581EF976A594D792D5 /* Pods_TryProcedureKit_iOS.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t65C5402F1DF5DA1500DCB059 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t3833776426F4F231C0D71DF9 /* Pods_TryProcedureKit_iOSTests.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\t16161B80B77EFE30228DDFDF /* Pods */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tDDEBF5EF4F1774FBA52EE748 /* Pods-TryProcedureKit.debug.xcconfig */,\n\t\t\t\tC43DCAAEFE574A655166C29E /* Pods-TryProcedureKit.release.xcconfig */,\n\t\t\t\t64E1871A3A35473F2C6303A9 /* Pods-TryProcedureKitTests.debug.xcconfig */,\n\t\t\t\t4C75AB65DA9F459E58F44D20 /* Pods-TryProcedureKitTests.release.xcconfig */,\n\t\t\t\t22D696D4AB45191E7B56C3F8 /* Pods-TryProcedureKit iOS.debug.xcconfig */,\n\t\t\t\tA80C8A224A4D10648271BF7F /* Pods-TryProcedureKit iOS.release.xcconfig */,\n\t\t\t\t20BA1F62FDB673FAF14C8FD0 /* Pods-TryProcedureKit iOSTests.debug.xcconfig */,\n\t\t\t\t566864A4B9D3236BD0492C34 /* Pods-TryProcedureKit iOSTests.release.xcconfig */,\n\t\t\t);\n\t\t\tname = Pods;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t65987D551DEDCB6D00868688 = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t65987D601DEDCB6D00868688 /* TryProcedureKit */,\n\t\t\t\t65987D721DEDCB6D00868688 /* TryProcedureKitTests */,\n\t\t\t\t65C540201DF5DA1500DCB059 /* TryProcedureKit iOS */,\n\t\t\t\t65C540351DF5DA1500DCB059 /* TryProcedureKit iOSTests */,\n\t\t\t\t65987D5F1DEDCB6D00868688 /* Products */,\n\t\t\t\t16161B80B77EFE30228DDFDF /* Pods */,\n\t\t\t\t6A4EA074A084AFA91D21B74C /* Frameworks */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t65987D5F1DEDCB6D00868688 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t65987D5E1DEDCB6D00868688 /* TryProcedureKit.app */,\n\t\t\t\t65987D6F1DEDCB6D00868688 /* TryProcedureKitTests.xctest */,\n\t\t\t\t65C5401F1DF5DA1500DCB059 /* TryProcedureKit iOS.app */,\n\t\t\t\t65C540321DF5DA1500DCB059 /* TryProcedureKit iOSTests.xctest */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t65987D601DEDCB6D00868688 /* TryProcedureKit */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t65987D611DEDCB6D00868688 /* AppDelegate.swift */,\n\t\t\t\t65987D631DEDCB6D00868688 /* ViewController.swift */,\n\t\t\t\t65987D651DEDCB6D00868688 /* Assets.xcassets */,\n\t\t\t\t65987D671DEDCB6D00868688 /* Main.storyboard */,\n\t\t\t\t65987D6A1DEDCB6D00868688 /* Info.plist */,\n\t\t\t);\n\t\t\tpath = TryProcedureKit;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t65987D721DEDCB6D00868688 /* TryProcedureKitTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t65987D731DEDCB6D00868688 /* TryProcedureKitTests.swift */,\n\t\t\t\t65987D751DEDCB6D00868688 /* Info.plist */,\n\t\t\t);\n\t\t\tpath = TryProcedureKitTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t65C540201DF5DA1500DCB059 /* TryProcedureKit iOS */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t65C540211DF5DA1500DCB059 /* AppDelegate.swift */,\n\t\t\t\t65C540231DF5DA1500DCB059 /* ViewController.swift */,\n\t\t\t\t65C540251DF5DA1500DCB059 /* Main.storyboard */,\n\t\t\t\t65C540281DF5DA1500DCB059 /* Assets.xcassets */,\n\t\t\t\t65C5402A1DF5DA1500DCB059 /* LaunchScreen.storyboard */,\n\t\t\t\t65C5402D1DF5DA1500DCB059 /* Info.plist */,\n\t\t\t);\n\t\t\tpath = \"TryProcedureKit iOS\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t65C540351DF5DA1500DCB059 /* TryProcedureKit iOSTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t65C540361DF5DA1500DCB059 /* TryProcedureKit_iOSTests.swift */,\n\t\t\t\t65C540381DF5DA1500DCB059 /* Info.plist */,\n\t\t\t);\n\t\t\tpath = \"TryProcedureKit iOSTests\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t6A4EA074A084AFA91D21B74C /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tD3711ECF3ED2EEF87B754C60 /* Pods_TryProcedureKit.framework */,\n\t\t\t\tA01E9CD09C0388F209F3BFEB /* Pods_TryProcedureKitTests.framework */,\n\t\t\t\t3E651D3358ADB59E3AC6FE61 /* Pods_TryProcedureKit_iOS.framework */,\n\t\t\t\tC945E52D1FE103F80AC10B19 /* Pods_TryProcedureKit_iOSTests.framework */,\n\t\t\t);\n\t\t\tname = Frameworks;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t65987D5D1DEDCB6D00868688 /* TryProcedureKit */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 65987D781DEDCB6D00868688 /* Build configuration list for PBXNativeTarget \"TryProcedureKit\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tCF2FFCBD41DC61EB25CA1F1A /* [CP] Check Pods Manifest.lock */,\n\t\t\t\t65987D5A1DEDCB6D00868688 /* Sources */,\n\t\t\t\t65987D5B1DEDCB6D00868688 /* Frameworks */,\n\t\t\t\t65987D5C1DEDCB6D00868688 /* Resources */,\n\t\t\t\t8E92736663D40AC48E98128E /* [CP] Embed Pods Frameworks */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = TryProcedureKit;\n\t\t\tproductName = TryProcedureKit;\n\t\t\tproductReference = 65987D5E1DEDCB6D00868688 /* TryProcedureKit.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n\t\t65987D6E1DEDCB6D00868688 /* TryProcedureKitTests */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 65987D7B1DEDCB6D00868688 /* Build configuration list for PBXNativeTarget \"TryProcedureKitTests\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tBF084573A9B0660F4C1D1C29 /* [CP] Check Pods Manifest.lock */,\n\t\t\t\t65987D6B1DEDCB6D00868688 /* Sources */,\n\t\t\t\t65987D6C1DEDCB6D00868688 /* Frameworks */,\n\t\t\t\t65987D6D1DEDCB6D00868688 /* Resources */,\n\t\t\t\t999CE9F151E217BE25FA8F09 /* [CP] Embed Pods Frameworks */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\t65987D711DEDCB6D00868688 /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = TryProcedureKitTests;\n\t\t\tproductName = TryProcedureKitTests;\n\t\t\tproductReference = 65987D6F1DEDCB6D00868688 /* TryProcedureKitTests.xctest */;\n\t\t\tproductType = \"com.apple.product-type.bundle.unit-test\";\n\t\t};\n\t\t65C5401E1DF5DA1500DCB059 /* TryProcedureKit iOS */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 65C5403D1DF5DA1500DCB059 /* Build configuration list for PBXNativeTarget \"TryProcedureKit iOS\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tBDE0E33DCEDDA35E8C213627 /* [CP] Check Pods Manifest.lock */,\n\t\t\t\t65C5401B1DF5DA1500DCB059 /* Sources */,\n\t\t\t\t65C5401C1DF5DA1500DCB059 /* Frameworks */,\n\t\t\t\t65C5401D1DF5DA1500DCB059 /* Resources */,\n\t\t\t\t91C29AF8EE5CC40A4A280F7A /* [CP] Embed Pods Frameworks */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = \"TryProcedureKit iOS\";\n\t\t\tproductName = \"TryProcedureKit iOS\";\n\t\t\tproductReference = 65C5401F1DF5DA1500DCB059 /* TryProcedureKit iOS.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n\t\t65C540311DF5DA1500DCB059 /* TryProcedureKit iOSTests */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 65C5403E1DF5DA1500DCB059 /* Build configuration list for PBXNativeTarget \"TryProcedureKit iOSTests\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t072369E216DED42A9E1B98F5 /* [CP] Check Pods Manifest.lock */,\n\t\t\t\t65C5402E1DF5DA1500DCB059 /* Sources */,\n\t\t\t\t65C5402F1DF5DA1500DCB059 /* Frameworks */,\n\t\t\t\t65C540301DF5DA1500DCB059 /* Resources */,\n\t\t\t\t1C7F0F2104C8D40CC298466C /* [CP] Embed Pods Frameworks */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\t65C540341DF5DA1500DCB059 /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = \"TryProcedureKit iOSTests\";\n\t\t\tproductName = \"TryProcedureKit iOSTests\";\n\t\t\tproductReference = 65C540321DF5DA1500DCB059 /* TryProcedureKit iOSTests.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\t65987D561DEDCB6D00868688 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastSwiftUpdateCheck = 0810;\n\t\t\t\tLastUpgradeCheck = 0940;\n\t\t\t\tORGANIZATIONNAME = ProcedureKit;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t65987D5D1DEDCB6D00868688 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 8.1;\n\t\t\t\t\t\tLastSwiftMigration = 0940;\n\t\t\t\t\t\tProvisioningStyle = Manual;\n\t\t\t\t\t};\n\t\t\t\t\t65987D6E1DEDCB6D00868688 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 8.1;\n\t\t\t\t\t\tLastSwiftMigration = 0940;\n\t\t\t\t\t\tProvisioningStyle = Manual;\n\t\t\t\t\t\tTestTargetID = 65987D5D1DEDCB6D00868688;\n\t\t\t\t\t};\n\t\t\t\t\t65C5401E1DF5DA1500DCB059 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 8.1;\n\t\t\t\t\t\tLastSwiftMigration = 0940;\n\t\t\t\t\t\tProvisioningStyle = Manual;\n\t\t\t\t\t};\n\t\t\t\t\t65C540311DF5DA1500DCB059 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 8.1;\n\t\t\t\t\t\tLastSwiftMigration = 0940;\n\t\t\t\t\t\tProvisioningStyle = Manual;\n\t\t\t\t\t\tTestTargetID = 65C5401E1DF5DA1500DCB059;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 65987D591DEDCB6D00868688 /* Build configuration list for PBXProject \"TryProcedureKit\" */;\n\t\t\tcompatibilityVersion = \"Xcode 3.2\";\n\t\t\tdevelopmentRegion = English;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = 65987D551DEDCB6D00868688;\n\t\t\tproductRefGroup = 65987D5F1DEDCB6D00868688 /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t65987D5D1DEDCB6D00868688 /* TryProcedureKit */,\n\t\t\t\t65987D6E1DEDCB6D00868688 /* TryProcedureKitTests */,\n\t\t\t\t65C5401E1DF5DA1500DCB059 /* TryProcedureKit iOS */,\n\t\t\t\t65C540311DF5DA1500DCB059 /* TryProcedureKit iOSTests */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t65987D5C1DEDCB6D00868688 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t65987D661DEDCB6D00868688 /* Assets.xcassets in Resources */,\n\t\t\t\t65987D691DEDCB6D00868688 /* Main.storyboard in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t65987D6D1DEDCB6D00868688 /* 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\t65C5401D1DF5DA1500DCB059 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t65C5402C1DF5DA1500DCB059 /* LaunchScreen.storyboard in Resources */,\n\t\t\t\t65C540291DF5DA1500DCB059 /* Assets.xcassets in Resources */,\n\t\t\t\t65C540271DF5DA1500DCB059 /* Main.storyboard in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t65C540301DF5DA1500DCB059 /* 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\t072369E216DED42A9E1B98F5 /* [CP] Check Pods Manifest.lock */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t\t\"${PODS_PODFILE_DIR_PATH}/Podfile.lock\",\n\t\t\t\t\"${PODS_ROOT}/Manifest.lock\",\n\t\t\t);\n\t\t\tname = \"[CP] Check Pods Manifest.lock\";\n\t\t\toutputPaths = (\n\t\t\t\t\"$(DERIVED_FILE_DIR)/Pods-TryProcedureKit iOSTests-checkManifestLockResult.txt\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"diff \\\"${PODS_PODFILE_DIR_PATH}/Podfile.lock\\\" \\\"${PODS_ROOT}/Manifest.lock\\\" > /dev/null\\nif [ $? != 0 ] ; then\\n    # print error to STDERR\\n    echo \\\"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\\\" >&2\\n    exit 1\\nfi\\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\\necho \\\"SUCCESS\\\" > \\\"${SCRIPT_OUTPUT_FILE_0}\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\t1C7F0F2104C8D40CC298466C /* [CP] Embed Pods Frameworks */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t\t\"${PODS_ROOT}/Target Support Files/Pods-TryProcedureKit iOSTests/Pods-TryProcedureKit iOSTests-frameworks.sh\",\n\t\t\t\t\"${BUILT_PRODUCTS_DIR}/ProcedureKit-iOS/ProcedureKit.framework\",\n\t\t\t\t\"${BUILT_PRODUCTS_DIR}/TestingProcedureKit-iOS/TestingProcedureKit.framework\",\n\t\t\t);\n\t\t\tname = \"[CP] Embed Pods Frameworks\";\n\t\t\toutputPaths = (\n\t\t\t\t\"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ProcedureKit.framework\",\n\t\t\t\t\"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/TestingProcedureKit.framework\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"\\\"${PODS_ROOT}/Target Support Files/Pods-TryProcedureKit iOSTests/Pods-TryProcedureKit iOSTests-frameworks.sh\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\t8E92736663D40AC48E98128E /* [CP] Embed Pods Frameworks */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t\t\"${PODS_ROOT}/Target Support Files/Pods-TryProcedureKit/Pods-TryProcedureKit-frameworks.sh\",\n\t\t\t\t\"${BUILT_PRODUCTS_DIR}/ProcedureKit-All-Cloud-CoreData-Location-Network-Standard/ProcedureKit.framework\",\n\t\t\t);\n\t\t\tname = \"[CP] Embed Pods Frameworks\";\n\t\t\toutputPaths = (\n\t\t\t\t\"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ProcedureKit.framework\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"\\\"${PODS_ROOT}/Target Support Files/Pods-TryProcedureKit/Pods-TryProcedureKit-frameworks.sh\\\"\\n\";\n\t\t};\n\t\t91C29AF8EE5CC40A4A280F7A /* [CP] Embed Pods Frameworks */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t\t\"${PODS_ROOT}/Target Support Files/Pods-TryProcedureKit iOS/Pods-TryProcedureKit iOS-frameworks.sh\",\n\t\t\t\t\"${BUILT_PRODUCTS_DIR}/ProcedureKit-ae76e0ea/ProcedureKit.framework\",\n\t\t\t);\n\t\t\tname = \"[CP] Embed Pods Frameworks\";\n\t\t\toutputPaths = (\n\t\t\t\t\"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ProcedureKit.framework\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"\\\"${PODS_ROOT}/Target Support Files/Pods-TryProcedureKit iOS/Pods-TryProcedureKit iOS-frameworks.sh\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\t999CE9F151E217BE25FA8F09 /* [CP] Embed Pods Frameworks */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t\t\"${PODS_ROOT}/Target Support Files/Pods-TryProcedureKitTests/Pods-TryProcedureKitTests-frameworks.sh\",\n\t\t\t\t\"${BUILT_PRODUCTS_DIR}/ProcedureKit-macOS/ProcedureKit.framework\",\n\t\t\t\t\"${BUILT_PRODUCTS_DIR}/TestingProcedureKit-macOS/TestingProcedureKit.framework\",\n\t\t\t);\n\t\t\tname = \"[CP] Embed Pods Frameworks\";\n\t\t\toutputPaths = (\n\t\t\t\t\"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ProcedureKit.framework\",\n\t\t\t\t\"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/TestingProcedureKit.framework\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"\\\"${PODS_ROOT}/Target Support Files/Pods-TryProcedureKitTests/Pods-TryProcedureKitTests-frameworks.sh\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\tBDE0E33DCEDDA35E8C213627 /* [CP] Check Pods Manifest.lock */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t\t\"${PODS_PODFILE_DIR_PATH}/Podfile.lock\",\n\t\t\t\t\"${PODS_ROOT}/Manifest.lock\",\n\t\t\t);\n\t\t\tname = \"[CP] Check Pods Manifest.lock\";\n\t\t\toutputPaths = (\n\t\t\t\t\"$(DERIVED_FILE_DIR)/Pods-TryProcedureKit iOS-checkManifestLockResult.txt\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"diff \\\"${PODS_PODFILE_DIR_PATH}/Podfile.lock\\\" \\\"${PODS_ROOT}/Manifest.lock\\\" > /dev/null\\nif [ $? != 0 ] ; then\\n    # print error to STDERR\\n    echo \\\"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\\\" >&2\\n    exit 1\\nfi\\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\\necho \\\"SUCCESS\\\" > \\\"${SCRIPT_OUTPUT_FILE_0}\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\tBF084573A9B0660F4C1D1C29 /* [CP] Check Pods Manifest.lock */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t\t\"${PODS_PODFILE_DIR_PATH}/Podfile.lock\",\n\t\t\t\t\"${PODS_ROOT}/Manifest.lock\",\n\t\t\t);\n\t\t\tname = \"[CP] Check Pods Manifest.lock\";\n\t\t\toutputPaths = (\n\t\t\t\t\"$(DERIVED_FILE_DIR)/Pods-TryProcedureKitTests-checkManifestLockResult.txt\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"diff \\\"${PODS_PODFILE_DIR_PATH}/Podfile.lock\\\" \\\"${PODS_ROOT}/Manifest.lock\\\" > /dev/null\\nif [ $? != 0 ] ; then\\n    # print error to STDERR\\n    echo \\\"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\\\" >&2\\n    exit 1\\nfi\\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\\necho \\\"SUCCESS\\\" > \\\"${SCRIPT_OUTPUT_FILE_0}\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\tCF2FFCBD41DC61EB25CA1F1A /* [CP] Check Pods Manifest.lock */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t\t\"${PODS_PODFILE_DIR_PATH}/Podfile.lock\",\n\t\t\t\t\"${PODS_ROOT}/Manifest.lock\",\n\t\t\t);\n\t\t\tname = \"[CP] Check Pods Manifest.lock\";\n\t\t\toutputPaths = (\n\t\t\t\t\"$(DERIVED_FILE_DIR)/Pods-TryProcedureKit-checkManifestLockResult.txt\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"diff \\\"${PODS_PODFILE_DIR_PATH}/Podfile.lock\\\" \\\"${PODS_ROOT}/Manifest.lock\\\" > /dev/null\\nif [ $? != 0 ] ; then\\n    # print error to STDERR\\n    echo \\\"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\\\" >&2\\n    exit 1\\nfi\\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\\necho \\\"SUCCESS\\\" > \\\"${SCRIPT_OUTPUT_FILE_0}\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n/* End PBXShellScriptBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t65987D5A1DEDCB6D00868688 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t65987D641DEDCB6D00868688 /* ViewController.swift in Sources */,\n\t\t\t\t65987D621DEDCB6D00868688 /* AppDelegate.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t65987D6B1DEDCB6D00868688 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t65987D741DEDCB6D00868688 /* TryProcedureKitTests.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t65C5401B1DF5DA1500DCB059 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t65C540241DF5DA1500DCB059 /* ViewController.swift in Sources */,\n\t\t\t\t65C540221DF5DA1500DCB059 /* AppDelegate.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t65C5402E1DF5DA1500DCB059 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t65C540371DF5DA1500DCB059 /* TryProcedureKit_iOSTests.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\t65987D711DEDCB6D00868688 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 65987D5D1DEDCB6D00868688 /* TryProcedureKit */;\n\t\t\ttargetProxy = 65987D701DEDCB6D00868688 /* PBXContainerItemProxy */;\n\t\t};\n\t\t65C540341DF5DA1500DCB059 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 65C5401E1DF5DA1500DCB059 /* TryProcedureKit iOS */;\n\t\t\ttargetProxy = 65C540331DF5DA1500DCB059 /* PBXContainerItemProxy */;\n\t\t};\n/* End PBXTargetDependency section */\n\n/* Begin PBXVariantGroup section */\n\t\t65987D671DEDCB6D00868688 /* Main.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t65987D681DEDCB6D00868688 /* Base */,\n\t\t\t);\n\t\t\tname = Main.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t65C540251DF5DA1500DCB059 /* Main.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t65C540261DF5DA1500DCB059 /* Base */,\n\t\t\t);\n\t\t\tname = Main.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t65C5402A1DF5DA1500DCB059 /* LaunchScreen.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t65C5402B1DF5DA1500DCB059 /* Base */,\n\t\t\t);\n\t\t\tname = LaunchScreen.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\t65987D761DEDCB6D00868688 /* 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_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_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_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_SUSPICIOUS_MOVES = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = macosx;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t65987D771DEDCB6D00868688 /* 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_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_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_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_SUSPICIOUS_MOVES = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tSDKROOT = macosx;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Owholemodule\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t65987D791DEDCB6D00868688 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = DDEBF5EF4F1774FBA52EE748 /* Pods-TryProcedureKit.debug.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = \"$(inherited)\";\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCODE_SIGN_STYLE = Manual;\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tINFOPLIST_FILE = TryProcedureKit/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/../Frameworks\";\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.13;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = run.kit.procedure.TryProcedureKit;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_VERSION = 4.0;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t65987D7A1DEDCB6D00868688 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = C43DCAAEFE574A655166C29E /* Pods-TryProcedureKit.release.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = \"$(inherited)\";\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCODE_SIGN_STYLE = Manual;\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tINFOPLIST_FILE = TryProcedureKit/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/../Frameworks\";\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.13;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = run.kit.procedure.TryProcedureKit;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_VERSION = 4.0;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t65987D7C1DEDCB6D00868688 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 64E1871A3A35473F2C6303A9 /* Pods-TryProcedureKitTests.debug.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = \"$(inherited)\";\n\t\t\t\tBUNDLE_LOADER = \"$(TEST_HOST)\";\n\t\t\t\tCODE_SIGN_STYLE = Manual;\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tINFOPLIST_FILE = TryProcedureKitTests/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = run.kit.procedure.TryProcedureKitTests;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_VERSION = 4.0;\n\t\t\t\tTEST_HOST = \"$(BUILT_PRODUCTS_DIR)/TryProcedureKit.app/Contents/MacOS/TryProcedureKit\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t65987D7D1DEDCB6D00868688 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 4C75AB65DA9F459E58F44D20 /* Pods-TryProcedureKitTests.release.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = \"$(inherited)\";\n\t\t\t\tBUNDLE_LOADER = \"$(TEST_HOST)\";\n\t\t\t\tCODE_SIGN_STYLE = Manual;\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tINFOPLIST_FILE = TryProcedureKitTests/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = run.kit.procedure.TryProcedureKitTests;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_VERSION = 4.0;\n\t\t\t\tTEST_HOST = \"$(BUILT_PRODUCTS_DIR)/TryProcedureKit.app/Contents/MacOS/TryProcedureKit\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t65C540391DF5DA1500DCB059 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 22D696D4AB45191E7B56C3F8 /* Pods-TryProcedureKit iOS.debug.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = \"$(inherited)\";\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCODE_SIGN_STYLE = Manual;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tINFOPLIST_FILE = \"TryProcedureKit iOS/Info.plist\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 10.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"run.kit.procedure.TryProcedureKit-iOS\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_VERSION = 4.0;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t65C5403A1DF5DA1500DCB059 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = A80C8A224A4D10648271BF7F /* Pods-TryProcedureKit iOS.release.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = \"$(inherited)\";\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCODE_SIGN_STYLE = Manual;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tINFOPLIST_FILE = \"TryProcedureKit iOS/Info.plist\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 10.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"run.kit.procedure.TryProcedureKit-iOS\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_VERSION = 4.0;\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t65C5403B1DF5DA1500DCB059 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 20BA1F62FDB673FAF14C8FD0 /* Pods-TryProcedureKit iOSTests.debug.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = \"$(inherited)\";\n\t\t\t\tBUNDLE_LOADER = \"$(TEST_HOST)\";\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCODE_SIGN_STYLE = Manual;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tINFOPLIST_FILE = \"TryProcedureKit iOSTests/Info.plist\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 10.1;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks @loader_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"run.kit.procedure.TryProcedureKit-iOSTests\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_VERSION = 4.0;\n\t\t\t\tTEST_HOST = \"$(BUILT_PRODUCTS_DIR)/TryProcedureKit iOS.app/TryProcedureKit iOS\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t65C5403C1DF5DA1500DCB059 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 566864A4B9D3236BD0492C34 /* Pods-TryProcedureKit iOSTests.release.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = \"$(inherited)\";\n\t\t\t\tBUNDLE_LOADER = \"$(TEST_HOST)\";\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCODE_SIGN_STYLE = Manual;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tINFOPLIST_FILE = \"TryProcedureKit iOSTests/Info.plist\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 10.1;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks @loader_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"run.kit.procedure.TryProcedureKit-iOSTests\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_VERSION = 4.0;\n\t\t\t\tTEST_HOST = \"$(BUILT_PRODUCTS_DIR)/TryProcedureKit iOS.app/TryProcedureKit iOS\";\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t65987D591DEDCB6D00868688 /* Build configuration list for PBXProject \"TryProcedureKit\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t65987D761DEDCB6D00868688 /* Debug */,\n\t\t\t\t65987D771DEDCB6D00868688 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t65987D781DEDCB6D00868688 /* Build configuration list for PBXNativeTarget \"TryProcedureKit\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t65987D791DEDCB6D00868688 /* Debug */,\n\t\t\t\t65987D7A1DEDCB6D00868688 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t65987D7B1DEDCB6D00868688 /* Build configuration list for PBXNativeTarget \"TryProcedureKitTests\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t65987D7C1DEDCB6D00868688 /* Debug */,\n\t\t\t\t65987D7D1DEDCB6D00868688 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t65C5403D1DF5DA1500DCB059 /* Build configuration list for PBXNativeTarget \"TryProcedureKit iOS\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t65C540391DF5DA1500DCB059 /* Debug */,\n\t\t\t\t65C5403A1DF5DA1500DCB059 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t65C5403E1DF5DA1500DCB059 /* Build configuration list for PBXNativeTarget \"TryProcedureKit iOSTests\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t65C5403B1DF5DA1500DCB059 /* Debug */,\n\t\t\t\t65C5403C1DF5DA1500DCB059 /* 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 = 65987D561DEDCB6D00868688 /* Project object */;\n}\n"
  },
  {
    "path": "Integrations/CocoaPods/TryProcedureKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"self:TryProcedureKit.xcodeproj\">\n   </FileRef>\n</Workspace>\n"
  },
  {
    "path": "Integrations/CocoaPods/TryProcedureKit.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>IDEDidComputeMac32BitWarning</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "Integrations/CocoaPods/TryProcedureKit.xcodeproj/xcshareddata/xcschemes/TryProcedureKit.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"0940\"\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 = \"65987D5D1DEDCB6D00868688\"\n               BuildableName = \"TryProcedureKit.app\"\n               BlueprintName = \"TryProcedureKit\"\n               ReferencedContainer = \"container:TryProcedureKit.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <Testables>\n         <TestableReference\n            skipped = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"65987D6E1DEDCB6D00868688\"\n               BuildableName = \"TryProcedureKitTests.xctest\"\n               BlueprintName = \"TryProcedureKitTests\"\n               ReferencedContainer = \"container:TryProcedureKit.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n      </Testables>\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"65987D5D1DEDCB6D00868688\"\n            BuildableName = \"TryProcedureKit.app\"\n            BlueprintName = \"TryProcedureKit\"\n            ReferencedContainer = \"container:TryProcedureKit.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"65987D5D1DEDCB6D00868688\"\n            BuildableName = \"TryProcedureKit.app\"\n            BlueprintName = \"TryProcedureKit\"\n            ReferencedContainer = \"container:TryProcedureKit.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"65987D5D1DEDCB6D00868688\"\n            BuildableName = \"TryProcedureKit.app\"\n            BlueprintName = \"TryProcedureKit\"\n            ReferencedContainer = \"container:TryProcedureKit.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "Integrations/CocoaPods/TryProcedureKit.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"group:TryProcedureKit.xcodeproj\">\n   </FileRef>\n   <FileRef\n      location = \"group:Pods/Pods.xcodeproj\">\n   </FileRef>\n</Workspace>\n"
  },
  {
    "path": "Integrations/CocoaPods/TryProcedureKit.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>IDEDidComputeMac32BitWarning</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "Integrations/CocoaPods/TryProcedureKitTests/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>BNDL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Integrations/CocoaPods/TryProcedureKitTests/TryProcedureKitTests.swift",
    "content": "//\n//  TryProcedureKitTests.swift\n//  TryProcedureKitTests\n//\n//  Created by Daniel Thorpe on 29/11/2016.\n//  Copyright © 2016 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport ProcedureKit\nimport TestingProcedureKit\n@testable import TryProcedureKit\n\nclass TestSuiteRuns: XCTestCase {\n\n    func test__suite_runs() {\n        XCTAssertTrue(true)\n    }\n}\n"
  },
  {
    "path": "Integrations/SPM/.gitignore",
    "content": ".DS_Store\n/.build\n/Packages\n/*.xcodeproj\n"
  },
  {
    "path": "Integrations/SPM/Package.swift",
    "content": "// swift-tools-version:4.2\n// The swift-tools-version declares the minimum version of Swift required to build this package.\n\nimport PackageDescription\n\nlet package = Package(\n    name: \"SPM-Integration-Check\",\n    dependencies: [\n        // Dependencies declare other packages that this package depends on.\n        // .package(url: /* package url */, from: \"1.0.0\"),\n        // Add the current branch of ProcedureKit as a dependency\n        .package(path: \"../..\")\n    ],\n    targets: [\n        // Targets are the basic building blocks of a package. A target can define a module or a test suite.\n        // Targets can depend on other targets in this package, and on products in packages which this package depends on.\n        .target(\n            name: \"SPM-Integration-Check\",\n            dependencies: [\n                \"ProcedureKit\"\n            ]),\n        .testTarget(\n            name: \"SPM-Integration-CheckTests\",\n            dependencies: [\"SPM-Integration-Check\"]),\n    ]\n)\n"
  },
  {
    "path": "Integrations/SPM/Sources/SPM-Integration-Check/main.swift",
    "content": "import ProcedureKit\n\nprint(\"Hello, world!\")\n"
  },
  {
    "path": "Integrations/SPM/Tests/SPM-Integration-CheckTests/SPM-Integration-CheckTests.swift",
    "content": "import XCTest\nimport class Foundation.Bundle\nimport ProcedureKit\n\nfinal class SwiftPackageManagerTests: XCTestCase {\n    func testExample() throws {\n        // This is an example of a functional test case.\n        // Use XCTAssert and related functions to verify your tests produce the correct\n        // results.\n\n        // Some of the APIs that we use below are available in macOS 10.13 and above.\n        guard #available(macOS 10.13, *) else {\n            return\n        }\n\n        let fooBinary = productsDirectory.appendingPathComponent(\"SPM-Integration-Check\")\n\n        let process = Process()\n        process.executableURL = fooBinary\n\n        let pipe = Pipe()\n        process.standardOutput = pipe\n\n        try process.run()\n        process.waitUntilExit()\n\n        let data = pipe.fileHandleForReading.readDataToEndOfFile()\n        let output = String(data: data, encoding: .utf8)\n\n        XCTAssertEqual(output, \"Hello, world!\\n\")\n    }\n\n    /// Returns path to the built products directory.\n    var productsDirectory: URL {\n      #if os(macOS)\n        for bundle in Bundle.allBundles where bundle.bundlePath.hasSuffix(\".xctest\") {\n            return bundle.bundleURL.deletingLastPathComponent()\n        }\n        fatalError(\"couldn't find the products directory\")\n      #else\n        return Bundle.main.bundleURL\n      #endif\n    }\n\n    static var allTests = [\n        (\"testExample\", testExample),\n    ]\n}\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2015, 2016, 2017, 2018 The ProcedureKit Contributors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n"
  },
  {
    "path": "Package.swift",
    "content": "// swift-tools-version:4.0\n\nimport PackageDescription\n\nlet pkg = Package(name: \"ProcedureKit\")\n\npkg.products = [\n    .library(name: \"ProcedureKit\", targets: [\"ProcedureKit\"]),\n    .library(name: \"ProcedureKitCloud\", targets: [\"ProcedureKitCloud\"]),\n    .library(name: \"ProcedureKitCoreData\", targets: [\"ProcedureKitCoreData\"]),\n    .library(name: \"ProcedureKitLocation\", targets: [\"ProcedureKitLocation\"]),\n    .library(name: \"ProcedureKitMac\", targets: [\"ProcedureKitMac\"]),\n    .library(name: \"ProcedureKitNetwork\", targets: [\"ProcedureKitNetwork\"]),\n    .library(name: \"TestingProcedureKit\", targets: [\"TestingProcedureKit\"])\n]\n\npkg.targets = [\n    .target(name: \"ProcedureKit\"),\n    .target(name: \"ProcedureKitCloud\", dependencies: [\"ProcedureKit\"]),\n    .target(name: \"ProcedureKitCoreData\", dependencies: [\"ProcedureKit\"]),    \n    .target(name: \"ProcedureKitLocation\", dependencies: [\"ProcedureKit\"]),\n    .target(name: \"ProcedureKitMac\", dependencies: [\"ProcedureKit\"]),\n    .target(name: \"ProcedureKitNetwork\", dependencies: [\"ProcedureKit\"]),\n    .target(name: \"TestingProcedureKit\", dependencies: [\"ProcedureKit\"]),\n    .testTarget(name: \"ProcedureKitTests\", dependencies: [\"ProcedureKit\", \"TestingProcedureKit\"]),\n    .testTarget(name: \"ProcedureKitStressTests\", dependencies: [\"ProcedureKit\", \"TestingProcedureKit\"]),\n    .testTarget(name: \"ProcedureKitCloudTests\", dependencies: [\"ProcedureKitCloud\", \"TestingProcedureKit\"]),\n    .testTarget(name: \"ProcedureKitCoreDataTests\", dependencies: [\"ProcedureKitCoreData\", \"TestingProcedureKit\"]),    \n    .testTarget(name: \"ProcedureKitLocationTests\", dependencies: [\"ProcedureKitLocation\", \"TestingProcedureKit\"]),\n    .testTarget(name: \"ProcedureKitMacTests\", dependencies: [\"ProcedureKitMac\", \"TestingProcedureKit\"]),\n    .testTarget(name: \"ProcedureKitNetworkTests\", dependencies: [\"ProcedureKitNetwork\", \"TestingProcedureKit\"]),\n]\n"
  },
  {
    "path": "Presentations/README.md",
    "content": "Included here are presentations slides which have been given about _Operations_ or _ProcedureKit_. In some cases the source materials, i.e. for diagrams is also included, however the Keynote/PowerPoint files may not. \n\nIf you which to include your own presentation information - please follow the folder structure which is already in place :)\n\nThanks so much for contributing! 💚\nDan\n\n# Presentations\n\n- June 2016, CocoaHeads Stockholm\n    Daniel Thorpe spoke about _Operations_ just before WWDC, unfortunately there wasn’t a video recording of this meetup.\n- July 2016, Sky UK iOS Community\n    Daniel Thorpe spoke about _Operations_ just after WWDC, at an internal community session at Sky (big media corp in the UK). Although the session was streamed on YouTube, no idea where that is. This talk is mostly a rehash of the CocoaHeads on, and is probably a little bit more refined. In the slides here, there are quite a few which were skipped when the talk was given, so it actually took ~ 40 minutes."
  },
  {
    "path": "ProcedureKit.podspec",
    "content": "Pod::Spec.new do |s|\n  s.name              = \"ProcedureKit\"\n  s.version           = \"5.2.0\"\n  s.summary           = \"Advanced Operations in Swift.\"\n  s.homepage          = \"https://github.com/ProcedureKit/ProcedureKit\"\n  s.license           = 'MIT'\n  s.authors           = { \"ProcedureKit Core Contributors\" => \"hello@procedure.kit.run\" }\n  s.source            = { :git => \"https://github.com/ProcedureKit/ProcedureKit.git\", :tag => s.version.to_s }\n  s.module_name       = 'ProcedureKit'\n\n  s.ios.deployment_target = '9.0'\n  s.watchos.deployment_target = '3.0'\n  s.tvos.deployment_target = '9.2'\n  s.osx.deployment_target = '10.11'\n  \n  # Ensure the correct version of Swift is used\n  s.swift_version = '5.0'\n\n  # Default spec is 'Standard'\n  s.default_subspec = 'Standard'\n\n  # Default core framework suitable for an iOS, watchOS, tvOS or macOS application\n  s.subspec 'Standard' do |ss|\n    ss.source_files = ['Sources/ProcedureKit']\n    ss.exclude_files = [\n      'Sources/TestingProcedureKit',\n      'Sources/ProcedureKitMobile',\n      'Sources/ProcedureKitMac',\n      'Sources/ProcedureKitTV',\n      'Sources/ProcedureKitNetwork',\n      'Sources/ProcedureKitCloud',\n      'Sources/ProcedureKitLocation'\n    ]\n  end\n\n  # ProcedureKitNetwork\n  s.subspec 'Network' do |ss|\n  \tss.dependency 'ProcedureKit/Standard'\n  \tss.source_files = ['Sources/ProcedureKitNetwork']\n  end\n\n  # ProcedureKitCloud\n  s.subspec 'Cloud' do |ss|\n  \tss.dependency 'ProcedureKit/Standard'\n  \tss.frameworks = 'CloudKit'\n  \tss.source_files = ['Sources/ProcedureKitCloud/**/*']\n  end\n\n  # ProcedureKitCoreData\n  s.subspec 'CoreData' do |ss|\n  \tss.dependency 'ProcedureKit/Standard'\n  \tss.frameworks = 'CoreData'\n  \tss.source_files = ['Sources/ProcedureKitCoreData']\n  end\n\n  # ProcedureKitLocation\n  s.subspec 'Location' do |ss|\n  \tss.dependency 'ProcedureKit/Standard'\n  \tss.frameworks = 'CoreLocation', 'MapKit'\n  \tss.source_files = ['Sources/ProcedureKitLocation']\n  end\n\n  # All cross-platform ProcedureKit\n  s.subspec 'All' do |ss|\n  \tss.dependency 'ProcedureKit/Network'\n  \tss.dependency 'ProcedureKit/Location'\n  \tss.dependency 'ProcedureKit/CoreData'  \t\n  \tss.dependency 'ProcedureKit/Cloud'\n  end\n\n  # ProcedureKitMobile\n  s.subspec 'Mobile' do |ss|\n    ss.platforms = { :ios => \"9.0\" }\n  \tss.dependency 'ProcedureKit/Standard'\n  \tss.source_files = ['Sources/ProcedureKitMobile']\n  end\n  \nend\n"
  },
  {
    "path": "ProcedureKit.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 51;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t65068FAD20C62AE300B0A0A3 /* MakesBackgroundManagedObjectContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65068FAC20C62AE300B0A0A3 /* MakesBackgroundManagedObjectContext.swift */; };\n\t\t651E670520C610D800BE520E /* CoreDataHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 651E670420C610D800BE520E /* CoreDataHelpers.swift */; };\n\t\t6527C35C2202026800D6F498 /* Decode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6527C35B2202026800D6F498 /* Decode.swift */; };\n\t\t6527C35E2202171F00D6F498 /* Encode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6527C35D2202171F00D6F498 /* Encode.swift */; };\n\t\t6527C360220217FE00D6F498 /* JSONCodingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6527C35F220217FE00D6F498 /* JSONCodingTests.swift */; };\n\t\t652F9015209C488600365B2D /* BatchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 652F9014209C488600365B2D /* BatchTests.swift */; };\n\t\t652F903D209E3E3D00365B2D /* IgnoreErrors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 652F903C209E3E3D00365B2D /* IgnoreErrors.swift */; };\n\t\t652F903F209E445200365B2D /* IgnoreErrorsProcedureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 652F903E209E445200365B2D /* IgnoreErrorsProcedureTests.swift */; };\n\t\t653C9FCA1D6097A40070B7A2 /* ProcedureKitMobile.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 653C9FC11D6097A40070B7A2 /* ProcedureKitMobile.framework */; };\n\t\t653C9FDB1D6098330070B7A2 /* ProcedureKitMobile.h in Headers */ = {isa = PBXBuildFile; fileRef = 653C9FDA1D6098330070B7A2 /* ProcedureKitMobile.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t653C9FDF1D6099110070B7A2 /* ProcedureKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65CFC5F01D608A5500CAD875 /* ProcedureKit.framework */; };\n\t\t653C9FE21D6099260070B7A2 /* TestingProcedureKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65CFC6161D60900000CAD875 /* TestingProcedureKit.framework */; };\n\t\t653C9FFC1D609E660070B7A2 /* ProcedureKitTV.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 653C9FF31D609E650070B7A2 /* ProcedureKitTV.framework */; };\n\t\t653CA00C1D609EE10070B7A2 /* ProcedureKitTV.h in Headers */ = {isa = PBXBuildFile; fileRef = 653CA00A1D609EDA0070B7A2 /* ProcedureKitTV.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t653CA00F1D609F9E0070B7A2 /* ProcedureKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65CFC5F01D608A5500CAD875 /* ProcedureKit.framework */; };\n\t\t653CA0121D609FA90070B7A2 /* TestingProcedureKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65CFC6161D60900000CAD875 /* TestingProcedureKit.framework */; };\n\t\t653CA01F1D60A34E0070B7A2 /* TestingProcedureKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65CFC6161D60900000CAD875 /* TestingProcedureKit.framework */; };\n\t\t653CA0201D60A34E0070B7A2 /* ProcedureKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65CFC5F01D608A5500CAD875 /* ProcedureKit.framework */; };\n\t\t653CA0391D60A5D10070B7A2 /* ProcedureKitMac.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 653CA0301D60A5D10070B7A2 /* ProcedureKitMac.framework */; };\n\t\t653CA0481D60A6060070B7A2 /* ProcedureKitMac.h in Headers */ = {isa = PBXBuildFile; fileRef = 653CA0471D60A6060070B7A2 /* ProcedureKitMac.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t653CA0501D60A7090070B7A2 /* ProcedureKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65CFC5F01D608A5500CAD875 /* ProcedureKit.framework */; };\n\t\t653CA0531D60A7130070B7A2 /* TestingProcedureKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65CFC6161D60900000CAD875 /* TestingProcedureKit.framework */; };\n\t\t653CA0631D60AA990070B7A2 /* ProcedureKitCloud.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 653CA05A1D60AA990070B7A2 /* ProcedureKitCloud.framework */; };\n\t\t653CA0741D60AB1B0070B7A2 /* ProcedureKitCloud.h in Headers */ = {isa = PBXBuildFile; fileRef = 653CA0731D60AB1B0070B7A2 /* ProcedureKitCloud.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t653CA0781D60ABC90070B7A2 /* ProcedureKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65CFC5F01D608A5500CAD875 /* ProcedureKit.framework */; };\n\t\t653CA07B1D60ABD30070B7A2 /* TestingProcedureKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65CFC6161D60900000CAD875 /* TestingProcedureKit.framework */; };\n\t\t6573A4FC21787D0000FDA362 /* ProcessManagedObjectContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6573A4FB21787D0000FDA362 /* ProcessManagedObjectContext.swift */; };\n\t\t658BE06F20BC69170021F11B /* ProcedureKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65CFC5F01D608A5500CAD875 /* ProcedureKit.framework */; };\n\t\t658BE07020BC69170021F11B /* TestingProcedureKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65CFC6161D60900000CAD875 /* TestingProcedureKit.framework */; };\n\t\t658BE07220BC72540021F11B /* MakeFetchedResultController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 658BE07120BC72540021F11B /* MakeFetchedResultController.swift */; };\n\t\t658BE07420BC77AD0021F11B /* MakeFetchedResultsControllerProcedureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 658BE07320BC77AD0021F11B /* MakeFetchedResultsControllerProcedureTests.swift */; };\n\t\t658BE07620BC99100021F11B /* InsertManagedObjects.swift in Sources */ = {isa = PBXBuildFile; fileRef = 658BE07520BC99100021F11B /* InsertManagedObjects.swift */; };\n\t\t658BE07820BCA0500021F11B /* InsertManagedObjectsProcedureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 658BE07720BCA0500021F11B /* InsertManagedObjectsProcedureTests.swift */; };\n\t\t659484271DAAA2B90028F83B /* ProcedureKitLocation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6594841E1DAAA2B90028F83B /* ProcedureKitLocation.framework */; };\n\t\t659484361DAAA3360028F83B /* ProcedureKitLocation.h in Headers */ = {isa = PBXBuildFile; fileRef = 659484351DAAA3360028F83B /* ProcedureKitLocation.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t6594843D1DAAA5430028F83B /* ProcedureKit.framework in Copy Files (2 items) */ = {isa = PBXBuildFile; fileRef = 65CFC5F01D608A5500CAD875 /* ProcedureKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };\n\t\t6594843E1DAAA5430028F83B /* TestingProcedureKit.framework in Copy Files (2 items) */ = {isa = PBXBuildFile; fileRef = 65CFC6161D60900000CAD875 /* TestingProcedureKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };\n\t\t65A0E4A220B85169002D6C8C /* ProcedureKitCoreData.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65A0E49920B85168002D6C8C /* ProcedureKitCoreData.framework */; };\n\t\t65A0E4B220B85213002D6C8C /* LoadCoreData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65A0E4B120B85213002D6C8C /* LoadCoreData.swift */; };\n\t\t65A0E4B420B85258002D6C8C /* ProcedureKitCoreData.h in Headers */ = {isa = PBXBuildFile; fileRef = 65A0E4B320B85258002D6C8C /* ProcedureKitCoreData.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t65A0E4BA20B8548D002D6C8C /* ProcedureKitCoreDataTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65A0E4B820B8548D002D6C8C /* ProcedureKitCoreDataTests.swift */; };\n\t\t65A0E4C120BB18EA002D6C8C /* TestDataModel.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 65A0E4BF20BB18EA002D6C8C /* TestDataModel.xcdatamodeld */; };\n\t\t65A0E4C320BB1975002D6C8C /* LoadCoreDataProcedureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65A0E4C220BB1975002D6C8C /* LoadCoreDataProcedureTests.swift */; };\n\t\t65A0E4C520BB2E51002D6C8C /* SaveManagedObjectContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65A0E4C420BB2E51002D6C8C /* SaveManagedObjectContext.swift */; };\n\t\t65A0E4C820BC5540002D6C8C /* SaveManagedObjectContextProcedureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65A0E4C620BC548A002D6C8C /* SaveManagedObjectContextProcedureTests.swift */; };\n\t\t65A1923920F88FD300E0D42C /* LoggingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65A1923820F88FD300E0D42C /* LoggingTests.swift */; };\n\t\t65A1923B20F8900100E0D42C /* TestableLogging.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65A1923A20F8900100E0D42C /* TestableLogging.swift */; };\n\t\t65A72C2A1DA7F37C008597CA /* ProcedureKit.framework in Copy Dependencies */ = {isa = PBXBuildFile; fileRef = 65CFC5F01D608A5500CAD875 /* ProcedureKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };\n\t\t65A72C2B1DA7F37C008597CA /* TestingProcedureKit.framework in Copy Dependencies */ = {isa = PBXBuildFile; fileRef = 65CFC6161D60900000CAD875 /* TestingProcedureKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };\n\t\t65AB7DDA209B95B400726796 /* Batch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65AB7DD9209B95B400726796 /* Batch.swift */; };\n\t\t65AEF19F20A3AE340089B6C8 /* ViewControllerContainment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65AEF19E20A3AE340089B6C8 /* ViewControllerContainment.swift */; };\n\t\t65B9AF482116D1D4004DA82B /* Result.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65B9AF472116D1D4004DA82B /* Result.swift */; };\n\t\t65C7BBC22085CEF4009A6D6E /* CKAcceptSharesOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D367DF1E1844F800D03E86 /* CKAcceptSharesOperation.swift */; };\n\t\t65C7BBC32085CF21009A6D6E /* CKDatabaseOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D367E01E1844F800D03E86 /* CKDatabaseOperation.swift */; };\n\t\t65C7BBC52085CF46009A6D6E /* CKDiscoverAllUserIdentitiesOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D367E21E1844F800D03E86 /* CKDiscoverAllUserIdentitiesOperation.swift */; };\n\t\t65C7BBC62085D0D3009A6D6E /* CKDiscoverUserIdentitiesOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D367E31E1844F800D03E86 /* CKDiscoverUserIdentitiesOperation.swift */; };\n\t\t65C7BBC82085D121009A6D6E /* CKFetchDatabaseChangesOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D367E51E1844F800D03E86 /* CKFetchDatabaseChangesOperation.swift */; };\n\t\t65C7BBC92085D17C009A6D6E /* CKFetchNotificationChangesOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D367E61E1844F800D03E86 /* CKFetchNotificationChangesOperation.swift */; };\n\t\t65C7BBCB2085D1B4009A6D6E /* CKFetchRecordsOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D367E81E1844F800D03E86 /* CKFetchRecordsOperation.swift */; };\n\t\t65C7BBCD2085D26F009A6D6E /* CKFetchRecordZoneChangesOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D367E91E1844F800D03E86 /* CKFetchRecordZoneChangesOperation.swift */; };\n\t\t65C7BBCE2085D294009A6D6E /* CKFetchRecordZonesOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D367EA1E1844F800D03E86 /* CKFetchRecordZonesOperation.swift */; };\n\t\t65C7BBCF2085D2A3009A6D6E /* CKFetchShareMetadataOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D367EB1E1844F800D03E86 /* CKFetchShareMetadataOperation.swift */; };\n\t\t65C7BBD02085D2B1009A6D6E /* CKFetchShareParticipantsOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D367EC1E1844F800D03E86 /* CKFetchShareParticipantsOperation.swift */; };\n\t\t65C7BBD12085D2DC009A6D6E /* CKFetchSubscriptionsOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D367ED1E1844F800D03E86 /* CKFetchSubscriptionsOperation.swift */; };\n\t\t65C7BBD22085D2E8009A6D6E /* CKMarkNotificationsReadOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D367EE1E1844F800D03E86 /* CKMarkNotificationsReadOperation.swift */; };\n\t\t65C7BBD32085D2EE009A6D6E /* CKModifyBadgeOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D367EF1E1844F800D03E86 /* CKModifyBadgeOperation.swift */; };\n\t\t65C7BBD42085D2F3009A6D6E /* CKModifyRecordsOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D367F01E1844F800D03E86 /* CKModifyRecordsOperation.swift */; };\n\t\t65C7BBD52085D30C009A6D6E /* CKModifyRecordZonesOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D367F11E1844F800D03E86 /* CKModifyRecordZonesOperation.swift */; };\n\t\t65C7BBD62085D31F009A6D6E /* CKModifySubscriptionsOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D367F21E1844F800D03E86 /* CKModifySubscriptionsOperation.swift */; };\n\t\t65C7BBD72085D329009A6D6E /* CKQueryOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D367F41E1844F800D03E86 /* CKQueryOperation.swift */; };\n\t\t65CFC5FA1D608A5500CAD875 /* ProcedureKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65CFC5F01D608A5500CAD875 /* ProcedureKit.framework */; };\n\t\t65CFC60B1D608AA700CAD875 /* ProcedureKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 65CFC60A1D608AA700CAD875 /* ProcedureKit.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t65CFC61F1D60904700CAD875 /* TestingProcedureKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 65CFC61E1D60904700CAD875 /* TestingProcedureKit.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t65CFC6231D60911C00CAD875 /* TestingProcedureKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65CFC6161D60900000CAD875 /* TestingProcedureKit.framework */; };\n\t\t65CFC6261D60912900CAD875 /* ProcedureKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65CFC5F01D608A5500CAD875 /* ProcedureKit.framework */; };\n\t\t65D3669B1E183F1900D03E86 /* CKAcceptSharesOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366811E183F1900D03E86 /* CKAcceptSharesOperationTests.swift */; };\n\t\t65D3669C1E183F1900D03E86 /* CKDatabaseOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366821E183F1900D03E86 /* CKDatabaseOperationTests.swift */; };\n\t\t65D3669E1E183F1900D03E86 /* CKDiscoverAllUserIdentitiesOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366841E183F1900D03E86 /* CKDiscoverAllUserIdentitiesOperationTests.swift */; };\n\t\t65D3669F1E183F1900D03E86 /* CKDiscoverUserIdentitiesOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366851E183F1900D03E86 /* CKDiscoverUserIdentitiesOperationTests.swift */; };\n\t\t65D366A11E183F1900D03E86 /* CKFetchAllChangesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366871E183F1900D03E86 /* CKFetchAllChangesTests.swift */; };\n\t\t65D366A21E183F1900D03E86 /* CKFetchDatabaseChangesOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366881E183F1900D03E86 /* CKFetchDatabaseChangesOperationTests.swift */; };\n\t\t65D366A31E183F1900D03E86 /* CKFetchNotificationChangesOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366891E183F1900D03E86 /* CKFetchNotificationChangesOperationTests.swift */; };\n\t\t65D366A51E183F1900D03E86 /* CKFetchRecordsOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D3668B1E183F1900D03E86 /* CKFetchRecordsOperationTests.swift */; };\n\t\t65D366A61E183F1900D03E86 /* CKFetchRecordZoneChangesOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D3668C1E183F1900D03E86 /* CKFetchRecordZoneChangesOperationTests.swift */; };\n\t\t65D366A71E183F1900D03E86 /* CKFetchRecordZonesOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D3668D1E183F1900D03E86 /* CKFetchRecordZonesOperationTests.swift */; };\n\t\t65D366A81E183F1900D03E86 /* CKFetchShareMetadataOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D3668E1E183F1900D03E86 /* CKFetchShareMetadataOperationTests.swift */; };\n\t\t65D366A91E183F1900D03E86 /* CKFetchShareParticipantsOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D3668F1E183F1900D03E86 /* CKFetchShareParticipantsOperationTests.swift */; };\n\t\t65D366AA1E183F1900D03E86 /* CKFetchSubscriptionsOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366901E183F1900D03E86 /* CKFetchSubscriptionsOperationTests.swift */; };\n\t\t65D366AB1E183F1900D03E86 /* CKMarkNotificationsReadOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366911E183F1900D03E86 /* CKMarkNotificationsReadOperationTests.swift */; };\n\t\t65D366AC1E183F1900D03E86 /* CKModifyBadgeOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366921E183F1900D03E86 /* CKModifyBadgeOperationTests.swift */; };\n\t\t65D366AD1E183F1900D03E86 /* CKModifyRecordsOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366931E183F1900D03E86 /* CKModifyRecordsOperationTests.swift */; };\n\t\t65D366AE1E183F1900D03E86 /* CKModifyRecordZonesOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366941E183F1900D03E86 /* CKModifyRecordZonesOperationTests.swift */; };\n\t\t65D366AF1E183F1900D03E86 /* CKModifySubscriptionsOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366951E183F1900D03E86 /* CKModifySubscriptionsOperationTests.swift */; };\n\t\t65D366B01E183F1900D03E86 /* CKOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366961E183F1900D03E86 /* CKOperationTests.swift */; };\n\t\t65D366B11E183F1900D03E86 /* CKQueryOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366971E183F1900D03E86 /* CKQueryOperationTests.swift */; };\n\t\t65D366B21E183F1900D03E86 /* CloudKitCapabilityTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366981E183F1900D03E86 /* CloudKitCapabilityTests.swift */; };\n\t\t65D366B31E183F1900D03E86 /* ProcedureKitCloudTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366991E183F1900D03E86 /* ProcedureKitCloudTests.swift */; };\n\t\t65D366B41E183F1900D03E86 /* TestableCloudKitContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D3669A1E183F1900D03E86 /* TestableCloudKitContainer.swift */; };\n\t\t65D366BC1E183F2600D03E86 /* LocationCapabilityTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366B61E183F2600D03E86 /* LocationCapabilityTests.swift */; };\n\t\t65D366BD1E183F2600D03E86 /* ProcedureKitLocationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366B71E183F2600D03E86 /* ProcedureKitLocationTests.swift */; };\n\t\t65D366BE1E183F2600D03E86 /* ReverseGeocodeProcedureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366B81E183F2600D03E86 /* ReverseGeocodeProcedureTests.swift */; };\n\t\t65D366BF1E183F2600D03E86 /* ReverseGeocodeUserLocationProcedureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366B91E183F2600D03E86 /* ReverseGeocodeUserLocationProcedureTests.swift */; };\n\t\t65D366C01E183F2600D03E86 /* TestableLocationServices.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366BA1E183F2600D03E86 /* TestableLocationServices.swift */; };\n\t\t65D366C11E183F2600D03E86 /* UserLocationProcedureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366BB1E183F2600D03E86 /* UserLocationProcedureTests.swift */; };\n\t\t65D366C51E183F3900D03E86 /* ProcedureKitMacTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366C31E183F3900D03E86 /* ProcedureKitMacTests.swift */; };\n\t\t65D366C61E183F3900D03E86 /* ProcessProcedureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366C41E183F3900D03E86 /* ProcessProcedureTests.swift */; };\n\t\t65D366CE1E183F5000D03E86 /* AlertProcedureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366C81E183F5000D03E86 /* AlertProcedureTests.swift */; };\n\t\t65D366CF1E183F5000D03E86 /* BackgroundObserverTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366C91E183F5000D03E86 /* BackgroundObserverTests.swift */; };\n\t\t65D366D01E183F5000D03E86 /* PresentationProcedureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366CA1E183F5000D03E86 /* PresentationProcedureTests.swift */; };\n\t\t65D366D11E183F5000D03E86 /* ProcedureKitMobileTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366CB1E183F5000D03E86 /* ProcedureKitMobileTests.swift */; };\n\t\t65D366D21E183F5000D03E86 /* TestableUIApplication.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366CC1E183F5000D03E86 /* TestableUIApplication.swift */; };\n\t\t65D366D31E183F5000D03E86 /* UIProcedureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366CD1E183F5000D03E86 /* UIProcedureTests.swift */; };\n\t\t65D366DC1E183F6400D03E86 /* NetworkDataProcedureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366D51E183F6400D03E86 /* NetworkDataProcedureTests.swift */; };\n\t\t65D366DD1E183F6400D03E86 /* NetworkDownloadProcedureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366D61E183F6400D03E86 /* NetworkDownloadProcedureTests.swift */; };\n\t\t65D366DE1E183F6400D03E86 /* NetworkProcedureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366D71E183F6400D03E86 /* NetworkProcedureTests.swift */; };\n\t\t65D366DF1E183F6400D03E86 /* NetworkReachabilityTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366D81E183F6400D03E86 /* NetworkReachabilityTests.swift */; };\n\t\t65D366E01E183F6400D03E86 /* NetworkUploadProcedureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366D91E183F6400D03E86 /* NetworkUploadProcedureTests.swift */; };\n\t\t65D366E11E183F6400D03E86 /* ProcedureKitNetworkTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366DA1E183F6400D03E86 /* ProcedureKitNetworkTests.swift */; };\n\t\t65D366E21E183F6400D03E86 /* URLTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366DB1E183F6400D03E86 /* URLTests.swift */; };\n\t\t65D366E51E183F8100D03E86 /* ProcedureKitTVTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366E41E183F8100D03E86 /* ProcedureKitTVTests.swift */; };\n\t\t65D367051E183FB000D03E86 /* AnyProcedureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366E71E183FB000D03E86 /* AnyProcedureTests.swift */; };\n\t\t65D367071E183FB000D03E86 /* BlockConditionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366E81E183FB000D03E86 /* BlockConditionTests.swift */; };\n\t\t65D367091E183FB000D03E86 /* BlockObserverTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366E91E183FB000D03E86 /* BlockObserverTests.swift */; };\n\t\t65D3670B1E183FB000D03E86 /* BlockProcedureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366EA1E183FB000D03E86 /* BlockProcedureTests.swift */; };\n\t\t65D3670D1E183FB000D03E86 /* CancellationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366EB1E183FB000D03E86 /* CancellationTests.swift */; };\n\t\t65D3670F1E183FB000D03E86 /* CapabilityTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366EC1E183FB000D03E86 /* CapabilityTests.swift */; };\n\t\t65D367111E183FB000D03E86 /* ComposedProcedureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366ED1E183FB000D03E86 /* ComposedProcedureTests.swift */; };\n\t\t65D367131E183FB000D03E86 /* ConditionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366EE1E183FB000D03E86 /* ConditionTests.swift */; };\n\t\t65D367151E183FB000D03E86 /* DelayProcedureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366EF1E183FB000D03E86 /* DelayProcedureTests.swift */; };\n\t\t65D367171E183FB000D03E86 /* FilterProcedureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366F01E183FB000D03E86 /* FilterProcedureTests.swift */; };\n\t\t65D367191E183FB000D03E86 /* FinishingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366F11E183FB000D03E86 /* FinishingTests.swift */; };\n\t\t65D3671B1E183FB000D03E86 /* GroupTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366F21E183FB000D03E86 /* GroupTests.swift */; };\n\t\t65D3671F1E183FB000D03E86 /* MapProcedureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366F41E183FB000D03E86 /* MapProcedureTests.swift */; };\n\t\t65D367211E183FB000D03E86 /* MutualExclusivityTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366F51E183FB000D03E86 /* MutualExclusivityTests.swift */; };\n\t\t65D367231E183FB000D03E86 /* NegatedConditionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366F61E183FB000D03E86 /* NegatedConditionTests.swift */; };\n\t\t65D367251E183FB000D03E86 /* NetworkObserverTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366F71E183FB000D03E86 /* NetworkObserverTests.swift */; };\n\t\t65D367271E183FB000D03E86 /* NoFailedDependenciesConditionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366F81E183FB000D03E86 /* NoFailedDependenciesConditionTests.swift */; };\n\t\t65D367291E183FB000D03E86 /* ProcedureKitErrorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366F91E183FB000D03E86 /* ProcedureKitErrorTests.swift */; };\n\t\t65D3672B1E183FB000D03E86 /* ProcedureKitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366FA1E183FB000D03E86 /* ProcedureKitTests.swift */; };\n\t\t65D3672D1E183FB000D03E86 /* ProcedureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366FB1E183FB000D03E86 /* ProcedureTests.swift */; };\n\t\t65D3672F1E183FB000D03E86 /* ProfilerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366FC1E183FB000D03E86 /* ProfilerTests.swift */; };\n\t\t65D367311E183FB000D03E86 /* ReachabilityTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366FD1E183FB000D03E86 /* ReachabilityTests.swift */; };\n\t\t65D367331E183FB000D03E86 /* ReduceProcedureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366FE1E183FB000D03E86 /* ReduceProcedureTests.swift */; };\n\t\t65D367351E183FB000D03E86 /* RepeatProcedureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D366FF1E183FB000D03E86 /* RepeatProcedureTests.swift */; };\n\t\t65D367371E183FB000D03E86 /* ResultInjectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D367001E183FB000D03E86 /* ResultInjectionTests.swift */; };\n\t\t65D367391E183FB000D03E86 /* RetryProcedureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D367011E183FB000D03E86 /* RetryProcedureTests.swift */; };\n\t\t65D3673B1E183FB000D03E86 /* SilentConditionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D367021E183FB000D03E86 /* SilentConditionTests.swift */; };\n\t\t65D3673D1E183FB000D03E86 /* TimeoutObserverTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D367031E183FB000D03E86 /* TimeoutObserverTests.swift */; };\n\t\t65D3673F1E183FB000D03E86 /* TransformProcedureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D367041E183FB000D03E86 /* TransformProcedureTests.swift */; };\n\t\t65D367471E183FBE00D03E86 /* BlockProcedureStressTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D367421E183FBE00D03E86 /* BlockProcedureStressTests.swift */; };\n\t\t65D367491E183FBE00D03E86 /* GroupStressTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D367431E183FBE00D03E86 /* GroupStressTests.swift */; };\n\t\t65D3674B1E183FBE00D03E86 /* ProcedureKitStressTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D367441E183FBE00D03E86 /* ProcedureKitStressTests.swift */; };\n\t\t65D3674D1E183FBE00D03E86 /* ProcedureStressTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D367451E183FBE00D03E86 /* ProcedureStressTests.swift */; };\n\t\t65D3674F1E183FBE00D03E86 /* RepeatStressTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D367461E183FBE00D03E86 /* RepeatStressTests.swift */; };\n\t\t65D367D21E1844E500D03E86 /* CapabilityTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D367C61E1844E500D03E86 /* CapabilityTestCase.swift */; };\n\t\t65D367D31E1844E500D03E86 /* ConcurrencyTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D367C71E1844E500D03E86 /* ConcurrencyTestCase.swift */; };\n\t\t65D367D41E1844E500D03E86 /* GroupTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D367C81E1844E500D03E86 /* GroupTestCase.swift */; };\n\t\t65D367D51E1844E500D03E86 /* ProcedureKitTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D367C91E1844E500D03E86 /* ProcedureKitTestCase.swift */; };\n\t\t65D367D61E1844E500D03E86 /* QueueTestDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D367CA1E1844E500D03E86 /* QueueTestDelegate.swift */; };\n\t\t65D367D71E1844E500D03E86 /* RepeatTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D367CB1E1844E500D03E86 /* RepeatTestCase.swift */; };\n\t\t65D367D81E1844E500D03E86 /* StressTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D367CC1E1844E500D03E86 /* StressTestCase.swift */; };\n\t\t65D367D91E1844E500D03E86 /* TestableNetwork.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D367CD1E1844E500D03E86 /* TestableNetwork.swift */; };\n\t\t65D367DA1E1844E500D03E86 /* TestableNetworkReachability.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D367CE1E1844E500D03E86 /* TestableNetworkReachability.swift */; };\n\t\t65D367DB1E1844E500D03E86 /* TestCondition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D367CF1E1844E500D03E86 /* TestCondition.swift */; };\n\t\t65D367DC1E1844E500D03E86 /* TestProcedure.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D367D01E1844E500D03E86 /* TestProcedure.swift */; };\n\t\t65D367DD1E1844E500D03E86 /* XCTAsserts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D367D11E1844E500D03E86 /* XCTAsserts.swift */; };\n\t\t65D3680D1E1844F800D03E86 /* CKOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D367F31E1844F800D03E86 /* CKOperation.swift */; };\n\t\t65D3680F1E1844F800D03E86 /* CloudKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D367F51E1844F800D03E86 /* CloudKit.swift */; };\n\t\t65D368101E1844F800D03E86 /* CloudKitCapability.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D367F61E1844F800D03E86 /* CloudKitCapability.swift */; };\n\t\t65D368111E1844F800D03E86 /* CloudKitError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D367F71E1844F800D03E86 /* CloudKitError.swift */; };\n\t\t65D368121E1844F800D03E86 /* CloudKitSupport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D367F81E1844F800D03E86 /* CloudKitSupport.swift */; };\n\t\t65D368191E18450200D03E86 /* LocationCapability.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D368141E18450200D03E86 /* LocationCapability.swift */; };\n\t\t65D3681A1E18450300D03E86 /* LocationSupport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D368151E18450200D03E86 /* LocationSupport.swift */; };\n\t\t65D3681B1E18450300D03E86 /* ReverseGeocode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D368161E18450200D03E86 /* ReverseGeocode.swift */; };\n\t\t65D3681C1E18450300D03E86 /* ReverseGeocodeUserLocation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D368171E18450200D03E86 /* ReverseGeocodeUserLocation.swift */; };\n\t\t65D3681D1E18450300D03E86 /* UserLocation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D368181E18450200D03E86 /* UserLocation.swift */; };\n\t\t65D368201E18451000D03E86 /* Process.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D3681F1E18451000D03E86 /* Process.swift */; };\n\t\t65D368261E18451C00D03E86 /* Alert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D368221E18451C00D03E86 /* Alert.swift */; };\n\t\t65D368271E18451C00D03E86 /* BackgroundObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D368231E18451C00D03E86 /* BackgroundObserver.swift */; };\n\t\t65D368281E18451C00D03E86 /* NetworkObserver+Mobile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D368241E18451C00D03E86 /* NetworkObserver+Mobile.swift */; };\n\t\t65D368291E18451C00D03E86 /* UI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D368251E18451C00D03E86 /* UI.swift */; };\n\t\t65D368311E18452900D03E86 /* Network.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D3682B1E18452900D03E86 /* Network.swift */; };\n\t\t65D368321E18452900D03E86 /* NetworkData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D3682C1E18452900D03E86 /* NetworkData.swift */; };\n\t\t65D368331E18452900D03E86 /* NetworkDownload.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D3682D1E18452900D03E86 /* NetworkDownload.swift */; };\n\t\t65D368341E18452900D03E86 /* NetworkReachability.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D3682E1E18452900D03E86 /* NetworkReachability.swift */; };\n\t\t65D368351E18452900D03E86 /* NetworkSupport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D3682F1E18452900D03E86 /* NetworkSupport.swift */; };\n\t\t65D368361E18452900D03E86 /* NetworkUpload.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D368301E18452900D03E86 /* NetworkUpload.swift */; };\n\t\t65D3688A1E184AA600D03E86 /* Any.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D368661E184AA600D03E86 /* Any.swift */; };\n\t\t65D3688B1E184AA600D03E86 /* AnyObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D368671E184AA600D03E86 /* AnyObserver.swift */; };\n\t\t65D3688C1E184AA600D03E86 /* Block.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D368681E184AA600D03E86 /* Block.swift */; };\n\t\t65D3688D1E184AA600D03E86 /* BlockCondition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D368691E184AA600D03E86 /* BlockCondition.swift */; };\n\t\t65D3688E1E184AA600D03E86 /* BlockObservers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D3686A1E184AA600D03E86 /* BlockObservers.swift */; };\n\t\t65D3688F1E184AA600D03E86 /* Capability.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D3686B1E184AA600D03E86 /* Capability.swift */; };\n\t\t65D368901E184AA600D03E86 /* Collection+ProcedureKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D3686C1E184AA600D03E86 /* Collection+ProcedureKit.swift */; };\n\t\t65D368911E184AA600D03E86 /* Composed.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D3686D1E184AA600D03E86 /* Composed.swift */; };\n\t\t65D368921E184AA600D03E86 /* Condition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D3686E1E184AA600D03E86 /* Condition.swift */; };\n\t\t65D368931E184AA600D03E86 /* Delay.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D3686F1E184AA600D03E86 /* Delay.swift */; };\n\t\t65D368941E184AA600D03E86 /* DispatchQueue+ProcedureKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D368701E184AA600D03E86 /* DispatchQueue+ProcedureKit.swift */; };\n\t\t65D368951E184AA600D03E86 /* Errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D368711E184AA600D03E86 /* Errors.swift */; };\n\t\t65D368961E184AA600D03E86 /* Filter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D368721E184AA600D03E86 /* Filter.swift */; };\n\t\t65D368971E184AA600D03E86 /* Group.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D368731E184AA600D03E86 /* Group.swift */; };\n\t\t65D368981E184AA600D03E86 /* Identity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D368741E184AA600D03E86 /* Identity.swift */; };\n\t\t65D368991E184AA600D03E86 /* Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D368751E184AA600D03E86 /* Logging.swift */; };\n\t\t65D3689A1E184AA600D03E86 /* Map.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D368761E184AA600D03E86 /* Map.swift */; };\n\t\t65D3689B1E184AA600D03E86 /* MutualExclusion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D368771E184AA600D03E86 /* MutualExclusion.swift */; };\n\t\t65D3689C1E184AA600D03E86 /* NegatedCondition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D368781E184AA600D03E86 /* NegatedCondition.swift */; };\n\t\t65D3689D1E184AA600D03E86 /* NetworkObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D368791E184AA600D03E86 /* NetworkObserver.swift */; };\n\t\t65D3689E1E184AA600D03E86 /* NoFailedDependenciesCondition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D3687A1E184AA600D03E86 /* NoFailedDependenciesCondition.swift */; };\n\t\t65D3689F1E184AA600D03E86 /* Operation+ProcedureKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D3687B1E184AA600D03E86 /* Operation+ProcedureKit.swift */; };\n\t\t65D368A01E184AA600D03E86 /* Procedure.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D3687C1E184AA600D03E86 /* Procedure.swift */; };\n\t\t65D368A11E184AA600D03E86 /* ProcedureObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D3687D1E184AA600D03E86 /* ProcedureObserver.swift */; };\n\t\t65D368A21E184AA600D03E86 /* ProcedureProcotol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D3687E1E184AA600D03E86 /* ProcedureProcotol.swift */; };\n\t\t65D368A31E184AA600D03E86 /* ProcedureQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D3687F1E184AA600D03E86 /* ProcedureQueue.swift */; };\n\t\t65D368A41E184AA600D03E86 /* ProcedureResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D368801E184AA600D03E86 /* ProcedureResult.swift */; };\n\t\t65D368A51E184AA600D03E86 /* Profiler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D368811E184AA600D03E86 /* Profiler.swift */; };\n\t\t65D368A61E184AA600D03E86 /* Reachability.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D368821E184AA600D03E86 /* Reachability.swift */; };\n\t\t65D368A71E184AA600D03E86 /* Reduce.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D368831E184AA600D03E86 /* Reduce.swift */; };\n\t\t65D368A81E184AA600D03E86 /* Repeat.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D368841E184AA600D03E86 /* Repeat.swift */; };\n\t\t65D368A91E184AA600D03E86 /* Retry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D368851E184AA600D03E86 /* Retry.swift */; };\n\t\t65D368AA1E184AA600D03E86 /* SilentCondition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D368861E184AA600D03E86 /* SilentCondition.swift */; };\n\t\t65D368AB1E184AA600D03E86 /* Support.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D368871E184AA600D03E86 /* Support.swift */; };\n\t\t65D368AC1E184AA600D03E86 /* TimeoutObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D368881E184AA600D03E86 /* TimeoutObserver.swift */; };\n\t\t65D368AD1E184AA600D03E86 /* Transform.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D368891E184AA600D03E86 /* Transform.swift */; };\n\t\t65D4BEF520C8A31100D85877 /* SignpostObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D4BEF420C8A31100D85877 /* SignpostObserver.swift */; };\n\t\t65E5EB8420C9CAEC00C46965 /* ProcedureKitInstruments.instrpkg in Sources */ = {isa = PBXBuildFile; fileRef = 65E5EB8320C9CAEC00C46965 /* ProcedureKitInstruments.instrpkg */; };\n\t\t65ECB2D61DB4F0C000F96F46 /* ProcedureKitNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65ECB2CD1DB4F0C000F96F46 /* ProcedureKitNetwork.framework */; };\n\t\t65ECB2EA1DB4F1A200F96F46 /* ProcedureKitNetwork.h in Headers */ = {isa = PBXBuildFile; fileRef = 65ECB2E81DB4F1A200F96F46 /* ProcedureKitNetwork.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t65ECB2EC1DB4F27700F96F46 /* TestingProcedureKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65CFC6161D60900000CAD875 /* TestingProcedureKit.framework */; };\n\t\t65ECB2F91DB50B8B00F96F46 /* ProcedureKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65CFC5F01D608A5500CAD875 /* ProcedureKit.framework */; };\n\t\t65ECB2FD1DB50BC500F96F46 /* ProcedureKit.framework in Copy Dependencies */ = {isa = PBXBuildFile; fileRef = 65CFC5F01D608A5500CAD875 /* ProcedureKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };\n\t\t65ECB2FE1DB50BC500F96F46 /* TestingProcedureKit.framework in Copy Dependencies */ = {isa = PBXBuildFile; fileRef = 65CFC6161D60900000CAD875 /* TestingProcedureKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };\n\t\t65ECB3001DB50BD900F96F46 /* ProcedureKit.framework in Copy Dependencies */ = {isa = PBXBuildFile; fileRef = 65CFC5F01D608A5500CAD875 /* ProcedureKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };\n\t\t65ECB3011DB50BD900F96F46 /* TestingProcedureKit.framework in Copy Dependencies */ = {isa = PBXBuildFile; fileRef = 65CFC6161D60900000CAD875 /* TestingProcedureKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };\n\t\t65FFC36F1E4BDF03005DC38F /* UserConfirmation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65FFC36E1E4BDF03005DC38F /* UserConfirmation.swift */; };\n\t\tEE3371091E29AD5A004272E9 /* DispatchQueueExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE3371071E29AD3E004272E9 /* DispatchQueueExtensionsTests.swift */; };\n\t\tEEE79AE81E21B9C90030C768 /* PendingEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEE79AE71E21B9C90030C768 /* PendingEvent.swift */; };\n\t\tEEE79AEB1E21B9D30030C768 /* ProcedureEventQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEE79AE91E21B9D30030C768 /* ProcedureEventQueue.swift */; };\n\t\tEEE79AEC1E21B9D30030C768 /* ProcedureFuture.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEE79AEA1E21B9D30030C768 /* ProcedureFuture.swift */; };\n\t\tEEE79AEE1E21C9750030C768 /* KVONotificationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEE79AED1E21C9750030C768 /* KVONotificationTests.swift */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXContainerItemProxy section */\n\t\t6532DD4B1DBC18DF00B030F5 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 65CFC5E51D608A1A00CAD875 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 65CFC5EF1D608A5500CAD875;\n\t\t\tremoteInfo = ProcedureKit;\n\t\t};\n\t\t6532DD4D1DBC18F800B030F5 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 65CFC5E51D608A1A00CAD875 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 65CFC5EF1D608A5500CAD875;\n\t\t\tremoteInfo = ProcedureKit;\n\t\t};\n\t\t6532DD4F1DBC190000B030F5 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 65CFC5E51D608A1A00CAD875 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 65CFC5EF1D608A5500CAD875;\n\t\t\tremoteInfo = ProcedureKit;\n\t\t};\n\t\t6532DD511DBC190600B030F5 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 65CFC5E51D608A1A00CAD875 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 65CFC5EF1D608A5500CAD875;\n\t\t\tremoteInfo = ProcedureKit;\n\t\t};\n\t\t6532DD531DBC190A00B030F5 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 65CFC5E51D608A1A00CAD875 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 65CFC5EF1D608A5500CAD875;\n\t\t\tremoteInfo = ProcedureKit;\n\t\t};\n\t\t6532DD551DBC190F00B030F5 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 65CFC5E51D608A1A00CAD875 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 65CFC5EF1D608A5500CAD875;\n\t\t\tremoteInfo = ProcedureKit;\n\t\t};\n\t\t6532DD571DBCDB3400B030F5 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 65CFC5E51D608A1A00CAD875 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 65CFC6151D60900000CAD875;\n\t\t\tremoteInfo = TestingProcedureKit;\n\t\t};\n\t\t65374F3220BC6553009948B4 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 65CFC5E51D608A1A00CAD875 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 65CFC5EF1D608A5500CAD875;\n\t\t\tremoteInfo = ProcedureKit;\n\t\t};\n\t\t653C9FCB1D6097A40070B7A2 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 65CFC5E51D608A1A00CAD875 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 653C9FC01D6097A40070B7A2;\n\t\t\tremoteInfo = \"ProcedureKit iOS\";\n\t\t};\n\t\t653C9FDD1D60990B0070B7A2 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 65CFC5E51D608A1A00CAD875 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 65CFC5EF1D608A5500CAD875;\n\t\t\tremoteInfo = ProcedureKit;\n\t\t};\n\t\t653C9FFD1D609E660070B7A2 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 65CFC5E51D608A1A00CAD875 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 653C9FF21D609E650070B7A2;\n\t\t\tremoteInfo = ProcedureKitTV;\n\t\t};\n\t\t653CA00D1D609F980070B7A2 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 65CFC5E51D608A1A00CAD875 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 65CFC5EF1D608A5500CAD875;\n\t\t\tremoteInfo = ProcedureKit;\n\t\t};\n\t\t653CA0101D609FA50070B7A2 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 65CFC5E51D608A1A00CAD875 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 65CFC6151D60900000CAD875;\n\t\t\tremoteInfo = TestingProcedureKit;\n\t\t};\n\t\t653CA0191D60A34E0070B7A2 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 65CFC5E51D608A1A00CAD875 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 65CFC6151D60900000CAD875;\n\t\t\tremoteInfo = TestingProcedureKit;\n\t\t};\n\t\t653CA01B1D60A34E0070B7A2 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 65CFC5E51D608A1A00CAD875 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 65CFC5EF1D608A5500CAD875;\n\t\t\tremoteInfo = ProcedureKit;\n\t\t};\n\t\t653CA03A1D60A5D10070B7A2 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 65CFC5E51D608A1A00CAD875 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 653CA02F1D60A5D10070B7A2;\n\t\t\tremoteInfo = ProcedureKitMac;\n\t\t};\n\t\t653CA04E1D60A7050070B7A2 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 65CFC5E51D608A1A00CAD875 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 65CFC5EF1D608A5500CAD875;\n\t\t\tremoteInfo = ProcedureKit;\n\t\t};\n\t\t653CA0511D60A70F0070B7A2 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 65CFC5E51D608A1A00CAD875 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 65CFC6151D60900000CAD875;\n\t\t\tremoteInfo = TestingProcedureKit;\n\t\t};\n\t\t653CA0641D60AA990070B7A2 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 65CFC5E51D608A1A00CAD875 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 653CA0591D60AA990070B7A2;\n\t\t\tremoteInfo = ProcedureKitCloud;\n\t\t};\n\t\t653CA0761D60ABC30070B7A2 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 65CFC5E51D608A1A00CAD875 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 65CFC5EF1D608A5500CAD875;\n\t\t\tremoteInfo = ProcedureKit;\n\t\t};\n\t\t653CA0791D60ABCE0070B7A2 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 65CFC5E51D608A1A00CAD875 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 65CFC6151D60900000CAD875;\n\t\t\tremoteInfo = TestingProcedureKit;\n\t\t};\n\t\t659484281DAAA2B90028F83B /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 65CFC5E51D608A1A00CAD875 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 6594841D1DAAA2B90028F83B;\n\t\t\tremoteInfo = ProcedureKitLocation;\n\t\t};\n\t\t659484471DAAB52B0028F83B /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 65CFC5E51D608A1A00CAD875 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 65CFC5EF1D608A5500CAD875;\n\t\t\tremoteInfo = ProcedureKit;\n\t\t};\n\t\t659484491DAAB5340028F83B /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 65CFC5E51D608A1A00CAD875 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 65CFC6151D60900000CAD875;\n\t\t\tremoteInfo = TestingProcedureKit;\n\t\t};\n\t\t65A0E4A320B85169002D6C8C /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 65CFC5E51D608A1A00CAD875 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 65A0E49820B85168002D6C8C;\n\t\t\tremoteInfo = ProcedureKitCoreData;\n\t\t};\n\t\t65A0E4BB20B85880002D6C8C /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 65CFC5E51D608A1A00CAD875 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 65CFC5EF1D608A5500CAD875;\n\t\t\tremoteInfo = ProcedureKit;\n\t\t};\n\t\t65A0E4BD20B8588F002D6C8C /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 65CFC5E51D608A1A00CAD875 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 65CFC6151D60900000CAD875;\n\t\t\tremoteInfo = TestingProcedureKit;\n\t\t};\n\t\t65CFC5FB1D608A5500CAD875 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 65CFC5E51D608A1A00CAD875 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 65CFC5EF1D608A5500CAD875;\n\t\t\tremoteInfo = ProcedureKit;\n\t\t};\n\t\t65CFC6211D60911400CAD875 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 65CFC5E51D608A1A00CAD875 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 65CFC6151D60900000CAD875;\n\t\t\tremoteInfo = TestingProcedureKit;\n\t\t};\n\t\t65CFC6241D60912400CAD875 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 65CFC5E51D608A1A00CAD875 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 65CFC5EF1D608A5500CAD875;\n\t\t\tremoteInfo = ProcedureKit;\n\t\t};\n\t\t65ECB2D71DB4F0C000F96F46 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 65CFC5E51D608A1A00CAD875 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 65ECB2CC1DB4F0C000F96F46;\n\t\t\tremoteInfo = ProcedureKitNetwork;\n\t\t};\n\t\t65ECB2F71DB50B7300F96F46 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 65CFC5E51D608A1A00CAD875 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 65CFC6151D60900000CAD875;\n\t\t\tremoteInfo = TestingProcedureKit;\n\t\t};\n\t\t65ECB2FA1DB50B8F00F96F46 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 65CFC5E51D608A1A00CAD875 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 65CFC5EF1D608A5500CAD875;\n\t\t\tremoteInfo = ProcedureKit;\n\t\t};\n/* End PBXContainerItemProxy section */\n\n/* Begin PBXCopyFilesBuildPhase section */\n\t\t659300891DA7F57000750212 /* CopyFiles */ = {\n\t\t\tisa = PBXCopyFilesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tdstPath = \"\";\n\t\t\tdstSubfolderSpec = 10;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t6594843C1DAAA52B0028F83B /* Copy Files (2 items) */ = {\n\t\t\tisa = PBXCopyFilesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tdstPath = \"\";\n\t\t\tdstSubfolderSpec = 10;\n\t\t\tfiles = (\n\t\t\t\t6594843D1DAAA5430028F83B /* ProcedureKit.framework in Copy Files (2 items) */,\n\t\t\t\t6594843E1DAAA5430028F83B /* TestingProcedureKit.framework in Copy Files (2 items) */,\n\t\t\t);\n\t\t\tname = \"Copy Files (2 items)\";\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t65A72C291DA7F352008597CA /* Copy Dependencies */ = {\n\t\t\tisa = PBXCopyFilesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tdstPath = \"\";\n\t\t\tdstSubfolderSpec = 10;\n\t\t\tfiles = (\n\t\t\t\t65A72C2A1DA7F37C008597CA /* ProcedureKit.framework in Copy Dependencies */,\n\t\t\t\t65A72C2B1DA7F37C008597CA /* TestingProcedureKit.framework in Copy Dependencies */,\n\t\t\t);\n\t\t\tname = \"Copy Dependencies\";\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t65ECB2FC1DB50BB500F96F46 /* Copy Dependencies */ = {\n\t\t\tisa = PBXCopyFilesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tdstPath = \"\";\n\t\t\tdstSubfolderSpec = 10;\n\t\t\tfiles = (\n\t\t\t\t65ECB2FD1DB50BC500F96F46 /* ProcedureKit.framework in Copy Dependencies */,\n\t\t\t\t65ECB2FE1DB50BC500F96F46 /* TestingProcedureKit.framework in Copy Dependencies */,\n\t\t\t);\n\t\t\tname = \"Copy Dependencies\";\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t65ECB2FF1DB50BCF00F96F46 /* Copy Dependencies */ = {\n\t\t\tisa = PBXCopyFilesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tdstPath = \"\";\n\t\t\tdstSubfolderSpec = 10;\n\t\t\tfiles = (\n\t\t\t\t65ECB3001DB50BD900F96F46 /* ProcedureKit.framework in Copy Dependencies */,\n\t\t\t\t65ECB3011DB50BD900F96F46 /* TestingProcedureKit.framework in Copy Dependencies */,\n\t\t\t);\n\t\t\tname = \"Copy Dependencies\";\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXCopyFilesBuildPhase section */\n\n/* Begin PBXFileReference section */\n\t\t65068FAC20C62AE300B0A0A3 /* MakesBackgroundManagedObjectContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MakesBackgroundManagedObjectContext.swift; sourceTree = \"<group>\"; };\n\t\t651E670420C610D800BE520E /* CoreDataHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreDataHelpers.swift; sourceTree = \"<group>\"; };\n\t\t6527C35B2202026800D6F498 /* Decode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Decode.swift; sourceTree = \"<group>\"; };\n\t\t6527C35D2202171F00D6F498 /* Encode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Encode.swift; sourceTree = \"<group>\"; };\n\t\t6527C35F220217FE00D6F498 /* JSONCodingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSONCodingTests.swift; sourceTree = \"<group>\"; };\n\t\t652F9014209C488600365B2D /* BatchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BatchTests.swift; sourceTree = \"<group>\"; };\n\t\t652F903C209E3E3D00365B2D /* IgnoreErrors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IgnoreErrors.swift; sourceTree = \"<group>\"; };\n\t\t652F903E209E445200365B2D /* IgnoreErrorsProcedureTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IgnoreErrorsProcedureTests.swift; sourceTree = \"<group>\"; };\n\t\t653C9FC11D6097A40070B7A2 /* ProcedureKitMobile.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ProcedureKitMobile.framework; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t653C9FDA1D6098330070B7A2 /* ProcedureKitMobile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ProcedureKitMobile.h; path = \"Supporting Files/ProcedureKitMobile.h\"; sourceTree = \"<group>\"; };\n\t\t653C9FDC1D6098650070B7A2 /* ProcedureKitMobile.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = ProcedureKitMobile.xcconfig; path = \"Supporting Files/ProcedureKitMobile.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t653C9FF31D609E650070B7A2 /* ProcedureKitTV.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ProcedureKitTV.framework; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t653C9FFB1D609E660070B7A2 /* ProcedureKitTVTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ProcedureKitTVTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t653CA00A1D609EDA0070B7A2 /* ProcedureKitTV.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ProcedureKitTV.h; path = \"Supporting Files/ProcedureKitTV.h\"; sourceTree = \"<group>\"; };\n\t\t653CA00B1D609EDA0070B7A2 /* ProcedureKitTV.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = ProcedureKitTV.xcconfig; path = \"Supporting Files/ProcedureKitTV.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t653CA0251D60A34E0070B7A2 /* ProcedureKitStressTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ProcedureKitStressTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t653CA0301D60A5D10070B7A2 /* ProcedureKitMac.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ProcedureKitMac.framework; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t653CA0381D60A5D10070B7A2 /* ProcedureKitMacTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ProcedureKitMacTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t653CA0471D60A6060070B7A2 /* ProcedureKitMac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ProcedureKitMac.h; path = \"Supporting Files/ProcedureKitMac.h\"; sourceTree = \"<group>\"; };\n\t\t653CA0491D60A6630070B7A2 /* ProcedureKitMac.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = ProcedureKitMac.xcconfig; path = \"Supporting Files/ProcedureKitMac.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t653CA0541D60AA6E0070B7A2 /* ProcedureKitMobileTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ProcedureKitMobileTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t653CA05A1D60AA990070B7A2 /* ProcedureKitCloud.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ProcedureKitCloud.framework; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t653CA0621D60AA990070B7A2 /* ProcedureKitCloudTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ProcedureKitCloudTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t653CA0731D60AB1B0070B7A2 /* ProcedureKitCloud.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ProcedureKitCloud.h; path = \"Supporting Files/ProcedureKitCloud.h\"; sourceTree = \"<group>\"; };\n\t\t653CA0751D60AB2B0070B7A2 /* ProcedureKitCloud.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = ProcedureKitCloud.xcconfig; path = \"Supporting Files/ProcedureKitCloud.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t6573A4FB21787D0000FDA362 /* ProcessManagedObjectContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProcessManagedObjectContext.swift; sourceTree = \"<group>\"; };\n\t\t658BE07120BC72540021F11B /* MakeFetchedResultController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MakeFetchedResultController.swift; sourceTree = \"<group>\"; };\n\t\t658BE07320BC77AD0021F11B /* MakeFetchedResultsControllerProcedureTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MakeFetchedResultsControllerProcedureTests.swift; sourceTree = \"<group>\"; };\n\t\t658BE07520BC99100021F11B /* InsertManagedObjects.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InsertManagedObjects.swift; sourceTree = \"<group>\"; };\n\t\t658BE07720BCA0500021F11B /* InsertManagedObjectsProcedureTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InsertManagedObjectsProcedureTests.swift; sourceTree = \"<group>\"; };\n\t\t6594841E1DAAA2B90028F83B /* ProcedureKitLocation.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ProcedureKitLocation.framework; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t659484261DAAA2B90028F83B /* ProcedureKitLocationTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ProcedureKitLocationTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t659484351DAAA3360028F83B /* ProcedureKitLocation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ProcedureKitLocation.h; path = \"Supporting Files/ProcedureKitLocation.h\"; sourceTree = \"<group>\"; };\n\t\t659484371DAAA3A60028F83B /* ProcedureKitLocation.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = ProcedureKitLocation.xcconfig; path = \"Supporting Files/ProcedureKitLocation.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t65A0E49920B85168002D6C8C /* ProcedureKitCoreData.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ProcedureKitCoreData.framework; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t65A0E4A120B85169002D6C8C /* ProcedureKitCoreDataTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ProcedureKitCoreDataTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t65A0E4B120B85213002D6C8C /* LoadCoreData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadCoreData.swift; sourceTree = \"<group>\"; };\n\t\t65A0E4B320B85258002D6C8C /* ProcedureKitCoreData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ProcedureKitCoreData.h; path = \"Supporting Files/ProcedureKitCoreData.h\"; sourceTree = \"<group>\"; };\n\t\t65A0E4B520B85297002D6C8C /* ProcedureKitCoreData.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = ProcedureKitCoreData.xcconfig; path = \"Supporting Files/ProcedureKitCoreData.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t65A0E4B820B8548D002D6C8C /* ProcedureKitCoreDataTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProcedureKitCoreDataTests.swift; sourceTree = \"<group>\"; };\n\t\t65A0E4C020BB18EA002D6C8C /* TestDataModel.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = TestDataModel.xcdatamodel; sourceTree = \"<group>\"; };\n\t\t65A0E4C220BB1975002D6C8C /* LoadCoreDataProcedureTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadCoreDataProcedureTests.swift; sourceTree = \"<group>\"; };\n\t\t65A0E4C420BB2E51002D6C8C /* SaveManagedObjectContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SaveManagedObjectContext.swift; sourceTree = \"<group>\"; };\n\t\t65A0E4C620BC548A002D6C8C /* SaveManagedObjectContextProcedureTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SaveManagedObjectContextProcedureTests.swift; sourceTree = \"<group>\"; };\n\t\t65A1923820F88FD300E0D42C /* LoggingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoggingTests.swift; sourceTree = \"<group>\"; };\n\t\t65A1923A20F8900100E0D42C /* TestableLogging.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestableLogging.swift; sourceTree = \"<group>\"; };\n\t\t65AB7DD9209B95B400726796 /* Batch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Batch.swift; sourceTree = \"<group>\"; };\n\t\t65AEF19E20A3AE340089B6C8 /* ViewControllerContainment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewControllerContainment.swift; sourceTree = \"<group>\"; };\n\t\t65B9AF472116D1D4004DA82B /* Result.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Result.swift; sourceTree = \"<group>\"; };\n\t\t65C88D761DC4EB4300C8D4EB /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Warnings.xcconfig; path = \"Supporting Files/Warnings.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t65CFC5F01D608A5500CAD875 /* ProcedureKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ProcedureKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t65CFC5F91D608A5500CAD875 /* ProcedureKitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ProcedureKitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t65CFC60A1D608AA700CAD875 /* ProcedureKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ProcedureKit.h; path = \"Supporting Files/ProcedureKit.h\"; sourceTree = \"<group>\"; };\n\t\t65CFC60D1D608AD200CAD875 /* Version.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Version.xcconfig; path = \"Supporting Files/Version.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t65CFC60E1D608AE200CAD875 /* ProcedureKit.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = ProcedureKit.xcconfig; path = \"Supporting Files/ProcedureKit.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t65CFC60F1D608B3000CAD875 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = \"Supporting Files/Info.plist\"; sourceTree = \"<group>\"; };\n\t\t65CFC6161D60900000CAD875 /* TestingProcedureKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = TestingProcedureKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t65CFC61E1D60904700CAD875 /* TestingProcedureKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestingProcedureKit.h; path = \"Supporting Files/TestingProcedureKit.h\"; sourceTree = \"<group>\"; };\n\t\t65CFC6201D60905000CAD875 /* TestingProcedureKit.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = TestingProcedureKit.xcconfig; path = \"Supporting Files/TestingProcedureKit.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t65D366811E183F1900D03E86 /* CKAcceptSharesOperationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CKAcceptSharesOperationTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366821E183F1900D03E86 /* CKDatabaseOperationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CKDatabaseOperationTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366841E183F1900D03E86 /* CKDiscoverAllUserIdentitiesOperationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CKDiscoverAllUserIdentitiesOperationTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366851E183F1900D03E86 /* CKDiscoverUserIdentitiesOperationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CKDiscoverUserIdentitiesOperationTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366871E183F1900D03E86 /* CKFetchAllChangesTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CKFetchAllChangesTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366881E183F1900D03E86 /* CKFetchDatabaseChangesOperationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CKFetchDatabaseChangesOperationTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366891E183F1900D03E86 /* CKFetchNotificationChangesOperationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CKFetchNotificationChangesOperationTests.swift; sourceTree = \"<group>\"; };\n\t\t65D3668B1E183F1900D03E86 /* CKFetchRecordsOperationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CKFetchRecordsOperationTests.swift; sourceTree = \"<group>\"; };\n\t\t65D3668C1E183F1900D03E86 /* CKFetchRecordZoneChangesOperationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CKFetchRecordZoneChangesOperationTests.swift; sourceTree = \"<group>\"; };\n\t\t65D3668D1E183F1900D03E86 /* CKFetchRecordZonesOperationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CKFetchRecordZonesOperationTests.swift; sourceTree = \"<group>\"; };\n\t\t65D3668E1E183F1900D03E86 /* CKFetchShareMetadataOperationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CKFetchShareMetadataOperationTests.swift; sourceTree = \"<group>\"; };\n\t\t65D3668F1E183F1900D03E86 /* CKFetchShareParticipantsOperationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CKFetchShareParticipantsOperationTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366901E183F1900D03E86 /* CKFetchSubscriptionsOperationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CKFetchSubscriptionsOperationTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366911E183F1900D03E86 /* CKMarkNotificationsReadOperationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CKMarkNotificationsReadOperationTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366921E183F1900D03E86 /* CKModifyBadgeOperationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CKModifyBadgeOperationTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366931E183F1900D03E86 /* CKModifyRecordsOperationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CKModifyRecordsOperationTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366941E183F1900D03E86 /* CKModifyRecordZonesOperationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CKModifyRecordZonesOperationTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366951E183F1900D03E86 /* CKModifySubscriptionsOperationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CKModifySubscriptionsOperationTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366961E183F1900D03E86 /* CKOperationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CKOperationTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366971E183F1900D03E86 /* CKQueryOperationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CKQueryOperationTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366981E183F1900D03E86 /* CloudKitCapabilityTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CloudKitCapabilityTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366991E183F1900D03E86 /* ProcedureKitCloudTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProcedureKitCloudTests.swift; sourceTree = \"<group>\"; };\n\t\t65D3669A1E183F1900D03E86 /* TestableCloudKitContainer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestableCloudKitContainer.swift; sourceTree = \"<group>\"; };\n\t\t65D366B61E183F2600D03E86 /* LocationCapabilityTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocationCapabilityTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366B71E183F2600D03E86 /* ProcedureKitLocationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProcedureKitLocationTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366B81E183F2600D03E86 /* ReverseGeocodeProcedureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReverseGeocodeProcedureTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366B91E183F2600D03E86 /* ReverseGeocodeUserLocationProcedureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReverseGeocodeUserLocationProcedureTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366BA1E183F2600D03E86 /* TestableLocationServices.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestableLocationServices.swift; sourceTree = \"<group>\"; };\n\t\t65D366BB1E183F2600D03E86 /* UserLocationProcedureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserLocationProcedureTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366C31E183F3900D03E86 /* ProcedureKitMacTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProcedureKitMacTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366C41E183F3900D03E86 /* ProcessProcedureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProcessProcedureTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366C81E183F5000D03E86 /* AlertProcedureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlertProcedureTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366C91E183F5000D03E86 /* BackgroundObserverTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BackgroundObserverTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366CA1E183F5000D03E86 /* PresentationProcedureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PresentationProcedureTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366CB1E183F5000D03E86 /* ProcedureKitMobileTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProcedureKitMobileTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366CC1E183F5000D03E86 /* TestableUIApplication.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestableUIApplication.swift; sourceTree = \"<group>\"; };\n\t\t65D366CD1E183F5000D03E86 /* UIProcedureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIProcedureTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366D51E183F6400D03E86 /* NetworkDataProcedureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkDataProcedureTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366D61E183F6400D03E86 /* NetworkDownloadProcedureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkDownloadProcedureTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366D71E183F6400D03E86 /* NetworkProcedureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkProcedureTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366D81E183F6400D03E86 /* NetworkReachabilityTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkReachabilityTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366D91E183F6400D03E86 /* NetworkUploadProcedureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkUploadProcedureTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366DA1E183F6400D03E86 /* ProcedureKitNetworkTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProcedureKitNetworkTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366DB1E183F6400D03E86 /* URLTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URLTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366E41E183F8100D03E86 /* ProcedureKitTVTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProcedureKitTVTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366E71E183FB000D03E86 /* AnyProcedureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnyProcedureTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366E81E183FB000D03E86 /* BlockConditionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BlockConditionTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366E91E183FB000D03E86 /* BlockObserverTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BlockObserverTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366EA1E183FB000D03E86 /* BlockProcedureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BlockProcedureTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366EB1E183FB000D03E86 /* CancellationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CancellationTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366EC1E183FB000D03E86 /* CapabilityTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CapabilityTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366ED1E183FB000D03E86 /* ComposedProcedureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ComposedProcedureTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366EE1E183FB000D03E86 /* ConditionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConditionTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366EF1E183FB000D03E86 /* DelayProcedureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DelayProcedureTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366F01E183FB000D03E86 /* FilterProcedureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FilterProcedureTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366F11E183FB000D03E86 /* FinishingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FinishingTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366F21E183FB000D03E86 /* GroupTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GroupTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366F41E183FB000D03E86 /* MapProcedureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MapProcedureTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366F51E183FB000D03E86 /* MutualExclusivityTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MutualExclusivityTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366F61E183FB000D03E86 /* NegatedConditionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NegatedConditionTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366F71E183FB000D03E86 /* NetworkObserverTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkObserverTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366F81E183FB000D03E86 /* NoFailedDependenciesConditionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NoFailedDependenciesConditionTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366F91E183FB000D03E86 /* ProcedureKitErrorTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProcedureKitErrorTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366FA1E183FB000D03E86 /* ProcedureKitTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProcedureKitTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366FB1E183FB000D03E86 /* ProcedureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProcedureTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366FC1E183FB000D03E86 /* ProfilerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProfilerTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366FD1E183FB000D03E86 /* ReachabilityTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReachabilityTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366FE1E183FB000D03E86 /* ReduceProcedureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReduceProcedureTests.swift; sourceTree = \"<group>\"; };\n\t\t65D366FF1E183FB000D03E86 /* RepeatProcedureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RepeatProcedureTests.swift; sourceTree = \"<group>\"; };\n\t\t65D367001E183FB000D03E86 /* ResultInjectionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ResultInjectionTests.swift; sourceTree = \"<group>\"; };\n\t\t65D367011E183FB000D03E86 /* RetryProcedureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RetryProcedureTests.swift; sourceTree = \"<group>\"; };\n\t\t65D367021E183FB000D03E86 /* SilentConditionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SilentConditionTests.swift; sourceTree = \"<group>\"; };\n\t\t65D367031E183FB000D03E86 /* TimeoutObserverTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimeoutObserverTests.swift; sourceTree = \"<group>\"; };\n\t\t65D367041E183FB000D03E86 /* TransformProcedureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransformProcedureTests.swift; sourceTree = \"<group>\"; };\n\t\t65D367421E183FBE00D03E86 /* BlockProcedureStressTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BlockProcedureStressTests.swift; sourceTree = \"<group>\"; };\n\t\t65D367431E183FBE00D03E86 /* GroupStressTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GroupStressTests.swift; sourceTree = \"<group>\"; };\n\t\t65D367441E183FBE00D03E86 /* ProcedureKitStressTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProcedureKitStressTests.swift; sourceTree = \"<group>\"; };\n\t\t65D367451E183FBE00D03E86 /* ProcedureStressTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProcedureStressTests.swift; sourceTree = \"<group>\"; };\n\t\t65D367461E183FBE00D03E86 /* RepeatStressTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RepeatStressTests.swift; sourceTree = \"<group>\"; };\n\t\t65D367C61E1844E500D03E86 /* CapabilityTestCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CapabilityTestCase.swift; sourceTree = \"<group>\"; };\n\t\t65D367C71E1844E500D03E86 /* ConcurrencyTestCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConcurrencyTestCase.swift; sourceTree = \"<group>\"; };\n\t\t65D367C81E1844E500D03E86 /* GroupTestCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GroupTestCase.swift; sourceTree = \"<group>\"; };\n\t\t65D367C91E1844E500D03E86 /* ProcedureKitTestCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProcedureKitTestCase.swift; sourceTree = \"<group>\"; };\n\t\t65D367CA1E1844E500D03E86 /* QueueTestDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QueueTestDelegate.swift; sourceTree = \"<group>\"; };\n\t\t65D367CB1E1844E500D03E86 /* RepeatTestCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RepeatTestCase.swift; sourceTree = \"<group>\"; };\n\t\t65D367CC1E1844E500D03E86 /* StressTestCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StressTestCase.swift; sourceTree = \"<group>\"; };\n\t\t65D367CD1E1844E500D03E86 /* TestableNetwork.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestableNetwork.swift; sourceTree = \"<group>\"; };\n\t\t65D367CE1E1844E500D03E86 /* TestableNetworkReachability.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestableNetworkReachability.swift; sourceTree = \"<group>\"; };\n\t\t65D367CF1E1844E500D03E86 /* TestCondition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestCondition.swift; sourceTree = \"<group>\"; };\n\t\t65D367D01E1844E500D03E86 /* TestProcedure.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestProcedure.swift; sourceTree = \"<group>\"; };\n\t\t65D367D11E1844E500D03E86 /* XCTAsserts.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XCTAsserts.swift; sourceTree = \"<group>\"; };\n\t\t65D367DF1E1844F800D03E86 /* CKAcceptSharesOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CKAcceptSharesOperation.swift; sourceTree = \"<group>\"; };\n\t\t65D367E01E1844F800D03E86 /* CKDatabaseOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CKDatabaseOperation.swift; sourceTree = \"<group>\"; };\n\t\t65D367E21E1844F800D03E86 /* CKDiscoverAllUserIdentitiesOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CKDiscoverAllUserIdentitiesOperation.swift; sourceTree = \"<group>\"; };\n\t\t65D367E31E1844F800D03E86 /* CKDiscoverUserIdentitiesOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CKDiscoverUserIdentitiesOperation.swift; sourceTree = \"<group>\"; };\n\t\t65D367E51E1844F800D03E86 /* CKFetchDatabaseChangesOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CKFetchDatabaseChangesOperation.swift; sourceTree = \"<group>\"; };\n\t\t65D367E61E1844F800D03E86 /* CKFetchNotificationChangesOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CKFetchNotificationChangesOperation.swift; sourceTree = \"<group>\"; };\n\t\t65D367E81E1844F800D03E86 /* CKFetchRecordsOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CKFetchRecordsOperation.swift; sourceTree = \"<group>\"; };\n\t\t65D367E91E1844F800D03E86 /* CKFetchRecordZoneChangesOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CKFetchRecordZoneChangesOperation.swift; sourceTree = \"<group>\"; };\n\t\t65D367EA1E1844F800D03E86 /* CKFetchRecordZonesOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CKFetchRecordZonesOperation.swift; sourceTree = \"<group>\"; };\n\t\t65D367EB1E1844F800D03E86 /* CKFetchShareMetadataOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CKFetchShareMetadataOperation.swift; sourceTree = \"<group>\"; };\n\t\t65D367EC1E1844F800D03E86 /* CKFetchShareParticipantsOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CKFetchShareParticipantsOperation.swift; sourceTree = \"<group>\"; };\n\t\t65D367ED1E1844F800D03E86 /* CKFetchSubscriptionsOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CKFetchSubscriptionsOperation.swift; sourceTree = \"<group>\"; };\n\t\t65D367EE1E1844F800D03E86 /* CKMarkNotificationsReadOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CKMarkNotificationsReadOperation.swift; sourceTree = \"<group>\"; };\n\t\t65D367EF1E1844F800D03E86 /* CKModifyBadgeOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CKModifyBadgeOperation.swift; sourceTree = \"<group>\"; };\n\t\t65D367F01E1844F800D03E86 /* CKModifyRecordsOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CKModifyRecordsOperation.swift; sourceTree = \"<group>\"; };\n\t\t65D367F11E1844F800D03E86 /* CKModifyRecordZonesOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CKModifyRecordZonesOperation.swift; sourceTree = \"<group>\"; };\n\t\t65D367F21E1844F800D03E86 /* CKModifySubscriptionsOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CKModifySubscriptionsOperation.swift; sourceTree = \"<group>\"; };\n\t\t65D367F31E1844F800D03E86 /* CKOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CKOperation.swift; sourceTree = \"<group>\"; };\n\t\t65D367F41E1844F800D03E86 /* CKQueryOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CKQueryOperation.swift; sourceTree = \"<group>\"; };\n\t\t65D367F51E1844F800D03E86 /* CloudKit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CloudKit.swift; sourceTree = \"<group>\"; };\n\t\t65D367F61E1844F800D03E86 /* CloudKitCapability.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CloudKitCapability.swift; sourceTree = \"<group>\"; };\n\t\t65D367F71E1844F800D03E86 /* CloudKitError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CloudKitError.swift; sourceTree = \"<group>\"; };\n\t\t65D367F81E1844F800D03E86 /* CloudKitSupport.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CloudKitSupport.swift; sourceTree = \"<group>\"; };\n\t\t65D368141E18450200D03E86 /* LocationCapability.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocationCapability.swift; sourceTree = \"<group>\"; };\n\t\t65D368151E18450200D03E86 /* LocationSupport.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocationSupport.swift; sourceTree = \"<group>\"; };\n\t\t65D368161E18450200D03E86 /* ReverseGeocode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReverseGeocode.swift; sourceTree = \"<group>\"; };\n\t\t65D368171E18450200D03E86 /* ReverseGeocodeUserLocation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReverseGeocodeUserLocation.swift; sourceTree = \"<group>\"; };\n\t\t65D368181E18450200D03E86 /* UserLocation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserLocation.swift; sourceTree = \"<group>\"; };\n\t\t65D3681F1E18451000D03E86 /* Process.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Process.swift; sourceTree = \"<group>\"; };\n\t\t65D368221E18451C00D03E86 /* Alert.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Alert.swift; sourceTree = \"<group>\"; };\n\t\t65D368231E18451C00D03E86 /* BackgroundObserver.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BackgroundObserver.swift; sourceTree = \"<group>\"; };\n\t\t65D368241E18451C00D03E86 /* NetworkObserver+Mobile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = \"NetworkObserver+Mobile.swift\"; sourceTree = \"<group>\"; };\n\t\t65D368251E18451C00D03E86 /* UI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UI.swift; sourceTree = \"<group>\"; };\n\t\t65D3682B1E18452900D03E86 /* Network.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Network.swift; sourceTree = \"<group>\"; };\n\t\t65D3682C1E18452900D03E86 /* NetworkData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkData.swift; sourceTree = \"<group>\"; };\n\t\t65D3682D1E18452900D03E86 /* NetworkDownload.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkDownload.swift; sourceTree = \"<group>\"; };\n\t\t65D3682E1E18452900D03E86 /* NetworkReachability.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkReachability.swift; sourceTree = \"<group>\"; };\n\t\t65D3682F1E18452900D03E86 /* NetworkSupport.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkSupport.swift; sourceTree = \"<group>\"; };\n\t\t65D368301E18452900D03E86 /* NetworkUpload.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkUpload.swift; sourceTree = \"<group>\"; };\n\t\t65D368661E184AA600D03E86 /* Any.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Any.swift; sourceTree = \"<group>\"; };\n\t\t65D368671E184AA600D03E86 /* AnyObserver.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnyObserver.swift; sourceTree = \"<group>\"; };\n\t\t65D368681E184AA600D03E86 /* Block.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Block.swift; sourceTree = \"<group>\"; };\n\t\t65D368691E184AA600D03E86 /* BlockCondition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BlockCondition.swift; sourceTree = \"<group>\"; };\n\t\t65D3686A1E184AA600D03E86 /* BlockObservers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BlockObservers.swift; sourceTree = \"<group>\"; };\n\t\t65D3686B1E184AA600D03E86 /* Capability.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Capability.swift; sourceTree = \"<group>\"; };\n\t\t65D3686C1E184AA600D03E86 /* Collection+ProcedureKit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = \"Collection+ProcedureKit.swift\"; sourceTree = \"<group>\"; };\n\t\t65D3686D1E184AA600D03E86 /* Composed.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Composed.swift; sourceTree = \"<group>\"; };\n\t\t65D3686E1E184AA600D03E86 /* Condition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Condition.swift; sourceTree = \"<group>\"; };\n\t\t65D3686F1E184AA600D03E86 /* Delay.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Delay.swift; sourceTree = \"<group>\"; };\n\t\t65D368701E184AA600D03E86 /* DispatchQueue+ProcedureKit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = \"DispatchQueue+ProcedureKit.swift\"; sourceTree = \"<group>\"; };\n\t\t65D368711E184AA600D03E86 /* Errors.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Errors.swift; sourceTree = \"<group>\"; };\n\t\t65D368721E184AA600D03E86 /* Filter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Filter.swift; sourceTree = \"<group>\"; };\n\t\t65D368731E184AA600D03E86 /* Group.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Group.swift; sourceTree = \"<group>\"; };\n\t\t65D368741E184AA600D03E86 /* Identity.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Identity.swift; sourceTree = \"<group>\"; };\n\t\t65D368751E184AA600D03E86 /* Logging.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Logging.swift; sourceTree = \"<group>\"; };\n\t\t65D368761E184AA600D03E86 /* Map.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Map.swift; sourceTree = \"<group>\"; };\n\t\t65D368771E184AA600D03E86 /* MutualExclusion.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MutualExclusion.swift; sourceTree = \"<group>\"; };\n\t\t65D368781E184AA600D03E86 /* NegatedCondition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NegatedCondition.swift; sourceTree = \"<group>\"; };\n\t\t65D368791E184AA600D03E86 /* NetworkObserver.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkObserver.swift; sourceTree = \"<group>\"; };\n\t\t65D3687A1E184AA600D03E86 /* NoFailedDependenciesCondition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NoFailedDependenciesCondition.swift; sourceTree = \"<group>\"; };\n\t\t65D3687B1E184AA600D03E86 /* Operation+ProcedureKit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = \"Operation+ProcedureKit.swift\"; sourceTree = \"<group>\"; };\n\t\t65D3687C1E184AA600D03E86 /* Procedure.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Procedure.swift; sourceTree = \"<group>\"; };\n\t\t65D3687D1E184AA600D03E86 /* ProcedureObserver.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProcedureObserver.swift; sourceTree = \"<group>\"; };\n\t\t65D3687E1E184AA600D03E86 /* ProcedureProcotol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProcedureProcotol.swift; sourceTree = \"<group>\"; };\n\t\t65D3687F1E184AA600D03E86 /* ProcedureQueue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProcedureQueue.swift; sourceTree = \"<group>\"; };\n\t\t65D368801E184AA600D03E86 /* ProcedureResult.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProcedureResult.swift; sourceTree = \"<group>\"; };\n\t\t65D368811E184AA600D03E86 /* Profiler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Profiler.swift; sourceTree = \"<group>\"; };\n\t\t65D368821E184AA600D03E86 /* Reachability.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Reachability.swift; sourceTree = \"<group>\"; };\n\t\t65D368831E184AA600D03E86 /* Reduce.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Reduce.swift; sourceTree = \"<group>\"; };\n\t\t65D368841E184AA600D03E86 /* Repeat.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Repeat.swift; sourceTree = \"<group>\"; };\n\t\t65D368851E184AA600D03E86 /* Retry.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Retry.swift; sourceTree = \"<group>\"; };\n\t\t65D368861E184AA600D03E86 /* SilentCondition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SilentCondition.swift; sourceTree = \"<group>\"; };\n\t\t65D368871E184AA600D03E86 /* Support.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Support.swift; sourceTree = \"<group>\"; };\n\t\t65D368881E184AA600D03E86 /* TimeoutObserver.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimeoutObserver.swift; sourceTree = \"<group>\"; };\n\t\t65D368891E184AA600D03E86 /* Transform.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Transform.swift; sourceTree = \"<group>\"; };\n\t\t65D4BEF420C8A31100D85877 /* SignpostObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignpostObserver.swift; sourceTree = \"<group>\"; };\n\t\t65D4BEF920C8DDA700D85877 /* ProcedureKitInstruments.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = ProcedureKitInstruments.xcconfig; path = \"Supporting Files/ProcedureKitInstruments.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t65E5EB8120C9CAEC00C46965 /* ProcedureKitInstruments.instrdst */ = {isa = PBXFileReference; explicitFileType = com.apple.instruments.instrdst; includeInIndex = 0; path = ProcedureKitInstruments.instrdst; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t65E5EB8320C9CAEC00C46965 /* ProcedureKitInstruments.instrpkg */ = {isa = PBXFileReference; lastKnownFileType = \"com.apple.instruments.package-definition\"; path = ProcedureKitInstruments.instrpkg; sourceTree = \"<group>\"; };\n\t\t65ECB2CD1DB4F0C000F96F46 /* ProcedureKitNetwork.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ProcedureKitNetwork.framework; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t65ECB2D51DB4F0C000F96F46 /* ProcedureKitNetworkTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ProcedureKitNetworkTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t65ECB2E81DB4F1A200F96F46 /* ProcedureKitNetwork.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ProcedureKitNetwork.h; path = \"Supporting Files/ProcedureKitNetwork.h\"; sourceTree = \"<group>\"; };\n\t\t65ECB2E91DB4F1A200F96F46 /* ProcedureKitNetwork.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = ProcedureKitNetwork.xcconfig; path = \"Supporting Files/ProcedureKitNetwork.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t65FFC36E1E4BDF03005DC38F /* UserConfirmation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserConfirmation.swift; sourceTree = \"<group>\"; };\n\t\tEE3371071E29AD3E004272E9 /* DispatchQueueExtensionsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DispatchQueueExtensionsTests.swift; sourceTree = \"<group>\"; };\n\t\tEEE79AE71E21B9C90030C768 /* PendingEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PendingEvent.swift; sourceTree = \"<group>\"; };\n\t\tEEE79AE91E21B9D30030C768 /* ProcedureEventQueue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProcedureEventQueue.swift; sourceTree = \"<group>\"; };\n\t\tEEE79AEA1E21B9D30030C768 /* ProcedureFuture.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProcedureFuture.swift; sourceTree = \"<group>\"; };\n\t\tEEE79AED1E21C9750030C768 /* KVONotificationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KVONotificationTests.swift; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t653C9FBD1D6097A40070B7A2 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t653C9FDF1D6099110070B7A2 /* ProcedureKit.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t653C9FC61D6097A40070B7A2 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t653C9FCA1D6097A40070B7A2 /* ProcedureKitMobile.framework in Frameworks */,\n\t\t\t\t653C9FE21D6099260070B7A2 /* TestingProcedureKit.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t653C9FEF1D609E650070B7A2 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t653CA00F1D609F9E0070B7A2 /* ProcedureKit.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t653C9FF81D609E660070B7A2 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t653CA0121D609FA90070B7A2 /* TestingProcedureKit.framework in Frameworks */,\n\t\t\t\t653C9FFC1D609E660070B7A2 /* ProcedureKitTV.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t653CA01E1D60A34E0070B7A2 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t653CA01F1D60A34E0070B7A2 /* TestingProcedureKit.framework in Frameworks */,\n\t\t\t\t653CA0201D60A34E0070B7A2 /* ProcedureKit.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t653CA02C1D60A5D10070B7A2 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t653CA0501D60A7090070B7A2 /* ProcedureKit.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t653CA0351D60A5D10070B7A2 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t653CA0531D60A7130070B7A2 /* TestingProcedureKit.framework in Frameworks */,\n\t\t\t\t653CA0391D60A5D10070B7A2 /* ProcedureKitMac.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t653CA0561D60AA990070B7A2 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t653CA0781D60ABC90070B7A2 /* ProcedureKit.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t653CA05F1D60AA990070B7A2 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t653CA0631D60AA990070B7A2 /* ProcedureKitCloud.framework in Frameworks */,\n\t\t\t\t653CA07B1D60ABD30070B7A2 /* TestingProcedureKit.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t6594841A1DAAA2B90028F83B /* 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\t659484231DAAA2B90028F83B /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t659484271DAAA2B90028F83B /* ProcedureKitLocation.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t65A0E49520B85168002D6C8C /* 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\t65A0E49E20B85169002D6C8C /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t658BE06F20BC69170021F11B /* ProcedureKit.framework in Frameworks */,\n\t\t\t\t658BE07020BC69170021F11B /* TestingProcedureKit.framework in Frameworks */,\n\t\t\t\t65A0E4A220B85169002D6C8C /* ProcedureKitCoreData.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t65CFC5EC1D608A5500CAD875 /* 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\t65CFC5F61D608A5500CAD875 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t65CFC6231D60911C00CAD875 /* TestingProcedureKit.framework in Frameworks */,\n\t\t\t\t65CFC5FA1D608A5500CAD875 /* ProcedureKit.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t65CFC6121D60900000CAD875 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t65CFC6261D60912900CAD875 /* ProcedureKit.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t65ECB2C91DB4F0C000F96F46 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t65ECB2F91DB50B8B00F96F46 /* ProcedureKit.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t65ECB2D21DB4F0C000F96F46 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t65ECB2EC1DB4F27700F96F46 /* TestingProcedureKit.framework in Frameworks */,\n\t\t\t\t65ECB2D61DB4F0C000F96F46 /* ProcedureKitNetwork.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\t653C9FD91D6097E20070B7A2 /* Tests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t65D366801E183F1900D03E86 /* ProcedureKitCloudTests */,\n\t\t\t\t65A0E4B620B8548D002D6C8C /* ProcedureKitCoreDataTests */,\n\t\t\t\t65D366B51E183F2600D03E86 /* ProcedureKitLocationTests */,\n\t\t\t\t65D366C21E183F3900D03E86 /* ProcedureKitMacTests */,\n\t\t\t\t65D366C71E183F5000D03E86 /* ProcedureKitMobileTests */,\n\t\t\t\t65D366D41E183F6400D03E86 /* ProcedureKitNetworkTests */,\n\t\t\t\t65D367411E183FBE00D03E86 /* ProcedureKitStressTests */,\n\t\t\t\t65D366E61E183FB000D03E86 /* ProcedureKitTests */,\n\t\t\t\t65D366E31E183F8100D03E86 /* ProcedureKitTVTests */,\n\t\t\t);\n\t\t\tname = Tests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t653CA02A1D60A4FB0070B7A2 /* ... */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t65CFC60C1D608AAA00CAD875 /* Supporting Files */,\n\t\t\t\t65CFC5F11D608A5500CAD875 /* Products */,\n\t\t\t);\n\t\t\tname = ...;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t657FCD502152D70E00F7D7E3 /* Record Operations */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t65D367E51E1844F800D03E86 /* CKFetchDatabaseChangesOperation.swift */,\n\t\t\t\t65D367E81E1844F800D03E86 /* CKFetchRecordsOperation.swift */,\n\t\t\t\t65D367E91E1844F800D03E86 /* CKFetchRecordZoneChangesOperation.swift */,\n\t\t\t\t65D367EA1E1844F800D03E86 /* CKFetchRecordZonesOperation.swift */,\n\t\t\t\t65D367F01E1844F800D03E86 /* CKModifyRecordsOperation.swift */,\n\t\t\t\t65D367F11E1844F800D03E86 /* CKModifyRecordZonesOperation.swift */,\n\t\t\t);\n\t\t\tpath = \"Record Operations\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t657FCD512152D78F00F7D7E3 /* Notification Operations */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t65D367E61E1844F800D03E86 /* CKFetchNotificationChangesOperation.swift */,\n\t\t\t\t65D367EE1E1844F800D03E86 /* CKMarkNotificationsReadOperation.swift */,\n\t\t\t);\n\t\t\tpath = \"Notification Operations\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t657FCD522152D82500F7D7E3 /* Subscription Operations */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t65D367ED1E1844F800D03E86 /* CKFetchSubscriptionsOperation.swift */,\n\t\t\t\t65D367F21E1844F800D03E86 /* CKModifySubscriptionsOperation.swift */,\n\t\t\t);\n\t\t\tpath = \"Subscription Operations\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t657FCD532152D86B00F7D7E3 /* Query Operations */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t65D367F41E1844F800D03E86 /* CKQueryOperation.swift */,\n\t\t\t);\n\t\t\tpath = \"Query Operations\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t657FCD542152D89A00F7D7E3 /* Share Operations */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t65D367DF1E1844F800D03E86 /* CKAcceptSharesOperation.swift */,\n\t\t\t\t65D367EB1E1844F800D03E86 /* CKFetchShareMetadataOperation.swift */,\n\t\t\t\t65D367EC1E1844F800D03E86 /* CKFetchShareParticipantsOperation.swift */,\n\t\t\t);\n\t\t\tpath = \"Share Operations\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t657FCD552152D91B00F7D7E3 /* Database Operations */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t65D367E01E1844F800D03E86 /* CKDatabaseOperation.swift */,\n\t\t\t\t65D367E21E1844F800D03E86 /* CKDiscoverAllUserIdentitiesOperation.swift */,\n\t\t\t\t65D367E31E1844F800D03E86 /* CKDiscoverUserIdentitiesOperation.swift */,\n\t\t\t\t65D367EF1E1844F800D03E86 /* CKModifyBadgeOperation.swift */,\n\t\t\t);\n\t\t\tpath = \"Database Operations\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t65A0E4B020B851D4002D6C8C /* ProcedureKitCoreData */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t651E670420C610D800BE520E /* CoreDataHelpers.swift */,\n\t\t\t\t658BE07520BC99100021F11B /* InsertManagedObjects.swift */,\n\t\t\t\t65A0E4B120B85213002D6C8C /* LoadCoreData.swift */,\n\t\t\t\t658BE07120BC72540021F11B /* MakeFetchedResultController.swift */,\n\t\t\t\t65068FAC20C62AE300B0A0A3 /* MakesBackgroundManagedObjectContext.swift */,\n\t\t\t\t6573A4FB21787D0000FDA362 /* ProcessManagedObjectContext.swift */,\n\t\t\t\t65A0E4C420BB2E51002D6C8C /* SaveManagedObjectContext.swift */,\n\t\t\t);\n\t\t\tname = ProcedureKitCoreData;\n\t\t\tpath = Sources/ProcedureKitCoreData;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t65A0E4B620B8548D002D6C8C /* ProcedureKitCoreDataTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t658BE07720BCA0500021F11B /* InsertManagedObjectsProcedureTests.swift */,\n\t\t\t\t65A0E4C220BB1975002D6C8C /* LoadCoreDataProcedureTests.swift */,\n\t\t\t\t658BE07320BC77AD0021F11B /* MakeFetchedResultsControllerProcedureTests.swift */,\n\t\t\t\t65A0E4B820B8548D002D6C8C /* ProcedureKitCoreDataTests.swift */,\n\t\t\t\t65A0E4C620BC548A002D6C8C /* SaveManagedObjectContextProcedureTests.swift */,\n\t\t\t\t65A0E4BF20BB18EA002D6C8C /* TestDataModel.xcdatamodeld */,\n\t\t\t);\n\t\t\tname = ProcedureKitCoreDataTests;\n\t\t\tpath = Tests/ProcedureKitCoreDataTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t65CFC5E41D608A1A00CAD875 = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t65D367BE1E1843ED00D03E86 /* Sources */,\n\t\t\t\t653C9FD91D6097E20070B7A2 /* Tests */,\n\t\t\t\t653CA02A1D60A4FB0070B7A2 /* ... */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t65CFC5F11D608A5500CAD875 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t65CFC5F01D608A5500CAD875 /* ProcedureKit.framework */,\n\t\t\t\t65CFC5F91D608A5500CAD875 /* ProcedureKitTests.xctest */,\n\t\t\t\t65CFC6161D60900000CAD875 /* TestingProcedureKit.framework */,\n\t\t\t\t653C9FC11D6097A40070B7A2 /* ProcedureKitMobile.framework */,\n\t\t\t\t653C9FF31D609E650070B7A2 /* ProcedureKitTV.framework */,\n\t\t\t\t653C9FFB1D609E660070B7A2 /* ProcedureKitTVTests.xctest */,\n\t\t\t\t653CA0251D60A34E0070B7A2 /* ProcedureKitStressTests.xctest */,\n\t\t\t\t653CA0301D60A5D10070B7A2 /* ProcedureKitMac.framework */,\n\t\t\t\t653CA0381D60A5D10070B7A2 /* ProcedureKitMacTests.xctest */,\n\t\t\t\t653CA0541D60AA6E0070B7A2 /* ProcedureKitMobileTests.xctest */,\n\t\t\t\t653CA05A1D60AA990070B7A2 /* ProcedureKitCloud.framework */,\n\t\t\t\t653CA0621D60AA990070B7A2 /* ProcedureKitCloudTests.xctest */,\n\t\t\t\t6594841E1DAAA2B90028F83B /* ProcedureKitLocation.framework */,\n\t\t\t\t659484261DAAA2B90028F83B /* ProcedureKitLocationTests.xctest */,\n\t\t\t\t65ECB2CD1DB4F0C000F96F46 /* ProcedureKitNetwork.framework */,\n\t\t\t\t65ECB2D51DB4F0C000F96F46 /* ProcedureKitNetworkTests.xctest */,\n\t\t\t\t65A0E49920B85168002D6C8C /* ProcedureKitCoreData.framework */,\n\t\t\t\t65A0E4A120B85169002D6C8C /* ProcedureKitCoreDataTests.xctest */,\n\t\t\t\t65E5EB8120C9CAEC00C46965 /* ProcedureKitInstruments.instrdst */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t65CFC60C1D608AAA00CAD875 /* Supporting Files */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t65CFC60A1D608AA700CAD875 /* ProcedureKit.h */,\n\t\t\t\t653CA0731D60AB1B0070B7A2 /* ProcedureKitCloud.h */,\n\t\t\t\t65A0E4B320B85258002D6C8C /* ProcedureKitCoreData.h */,\n\t\t\t\t659484351DAAA3360028F83B /* ProcedureKitLocation.h */,\n\t\t\t\t653CA0471D60A6060070B7A2 /* ProcedureKitMac.h */,\n\t\t\t\t653C9FDA1D6098330070B7A2 /* ProcedureKitMobile.h */,\n\t\t\t\t65ECB2E81DB4F1A200F96F46 /* ProcedureKitNetwork.h */,\n\t\t\t\t653CA00A1D609EDA0070B7A2 /* ProcedureKitTV.h */,\n\t\t\t\t65CFC61E1D60904700CAD875 /* TestingProcedureKit.h */,\n\t\t\t\t65CFC60F1D608B3000CAD875 /* Info.plist */,\n\t\t\t\t65CFC60E1D608AE200CAD875 /* ProcedureKit.xcconfig */,\n\t\t\t\t653CA0751D60AB2B0070B7A2 /* ProcedureKitCloud.xcconfig */,\n\t\t\t\t65A0E4B520B85297002D6C8C /* ProcedureKitCoreData.xcconfig */,\n\t\t\t\t65D4BEF920C8DDA700D85877 /* ProcedureKitInstruments.xcconfig */,\n\t\t\t\t659484371DAAA3A60028F83B /* ProcedureKitLocation.xcconfig */,\n\t\t\t\t653CA0491D60A6630070B7A2 /* ProcedureKitMac.xcconfig */,\n\t\t\t\t653C9FDC1D6098650070B7A2 /* ProcedureKitMobile.xcconfig */,\n\t\t\t\t65ECB2E91DB4F1A200F96F46 /* ProcedureKitNetwork.xcconfig */,\n\t\t\t\t653CA00B1D609EDA0070B7A2 /* ProcedureKitTV.xcconfig */,\n\t\t\t\t65CFC6201D60905000CAD875 /* TestingProcedureKit.xcconfig */,\n\t\t\t\t65CFC60D1D608AD200CAD875 /* Version.xcconfig */,\n\t\t\t\t65C88D761DC4EB4300C8D4EB /* Warnings.xcconfig */,\n\t\t\t);\n\t\t\tname = \"Supporting Files\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t65D366801E183F1900D03E86 /* ProcedureKitCloudTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t65D366811E183F1900D03E86 /* CKAcceptSharesOperationTests.swift */,\n\t\t\t\t65D366821E183F1900D03E86 /* CKDatabaseOperationTests.swift */,\n\t\t\t\t65D366841E183F1900D03E86 /* CKDiscoverAllUserIdentitiesOperationTests.swift */,\n\t\t\t\t65D366851E183F1900D03E86 /* CKDiscoverUserIdentitiesOperationTests.swift */,\n\t\t\t\t65D366871E183F1900D03E86 /* CKFetchAllChangesTests.swift */,\n\t\t\t\t65D366881E183F1900D03E86 /* CKFetchDatabaseChangesOperationTests.swift */,\n\t\t\t\t65D366891E183F1900D03E86 /* CKFetchNotificationChangesOperationTests.swift */,\n\t\t\t\t65D3668B1E183F1900D03E86 /* CKFetchRecordsOperationTests.swift */,\n\t\t\t\t65D3668C1E183F1900D03E86 /* CKFetchRecordZoneChangesOperationTests.swift */,\n\t\t\t\t65D3668D1E183F1900D03E86 /* CKFetchRecordZonesOperationTests.swift */,\n\t\t\t\t65D3668E1E183F1900D03E86 /* CKFetchShareMetadataOperationTests.swift */,\n\t\t\t\t65D3668F1E183F1900D03E86 /* CKFetchShareParticipantsOperationTests.swift */,\n\t\t\t\t65D366901E183F1900D03E86 /* CKFetchSubscriptionsOperationTests.swift */,\n\t\t\t\t65D366911E183F1900D03E86 /* CKMarkNotificationsReadOperationTests.swift */,\n\t\t\t\t65D366921E183F1900D03E86 /* CKModifyBadgeOperationTests.swift */,\n\t\t\t\t65D366931E183F1900D03E86 /* CKModifyRecordsOperationTests.swift */,\n\t\t\t\t65D366941E183F1900D03E86 /* CKModifyRecordZonesOperationTests.swift */,\n\t\t\t\t65D366951E183F1900D03E86 /* CKModifySubscriptionsOperationTests.swift */,\n\t\t\t\t65D366961E183F1900D03E86 /* CKOperationTests.swift */,\n\t\t\t\t65D366971E183F1900D03E86 /* CKQueryOperationTests.swift */,\n\t\t\t\t65D366981E183F1900D03E86 /* CloudKitCapabilityTests.swift */,\n\t\t\t\t65D366991E183F1900D03E86 /* ProcedureKitCloudTests.swift */,\n\t\t\t\t65D3669A1E183F1900D03E86 /* TestableCloudKitContainer.swift */,\n\t\t\t);\n\t\t\tname = ProcedureKitCloudTests;\n\t\t\tpath = Tests/ProcedureKitCloudTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t65D366B51E183F2600D03E86 /* ProcedureKitLocationTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t65D366B61E183F2600D03E86 /* LocationCapabilityTests.swift */,\n\t\t\t\t65D366B71E183F2600D03E86 /* ProcedureKitLocationTests.swift */,\n\t\t\t\t65D366B81E183F2600D03E86 /* ReverseGeocodeProcedureTests.swift */,\n\t\t\t\t65D366B91E183F2600D03E86 /* ReverseGeocodeUserLocationProcedureTests.swift */,\n\t\t\t\t65D366BA1E183F2600D03E86 /* TestableLocationServices.swift */,\n\t\t\t\t65D366BB1E183F2600D03E86 /* UserLocationProcedureTests.swift */,\n\t\t\t);\n\t\t\tname = ProcedureKitLocationTests;\n\t\t\tpath = Tests/ProcedureKitLocationTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t65D366C21E183F3900D03E86 /* ProcedureKitMacTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t65D366C31E183F3900D03E86 /* ProcedureKitMacTests.swift */,\n\t\t\t\t65D366C41E183F3900D03E86 /* ProcessProcedureTests.swift */,\n\t\t\t);\n\t\t\tname = ProcedureKitMacTests;\n\t\t\tpath = Tests/ProcedureKitMacTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t65D366C71E183F5000D03E86 /* ProcedureKitMobileTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t65D366C81E183F5000D03E86 /* AlertProcedureTests.swift */,\n\t\t\t\t65D366C91E183F5000D03E86 /* BackgroundObserverTests.swift */,\n\t\t\t\t65D366CA1E183F5000D03E86 /* PresentationProcedureTests.swift */,\n\t\t\t\t65D366CB1E183F5000D03E86 /* ProcedureKitMobileTests.swift */,\n\t\t\t\t65D366CC1E183F5000D03E86 /* TestableUIApplication.swift */,\n\t\t\t\t65D366CD1E183F5000D03E86 /* UIProcedureTests.swift */,\n\t\t\t);\n\t\t\tname = ProcedureKitMobileTests;\n\t\t\tpath = Tests/ProcedureKitMobileTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t65D366D41E183F6400D03E86 /* ProcedureKitNetworkTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t65D366D51E183F6400D03E86 /* NetworkDataProcedureTests.swift */,\n\t\t\t\t65D366D61E183F6400D03E86 /* NetworkDownloadProcedureTests.swift */,\n\t\t\t\t65D366D71E183F6400D03E86 /* NetworkProcedureTests.swift */,\n\t\t\t\t65D366D81E183F6400D03E86 /* NetworkReachabilityTests.swift */,\n\t\t\t\t65D366D91E183F6400D03E86 /* NetworkUploadProcedureTests.swift */,\n\t\t\t\t65D366DA1E183F6400D03E86 /* ProcedureKitNetworkTests.swift */,\n\t\t\t\t65D366DB1E183F6400D03E86 /* URLTests.swift */,\n\t\t\t);\n\t\t\tname = ProcedureKitNetworkTests;\n\t\t\tpath = Tests/ProcedureKitNetworkTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t65D366E31E183F8100D03E86 /* ProcedureKitTVTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t65D366E41E183F8100D03E86 /* ProcedureKitTVTests.swift */,\n\t\t\t);\n\t\t\tname = ProcedureKitTVTests;\n\t\t\tpath = Tests/ProcedureKitTVTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t65D366E61E183FB000D03E86 /* ProcedureKitTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t65D366E71E183FB000D03E86 /* AnyProcedureTests.swift */,\n\t\t\t\t652F9014209C488600365B2D /* BatchTests.swift */,\n\t\t\t\t65D366E81E183FB000D03E86 /* BlockConditionTests.swift */,\n\t\t\t\t65D366E91E183FB000D03E86 /* BlockObserverTests.swift */,\n\t\t\t\t65D366EA1E183FB000D03E86 /* BlockProcedureTests.swift */,\n\t\t\t\t65D366EB1E183FB000D03E86 /* CancellationTests.swift */,\n\t\t\t\t65D366EC1E183FB000D03E86 /* CapabilityTests.swift */,\n\t\t\t\t65D366ED1E183FB000D03E86 /* ComposedProcedureTests.swift */,\n\t\t\t\t65D366EE1E183FB000D03E86 /* ConditionTests.swift */,\n\t\t\t\t65D366EF1E183FB000D03E86 /* DelayProcedureTests.swift */,\n\t\t\t\tEE3371071E29AD3E004272E9 /* DispatchQueueExtensionsTests.swift */,\n\t\t\t\t65D366F01E183FB000D03E86 /* FilterProcedureTests.swift */,\n\t\t\t\t65D366F11E183FB000D03E86 /* FinishingTests.swift */,\n\t\t\t\t65D366F21E183FB000D03E86 /* GroupTests.swift */,\n\t\t\t\t652F903E209E445200365B2D /* IgnoreErrorsProcedureTests.swift */,\n\t\t\t\t6527C35F220217FE00D6F498 /* JSONCodingTests.swift */,\n\t\t\t\tEEE79AED1E21C9750030C768 /* KVONotificationTests.swift */,\n\t\t\t\t65A1923820F88FD300E0D42C /* LoggingTests.swift */,\n\t\t\t\t65D366F41E183FB000D03E86 /* MapProcedureTests.swift */,\n\t\t\t\t65D366F51E183FB000D03E86 /* MutualExclusivityTests.swift */,\n\t\t\t\t65D366F61E183FB000D03E86 /* NegatedConditionTests.swift */,\n\t\t\t\t65D366F71E183FB000D03E86 /* NetworkObserverTests.swift */,\n\t\t\t\t65D366F81E183FB000D03E86 /* NoFailedDependenciesConditionTests.swift */,\n\t\t\t\t65D366F91E183FB000D03E86 /* ProcedureKitErrorTests.swift */,\n\t\t\t\t65D366FA1E183FB000D03E86 /* ProcedureKitTests.swift */,\n\t\t\t\t65D366FB1E183FB000D03E86 /* ProcedureTests.swift */,\n\t\t\t\t65D366FC1E183FB000D03E86 /* ProfilerTests.swift */,\n\t\t\t\t65D366FD1E183FB000D03E86 /* ReachabilityTests.swift */,\n\t\t\t\t65D366FE1E183FB000D03E86 /* ReduceProcedureTests.swift */,\n\t\t\t\t65D366FF1E183FB000D03E86 /* RepeatProcedureTests.swift */,\n\t\t\t\t65D367001E183FB000D03E86 /* ResultInjectionTests.swift */,\n\t\t\t\t65D367011E183FB000D03E86 /* RetryProcedureTests.swift */,\n\t\t\t\t65D367021E183FB000D03E86 /* SilentConditionTests.swift */,\n\t\t\t\t65D367031E183FB000D03E86 /* TimeoutObserverTests.swift */,\n\t\t\t\t65D367041E183FB000D03E86 /* TransformProcedureTests.swift */,\n\t\t\t);\n\t\t\tname = ProcedureKitTests;\n\t\t\tpath = Tests/ProcedureKitTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t65D367411E183FBE00D03E86 /* ProcedureKitStressTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t65D367421E183FBE00D03E86 /* BlockProcedureStressTests.swift */,\n\t\t\t\t65D367431E183FBE00D03E86 /* GroupStressTests.swift */,\n\t\t\t\t65D367441E183FBE00D03E86 /* ProcedureKitStressTests.swift */,\n\t\t\t\t65D367451E183FBE00D03E86 /* ProcedureStressTests.swift */,\n\t\t\t\t65D367461E183FBE00D03E86 /* RepeatStressTests.swift */,\n\t\t\t);\n\t\t\tname = ProcedureKitStressTests;\n\t\t\tpath = Tests/ProcedureKitStressTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t65D367BE1E1843ED00D03E86 /* Sources */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t65D368651E184AA600D03E86 /* ProcedureKit */,\n\t\t\t\t65D367DE1E1844F800D03E86 /* ProcedureKitCloud */,\n\t\t\t\t65A0E4B020B851D4002D6C8C /* ProcedureKitCoreData */,\n\t\t\t\t65E5EB8220C9CAEC00C46965 /* ProcedureKitInstruments */,\n\t\t\t\t65D368131E18450200D03E86 /* ProcedureKitLocation */,\n\t\t\t\t65D3681E1E18451000D03E86 /* ProcedureKitMac */,\n\t\t\t\t65D368211E18451C00D03E86 /* ProcedureKitMobile */,\n\t\t\t\t65D3682A1E18452900D03E86 /* ProcedureKitNetwork */,\n\t\t\t\t65D367C51E1844E500D03E86 /* TestingProcedureKit */,\n\t\t\t);\n\t\t\tname = Sources;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t65D367C51E1844E500D03E86 /* TestingProcedureKit */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t65D367C61E1844E500D03E86 /* CapabilityTestCase.swift */,\n\t\t\t\t65D367C71E1844E500D03E86 /* ConcurrencyTestCase.swift */,\n\t\t\t\t65D367C81E1844E500D03E86 /* GroupTestCase.swift */,\n\t\t\t\t65D367C91E1844E500D03E86 /* ProcedureKitTestCase.swift */,\n\t\t\t\t65D367CA1E1844E500D03E86 /* QueueTestDelegate.swift */,\n\t\t\t\t65D367CB1E1844E500D03E86 /* RepeatTestCase.swift */,\n\t\t\t\t65D367CC1E1844E500D03E86 /* StressTestCase.swift */,\n\t\t\t\t65A1923A20F8900100E0D42C /* TestableLogging.swift */,\n\t\t\t\t65D367CD1E1844E500D03E86 /* TestableNetwork.swift */,\n\t\t\t\t65D367CE1E1844E500D03E86 /* TestableNetworkReachability.swift */,\n\t\t\t\t65D367CF1E1844E500D03E86 /* TestCondition.swift */,\n\t\t\t\t65D367D01E1844E500D03E86 /* TestProcedure.swift */,\n\t\t\t\t65D367D11E1844E500D03E86 /* XCTAsserts.swift */,\n\t\t\t);\n\t\t\tname = TestingProcedureKit;\n\t\t\tpath = Sources/TestingProcedureKit;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t65D367DE1E1844F800D03E86 /* ProcedureKitCloud */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t65D367F31E1844F800D03E86 /* CKOperation.swift */,\n\t\t\t\t65D367F51E1844F800D03E86 /* CloudKit.swift */,\n\t\t\t\t65D367F61E1844F800D03E86 /* CloudKitCapability.swift */,\n\t\t\t\t65D367F71E1844F800D03E86 /* CloudKitError.swift */,\n\t\t\t\t65D367F81E1844F800D03E86 /* CloudKitSupport.swift */,\n\t\t\t\t657FCD552152D91B00F7D7E3 /* Database Operations */,\n\t\t\t\t657FCD512152D78F00F7D7E3 /* Notification Operations */,\n\t\t\t\t657FCD532152D86B00F7D7E3 /* Query Operations */,\n\t\t\t\t657FCD502152D70E00F7D7E3 /* Record Operations */,\n\t\t\t\t657FCD542152D89A00F7D7E3 /* Share Operations */,\n\t\t\t\t657FCD522152D82500F7D7E3 /* Subscription Operations */,\n\t\t\t);\n\t\t\tname = ProcedureKitCloud;\n\t\t\tpath = Sources/ProcedureKitCloud;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t65D368131E18450200D03E86 /* ProcedureKitLocation */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t65D368141E18450200D03E86 /* LocationCapability.swift */,\n\t\t\t\t65D368151E18450200D03E86 /* LocationSupport.swift */,\n\t\t\t\t65D368161E18450200D03E86 /* ReverseGeocode.swift */,\n\t\t\t\t65D368171E18450200D03E86 /* ReverseGeocodeUserLocation.swift */,\n\t\t\t\t65D368181E18450200D03E86 /* UserLocation.swift */,\n\t\t\t);\n\t\t\tname = ProcedureKitLocation;\n\t\t\tpath = Sources/ProcedureKitLocation;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t65D3681E1E18451000D03E86 /* ProcedureKitMac */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t65D3681F1E18451000D03E86 /* Process.swift */,\n\t\t\t);\n\t\t\tname = ProcedureKitMac;\n\t\t\tpath = Sources/ProcedureKitMac;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t65D368211E18451C00D03E86 /* ProcedureKitMobile */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t65D368221E18451C00D03E86 /* Alert.swift */,\n\t\t\t\t65D368231E18451C00D03E86 /* BackgroundObserver.swift */,\n\t\t\t\t65D368241E18451C00D03E86 /* NetworkObserver+Mobile.swift */,\n\t\t\t\t65D368251E18451C00D03E86 /* UI.swift */,\n\t\t\t\t65FFC36E1E4BDF03005DC38F /* UserConfirmation.swift */,\n\t\t\t\t65AEF19E20A3AE340089B6C8 /* ViewControllerContainment.swift */,\n\t\t\t);\n\t\t\tname = ProcedureKitMobile;\n\t\t\tpath = Sources/ProcedureKitMobile;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t65D3682A1E18452900D03E86 /* ProcedureKitNetwork */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t65D3682B1E18452900D03E86 /* Network.swift */,\n\t\t\t\t65D3682C1E18452900D03E86 /* NetworkData.swift */,\n\t\t\t\t65D3682D1E18452900D03E86 /* NetworkDownload.swift */,\n\t\t\t\t65D3682E1E18452900D03E86 /* NetworkReachability.swift */,\n\t\t\t\t65D3682F1E18452900D03E86 /* NetworkSupport.swift */,\n\t\t\t\t65D368301E18452900D03E86 /* NetworkUpload.swift */,\n\t\t\t);\n\t\t\tname = ProcedureKitNetwork;\n\t\t\tpath = Sources/ProcedureKitNetwork;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t65D368651E184AA600D03E86 /* ProcedureKit */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t65D368711E184AA600D03E86 /* Errors.swift */,\n\t\t\t\t65D368821E184AA600D03E86 /* Reachability.swift */,\n\t\t\t\t65D368871E184AA600D03E86 /* Support.swift */,\n\t\t\t\t65D368B01E184AE500D03E86 /* Conditions */,\n\t\t\t\t65D368B21E184B0000D03E86 /* Core */,\n\t\t\t\t65D368B11E184AF000D03E86 /* Extensions */,\n\t\t\t\t65D368AF1E184AD000D03E86 /* Observers */,\n\t\t\t\t65D368AE1E184ABF00D03E86 /* Procedures */,\n\t\t\t);\n\t\t\tname = ProcedureKit;\n\t\t\tpath = Sources/ProcedureKit;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t65D368AE1E184ABF00D03E86 /* Procedures */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t65D368661E184AA600D03E86 /* Any.swift */,\n\t\t\t\t65AB7DD9209B95B400726796 /* Batch.swift */,\n\t\t\t\t65D368681E184AA600D03E86 /* Block.swift */,\n\t\t\t\t65D3686B1E184AA600D03E86 /* Capability.swift */,\n\t\t\t\t65D3686D1E184AA600D03E86 /* Composed.swift */,\n\t\t\t\t6527C35B2202026800D6F498 /* Decode.swift */,\n\t\t\t\t65D3686F1E184AA600D03E86 /* Delay.swift */,\n\t\t\t\t6527C35D2202171F00D6F498 /* Encode.swift */,\n\t\t\t\t65D368721E184AA600D03E86 /* Filter.swift */,\n\t\t\t\t65D368731E184AA600D03E86 /* Group.swift */,\n\t\t\t\t652F903C209E3E3D00365B2D /* IgnoreErrors.swift */,\n\t\t\t\t65D368761E184AA600D03E86 /* Map.swift */,\n\t\t\t\t65D368831E184AA600D03E86 /* Reduce.swift */,\n\t\t\t\t65D368841E184AA600D03E86 /* Repeat.swift */,\n\t\t\t\t65B9AF472116D1D4004DA82B /* Result.swift */,\n\t\t\t\t65D368851E184AA600D03E86 /* Retry.swift */,\n\t\t\t\t65D368891E184AA600D03E86 /* Transform.swift */,\n\t\t\t);\n\t\t\tname = Procedures;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t65D368AF1E184AD000D03E86 /* Observers */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t65D368671E184AA600D03E86 /* AnyObserver.swift */,\n\t\t\t\t65D3686A1E184AA600D03E86 /* BlockObservers.swift */,\n\t\t\t\t65D368791E184AA600D03E86 /* NetworkObserver.swift */,\n\t\t\t\t65D368811E184AA600D03E86 /* Profiler.swift */,\n\t\t\t\t65D4BEF420C8A31100D85877 /* SignpostObserver.swift */,\n\t\t\t\t65D368881E184AA600D03E86 /* TimeoutObserver.swift */,\n\t\t\t);\n\t\t\tname = Observers;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t65D368B01E184AE500D03E86 /* Conditions */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t65D368691E184AA600D03E86 /* BlockCondition.swift */,\n\t\t\t\t65D368771E184AA600D03E86 /* MutualExclusion.swift */,\n\t\t\t\t65D368781E184AA600D03E86 /* NegatedCondition.swift */,\n\t\t\t\t65D3687A1E184AA600D03E86 /* NoFailedDependenciesCondition.swift */,\n\t\t\t\t65D368861E184AA600D03E86 /* SilentCondition.swift */,\n\t\t\t);\n\t\t\tname = Conditions;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t65D368B11E184AF000D03E86 /* Extensions */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t65D3686C1E184AA600D03E86 /* Collection+ProcedureKit.swift */,\n\t\t\t\t65D368701E184AA600D03E86 /* DispatchQueue+ProcedureKit.swift */,\n\t\t\t\t65D3687B1E184AA600D03E86 /* Operation+ProcedureKit.swift */,\n\t\t\t);\n\t\t\tname = Extensions;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t65D368B21E184B0000D03E86 /* Core */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t65D3686E1E184AA600D03E86 /* Condition.swift */,\n\t\t\t\t65D368741E184AA600D03E86 /* Identity.swift */,\n\t\t\t\t65D368751E184AA600D03E86 /* Logging.swift */,\n\t\t\t\tEEE79AE71E21B9C90030C768 /* PendingEvent.swift */,\n\t\t\t\t65D3687C1E184AA600D03E86 /* Procedure.swift */,\n\t\t\t\tEEE79AE91E21B9D30030C768 /* ProcedureEventQueue.swift */,\n\t\t\t\tEEE79AEA1E21B9D30030C768 /* ProcedureFuture.swift */,\n\t\t\t\t65D3687D1E184AA600D03E86 /* ProcedureObserver.swift */,\n\t\t\t\t65D3687E1E184AA600D03E86 /* ProcedureProcotol.swift */,\n\t\t\t\t65D3687F1E184AA600D03E86 /* ProcedureQueue.swift */,\n\t\t\t\t65D368801E184AA600D03E86 /* ProcedureResult.swift */,\n\t\t\t);\n\t\t\tname = Core;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t65E5EB8220C9CAEC00C46965 /* ProcedureKitInstruments */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t65E5EB8320C9CAEC00C46965 /* ProcedureKitInstruments.instrpkg */,\n\t\t\t);\n\t\t\tname = ProcedureKitInstruments;\n\t\t\tpath = Sources/ProcedureKitInstruments;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXHeadersBuildPhase section */\n\t\t653C9FBE1D6097A40070B7A2 /* Headers */ = {\n\t\t\tisa = PBXHeadersBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t653C9FDB1D6098330070B7A2 /* ProcedureKitMobile.h in Headers */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t653C9FF01D609E650070B7A2 /* Headers */ = {\n\t\t\tisa = PBXHeadersBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t653CA00C1D609EE10070B7A2 /* ProcedureKitTV.h in Headers */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t653CA02D1D60A5D10070B7A2 /* Headers */ = {\n\t\t\tisa = PBXHeadersBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t653CA0481D60A6060070B7A2 /* ProcedureKitMac.h in Headers */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t653CA0571D60AA990070B7A2 /* Headers */ = {\n\t\t\tisa = PBXHeadersBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t653CA0741D60AB1B0070B7A2 /* ProcedureKitCloud.h in Headers */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t6594841B1DAAA2B90028F83B /* Headers */ = {\n\t\t\tisa = PBXHeadersBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t659484361DAAA3360028F83B /* ProcedureKitLocation.h in Headers */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t65A0E49620B85168002D6C8C /* Headers */ = {\n\t\t\tisa = PBXHeadersBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t65A0E4B420B85258002D6C8C /* ProcedureKitCoreData.h in Headers */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t65CFC5ED1D608A5500CAD875 /* Headers */ = {\n\t\t\tisa = PBXHeadersBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t65CFC60B1D608AA700CAD875 /* ProcedureKit.h in Headers */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t65CFC6131D60900000CAD875 /* Headers */ = {\n\t\t\tisa = PBXHeadersBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t65CFC61F1D60904700CAD875 /* TestingProcedureKit.h in Headers */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t65ECB2CA1DB4F0C000F96F46 /* Headers */ = {\n\t\t\tisa = PBXHeadersBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t65ECB2EA1DB4F1A200F96F46 /* ProcedureKitNetwork.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\t653C9FC01D6097A40070B7A2 /* ProcedureKitMobile */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 653C9FD61D6097A40070B7A2 /* Build configuration list for PBXNativeTarget \"ProcedureKitMobile\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t653C9FBC1D6097A40070B7A2 /* Sources */,\n\t\t\t\t653C9FBD1D6097A40070B7A2 /* Frameworks */,\n\t\t\t\t653C9FBE1D6097A40070B7A2 /* Headers */,\n\t\t\t\t653C9FBF1D6097A40070B7A2 /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\t653C9FDE1D60990B0070B7A2 /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = ProcedureKitMobile;\n\t\t\tproductName = \"ProcedureKit iOS\";\n\t\t\tproductReference = 653C9FC11D6097A40070B7A2 /* ProcedureKitMobile.framework */;\n\t\t\tproductType = \"com.apple.product-type.framework\";\n\t\t};\n\t\t653C9FC81D6097A40070B7A2 /* ProcedureKitMobileTests */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 653C9FD71D6097A40070B7A2 /* Build configuration list for PBXNativeTarget \"ProcedureKitMobileTests\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t653C9FC51D6097A40070B7A2 /* Sources */,\n\t\t\t\t653C9FC61D6097A40070B7A2 /* Frameworks */,\n\t\t\t\t653C9FC71D6097A40070B7A2 /* Resources */,\n\t\t\t\t65A72C291DA7F352008597CA /* Copy Dependencies */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\t6532DD521DBC190600B030F5 /* PBXTargetDependency */,\n\t\t\t\t653C9FCC1D6097A40070B7A2 /* PBXTargetDependency */,\n\t\t\t\t6532DD581DBCDB3400B030F5 /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = ProcedureKitMobileTests;\n\t\t\tproductName = \"ProcedureKit iOSTests\";\n\t\t\tproductReference = 653CA0541D60AA6E0070B7A2 /* ProcedureKitMobileTests.xctest */;\n\t\t\tproductType = \"com.apple.product-type.bundle.unit-test\";\n\t\t};\n\t\t653C9FF21D609E650070B7A2 /* ProcedureKitTV */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 653CA0041D609E660070B7A2 /* Build configuration list for PBXNativeTarget \"ProcedureKitTV\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t653C9FEE1D609E650070B7A2 /* Sources */,\n\t\t\t\t653C9FEF1D609E650070B7A2 /* Frameworks */,\n\t\t\t\t653C9FF01D609E650070B7A2 /* Headers */,\n\t\t\t\t653C9FF11D609E650070B7A2 /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\t653CA00E1D609F980070B7A2 /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = ProcedureKitTV;\n\t\t\tproductName = ProcedureKitTV;\n\t\t\tproductReference = 653C9FF31D609E650070B7A2 /* ProcedureKitTV.framework */;\n\t\t\tproductType = \"com.apple.product-type.framework\";\n\t\t};\n\t\t653C9FFA1D609E660070B7A2 /* ProcedureKitTVTests */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 653CA0071D609E660070B7A2 /* Build configuration list for PBXNativeTarget \"ProcedureKitTVTests\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t653C9FF71D609E660070B7A2 /* Sources */,\n\t\t\t\t653C9FF81D609E660070B7A2 /* Frameworks */,\n\t\t\t\t653C9FF91D609E660070B7A2 /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\t6532DD541DBC190A00B030F5 /* PBXTargetDependency */,\n\t\t\t\t653C9FFE1D609E660070B7A2 /* PBXTargetDependency */,\n\t\t\t\t653CA0111D609FA50070B7A2 /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = ProcedureKitTVTests;\n\t\t\tproductName = ProcedureKitTVTests;\n\t\t\tproductReference = 653C9FFB1D609E660070B7A2 /* ProcedureKitTVTests.xctest */;\n\t\t\tproductType = \"com.apple.product-type.bundle.unit-test\";\n\t\t};\n\t\t653CA0171D60A34E0070B7A2 /* ProcedureKitStressTests */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 653CA0221D60A34E0070B7A2 /* Build configuration list for PBXNativeTarget \"ProcedureKitStressTests\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t653CA01C1D60A34E0070B7A2 /* Sources */,\n\t\t\t\t653CA01E1D60A34E0070B7A2 /* Frameworks */,\n\t\t\t\t653CA0211D60A34E0070B7A2 /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\t653CA0181D60A34E0070B7A2 /* PBXTargetDependency */,\n\t\t\t\t653CA01A1D60A34E0070B7A2 /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = ProcedureKitStressTests;\n\t\t\tproductName = ProcedureKitTests;\n\t\t\tproductReference = 653CA0251D60A34E0070B7A2 /* ProcedureKitStressTests.xctest */;\n\t\t\tproductType = \"com.apple.product-type.bundle.unit-test\";\n\t\t};\n\t\t653CA02F1D60A5D10070B7A2 /* ProcedureKitMac */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 653CA0411D60A5D10070B7A2 /* Build configuration list for PBXNativeTarget \"ProcedureKitMac\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t653CA02B1D60A5D10070B7A2 /* Sources */,\n\t\t\t\t653CA02C1D60A5D10070B7A2 /* Frameworks */,\n\t\t\t\t653CA02D1D60A5D10070B7A2 /* Headers */,\n\t\t\t\t653CA02E1D60A5D10070B7A2 /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\t653CA04F1D60A7050070B7A2 /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = ProcedureKitMac;\n\t\t\tproductName = ProcedureKitMac;\n\t\t\tproductReference = 653CA0301D60A5D10070B7A2 /* ProcedureKitMac.framework */;\n\t\t\tproductType = \"com.apple.product-type.framework\";\n\t\t};\n\t\t653CA0371D60A5D10070B7A2 /* ProcedureKitMacTests */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 653CA0441D60A5D10070B7A2 /* Build configuration list for PBXNativeTarget \"ProcedureKitMacTests\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t653CA0341D60A5D10070B7A2 /* Sources */,\n\t\t\t\t653CA0351D60A5D10070B7A2 /* Frameworks */,\n\t\t\t\t653CA0361D60A5D10070B7A2 /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\t6532DD561DBC190F00B030F5 /* PBXTargetDependency */,\n\t\t\t\t653CA03B1D60A5D10070B7A2 /* PBXTargetDependency */,\n\t\t\t\t653CA0521D60A70F0070B7A2 /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = ProcedureKitMacTests;\n\t\t\tproductName = ProcedureKitMacTests;\n\t\t\tproductReference = 653CA0381D60A5D10070B7A2 /* ProcedureKitMacTests.xctest */;\n\t\t\tproductType = \"com.apple.product-type.bundle.unit-test\";\n\t\t};\n\t\t653CA0591D60AA990070B7A2 /* ProcedureKitCloud */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 653CA06F1D60AA9A0070B7A2 /* Build configuration list for PBXNativeTarget \"ProcedureKitCloud\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t653CA0551D60AA990070B7A2 /* Sources */,\n\t\t\t\t653CA0561D60AA990070B7A2 /* Frameworks */,\n\t\t\t\t653CA0571D60AA990070B7A2 /* Headers */,\n\t\t\t\t653CA0581D60AA990070B7A2 /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\t653CA0771D60ABC30070B7A2 /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = ProcedureKitCloud;\n\t\t\tproductName = ProcedureKitCloud;\n\t\t\tproductReference = 653CA05A1D60AA990070B7A2 /* ProcedureKitCloud.framework */;\n\t\t\tproductType = \"com.apple.product-type.framework\";\n\t\t};\n\t\t653CA0611D60AA990070B7A2 /* ProcedureKitCloudTests */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 653CA0701D60AA9A0070B7A2 /* Build configuration list for PBXNativeTarget \"ProcedureKitCloudTests\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t653CA05E1D60AA990070B7A2 /* Sources */,\n\t\t\t\t653CA05F1D60AA990070B7A2 /* Frameworks */,\n\t\t\t\t653CA0601D60AA990070B7A2 /* Resources */,\n\t\t\t\t65ECB2FF1DB50BCF00F96F46 /* Copy Dependencies */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\t6532DD4E1DBC18F800B030F5 /* PBXTargetDependency */,\n\t\t\t\t653CA0651D60AA990070B7A2 /* PBXTargetDependency */,\n\t\t\t\t653CA07A1D60ABCE0070B7A2 /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = ProcedureKitCloudTests;\n\t\t\tproductName = ProcedureKitCloudTests;\n\t\t\tproductReference = 653CA0621D60AA990070B7A2 /* ProcedureKitCloudTests.xctest */;\n\t\t\tproductType = \"com.apple.product-type.bundle.unit-test\";\n\t\t};\n\t\t6594841D1DAAA2B90028F83B /* ProcedureKitLocation */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 659484331DAAA2B90028F83B /* Build configuration list for PBXNativeTarget \"ProcedureKitLocation\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t659484191DAAA2B90028F83B /* Sources */,\n\t\t\t\t6594841A1DAAA2B90028F83B /* Frameworks */,\n\t\t\t\t6594841B1DAAA2B90028F83B /* Headers */,\n\t\t\t\t6594841C1DAAA2B90028F83B /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\t659484481DAAB52B0028F83B /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = ProcedureKitLocation;\n\t\t\tproductName = ProcedureKitLocation;\n\t\t\tproductReference = 6594841E1DAAA2B90028F83B /* ProcedureKitLocation.framework */;\n\t\t\tproductType = \"com.apple.product-type.framework\";\n\t\t};\n\t\t659484251DAAA2B90028F83B /* ProcedureKitLocationTests */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 659484341DAAA2B90028F83B /* Build configuration list for PBXNativeTarget \"ProcedureKitLocationTests\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t659484221DAAA2B90028F83B /* Sources */,\n\t\t\t\t659484231DAAA2B90028F83B /* Frameworks */,\n\t\t\t\t659484241DAAA2B90028F83B /* Resources */,\n\t\t\t\t6594843C1DAAA52B0028F83B /* Copy Files (2 items) */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\t6532DD501DBC190000B030F5 /* PBXTargetDependency */,\n\t\t\t\t659484291DAAA2B90028F83B /* PBXTargetDependency */,\n\t\t\t\t6594844A1DAAB5340028F83B /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = ProcedureKitLocationTests;\n\t\t\tproductName = ProcedureKitLocationTests;\n\t\t\tproductReference = 659484261DAAA2B90028F83B /* ProcedureKitLocationTests.xctest */;\n\t\t\tproductType = \"com.apple.product-type.bundle.unit-test\";\n\t\t};\n\t\t65A0E49820B85168002D6C8C /* ProcedureKitCoreData */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 65A0E4AE20B85169002D6C8C /* Build configuration list for PBXNativeTarget \"ProcedureKitCoreData\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t65A0E49420B85168002D6C8C /* Sources */,\n\t\t\t\t65A0E49520B85168002D6C8C /* Frameworks */,\n\t\t\t\t65A0E49620B85168002D6C8C /* Headers */,\n\t\t\t\t65A0E49720B85168002D6C8C /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\t65A0E4BC20B85880002D6C8C /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = ProcedureKitCoreData;\n\t\t\tproductName = ProcedureKitCoreData;\n\t\t\tproductReference = 65A0E49920B85168002D6C8C /* ProcedureKitCoreData.framework */;\n\t\t\tproductType = \"com.apple.product-type.framework\";\n\t\t};\n\t\t65A0E4A020B85169002D6C8C /* ProcedureKitCoreDataTests */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 65A0E4AF20B85169002D6C8C /* Build configuration list for PBXNativeTarget \"ProcedureKitCoreDataTests\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t65A0E49D20B85169002D6C8C /* Sources */,\n\t\t\t\t65A0E49E20B85169002D6C8C /* Frameworks */,\n\t\t\t\t65A0E49F20B85169002D6C8C /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\t65374F3320BC6553009948B4 /* PBXTargetDependency */,\n\t\t\t\t65A0E4BE20B8588F002D6C8C /* PBXTargetDependency */,\n\t\t\t\t65A0E4A420B85169002D6C8C /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = ProcedureKitCoreDataTests;\n\t\t\tproductName = ProcedureKitCoreDataTests;\n\t\t\tproductReference = 65A0E4A120B85169002D6C8C /* ProcedureKitCoreDataTests.xctest */;\n\t\t\tproductType = \"com.apple.product-type.bundle.unit-test\";\n\t\t};\n\t\t65CFC5EF1D608A5500CAD875 /* ProcedureKit */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 65CFC6061D608A5500CAD875 /* Build configuration list for PBXNativeTarget \"ProcedureKit\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t65CFC5EB1D608A5500CAD875 /* Sources */,\n\t\t\t\t65CFC5EC1D608A5500CAD875 /* Frameworks */,\n\t\t\t\t65CFC5ED1D608A5500CAD875 /* Headers */,\n\t\t\t\t65CFC5EE1D608A5500CAD875 /* 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 = ProcedureKit;\n\t\t\tproductName = ProcedureKit;\n\t\t\tproductReference = 65CFC5F01D608A5500CAD875 /* ProcedureKit.framework */;\n\t\t\tproductType = \"com.apple.product-type.framework\";\n\t\t};\n\t\t65CFC5F81D608A5500CAD875 /* ProcedureKitTests */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 65CFC6071D608A5500CAD875 /* Build configuration list for PBXNativeTarget \"ProcedureKitTests\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t65CFC5F51D608A5500CAD875 /* Sources */,\n\t\t\t\t65CFC5F61D608A5500CAD875 /* Frameworks */,\n\t\t\t\t65CFC5F71D608A5500CAD875 /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\t65CFC6221D60911400CAD875 /* PBXTargetDependency */,\n\t\t\t\t65CFC5FC1D608A5500CAD875 /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = ProcedureKitTests;\n\t\t\tproductName = ProcedureKitTests;\n\t\t\tproductReference = 65CFC5F91D608A5500CAD875 /* ProcedureKitTests.xctest */;\n\t\t\tproductType = \"com.apple.product-type.bundle.unit-test\";\n\t\t};\n\t\t65CFC6151D60900000CAD875 /* TestingProcedureKit */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 65CFC61D1D60900000CAD875 /* Build configuration list for PBXNativeTarget \"TestingProcedureKit\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t65CFC6111D60900000CAD875 /* Sources */,\n\t\t\t\t65CFC6121D60900000CAD875 /* Frameworks */,\n\t\t\t\t65CFC6131D60900000CAD875 /* Headers */,\n\t\t\t\t65CFC6141D60900000CAD875 /* Resources */,\n\t\t\t\t659300891DA7F57000750212 /* CopyFiles */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\t65CFC6251D60912400CAD875 /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = TestingProcedureKit;\n\t\t\tproductName = TestingProcedureKit;\n\t\t\tproductReference = 65CFC6161D60900000CAD875 /* TestingProcedureKit.framework */;\n\t\t\tproductType = \"com.apple.product-type.framework\";\n\t\t};\n\t\t65E5EB8020C9CAEC00C46965 /* ProcedureKitInstruments */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 65E5EB8520C9CAEC00C46965 /* Build configuration list for PBXNativeTarget \"ProcedureKitInstruments\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t65E5EB7F20C9CAEC00C46965 /* Sources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = ProcedureKitInstruments;\n\t\t\tproductName = ProcedureKitInstruments;\n\t\t\tproductReference = 65E5EB8120C9CAEC00C46965 /* ProcedureKitInstruments.instrdst */;\n\t\t\tproductType = \"com.apple.product-type.instruments-package\";\n\t\t};\n\t\t65ECB2CC1DB4F0C000F96F46 /* ProcedureKitNetwork */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 65ECB2DE1DB4F0C000F96F46 /* Build configuration list for PBXNativeTarget \"ProcedureKitNetwork\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t65ECB2C81DB4F0C000F96F46 /* Sources */,\n\t\t\t\t65ECB2C91DB4F0C000F96F46 /* Frameworks */,\n\t\t\t\t65ECB2CA1DB4F0C000F96F46 /* Headers */,\n\t\t\t\t65ECB2CB1DB4F0C000F96F46 /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\t65ECB2FB1DB50B8F00F96F46 /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = ProcedureKitNetwork;\n\t\t\tproductName = ProcedureKitNetwork;\n\t\t\tproductReference = 65ECB2CD1DB4F0C000F96F46 /* ProcedureKitNetwork.framework */;\n\t\t\tproductType = \"com.apple.product-type.framework\";\n\t\t};\n\t\t65ECB2D41DB4F0C000F96F46 /* ProcedureKitNetworkTests */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 65ECB2E11DB4F0C000F96F46 /* Build configuration list for PBXNativeTarget \"ProcedureKitNetworkTests\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t65ECB2D11DB4F0C000F96F46 /* Sources */,\n\t\t\t\t65ECB2D21DB4F0C000F96F46 /* Frameworks */,\n\t\t\t\t65ECB2D31DB4F0C000F96F46 /* Resources */,\n\t\t\t\t65ECB2FC1DB50BB500F96F46 /* Copy Dependencies */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\t6532DD4C1DBC18DF00B030F5 /* PBXTargetDependency */,\n\t\t\t\t65ECB2F81DB50B7300F96F46 /* PBXTargetDependency */,\n\t\t\t\t65ECB2D81DB4F0C000F96F46 /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = ProcedureKitNetworkTests;\n\t\t\tproductName = ProcedureKitNetworkTests;\n\t\t\tproductReference = 65ECB2D51DB4F0C000F96F46 /* ProcedureKitNetworkTests.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\t65CFC5E51D608A1A00CAD875 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tCLASSPREFIX = PCK;\n\t\t\t\tDefaultBuildSystemTypeForWorkspace = Latest;\n\t\t\t\tLastSwiftUpdateCheck = 0930;\n\t\t\t\tLastUpgradeCheck = 1020;\n\t\t\t\tORGANIZATIONNAME = ProcedureKit;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t653C9FC01D6097A40070B7A2 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 8.0;\n\t\t\t\t\t\tLastSwiftMigration = 1020;\n\t\t\t\t\t};\n\t\t\t\t\t653C9FC81D6097A40070B7A2 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 8.0;\n\t\t\t\t\t\tLastSwiftMigration = 1020;\n\t\t\t\t\t\tProvisioningStyle = Manual;\n\t\t\t\t\t};\n\t\t\t\t\t653C9FF21D609E650070B7A2 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 8.0;\n\t\t\t\t\t\tLastSwiftMigration = 0920;\n\t\t\t\t\t};\n\t\t\t\t\t653C9FFA1D609E660070B7A2 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 8.0;\n\t\t\t\t\t\tLastSwiftMigration = 1020;\n\t\t\t\t\t\tProvisioningStyle = Manual;\n\t\t\t\t\t};\n\t\t\t\t\t653CA0171D60A34E0070B7A2 = {\n\t\t\t\t\t\tLastSwiftMigration = 1020;\n\t\t\t\t\t};\n\t\t\t\t\t653CA02F1D60A5D10070B7A2 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 8.0;\n\t\t\t\t\t\tLastSwiftMigration = 1020;\n\t\t\t\t\t};\n\t\t\t\t\t653CA0371D60A5D10070B7A2 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 8.0;\n\t\t\t\t\t\tLastSwiftMigration = 1020;\n\t\t\t\t\t\tProvisioningStyle = Manual;\n\t\t\t\t\t};\n\t\t\t\t\t653CA0591D60AA990070B7A2 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 8.0;\n\t\t\t\t\t\tLastSwiftMigration = 1020;\n\t\t\t\t\t};\n\t\t\t\t\t653CA0611D60AA990070B7A2 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 8.0;\n\t\t\t\t\t\tLastSwiftMigration = 1020;\n\t\t\t\t\t\tProvisioningStyle = Manual;\n\t\t\t\t\t};\n\t\t\t\t\t6594841D1DAAA2B90028F83B = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 8.0;\n\t\t\t\t\t\tLastSwiftMigration = 1020;\n\t\t\t\t\t};\n\t\t\t\t\t659484251DAAA2B90028F83B = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 8.0;\n\t\t\t\t\t\tLastSwiftMigration = 1020;\n\t\t\t\t\t\tProvisioningStyle = Automatic;\n\t\t\t\t\t};\n\t\t\t\t\t65A0E49820B85168002D6C8C = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 9.3;\n\t\t\t\t\t\tLastSwiftMigration = 1020;\n\t\t\t\t\t};\n\t\t\t\t\t65A0E4A020B85169002D6C8C = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 9.3;\n\t\t\t\t\t\tLastSwiftMigration = 1020;\n\t\t\t\t\t};\n\t\t\t\t\t65CFC5EF1D608A5500CAD875 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 8.0;\n\t\t\t\t\t\tLastSwiftMigration = 1020;\n\t\t\t\t\t};\n\t\t\t\t\t65CFC5F81D608A5500CAD875 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 8.0;\n\t\t\t\t\t\tLastSwiftMigration = 1020;\n\t\t\t\t\t\tProvisioningStyle = Automatic;\n\t\t\t\t\t};\n\t\t\t\t\t65CFC6151D60900000CAD875 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 8.0;\n\t\t\t\t\t\tLastSwiftMigration = 1020;\n\t\t\t\t\t};\n\t\t\t\t\t65E5EB8020C9CAEC00C46965 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 10.0;\n\t\t\t\t\t};\n\t\t\t\t\t65ECB2CC1DB4F0C000F96F46 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 8.0;\n\t\t\t\t\t\tLastSwiftMigration = 1020;\n\t\t\t\t\t};\n\t\t\t\t\t65ECB2D41DB4F0C000F96F46 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 8.0;\n\t\t\t\t\t\tLastSwiftMigration = 1020;\n\t\t\t\t\t\tProvisioningStyle = Automatic;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 65CFC5E81D608A1A00CAD875 /* Build configuration list for PBXProject \"ProcedureKit\" */;\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 = 65CFC5E41D608A1A00CAD875;\n\t\t\tproductRefGroup = 65CFC5F11D608A5500CAD875 /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t65CFC5EF1D608A5500CAD875 /* ProcedureKit */,\n\t\t\t\t65CFC6151D60900000CAD875 /* TestingProcedureKit */,\n\t\t\t\t65CFC5F81D608A5500CAD875 /* ProcedureKitTests */,\n\t\t\t\t653CA0171D60A34E0070B7A2 /* ProcedureKitStressTests */,\n\t\t\t\t653CA0591D60AA990070B7A2 /* ProcedureKitCloud */,\n\t\t\t\t653CA0611D60AA990070B7A2 /* ProcedureKitCloudTests */,\n\t\t\t\t65A0E49820B85168002D6C8C /* ProcedureKitCoreData */,\n\t\t\t\t65A0E4A020B85169002D6C8C /* ProcedureKitCoreDataTests */,\n\t\t\t\t6594841D1DAAA2B90028F83B /* ProcedureKitLocation */,\n\t\t\t\t659484251DAAA2B90028F83B /* ProcedureKitLocationTests */,\n\t\t\t\t653CA02F1D60A5D10070B7A2 /* ProcedureKitMac */,\n\t\t\t\t653CA0371D60A5D10070B7A2 /* ProcedureKitMacTests */,\n\t\t\t\t653C9FC01D6097A40070B7A2 /* ProcedureKitMobile */,\n\t\t\t\t653C9FC81D6097A40070B7A2 /* ProcedureKitMobileTests */,\n\t\t\t\t65ECB2CC1DB4F0C000F96F46 /* ProcedureKitNetwork */,\n\t\t\t\t65ECB2D41DB4F0C000F96F46 /* ProcedureKitNetworkTests */,\n\t\t\t\t653C9FF21D609E650070B7A2 /* ProcedureKitTV */,\n\t\t\t\t653C9FFA1D609E660070B7A2 /* ProcedureKitTVTests */,\n\t\t\t\t65E5EB8020C9CAEC00C46965 /* ProcedureKitInstruments */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t653C9FBF1D6097A40070B7A2 /* 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\t653C9FC71D6097A40070B7A2 /* 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\t653C9FF11D609E650070B7A2 /* 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\t653C9FF91D609E660070B7A2 /* 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\t653CA0211D60A34E0070B7A2 /* 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\t653CA02E1D60A5D10070B7A2 /* 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\t653CA0361D60A5D10070B7A2 /* 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\t653CA0581D60AA990070B7A2 /* 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\t653CA0601D60AA990070B7A2 /* 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\t6594841C1DAAA2B90028F83B /* 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\t659484241DAAA2B90028F83B /* 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\t65A0E49720B85168002D6C8C /* 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\t65A0E49F20B85169002D6C8C /* 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\t65CFC5EE1D608A5500CAD875 /* 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\t65CFC5F71D608A5500CAD875 /* 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\t65CFC6141D60900000CAD875 /* 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\t65ECB2CB1DB4F0C000F96F46 /* 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\t65ECB2D31DB4F0C000F96F46 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t653C9FBC1D6097A40070B7A2 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t65FFC36F1E4BDF03005DC38F /* UserConfirmation.swift in Sources */,\n\t\t\t\t65AEF19F20A3AE340089B6C8 /* ViewControllerContainment.swift in Sources */,\n\t\t\t\t65D368261E18451C00D03E86 /* Alert.swift in Sources */,\n\t\t\t\t65D368291E18451C00D03E86 /* UI.swift in Sources */,\n\t\t\t\t65D368281E18451C00D03E86 /* NetworkObserver+Mobile.swift in Sources */,\n\t\t\t\t65D368271E18451C00D03E86 /* BackgroundObserver.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t653C9FC51D6097A40070B7A2 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t65D366D11E183F5000D03E86 /* ProcedureKitMobileTests.swift in Sources */,\n\t\t\t\t65D366CE1E183F5000D03E86 /* AlertProcedureTests.swift in Sources */,\n\t\t\t\t65D366D21E183F5000D03E86 /* TestableUIApplication.swift in Sources */,\n\t\t\t\t65D366CF1E183F5000D03E86 /* BackgroundObserverTests.swift in Sources */,\n\t\t\t\t65D366D31E183F5000D03E86 /* UIProcedureTests.swift in Sources */,\n\t\t\t\t65D366D01E183F5000D03E86 /* PresentationProcedureTests.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t653C9FEE1D609E650070B7A2 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t653C9FF71D609E660070B7A2 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t65D366E51E183F8100D03E86 /* ProcedureKitTVTests.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t653CA01C1D60A34E0070B7A2 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t65D3674B1E183FBE00D03E86 /* ProcedureKitStressTests.swift in Sources */,\n\t\t\t\t65D3674D1E183FBE00D03E86 /* ProcedureStressTests.swift in Sources */,\n\t\t\t\t65D367491E183FBE00D03E86 /* GroupStressTests.swift in Sources */,\n\t\t\t\t65D3674F1E183FBE00D03E86 /* RepeatStressTests.swift in Sources */,\n\t\t\t\t65D367471E183FBE00D03E86 /* BlockProcedureStressTests.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t653CA02B1D60A5D10070B7A2 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t65D368201E18451000D03E86 /* Process.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t653CA0341D60A5D10070B7A2 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t65D366C61E183F3900D03E86 /* ProcessProcedureTests.swift in Sources */,\n\t\t\t\t65D366C51E183F3900D03E86 /* ProcedureKitMacTests.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t653CA0551D60AA990070B7A2 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t65D368121E1844F800D03E86 /* CloudKitSupport.swift in Sources */,\n\t\t\t\t65C7BBC62085D0D3009A6D6E /* CKDiscoverUserIdentitiesOperation.swift in Sources */,\n\t\t\t\t65C7BBD52085D30C009A6D6E /* CKModifyRecordZonesOperation.swift in Sources */,\n\t\t\t\t65C7BBCE2085D294009A6D6E /* CKFetchRecordZonesOperation.swift in Sources */,\n\t\t\t\t65C7BBD72085D329009A6D6E /* CKQueryOperation.swift in Sources */,\n\t\t\t\t65C7BBC52085CF46009A6D6E /* CKDiscoverAllUserIdentitiesOperation.swift in Sources */,\n\t\t\t\t65C7BBD32085D2EE009A6D6E /* CKModifyBadgeOperation.swift in Sources */,\n\t\t\t\t65C7BBC82085D121009A6D6E /* CKFetchDatabaseChangesOperation.swift in Sources */,\n\t\t\t\t65D368111E1844F800D03E86 /* CloudKitError.swift in Sources */,\n\t\t\t\t65C7BBD02085D2B1009A6D6E /* CKFetchShareParticipantsOperation.swift in Sources */,\n\t\t\t\t65C7BBCF2085D2A3009A6D6E /* CKFetchShareMetadataOperation.swift in Sources */,\n\t\t\t\t65C7BBD22085D2E8009A6D6E /* CKMarkNotificationsReadOperation.swift in Sources */,\n\t\t\t\t65C7BBC32085CF21009A6D6E /* CKDatabaseOperation.swift in Sources */,\n\t\t\t\t65D368101E1844F800D03E86 /* CloudKitCapability.swift in Sources */,\n\t\t\t\t65D3680D1E1844F800D03E86 /* CKOperation.swift in Sources */,\n\t\t\t\t65D3680F1E1844F800D03E86 /* CloudKit.swift in Sources */,\n\t\t\t\t65C7BBD12085D2DC009A6D6E /* CKFetchSubscriptionsOperation.swift in Sources */,\n\t\t\t\t65C7BBC92085D17C009A6D6E /* CKFetchNotificationChangesOperation.swift in Sources */,\n\t\t\t\t65C7BBD42085D2F3009A6D6E /* CKModifyRecordsOperation.swift in Sources */,\n\t\t\t\t65C7BBC22085CEF4009A6D6E /* CKAcceptSharesOperation.swift in Sources */,\n\t\t\t\t65C7BBCB2085D1B4009A6D6E /* CKFetchRecordsOperation.swift in Sources */,\n\t\t\t\t65C7BBCD2085D26F009A6D6E /* CKFetchRecordZoneChangesOperation.swift in Sources */,\n\t\t\t\t65C7BBD62085D31F009A6D6E /* CKModifySubscriptionsOperation.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t653CA05E1D60AA990070B7A2 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t65D366A31E183F1900D03E86 /* CKFetchNotificationChangesOperationTests.swift in Sources */,\n\t\t\t\t65D3669C1E183F1900D03E86 /* CKDatabaseOperationTests.swift in Sources */,\n\t\t\t\t65D366A51E183F1900D03E86 /* CKFetchRecordsOperationTests.swift in Sources */,\n\t\t\t\t65D366AC1E183F1900D03E86 /* CKModifyBadgeOperationTests.swift in Sources */,\n\t\t\t\t65D366B41E183F1900D03E86 /* TestableCloudKitContainer.swift in Sources */,\n\t\t\t\t65D366A91E183F1900D03E86 /* CKFetchShareParticipantsOperationTests.swift in Sources */,\n\t\t\t\t65D366AA1E183F1900D03E86 /* CKFetchSubscriptionsOperationTests.swift in Sources */,\n\t\t\t\t65D366B11E183F1900D03E86 /* CKQueryOperationTests.swift in Sources */,\n\t\t\t\t65D366AB1E183F1900D03E86 /* CKMarkNotificationsReadOperationTests.swift in Sources */,\n\t\t\t\t65D366A81E183F1900D03E86 /* CKFetchShareMetadataOperationTests.swift in Sources */,\n\t\t\t\t65D366AE1E183F1900D03E86 /* CKModifyRecordZonesOperationTests.swift in Sources */,\n\t\t\t\t65D366A11E183F1900D03E86 /* CKFetchAllChangesTests.swift in Sources */,\n\t\t\t\t65D366B01E183F1900D03E86 /* CKOperationTests.swift in Sources */,\n\t\t\t\t65D366A61E183F1900D03E86 /* CKFetchRecordZoneChangesOperationTests.swift in Sources */,\n\t\t\t\t65D3669E1E183F1900D03E86 /* CKDiscoverAllUserIdentitiesOperationTests.swift in Sources */,\n\t\t\t\t65D366A21E183F1900D03E86 /* CKFetchDatabaseChangesOperationTests.swift in Sources */,\n\t\t\t\t65D366AF1E183F1900D03E86 /* CKModifySubscriptionsOperationTests.swift in Sources */,\n\t\t\t\t65D366AD1E183F1900D03E86 /* CKModifyRecordsOperationTests.swift in Sources */,\n\t\t\t\t65D366B21E183F1900D03E86 /* CloudKitCapabilityTests.swift in Sources */,\n\t\t\t\t65D3669F1E183F1900D03E86 /* CKDiscoverUserIdentitiesOperationTests.swift in Sources */,\n\t\t\t\t65D3669B1E183F1900D03E86 /* CKAcceptSharesOperationTests.swift in Sources */,\n\t\t\t\t65D366B31E183F1900D03E86 /* ProcedureKitCloudTests.swift in Sources */,\n\t\t\t\t65D366A71E183F1900D03E86 /* CKFetchRecordZonesOperationTests.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t659484191DAAA2B90028F83B /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t65D3681A1E18450300D03E86 /* LocationSupport.swift in Sources */,\n\t\t\t\t65D368191E18450200D03E86 /* LocationCapability.swift in Sources */,\n\t\t\t\t65D3681C1E18450300D03E86 /* ReverseGeocodeUserLocation.swift in Sources */,\n\t\t\t\t65D3681B1E18450300D03E86 /* ReverseGeocode.swift in Sources */,\n\t\t\t\t65D3681D1E18450300D03E86 /* UserLocation.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t659484221DAAA2B90028F83B /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t65D366BE1E183F2600D03E86 /* ReverseGeocodeProcedureTests.swift in Sources */,\n\t\t\t\t65D366C01E183F2600D03E86 /* TestableLocationServices.swift in Sources */,\n\t\t\t\t65D366BF1E183F2600D03E86 /* ReverseGeocodeUserLocationProcedureTests.swift in Sources */,\n\t\t\t\t65D366BC1E183F2600D03E86 /* LocationCapabilityTests.swift in Sources */,\n\t\t\t\t65D366C11E183F2600D03E86 /* UserLocationProcedureTests.swift in Sources */,\n\t\t\t\t65D366BD1E183F2600D03E86 /* ProcedureKitLocationTests.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t65A0E49420B85168002D6C8C /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t651E670520C610D800BE520E /* CoreDataHelpers.swift in Sources */,\n\t\t\t\t65A0E4B220B85213002D6C8C /* LoadCoreData.swift in Sources */,\n\t\t\t\t65068FAD20C62AE300B0A0A3 /* MakesBackgroundManagedObjectContext.swift in Sources */,\n\t\t\t\t658BE07620BC99100021F11B /* InsertManagedObjects.swift in Sources */,\n\t\t\t\t658BE07220BC72540021F11B /* MakeFetchedResultController.swift in Sources */,\n\t\t\t\t65A0E4C520BB2E51002D6C8C /* SaveManagedObjectContext.swift in Sources */,\n\t\t\t\t6573A4FC21787D0000FDA362 /* ProcessManagedObjectContext.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t65A0E49D20B85169002D6C8C /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t65A0E4C120BB18EA002D6C8C /* TestDataModel.xcdatamodeld in Sources */,\n\t\t\t\t658BE07820BCA0500021F11B /* InsertManagedObjectsProcedureTests.swift in Sources */,\n\t\t\t\t65A0E4BA20B8548D002D6C8C /* ProcedureKitCoreDataTests.swift in Sources */,\n\t\t\t\t65A0E4C320BB1975002D6C8C /* LoadCoreDataProcedureTests.swift in Sources */,\n\t\t\t\t65A0E4C820BC5540002D6C8C /* SaveManagedObjectContextProcedureTests.swift in Sources */,\n\t\t\t\t658BE07420BC77AD0021F11B /* MakeFetchedResultsControllerProcedureTests.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t65CFC5EB1D608A5500CAD875 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t65D3689C1E184AA600D03E86 /* NegatedCondition.swift in Sources */,\n\t\t\t\t65D3688E1E184AA600D03E86 /* BlockObservers.swift in Sources */,\n\t\t\t\t65D3689D1E184AA600D03E86 /* NetworkObserver.swift in Sources */,\n\t\t\t\t65D368921E184AA600D03E86 /* Condition.swift in Sources */,\n\t\t\t\t65D368901E184AA600D03E86 /* Collection+ProcedureKit.swift in Sources */,\n\t\t\t\t65D3688C1E184AA600D03E86 /* Block.swift in Sources */,\n\t\t\t\t65D3689A1E184AA600D03E86 /* Map.swift in Sources */,\n\t\t\t\t65D368A61E184AA600D03E86 /* Reachability.swift in Sources */,\n\t\t\t\t65D368951E184AA600D03E86 /* Errors.swift in Sources */,\n\t\t\t\t65D3689F1E184AA600D03E86 /* Operation+ProcedureKit.swift in Sources */,\n\t\t\t\t65D368941E184AA600D03E86 /* DispatchQueue+ProcedureKit.swift in Sources */,\n\t\t\t\t65D368A21E184AA600D03E86 /* ProcedureProcotol.swift in Sources */,\n\t\t\t\tEEE79AEB1E21B9D30030C768 /* ProcedureEventQueue.swift in Sources */,\n\t\t\t\t65D368AC1E184AA600D03E86 /* TimeoutObserver.swift in Sources */,\n\t\t\t\tEEE79AE81E21B9C90030C768 /* PendingEvent.swift in Sources */,\n\t\t\t\t65D3689E1E184AA600D03E86 /* NoFailedDependenciesCondition.swift in Sources */,\n\t\t\t\t65AB7DDA209B95B400726796 /* Batch.swift in Sources */,\n\t\t\t\t65D368A41E184AA600D03E86 /* ProcedureResult.swift in Sources */,\n\t\t\t\t6527C35C2202026800D6F498 /* Decode.swift in Sources */,\n\t\t\t\t65B9AF482116D1D4004DA82B /* Result.swift in Sources */,\n\t\t\t\t65D368A81E184AA600D03E86 /* Repeat.swift in Sources */,\n\t\t\t\t6527C35E2202171F00D6F498 /* Encode.swift in Sources */,\n\t\t\t\t65D368AB1E184AA600D03E86 /* Support.swift in Sources */,\n\t\t\t\t65D368911E184AA600D03E86 /* Composed.swift in Sources */,\n\t\t\t\t65D368981E184AA600D03E86 /* Identity.swift in Sources */,\n\t\t\t\tEEE79AEC1E21B9D30030C768 /* ProcedureFuture.swift in Sources */,\n\t\t\t\t65D368971E184AA600D03E86 /* Group.swift in Sources */,\n\t\t\t\t65D368A51E184AA600D03E86 /* Profiler.swift in Sources */,\n\t\t\t\t65D3688D1E184AA600D03E86 /* BlockCondition.swift in Sources */,\n\t\t\t\t65D3688B1E184AA600D03E86 /* AnyObserver.swift in Sources */,\n\t\t\t\t65D3688A1E184AA600D03E86 /* Any.swift in Sources */,\n\t\t\t\t65D368A01E184AA600D03E86 /* Procedure.swift in Sources */,\n\t\t\t\t65D368A31E184AA600D03E86 /* ProcedureQueue.swift in Sources */,\n\t\t\t\t65D368961E184AA600D03E86 /* Filter.swift in Sources */,\n\t\t\t\t65D368A11E184AA600D03E86 /* ProcedureObserver.swift in Sources */,\n\t\t\t\t65D368A71E184AA600D03E86 /* Reduce.swift in Sources */,\n\t\t\t\t65D3688F1E184AA600D03E86 /* Capability.swift in Sources */,\n\t\t\t\t652F903D209E3E3D00365B2D /* IgnoreErrors.swift in Sources */,\n\t\t\t\t65D368A91E184AA600D03E86 /* Retry.swift in Sources */,\n\t\t\t\t65D368931E184AA600D03E86 /* Delay.swift in Sources */,\n\t\t\t\t65D4BEF520C8A31100D85877 /* SignpostObserver.swift in Sources */,\n\t\t\t\t65D3689B1E184AA600D03E86 /* MutualExclusion.swift in Sources */,\n\t\t\t\t65D368991E184AA600D03E86 /* Logging.swift in Sources */,\n\t\t\t\t65D368AD1E184AA600D03E86 /* Transform.swift in Sources */,\n\t\t\t\t65D368AA1E184AA600D03E86 /* SilentCondition.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t65CFC5F51D608A5500CAD875 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t652F903F209E445200365B2D /* IgnoreErrorsProcedureTests.swift in Sources */,\n\t\t\t\t65D367091E183FB000D03E86 /* BlockObserverTests.swift in Sources */,\n\t\t\t\t65D367391E183FB000D03E86 /* RetryProcedureTests.swift in Sources */,\n\t\t\t\t65A1923920F88FD300E0D42C /* LoggingTests.swift in Sources */,\n\t\t\t\t65D367331E183FB000D03E86 /* ReduceProcedureTests.swift in Sources */,\n\t\t\t\t65D367251E183FB000D03E86 /* NetworkObserverTests.swift in Sources */,\n\t\t\t\t65D367191E183FB000D03E86 /* FinishingTests.swift in Sources */,\n\t\t\t\tEEE79AEE1E21C9750030C768 /* KVONotificationTests.swift in Sources */,\n\t\t\t\t65D367131E183FB000D03E86 /* ConditionTests.swift in Sources */,\n\t\t\t\t65D3673D1E183FB000D03E86 /* TimeoutObserverTests.swift in Sources */,\n\t\t\t\tEE3371091E29AD5A004272E9 /* DispatchQueueExtensionsTests.swift in Sources */,\n\t\t\t\t65D3673F1E183FB000D03E86 /* TransformProcedureTests.swift in Sources */,\n\t\t\t\t652F9015209C488600365B2D /* BatchTests.swift in Sources */,\n\t\t\t\t65D367051E183FB000D03E86 /* AnyProcedureTests.swift in Sources */,\n\t\t\t\t65D3672B1E183FB000D03E86 /* ProcedureKitTests.swift in Sources */,\n\t\t\t\t65D3670D1E183FB000D03E86 /* CancellationTests.swift in Sources */,\n\t\t\t\t65D3670F1E183FB000D03E86 /* CapabilityTests.swift in Sources */,\n\t\t\t\t65D367071E183FB000D03E86 /* BlockConditionTests.swift in Sources */,\n\t\t\t\t65D367231E183FB000D03E86 /* NegatedConditionTests.swift in Sources */,\n\t\t\t\t65D367351E183FB000D03E86 /* RepeatProcedureTests.swift in Sources */,\n\t\t\t\t65D3672D1E183FB000D03E86 /* ProcedureTests.swift in Sources */,\n\t\t\t\t65D367371E183FB000D03E86 /* ResultInjectionTests.swift in Sources */,\n\t\t\t\t65D3671F1E183FB000D03E86 /* MapProcedureTests.swift in Sources */,\n\t\t\t\t6527C360220217FE00D6F498 /* JSONCodingTests.swift in Sources */,\n\t\t\t\t65D3671B1E183FB000D03E86 /* GroupTests.swift in Sources */,\n\t\t\t\t65D3673B1E183FB000D03E86 /* SilentConditionTests.swift in Sources */,\n\t\t\t\t65D367271E183FB000D03E86 /* NoFailedDependenciesConditionTests.swift in Sources */,\n\t\t\t\t65D367311E183FB000D03E86 /* ReachabilityTests.swift in Sources */,\n\t\t\t\t65D367291E183FB000D03E86 /* ProcedureKitErrorTests.swift in Sources */,\n\t\t\t\t65D367111E183FB000D03E86 /* ComposedProcedureTests.swift in Sources */,\n\t\t\t\t65D367211E183FB000D03E86 /* MutualExclusivityTests.swift in Sources */,\n\t\t\t\t65D3672F1E183FB000D03E86 /* ProfilerTests.swift in Sources */,\n\t\t\t\t65D367171E183FB000D03E86 /* FilterProcedureTests.swift in Sources */,\n\t\t\t\t65D367151E183FB000D03E86 /* DelayProcedureTests.swift in Sources */,\n\t\t\t\t65D3670B1E183FB000D03E86 /* BlockProcedureTests.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t65CFC6111D60900000CAD875 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t65D367DC1E1844E500D03E86 /* TestProcedure.swift in Sources */,\n\t\t\t\t65D367DA1E1844E500D03E86 /* TestableNetworkReachability.swift in Sources */,\n\t\t\t\t65D367D71E1844E500D03E86 /* RepeatTestCase.swift in Sources */,\n\t\t\t\t65D367DD1E1844E500D03E86 /* XCTAsserts.swift in Sources */,\n\t\t\t\t65D367D41E1844E500D03E86 /* GroupTestCase.swift in Sources */,\n\t\t\t\t65D367D21E1844E500D03E86 /* CapabilityTestCase.swift in Sources */,\n\t\t\t\t65D367D81E1844E500D03E86 /* StressTestCase.swift in Sources */,\n\t\t\t\t65A1923B20F8900100E0D42C /* TestableLogging.swift in Sources */,\n\t\t\t\t65D367D61E1844E500D03E86 /* QueueTestDelegate.swift in Sources */,\n\t\t\t\t65D367D51E1844E500D03E86 /* ProcedureKitTestCase.swift in Sources */,\n\t\t\t\t65D367DB1E1844E500D03E86 /* TestCondition.swift in Sources */,\n\t\t\t\t65D367D91E1844E500D03E86 /* TestableNetwork.swift in Sources */,\n\t\t\t\t65D367D31E1844E500D03E86 /* ConcurrencyTestCase.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t65E5EB7F20C9CAEC00C46965 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t65E5EB8420C9CAEC00C46965 /* ProcedureKitInstruments.instrpkg in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t65ECB2C81DB4F0C000F96F46 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t65D368351E18452900D03E86 /* NetworkSupport.swift in Sources */,\n\t\t\t\t65D368321E18452900D03E86 /* NetworkData.swift in Sources */,\n\t\t\t\t65D368331E18452900D03E86 /* NetworkDownload.swift in Sources */,\n\t\t\t\t65D368361E18452900D03E86 /* NetworkUpload.swift in Sources */,\n\t\t\t\t65D368311E18452900D03E86 /* Network.swift in Sources */,\n\t\t\t\t65D368341E18452900D03E86 /* NetworkReachability.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t65ECB2D11DB4F0C000F96F46 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t65D366DC1E183F6400D03E86 /* NetworkDataProcedureTests.swift in Sources */,\n\t\t\t\t65D366E11E183F6400D03E86 /* ProcedureKitNetworkTests.swift in Sources */,\n\t\t\t\t65D366E01E183F6400D03E86 /* NetworkUploadProcedureTests.swift in Sources */,\n\t\t\t\t65D366E21E183F6400D03E86 /* URLTests.swift in Sources */,\n\t\t\t\t65D366DE1E183F6400D03E86 /* NetworkProcedureTests.swift in Sources */,\n\t\t\t\t65D366DD1E183F6400D03E86 /* NetworkDownloadProcedureTests.swift in Sources */,\n\t\t\t\t65D366DF1E183F6400D03E86 /* NetworkReachabilityTests.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\t6532DD4C1DBC18DF00B030F5 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 65CFC5EF1D608A5500CAD875 /* ProcedureKit */;\n\t\t\ttargetProxy = 6532DD4B1DBC18DF00B030F5 /* PBXContainerItemProxy */;\n\t\t};\n\t\t6532DD4E1DBC18F800B030F5 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 65CFC5EF1D608A5500CAD875 /* ProcedureKit */;\n\t\t\ttargetProxy = 6532DD4D1DBC18F800B030F5 /* PBXContainerItemProxy */;\n\t\t};\n\t\t6532DD501DBC190000B030F5 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 65CFC5EF1D608A5500CAD875 /* ProcedureKit */;\n\t\t\ttargetProxy = 6532DD4F1DBC190000B030F5 /* PBXContainerItemProxy */;\n\t\t};\n\t\t6532DD521DBC190600B030F5 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 65CFC5EF1D608A5500CAD875 /* ProcedureKit */;\n\t\t\ttargetProxy = 6532DD511DBC190600B030F5 /* PBXContainerItemProxy */;\n\t\t};\n\t\t6532DD541DBC190A00B030F5 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 65CFC5EF1D608A5500CAD875 /* ProcedureKit */;\n\t\t\ttargetProxy = 6532DD531DBC190A00B030F5 /* PBXContainerItemProxy */;\n\t\t};\n\t\t6532DD561DBC190F00B030F5 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 65CFC5EF1D608A5500CAD875 /* ProcedureKit */;\n\t\t\ttargetProxy = 6532DD551DBC190F00B030F5 /* PBXContainerItemProxy */;\n\t\t};\n\t\t6532DD581DBCDB3400B030F5 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 65CFC6151D60900000CAD875 /* TestingProcedureKit */;\n\t\t\ttargetProxy = 6532DD571DBCDB3400B030F5 /* PBXContainerItemProxy */;\n\t\t};\n\t\t65374F3320BC6553009948B4 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 65CFC5EF1D608A5500CAD875 /* ProcedureKit */;\n\t\t\ttargetProxy = 65374F3220BC6553009948B4 /* PBXContainerItemProxy */;\n\t\t};\n\t\t653C9FCC1D6097A40070B7A2 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 653C9FC01D6097A40070B7A2 /* ProcedureKitMobile */;\n\t\t\ttargetProxy = 653C9FCB1D6097A40070B7A2 /* PBXContainerItemProxy */;\n\t\t};\n\t\t653C9FDE1D60990B0070B7A2 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 65CFC5EF1D608A5500CAD875 /* ProcedureKit */;\n\t\t\ttargetProxy = 653C9FDD1D60990B0070B7A2 /* PBXContainerItemProxy */;\n\t\t};\n\t\t653C9FFE1D609E660070B7A2 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 653C9FF21D609E650070B7A2 /* ProcedureKitTV */;\n\t\t\ttargetProxy = 653C9FFD1D609E660070B7A2 /* PBXContainerItemProxy */;\n\t\t};\n\t\t653CA00E1D609F980070B7A2 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 65CFC5EF1D608A5500CAD875 /* ProcedureKit */;\n\t\t\ttargetProxy = 653CA00D1D609F980070B7A2 /* PBXContainerItemProxy */;\n\t\t};\n\t\t653CA0111D609FA50070B7A2 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 65CFC6151D60900000CAD875 /* TestingProcedureKit */;\n\t\t\ttargetProxy = 653CA0101D609FA50070B7A2 /* PBXContainerItemProxy */;\n\t\t};\n\t\t653CA0181D60A34E0070B7A2 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 65CFC6151D60900000CAD875 /* TestingProcedureKit */;\n\t\t\ttargetProxy = 653CA0191D60A34E0070B7A2 /* PBXContainerItemProxy */;\n\t\t};\n\t\t653CA01A1D60A34E0070B7A2 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 65CFC5EF1D608A5500CAD875 /* ProcedureKit */;\n\t\t\ttargetProxy = 653CA01B1D60A34E0070B7A2 /* PBXContainerItemProxy */;\n\t\t};\n\t\t653CA03B1D60A5D10070B7A2 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 653CA02F1D60A5D10070B7A2 /* ProcedureKitMac */;\n\t\t\ttargetProxy = 653CA03A1D60A5D10070B7A2 /* PBXContainerItemProxy */;\n\t\t};\n\t\t653CA04F1D60A7050070B7A2 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 65CFC5EF1D608A5500CAD875 /* ProcedureKit */;\n\t\t\ttargetProxy = 653CA04E1D60A7050070B7A2 /* PBXContainerItemProxy */;\n\t\t};\n\t\t653CA0521D60A70F0070B7A2 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 65CFC6151D60900000CAD875 /* TestingProcedureKit */;\n\t\t\ttargetProxy = 653CA0511D60A70F0070B7A2 /* PBXContainerItemProxy */;\n\t\t};\n\t\t653CA0651D60AA990070B7A2 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 653CA0591D60AA990070B7A2 /* ProcedureKitCloud */;\n\t\t\ttargetProxy = 653CA0641D60AA990070B7A2 /* PBXContainerItemProxy */;\n\t\t};\n\t\t653CA0771D60ABC30070B7A2 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 65CFC5EF1D608A5500CAD875 /* ProcedureKit */;\n\t\t\ttargetProxy = 653CA0761D60ABC30070B7A2 /* PBXContainerItemProxy */;\n\t\t};\n\t\t653CA07A1D60ABCE0070B7A2 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 65CFC6151D60900000CAD875 /* TestingProcedureKit */;\n\t\t\ttargetProxy = 653CA0791D60ABCE0070B7A2 /* PBXContainerItemProxy */;\n\t\t};\n\t\t659484291DAAA2B90028F83B /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 6594841D1DAAA2B90028F83B /* ProcedureKitLocation */;\n\t\t\ttargetProxy = 659484281DAAA2B90028F83B /* PBXContainerItemProxy */;\n\t\t};\n\t\t659484481DAAB52B0028F83B /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 65CFC5EF1D608A5500CAD875 /* ProcedureKit */;\n\t\t\ttargetProxy = 659484471DAAB52B0028F83B /* PBXContainerItemProxy */;\n\t\t};\n\t\t6594844A1DAAB5340028F83B /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 65CFC6151D60900000CAD875 /* TestingProcedureKit */;\n\t\t\ttargetProxy = 659484491DAAB5340028F83B /* PBXContainerItemProxy */;\n\t\t};\n\t\t65A0E4A420B85169002D6C8C /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 65A0E49820B85168002D6C8C /* ProcedureKitCoreData */;\n\t\t\ttargetProxy = 65A0E4A320B85169002D6C8C /* PBXContainerItemProxy */;\n\t\t};\n\t\t65A0E4BC20B85880002D6C8C /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 65CFC5EF1D608A5500CAD875 /* ProcedureKit */;\n\t\t\ttargetProxy = 65A0E4BB20B85880002D6C8C /* PBXContainerItemProxy */;\n\t\t};\n\t\t65A0E4BE20B8588F002D6C8C /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 65CFC6151D60900000CAD875 /* TestingProcedureKit */;\n\t\t\ttargetProxy = 65A0E4BD20B8588F002D6C8C /* PBXContainerItemProxy */;\n\t\t};\n\t\t65CFC5FC1D608A5500CAD875 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 65CFC5EF1D608A5500CAD875 /* ProcedureKit */;\n\t\t\ttargetProxy = 65CFC5FB1D608A5500CAD875 /* PBXContainerItemProxy */;\n\t\t};\n\t\t65CFC6221D60911400CAD875 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 65CFC6151D60900000CAD875 /* TestingProcedureKit */;\n\t\t\ttargetProxy = 65CFC6211D60911400CAD875 /* PBXContainerItemProxy */;\n\t\t};\n\t\t65CFC6251D60912400CAD875 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 65CFC5EF1D608A5500CAD875 /* ProcedureKit */;\n\t\t\ttargetProxy = 65CFC6241D60912400CAD875 /* PBXContainerItemProxy */;\n\t\t};\n\t\t65ECB2D81DB4F0C000F96F46 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 65ECB2CC1DB4F0C000F96F46 /* ProcedureKitNetwork */;\n\t\t\ttargetProxy = 65ECB2D71DB4F0C000F96F46 /* PBXContainerItemProxy */;\n\t\t};\n\t\t65ECB2F81DB50B7300F96F46 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 65CFC6151D60900000CAD875 /* TestingProcedureKit */;\n\t\t\ttargetProxy = 65ECB2F71DB50B7300F96F46 /* PBXContainerItemProxy */;\n\t\t};\n\t\t65ECB2FB1DB50B8F00F96F46 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 65CFC5EF1D608A5500CAD875 /* ProcedureKit */;\n\t\t\ttargetProxy = 65ECB2FA1DB50B8F00F96F46 /* PBXContainerItemProxy */;\n\t\t};\n/* End PBXTargetDependency section */\n\n/* Begin XCBuildConfiguration section */\n\t\t653C9FD21D6097A40070B7A2 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 653C9FDC1D6098650070B7A2 /* ProcedureKitMobile.xcconfig */;\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_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_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_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVES = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCODE_SIGN_STYLE = Manual;\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\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tDYLIB_COMPATIBILITY_VERSION = 1;\n\t\t\t\tDYLIB_CURRENT_VERSION = 1;\n\t\t\t\tDYLIB_INSTALL_NAME_BASE = \"@rpath\";\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tINSTALL_PATH = \"$(LOCAL_LIBRARY_DIR)/Frameworks\";\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;\n\t\t\t\tSWIFT_COMPILATION_MODE = singlefile;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVERSIONING_SYSTEM = \"apple-generic\";\n\t\t\t\tVERSION_INFO_PREFIX = \"\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t653C9FD31D6097A40070B7A2 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 653C9FDC1D6098650070B7A2 /* ProcedureKitMobile.xcconfig */;\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_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_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_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVES = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCODE_SIGN_STYLE = Manual;\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\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tDYLIB_COMPATIBILITY_VERSION = 1;\n\t\t\t\tDYLIB_CURRENT_VERSION = 1;\n\t\t\t\tDYLIB_INSTALL_NAME_BASE = \"@rpath\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tINSTALL_PATH = \"$(LOCAL_LIBRARY_DIR)/Frameworks\";\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSKIP_INSTALL = YES;\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\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t\tVERSIONING_SYSTEM = \"apple-generic\";\n\t\t\t\tVERSION_INFO_PREFIX = \"\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t653C9FD41D6097A40070B7A2 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 653C9FDC1D6098650070B7A2 /* ProcedureKitMobile.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_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_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVES = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 10.0;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;\n\t\t\t\tSWIFT_COMPILATION_MODE = singlefile;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTVOS_DEPLOYMENT_TARGET = 10.0;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t653C9FD51D6097A40070B7A2 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 653C9FDC1D6098650070B7A2 /* ProcedureKitMobile.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_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_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVES = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 10.0;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tSDKROOT = iphoneos;\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 = 10.0;\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t653CA0051D609E660070B7A2 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 653CA00B1D609EDA0070B7A2 /* ProcedureKitTV.xcconfig */;\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_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_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_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVES = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCODE_SIGN_STYLE = Manual;\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\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tDYLIB_COMPATIBILITY_VERSION = 1;\n\t\t\t\tDYLIB_CURRENT_VERSION = 1;\n\t\t\t\tDYLIB_INSTALL_NAME_BASE = \"@rpath\";\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tINSTALL_PATH = \"$(LOCAL_LIBRARY_DIR)/Frameworks\";\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;\n\t\t\t\tSWIFT_COMPILATION_MODE = singlefile;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tTARGETED_DEVICE_FAMILY = 3;\n\t\t\t\tVERSIONING_SYSTEM = \"apple-generic\";\n\t\t\t\tVERSION_INFO_PREFIX = \"\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t653CA0061D609E660070B7A2 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 653CA00B1D609EDA0070B7A2 /* ProcedureKitTV.xcconfig */;\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_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_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_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVES = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCODE_SIGN_STYLE = Manual;\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\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tDYLIB_COMPATIBILITY_VERSION = 1;\n\t\t\t\tDYLIB_CURRENT_VERSION = 1;\n\t\t\t\tDYLIB_INSTALL_NAME_BASE = \"@rpath\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tINSTALL_PATH = \"$(LOCAL_LIBRARY_DIR)/Frameworks\";\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t\tSWIFT_COMPILATION_MODE = wholemodule;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-O\";\n\t\t\t\tTARGETED_DEVICE_FAMILY = 3;\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t\tVERSIONING_SYSTEM = \"apple-generic\";\n\t\t\t\tVERSION_INFO_PREFIX = \"\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t653CA0081D609E660070B7A2 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 653CA00B1D609EDA0070B7A2 /* ProcedureKitTV.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_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_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVES = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tSDKROOT = appletvos;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;\n\t\t\t\tSWIFT_COMPILATION_MODE = singlefile;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTVOS_DEPLOYMENT_TARGET = 10.0;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t653CA0091D609E660070B7A2 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 653CA00B1D609EDA0070B7A2 /* ProcedureKitTV.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_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_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVES = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tSDKROOT = appletvos;\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 = 10.0;\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t653CA0231D60A34E0070B7A2 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_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_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVES = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = run.kit.procedure.ProcedureKitStressTests;\n\t\t\t\tPRODUCT_MODULE_NAME = ProcedureKitStressTests;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;\n\t\t\t\tSWIFT_COMPILATION_MODE = singlefile;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t653CA0241D60A34E0070B7A2 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_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_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVES = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = run.kit.procedure.ProcedureKitStressTests;\n\t\t\t\tPRODUCT_MODULE_NAME = ProcedureKitStressTests;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\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};\n\t\t\tname = Release;\n\t\t};\n\t\t653CA0421D60A5D10070B7A2 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 653CA0491D60A6630070B7A2 /* ProcedureKitMac.xcconfig */;\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_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_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_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVES = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCODE_SIGN_STYLE = Manual;\n\t\t\t\tCOMBINE_HIDPI_IMAGES = 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\tDEFINES_MODULE = YES;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tDYLIB_COMPATIBILITY_VERSION = 1;\n\t\t\t\tDYLIB_CURRENT_VERSION = 1;\n\t\t\t\tDYLIB_INSTALL_NAME_BASE = \"@rpath\";\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tFRAMEWORK_VERSION = A;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\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\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;\n\t\t\t\tSWIFT_COMPILATION_MODE = singlefile;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tVERSIONING_SYSTEM = \"apple-generic\";\n\t\t\t\tVERSION_INFO_PREFIX = \"\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t653CA0431D60A5D10070B7A2 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 653CA0491D60A6630070B7A2 /* ProcedureKitMac.xcconfig */;\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_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_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_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVES = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCODE_SIGN_STYLE = Manual;\n\t\t\t\tCOMBINE_HIDPI_IMAGES = 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\tDEFINES_MODULE = YES;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tDYLIB_COMPATIBILITY_VERSION = 1;\n\t\t\t\tDYLIB_CURRENT_VERSION = 1;\n\t\t\t\tDYLIB_INSTALL_NAME_BASE = \"@rpath\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tFRAMEWORK_VERSION = A;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\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\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSKIP_INSTALL = YES;\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\tVERSIONING_SYSTEM = \"apple-generic\";\n\t\t\t\tVERSION_INFO_PREFIX = \"\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t653CA0451D60A5D10070B7A2 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 653CA0491D60A6630070B7A2 /* ProcedureKitMac.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_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_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVES = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tSDKROOT = macosx;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;\n\t\t\t\tSWIFT_COMPILATION_MODE = singlefile;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t653CA0461D60A5D10070B7A2 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 653CA0491D60A6630070B7A2 /* ProcedureKitMac.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_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_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVES = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tSDKROOT = macosx;\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};\n\t\t\tname = Release;\n\t\t};\n\t\t653CA06B1D60AA9A0070B7A2 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 653CA0751D60AB2B0070B7A2 /* ProcedureKitCloud.xcconfig */;\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_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_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_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVES = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCODE_SIGN_STYLE = Manual;\n\t\t\t\tCOMBINE_HIDPI_IMAGES = 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\tDEFINES_MODULE = YES;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tDYLIB_COMPATIBILITY_VERSION = 1;\n\t\t\t\tDYLIB_CURRENT_VERSION = 1;\n\t\t\t\tDYLIB_INSTALL_NAME_BASE = \"@rpath\";\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tFRAMEWORK_VERSION = A;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\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\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;\n\t\t\t\tSWIFT_COMPILATION_MODE = singlefile;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tVERSIONING_SYSTEM = \"apple-generic\";\n\t\t\t\tVERSION_INFO_PREFIX = \"\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t653CA06C1D60AA9A0070B7A2 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 653CA0751D60AB2B0070B7A2 /* ProcedureKitCloud.xcconfig */;\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_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_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_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVES = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCODE_SIGN_STYLE = Manual;\n\t\t\t\tCOMBINE_HIDPI_IMAGES = 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\tDEFINES_MODULE = YES;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tDYLIB_COMPATIBILITY_VERSION = 1;\n\t\t\t\tDYLIB_CURRENT_VERSION = 1;\n\t\t\t\tDYLIB_INSTALL_NAME_BASE = \"@rpath\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tFRAMEWORK_VERSION = A;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\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\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSKIP_INSTALL = YES;\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\tVERSIONING_SYSTEM = \"apple-generic\";\n\t\t\t\tVERSION_INFO_PREFIX = \"\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t653CA06D1D60AA9A0070B7A2 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 653CA0751D60AB2B0070B7A2 /* ProcedureKitCloud.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_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_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVES = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 10.0;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;\n\t\t\t\tSWIFT_COMPILATION_MODE = singlefile;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTVOS_DEPLOYMENT_TARGET = 10.0;\n\t\t\t\tWATCHOS_DEPLOYMENT_TARGET = 3.0;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t653CA06E1D60AA9A0070B7A2 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 653CA0751D60AB2B0070B7A2 /* ProcedureKitCloud.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_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_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVES = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 10.0;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\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 = 10.0;\n\t\t\t\tWATCHOS_DEPLOYMENT_TARGET = 3.0;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t6594842F1DAAA2B90028F83B /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 659484371DAAA3A60028F83B /* ProcedureKitLocation.xcconfig */;\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_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_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_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVES = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCODE_SIGN_STYLE = Manual;\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\tDEFINES_MODULE = YES;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tDYLIB_COMPATIBILITY_VERSION = 1;\n\t\t\t\tDYLIB_CURRENT_VERSION = 1;\n\t\t\t\tDYLIB_INSTALL_NAME_BASE = \"@rpath\";\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\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\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;\n\t\t\t\tSWIFT_COMPILATION_MODE = singlefile;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVERSIONING_SYSTEM = \"apple-generic\";\n\t\t\t\tVERSION_INFO_PREFIX = \"\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t659484301DAAA2B90028F83B /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 659484371DAAA3A60028F83B /* ProcedureKitLocation.xcconfig */;\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_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_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_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVES = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCODE_SIGN_STYLE = Manual;\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\tDEFINES_MODULE = YES;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tDYLIB_COMPATIBILITY_VERSION = 1;\n\t\t\t\tDYLIB_CURRENT_VERSION = 1;\n\t\t\t\tDYLIB_INSTALL_NAME_BASE = \"@rpath\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\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\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSKIP_INSTALL = YES;\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\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t\tVERSIONING_SYSTEM = \"apple-generic\";\n\t\t\t\tVERSION_INFO_PREFIX = \"\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t659484311DAAA2B90028F83B /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 659484371DAAA3A60028F83B /* ProcedureKitLocation.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_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_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVES = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;\n\t\t\t\tSWIFT_COMPILATION_MODE = singlefile;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t659484321DAAA2B90028F83B /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 659484371DAAA3A60028F83B /* ProcedureKitLocation.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_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_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVES = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\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\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t65A0E4AA20B85169002D6C8C /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 65A0E4B520B85297002D6C8C /* ProcedureKitCoreData.xcconfig */;\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_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_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_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_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\tCOMBINE_HIDPI_IMAGES = 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\tDEFINES_MODULE = YES;\n\t\t\t\tDYLIB_COMPATIBILITY_VERSION = 1;\n\t\t\t\tDYLIB_CURRENT_VERSION = 1;\n\t\t\t\tDYLIB_INSTALL_NAME_BASE = \"@rpath\";\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tFRAMEWORK_VERSION = A;\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\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\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME:c99extidentifier)\";\n\t\t\t\tSKIP_INSTALL = YES;\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\tVERSIONING_SYSTEM = \"apple-generic\";\n\t\t\t\tVERSION_INFO_PREFIX = \"\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t65A0E4AB20B85169002D6C8C /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 65A0E4B520B85297002D6C8C /* ProcedureKitCoreData.xcconfig */;\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_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_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_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_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\tCOMBINE_HIDPI_IMAGES = 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\tDEFINES_MODULE = YES;\n\t\t\t\tDYLIB_COMPATIBILITY_VERSION = 1;\n\t\t\t\tDYLIB_CURRENT_VERSION = 1;\n\t\t\t\tDYLIB_INSTALL_NAME_BASE = \"@rpath\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tFRAMEWORK_VERSION = A;\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\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\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME:c99extidentifier)\";\n\t\t\t\tSKIP_INSTALL = YES;\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\tVERSIONING_SYSTEM = \"apple-generic\";\n\t\t\t\tVERSION_INFO_PREFIX = \"\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t65A0E4AC20B85169002D6C8C /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 65A0E4B520B85297002D6C8C /* ProcedureKitCoreData.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;\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_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_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_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\tCODE_SIGN_STYLE = Manual;\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\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\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\tMTL_ENABLE_DEBUG_INFO = YES;\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};\n\t\t\tname = Debug;\n\t\t};\n\t\t65A0E4AD20B85169002D6C8C /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 65A0E4B520B85297002D6C8C /* ProcedureKitCoreData.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;\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_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_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_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\tCODE_SIGN_STYLE = Manual;\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = 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\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\tMTL_ENABLE_DEBUG_INFO = NO;\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};\n\t\t\tname = Release;\n\t\t};\n\t\t65CFC5E91D608A1A00CAD875 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 65CFC60E1D608AE200CAD875 /* ProcedureKit.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"\";\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t65CFC5EA1D608A1A00CAD875 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 65CFC60E1D608AE200CAD875 /* ProcedureKit.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"\";\n\t\t\t\tSWIFT_COMPILATION_MODE = wholemodule;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t65CFC6021D608A5500CAD875 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVES = YES;\n\t\t\t\tCODE_SIGN_STYLE = Manual;\n\t\t\t\tCOMBINE_HIDPI_IMAGES = 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\tDEFINES_MODULE = YES;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tDYLIB_COMPATIBILITY_VERSION = 1;\n\t\t\t\tDYLIB_CURRENT_VERSION = 1;\n\t\t\t\tDYLIB_INSTALL_NAME_BASE = \"@rpath\";\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tFRAMEWORK_VERSION = A;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\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\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;\n\t\t\t\tSWIFT_COMPILATION_MODE = singlefile;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tVERSIONING_SYSTEM = \"apple-generic\";\n\t\t\t\tVERSION_INFO_PREFIX = \"\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t65CFC6031D608A5500CAD875 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVES = YES;\n\t\t\t\tCODE_SIGN_STYLE = Manual;\n\t\t\t\tCOMBINE_HIDPI_IMAGES = 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\tDEFINES_MODULE = YES;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tDYLIB_COMPATIBILITY_VERSION = 1;\n\t\t\t\tDYLIB_CURRENT_VERSION = 1;\n\t\t\t\tDYLIB_INSTALL_NAME_BASE = \"@rpath\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tFRAMEWORK_VERSION = A;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\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\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSKIP_INSTALL = YES;\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\tVERSIONING_SYSTEM = \"apple-generic\";\n\t\t\t\tVERSION_INFO_PREFIX = \"\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t65CFC6041D608A5500CAD875 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_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_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVES = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;\n\t\t\t\tSWIFT_COMPILATION_MODE = singlefile;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t65CFC6051D608A5500CAD875 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_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_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVES = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\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};\n\t\t\tname = Release;\n\t\t};\n\t\t65CFC61B1D60900000CAD875 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 65CFC6201D60905000CAD875 /* TestingProcedureKit.xcconfig */;\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_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_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_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVES = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCODE_SIGN_STYLE = Manual;\n\t\t\t\tCOMBINE_HIDPI_IMAGES = 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\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tDYLIB_COMPATIBILITY_VERSION = 1;\n\t\t\t\tDYLIB_CURRENT_VERSION = 1;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tFRAMEWORK_VERSION = A;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;\n\t\t\t\tSWIFT_COMPILATION_MODE = singlefile;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tVERSIONING_SYSTEM = \"apple-generic\";\n\t\t\t\tVERSION_INFO_PREFIX = \"\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t65CFC61C1D60900000CAD875 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 65CFC6201D60905000CAD875 /* TestingProcedureKit.xcconfig */;\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_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_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_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVES = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCODE_SIGN_STYLE = Manual;\n\t\t\t\tCOMBINE_HIDPI_IMAGES = 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\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tDYLIB_COMPATIBILITY_VERSION = 1;\n\t\t\t\tDYLIB_CURRENT_VERSION = 1;\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tFRAMEWORK_VERSION = A;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSKIP_INSTALL = YES;\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\tVERSIONING_SYSTEM = \"apple-generic\";\n\t\t\t\tVERSION_INFO_PREFIX = \"\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t65E5EB8620C9CAEC00C46965 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tINSTALL_PATH = \"$(LOCAL_LIBRARY_DIR)/Instruments/Packages\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tVERSIONING_SYSTEM = \"\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t65E5EB8720C9CAEC00C46965 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tINSTALL_PATH = \"$(LOCAL_LIBRARY_DIR)/Instruments/Packages\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tVERSIONING_SYSTEM = \"\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t65ECB2DF1DB4F0C000F96F46 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 65ECB2E91DB4F1A200F96F46 /* ProcedureKitNetwork.xcconfig */;\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_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_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_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVES = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCODE_SIGN_STYLE = Manual;\n\t\t\t\tCOMBINE_HIDPI_IMAGES = 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\tDEFINES_MODULE = YES;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tDYLIB_COMPATIBILITY_VERSION = 1;\n\t\t\t\tDYLIB_CURRENT_VERSION = 1;\n\t\t\t\tDYLIB_INSTALL_NAME_BASE = \"@rpath\";\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tFRAMEWORK_VERSION = A;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\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\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;\n\t\t\t\tSWIFT_COMPILATION_MODE = singlefile;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tVERSIONING_SYSTEM = \"apple-generic\";\n\t\t\t\tVERSION_INFO_PREFIX = \"\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t65ECB2E01DB4F0C000F96F46 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 65ECB2E91DB4F1A200F96F46 /* ProcedureKitNetwork.xcconfig */;\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_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_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_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVES = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCODE_SIGN_STYLE = Manual;\n\t\t\t\tCOMBINE_HIDPI_IMAGES = 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\tDEFINES_MODULE = YES;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tDYLIB_COMPATIBILITY_VERSION = 1;\n\t\t\t\tDYLIB_CURRENT_VERSION = 1;\n\t\t\t\tDYLIB_INSTALL_NAME_BASE = \"@rpath\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tFRAMEWORK_VERSION = A;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\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\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSKIP_INSTALL = YES;\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\tVERSIONING_SYSTEM = \"apple-generic\";\n\t\t\t\tVERSION_INFO_PREFIX = \"\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t65ECB2E21DB4F0C000F96F46 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 65ECB2E91DB4F1A200F96F46 /* ProcedureKitNetwork.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_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_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVES = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;\n\t\t\t\tSWIFT_COMPILATION_MODE = singlefile;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t65ECB2E31DB4F0C000F96F46 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 65ECB2E91DB4F1A200F96F46 /* ProcedureKitNetwork.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_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_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVES = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\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};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t653C9FD61D6097A40070B7A2 /* Build configuration list for PBXNativeTarget \"ProcedureKitMobile\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t653C9FD21D6097A40070B7A2 /* Debug */,\n\t\t\t\t653C9FD31D6097A40070B7A2 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t653C9FD71D6097A40070B7A2 /* Build configuration list for PBXNativeTarget \"ProcedureKitMobileTests\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t653C9FD41D6097A40070B7A2 /* Debug */,\n\t\t\t\t653C9FD51D6097A40070B7A2 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t653CA0041D609E660070B7A2 /* Build configuration list for PBXNativeTarget \"ProcedureKitTV\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t653CA0051D609E660070B7A2 /* Debug */,\n\t\t\t\t653CA0061D609E660070B7A2 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t653CA0071D609E660070B7A2 /* Build configuration list for PBXNativeTarget \"ProcedureKitTVTests\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t653CA0081D609E660070B7A2 /* Debug */,\n\t\t\t\t653CA0091D609E660070B7A2 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t653CA0221D60A34E0070B7A2 /* Build configuration list for PBXNativeTarget \"ProcedureKitStressTests\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t653CA0231D60A34E0070B7A2 /* Debug */,\n\t\t\t\t653CA0241D60A34E0070B7A2 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t653CA0411D60A5D10070B7A2 /* Build configuration list for PBXNativeTarget \"ProcedureKitMac\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t653CA0421D60A5D10070B7A2 /* Debug */,\n\t\t\t\t653CA0431D60A5D10070B7A2 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t653CA0441D60A5D10070B7A2 /* Build configuration list for PBXNativeTarget \"ProcedureKitMacTests\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t653CA0451D60A5D10070B7A2 /* Debug */,\n\t\t\t\t653CA0461D60A5D10070B7A2 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t653CA06F1D60AA9A0070B7A2 /* Build configuration list for PBXNativeTarget \"ProcedureKitCloud\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t653CA06B1D60AA9A0070B7A2 /* Debug */,\n\t\t\t\t653CA06C1D60AA9A0070B7A2 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t653CA0701D60AA9A0070B7A2 /* Build configuration list for PBXNativeTarget \"ProcedureKitCloudTests\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t653CA06D1D60AA9A0070B7A2 /* Debug */,\n\t\t\t\t653CA06E1D60AA9A0070B7A2 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t659484331DAAA2B90028F83B /* Build configuration list for PBXNativeTarget \"ProcedureKitLocation\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t6594842F1DAAA2B90028F83B /* Debug */,\n\t\t\t\t659484301DAAA2B90028F83B /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t659484341DAAA2B90028F83B /* Build configuration list for PBXNativeTarget \"ProcedureKitLocationTests\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t659484311DAAA2B90028F83B /* Debug */,\n\t\t\t\t659484321DAAA2B90028F83B /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t65A0E4AE20B85169002D6C8C /* Build configuration list for PBXNativeTarget \"ProcedureKitCoreData\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t65A0E4AA20B85169002D6C8C /* Debug */,\n\t\t\t\t65A0E4AB20B85169002D6C8C /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t65A0E4AF20B85169002D6C8C /* Build configuration list for PBXNativeTarget \"ProcedureKitCoreDataTests\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t65A0E4AC20B85169002D6C8C /* Debug */,\n\t\t\t\t65A0E4AD20B85169002D6C8C /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t65CFC5E81D608A1A00CAD875 /* Build configuration list for PBXProject \"ProcedureKit\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t65CFC5E91D608A1A00CAD875 /* Debug */,\n\t\t\t\t65CFC5EA1D608A1A00CAD875 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t65CFC6061D608A5500CAD875 /* Build configuration list for PBXNativeTarget \"ProcedureKit\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t65CFC6021D608A5500CAD875 /* Debug */,\n\t\t\t\t65CFC6031D608A5500CAD875 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t65CFC6071D608A5500CAD875 /* Build configuration list for PBXNativeTarget \"ProcedureKitTests\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t65CFC6041D608A5500CAD875 /* Debug */,\n\t\t\t\t65CFC6051D608A5500CAD875 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t65CFC61D1D60900000CAD875 /* Build configuration list for PBXNativeTarget \"TestingProcedureKit\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t65CFC61B1D60900000CAD875 /* Debug */,\n\t\t\t\t65CFC61C1D60900000CAD875 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t65E5EB8520C9CAEC00C46965 /* Build configuration list for PBXNativeTarget \"ProcedureKitInstruments\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t65E5EB8620C9CAEC00C46965 /* Debug */,\n\t\t\t\t65E5EB8720C9CAEC00C46965 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t65ECB2DE1DB4F0C000F96F46 /* Build configuration list for PBXNativeTarget \"ProcedureKitNetwork\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t65ECB2DF1DB4F0C000F96F46 /* Debug */,\n\t\t\t\t65ECB2E01DB4F0C000F96F46 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t65ECB2E11DB4F0C000F96F46 /* Build configuration list for PBXNativeTarget \"ProcedureKitNetworkTests\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t65ECB2E21DB4F0C000F96F46 /* Debug */,\n\t\t\t\t65ECB2E31DB4F0C000F96F46 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\n/* Begin XCVersionGroup section */\n\t\t65A0E4BF20BB18EA002D6C8C /* TestDataModel.xcdatamodeld */ = {\n\t\t\tisa = XCVersionGroup;\n\t\t\tchildren = (\n\t\t\t\t65A0E4C020BB18EA002D6C8C /* TestDataModel.xcdatamodel */,\n\t\t\t);\n\t\t\tcurrentVersion = 65A0E4C020BB18EA002D6C8C /* TestDataModel.xcdatamodel */;\n\t\t\tpath = TestDataModel.xcdatamodeld;\n\t\t\tsourceTree = \"<group>\";\n\t\t\tversionGroupType = wrapper.xcdatamodel;\n\t\t};\n/* End XCVersionGroup section */\n\t};\n\trootObject = 65CFC5E51D608A1A00CAD875 /* Project object */;\n}\n"
  },
  {
    "path": "ProcedureKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"self:ProcedureKit.xcodeproj\">\n   </FileRef>\n</Workspace>\n"
  },
  {
    "path": "ProcedureKit.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>IDEDidComputeMac32BitWarning</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "ProcedureKit.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings",
    "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>BuildSystemType</key>\n\t<string>Latest</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "ProcedureKit.xcodeproj/xcshareddata/xcbaselines/653CA0171D60A34E0070B7A2.xcbaseline/6DA284CC-3922-4524-95E8-F180E4F487EF.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>classNames</key>\n\t<dict>\n\t\t<key>ProcedureCompletionBlockStressTest</key>\n\t\t<dict>\n\t\t\t<key>test__completion_blocks()</key>\n\t\t\t<dict>\n\t\t\t\t<key>com.apple.XCTPerformanceMetric_WallClockTime</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>baselineAverage</key>\n\t\t\t\t\t<real>19.113</real>\n\t\t\t\t\t<key>baselineIntegrationDisplayName</key>\n\t\t\t\t\t<string>13 Sep 2016, 22:08:14</string>\n\t\t\t\t\t<key>maxPercentRelativeStandardDeviation</key>\n\t\t\t\t\t<real>15</real>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t</dict>\n\t</dict>\n</dict>\n</plist>\n"
  },
  {
    "path": "ProcedureKit.xcodeproj/xcshareddata/xcbaselines/653CA0171D60A34E0070B7A2.xcbaseline/D985A880-E116-4CF0-97E0-2E8A8D0C0F69.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>classNames</key>\n\t<dict>\n\t\t<key>ProcedureCompletionBlockStressTest</key>\n\t\t<dict>\n\t\t\t<key>test__completion_blocks()</key>\n\t\t\t<dict>\n\t\t\t\t<key>com.apple.XCTPerformanceMetric_WallClockTime</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>baselineAverage</key>\n\t\t\t\t\t<real>4.442</real>\n\t\t\t\t\t<key>baselineIntegrationDisplayName</key>\n\t\t\t\t\t<string>17 Sep 2016, 18:25:49</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t</dict>\n\t</dict>\n</dict>\n</plist>\n"
  },
  {
    "path": "ProcedureKit.xcodeproj/xcshareddata/xcbaselines/653CA0171D60A34E0070B7A2.xcbaseline/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>runDestinationsByUUID</key>\n\t<dict>\n\t\t<key>6DA284CC-3922-4524-95E8-F180E4F487EF</key>\n\t\t<dict>\n\t\t\t<key>localComputer</key>\n\t\t\t<dict>\n\t\t\t\t<key>busSpeedInMHz</key>\n\t\t\t\t<integer>100</integer>\n\t\t\t\t<key>cpuCount</key>\n\t\t\t\t<integer>1</integer>\n\t\t\t\t<key>cpuKind</key>\n\t\t\t\t<string>Intel Core i7</string>\n\t\t\t\t<key>cpuSpeedInMHz</key>\n\t\t\t\t<integer>4000</integer>\n\t\t\t\t<key>logicalCPUCoresPerPackage</key>\n\t\t\t\t<integer>8</integer>\n\t\t\t\t<key>modelCode</key>\n\t\t\t\t<string>iMac17,1</string>\n\t\t\t\t<key>physicalCPUCoresPerPackage</key>\n\t\t\t\t<integer>4</integer>\n\t\t\t\t<key>platformIdentifier</key>\n\t\t\t\t<string>com.apple.platform.macosx</string>\n\t\t\t</dict>\n\t\t\t<key>targetArchitecture</key>\n\t\t\t<string>x86_64</string>\n\t\t</dict>\n\t\t<key>D985A880-E116-4CF0-97E0-2E8A8D0C0F69</key>\n\t\t<dict>\n\t\t\t<key>localComputer</key>\n\t\t\t<dict>\n\t\t\t\t<key>busSpeedInMHz</key>\n\t\t\t\t<integer>100</integer>\n\t\t\t\t<key>cpuCount</key>\n\t\t\t\t<integer>1</integer>\n\t\t\t\t<key>cpuKind</key>\n\t\t\t\t<string>6-Core Intel Xeon E5</string>\n\t\t\t\t<key>cpuSpeedInMHz</key>\n\t\t\t\t<integer>3500</integer>\n\t\t\t\t<key>logicalCPUCoresPerPackage</key>\n\t\t\t\t<integer>12</integer>\n\t\t\t\t<key>modelCode</key>\n\t\t\t\t<string>MacPro6,1</string>\n\t\t\t\t<key>physicalCPUCoresPerPackage</key>\n\t\t\t\t<integer>6</integer>\n\t\t\t\t<key>platformIdentifier</key>\n\t\t\t\t<string>com.apple.platform.macosx</string>\n\t\t\t</dict>\n\t\t\t<key>targetArchitecture</key>\n\t\t\t<string>x86_64</string>\n\t\t</dict>\n\t</dict>\n</dict>\n</plist>\n"
  },
  {
    "path": "ProcedureKit.xcodeproj/xcshareddata/xcschemes/Mac.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1020\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"NO\"\n            buildForArchiving = \"NO\"\n            buildForAnalyzing = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"65CFC5F81D608A5500CAD875\"\n               BuildableName = \"ProcedureKitTests.xctest\"\n               BlueprintName = \"ProcedureKitTests\"\n               ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"NO\"\n            buildForArchiving = \"NO\"\n            buildForAnalyzing = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"653CA0611D60AA990070B7A2\"\n               BuildableName = \"ProcedureKitCloudTests.xctest\"\n               BlueprintName = \"ProcedureKitCloudTests\"\n               ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"NO\"\n            buildForArchiving = \"NO\"\n            buildForAnalyzing = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"65A0E4A020B85169002D6C8C\"\n               BuildableName = \"ProcedureKitCoreDataTests.xctest\"\n               BlueprintName = \"ProcedureKitCoreDataTests\"\n               ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"NO\"\n            buildForArchiving = \"NO\"\n            buildForAnalyzing = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"659484251DAAA2B90028F83B\"\n               BuildableName = \"ProcedureKitLocationTests.xctest\"\n               BlueprintName = \"ProcedureKitLocationTests\"\n               ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"NO\"\n            buildForArchiving = \"NO\"\n            buildForAnalyzing = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"653CA0371D60A5D10070B7A2\"\n               BuildableName = \"ProcedureKitMacTests.xctest\"\n               BlueprintName = \"ProcedureKitMacTests\"\n               ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"NO\"\n            buildForArchiving = \"NO\"\n            buildForAnalyzing = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"65ECB2D41DB4F0C000F96F46\"\n               BuildableName = \"ProcedureKitNetworkTests.xctest\"\n               BlueprintName = \"ProcedureKitNetworkTests\"\n               ReferencedContainer = \"container:ProcedureKit.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      codeCoverageEnabled = \"YES\"\n      onlyGenerateCoverageForSpecifiedTargets = \"YES\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <CodeCoverageTargets>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"65CFC5EF1D608A5500CAD875\"\n            BuildableName = \"ProcedureKit.framework\"\n            BlueprintName = \"ProcedureKit\"\n            ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n         </BuildableReference>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"65A0E49820B85168002D6C8C\"\n            BuildableName = \"ProcedureKitCoreData.framework\"\n            BlueprintName = \"ProcedureKitCoreData\"\n            ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n         </BuildableReference>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"6594841D1DAAA2B90028F83B\"\n            BuildableName = \"ProcedureKitLocation.framework\"\n            BlueprintName = \"ProcedureKitLocation\"\n            ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n         </BuildableReference>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"653CA02F1D60A5D10070B7A2\"\n            BuildableName = \"ProcedureKitMac.framework\"\n            BlueprintName = \"ProcedureKitMac\"\n            ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n         </BuildableReference>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"65ECB2CC1DB4F0C000F96F46\"\n            BuildableName = \"ProcedureKitNetwork.framework\"\n            BlueprintName = \"ProcedureKitNetwork\"\n            ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n         </BuildableReference>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"653CA0591D60AA990070B7A2\"\n            BuildableName = \"ProcedureKitCloud.framework\"\n            BlueprintName = \"ProcedureKitCloud\"\n            ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n         </BuildableReference>\n      </CodeCoverageTargets>\n      <Testables>\n         <TestableReference\n            skipped = \"NO\"\n            testExecutionOrdering = \"random\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"65CFC5F81D608A5500CAD875\"\n               BuildableName = \"ProcedureKitTests.xctest\"\n               BlueprintName = \"ProcedureKitTests\"\n               ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n         <TestableReference\n            skipped = \"NO\"\n            testExecutionOrdering = \"random\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"653CA0611D60AA990070B7A2\"\n               BuildableName = \"ProcedureKitCloudTests.xctest\"\n               BlueprintName = \"ProcedureKitCloudTests\"\n               ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n         <TestableReference\n            skipped = \"NO\"\n            testExecutionOrdering = \"random\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"65A0E4A020B85169002D6C8C\"\n               BuildableName = \"ProcedureKitCoreDataTests.xctest\"\n               BlueprintName = \"ProcedureKitCoreDataTests\"\n               ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n         <TestableReference\n            skipped = \"NO\"\n            testExecutionOrdering = \"random\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"659484251DAAA2B90028F83B\"\n               BuildableName = \"ProcedureKitLocationTests.xctest\"\n               BlueprintName = \"ProcedureKitLocationTests\"\n               ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n         <TestableReference\n            skipped = \"NO\"\n            testExecutionOrdering = \"random\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"653CA0371D60A5D10070B7A2\"\n               BuildableName = \"ProcedureKitMacTests.xctest\"\n               BlueprintName = \"ProcedureKitMacTests\"\n               ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n         <TestableReference\n            skipped = \"NO\"\n            testExecutionOrdering = \"random\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"65ECB2D41DB4F0C000F96F46\"\n               BuildableName = \"ProcedureKitNetworkTests.xctest\"\n               BlueprintName = \"ProcedureKitNetworkTests\"\n               ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n      </Testables>\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"65CFC5F81D608A5500CAD875\"\n            BuildableName = \"ProcedureKitTests.xctest\"\n            BlueprintName = \"ProcedureKitTests\"\n            ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"65CFC5F81D608A5500CAD875\"\n            BuildableName = \"ProcedureKitTests.xctest\"\n            BlueprintName = \"ProcedureKitTests\"\n            ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "ProcedureKit.xcodeproj/xcshareddata/xcschemes/ProcedureKit.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1020\"\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 = \"65CFC5EF1D608A5500CAD875\"\n               BuildableName = \"ProcedureKit.framework\"\n               BlueprintName = \"ProcedureKit\"\n               ReferencedContainer = \"container:ProcedureKit.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      enableThreadSanitizer = \"YES\"\n      enableUBSanitizer = \"YES\"\n      codeCoverageEnabled = \"YES\"\n      onlyGenerateCoverageForSpecifiedTargets = \"YES\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <CodeCoverageTargets>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"65CFC5EF1D608A5500CAD875\"\n            BuildableName = \"ProcedureKit.framework\"\n            BlueprintName = \"ProcedureKit\"\n            ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n         </BuildableReference>\n      </CodeCoverageTargets>\n      <Testables>\n         <TestableReference\n            skipped = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"65CFC5F81D608A5500CAD875\"\n               BuildableName = \"ProcedureKitTests.xctest\"\n               BlueprintName = \"ProcedureKitTests\"\n               ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n      </Testables>\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"65CFC5EF1D608A5500CAD875\"\n            BuildableName = \"ProcedureKit.framework\"\n            BlueprintName = \"ProcedureKit\"\n            ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"65CFC5EF1D608A5500CAD875\"\n            BuildableName = \"ProcedureKit.framework\"\n            BlueprintName = \"ProcedureKit\"\n            ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"65CFC5EF1D608A5500CAD875\"\n            BuildableName = \"ProcedureKit.framework\"\n            BlueprintName = \"ProcedureKit\"\n            ReferencedContainer = \"container:ProcedureKit.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": "ProcedureKit.xcodeproj/xcshareddata/xcschemes/ProcedureKitCloud.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1020\"\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 = \"653CA0591D60AA990070B7A2\"\n               BuildableName = \"ProcedureKitCloud.framework\"\n               BlueprintName = \"ProcedureKitCloud\"\n               ReferencedContainer = \"container:ProcedureKit.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      enableThreadSanitizer = \"YES\"\n      enableUBSanitizer = \"YES\"\n      codeCoverageEnabled = \"YES\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <Testables>\n         <TestableReference\n            skipped = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"653CA0611D60AA990070B7A2\"\n               BuildableName = \"ProcedureKitCloudTests.xctest\"\n               BlueprintName = \"ProcedureKitCloudTests\"\n               ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n      </Testables>\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"653CA0591D60AA990070B7A2\"\n            BuildableName = \"ProcedureKitCloud.framework\"\n            BlueprintName = \"ProcedureKitCloud\"\n            ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"653CA0591D60AA990070B7A2\"\n            BuildableName = \"ProcedureKitCloud.framework\"\n            BlueprintName = \"ProcedureKitCloud\"\n            ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"653CA0591D60AA990070B7A2\"\n            BuildableName = \"ProcedureKitCloud.framework\"\n            BlueprintName = \"ProcedureKitCloud\"\n            ReferencedContainer = \"container:ProcedureKit.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": "ProcedureKit.xcodeproj/xcshareddata/xcschemes/ProcedureKitCoreData.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1020\"\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 = \"65A0E49820B85168002D6C8C\"\n               BuildableName = \"ProcedureKitCoreData.framework\"\n               BlueprintName = \"ProcedureKitCoreData\"\n               ReferencedContainer = \"container:ProcedureKit.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      codeCoverageEnabled = \"YES\"\n      onlyGenerateCoverageForSpecifiedTargets = \"YES\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <CodeCoverageTargets>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"65A0E49820B85168002D6C8C\"\n            BuildableName = \"ProcedureKitCoreData.framework\"\n            BlueprintName = \"ProcedureKitCoreData\"\n            ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n         </BuildableReference>\n      </CodeCoverageTargets>\n      <Testables>\n         <TestableReference\n            skipped = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"65A0E4A020B85169002D6C8C\"\n               BuildableName = \"ProcedureKitCoreDataTests.xctest\"\n               BlueprintName = \"ProcedureKitCoreDataTests\"\n               ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n      </Testables>\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"65A0E49820B85168002D6C8C\"\n            BuildableName = \"ProcedureKitCoreData.framework\"\n            BlueprintName = \"ProcedureKitCoreData\"\n            ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"65A0E49820B85168002D6C8C\"\n            BuildableName = \"ProcedureKitCoreData.framework\"\n            BlueprintName = \"ProcedureKitCoreData\"\n            ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"65A0E49820B85168002D6C8C\"\n            BuildableName = \"ProcedureKitCoreData.framework\"\n            BlueprintName = \"ProcedureKitCoreData\"\n            ReferencedContainer = \"container:ProcedureKit.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": "ProcedureKit.xcodeproj/xcshareddata/xcschemes/ProcedureKitLocation.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1020\"\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 = \"6594841D1DAAA2B90028F83B\"\n               BuildableName = \"ProcedureKitLocation.framework\"\n               BlueprintName = \"ProcedureKitLocation\"\n               ReferencedContainer = \"container:ProcedureKit.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      enableThreadSanitizer = \"YES\"\n      enableUBSanitizer = \"YES\"\n      codeCoverageEnabled = \"YES\"\n      onlyGenerateCoverageForSpecifiedTargets = \"YES\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <CodeCoverageTargets>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"6594841D1DAAA2B90028F83B\"\n            BuildableName = \"ProcedureKitLocation.framework\"\n            BlueprintName = \"ProcedureKitLocation\"\n            ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n         </BuildableReference>\n      </CodeCoverageTargets>\n      <Testables>\n         <TestableReference\n            skipped = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"659484251DAAA2B90028F83B\"\n               BuildableName = \"ProcedureKitLocationTests.xctest\"\n               BlueprintName = \"ProcedureKitLocationTests\"\n               ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n      </Testables>\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"6594841D1DAAA2B90028F83B\"\n            BuildableName = \"ProcedureKitLocation.framework\"\n            BlueprintName = \"ProcedureKitLocation\"\n            ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"6594841D1DAAA2B90028F83B\"\n            BuildableName = \"ProcedureKitLocation.framework\"\n            BlueprintName = \"ProcedureKitLocation\"\n            ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"6594841D1DAAA2B90028F83B\"\n            BuildableName = \"ProcedureKitLocation.framework\"\n            BlueprintName = \"ProcedureKitLocation\"\n            ReferencedContainer = \"container:ProcedureKit.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": "ProcedureKit.xcodeproj/xcshareddata/xcschemes/ProcedureKitMac.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1020\"\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 = \"653CA02F1D60A5D10070B7A2\"\n               BuildableName = \"ProcedureKitMac.framework\"\n               BlueprintName = \"ProcedureKitMac\"\n               ReferencedContainer = \"container:ProcedureKit.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      enableThreadSanitizer = \"YES\"\n      enableUBSanitizer = \"YES\"\n      codeCoverageEnabled = \"YES\"\n      onlyGenerateCoverageForSpecifiedTargets = \"YES\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <CodeCoverageTargets>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"653CA02F1D60A5D10070B7A2\"\n            BuildableName = \"ProcedureKitMac.framework\"\n            BlueprintName = \"ProcedureKitMac\"\n            ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n         </BuildableReference>\n      </CodeCoverageTargets>\n      <Testables>\n         <TestableReference\n            skipped = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"653CA0371D60A5D10070B7A2\"\n               BuildableName = \"ProcedureKitMacTests.xctest\"\n               BlueprintName = \"ProcedureKitMacTests\"\n               ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n      </Testables>\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"653CA02F1D60A5D10070B7A2\"\n            BuildableName = \"ProcedureKitMac.framework\"\n            BlueprintName = \"ProcedureKitMac\"\n            ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"653CA02F1D60A5D10070B7A2\"\n            BuildableName = \"ProcedureKitMac.framework\"\n            BlueprintName = \"ProcedureKitMac\"\n            ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"653CA02F1D60A5D10070B7A2\"\n            BuildableName = \"ProcedureKitMac.framework\"\n            BlueprintName = \"ProcedureKitMac\"\n            ReferencedContainer = \"container:ProcedureKit.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": "ProcedureKit.xcodeproj/xcshareddata/xcschemes/ProcedureKitMobile.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1020\"\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 = \"653C9FC01D6097A40070B7A2\"\n               BuildableName = \"ProcedureKitMobile.framework\"\n               BlueprintName = \"ProcedureKitMobile\"\n               ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"NO\"\n            buildForProfiling = \"NO\"\n            buildForArchiving = \"NO\"\n            buildForAnalyzing = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"653C9FC81D6097A40070B7A2\"\n               BuildableName = \"ProcedureKitMobileTests.xctest\"\n               BlueprintName = \"ProcedureKitMobileTests\"\n               ReferencedContainer = \"container:ProcedureKit.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      enableThreadSanitizer = \"YES\"\n      enableUBSanitizer = \"YES\"\n      codeCoverageEnabled = \"YES\"\n      onlyGenerateCoverageForSpecifiedTargets = \"YES\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <CodeCoverageTargets>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"653C9FC01D6097A40070B7A2\"\n            BuildableName = \"ProcedureKitMobile.framework\"\n            BlueprintName = \"ProcedureKitMobile\"\n            ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n         </BuildableReference>\n      </CodeCoverageTargets>\n      <Testables>\n         <TestableReference\n            skipped = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"653C9FC81D6097A40070B7A2\"\n               BuildableName = \"ProcedureKitMobileTests.xctest\"\n               BlueprintName = \"ProcedureKitMobileTests\"\n               ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n      </Testables>\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"653C9FC01D6097A40070B7A2\"\n            BuildableName = \"ProcedureKitMobile.framework\"\n            BlueprintName = \"ProcedureKitMobile\"\n            ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"653C9FC01D6097A40070B7A2\"\n            BuildableName = \"ProcedureKitMobile.framework\"\n            BlueprintName = \"ProcedureKitMobile\"\n            ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"653C9FC01D6097A40070B7A2\"\n            BuildableName = \"ProcedureKitMobile.framework\"\n            BlueprintName = \"ProcedureKitMobile\"\n            ReferencedContainer = \"container:ProcedureKit.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": "ProcedureKit.xcodeproj/xcshareddata/xcschemes/ProcedureKitNetwork.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1020\"\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 = \"65ECB2CC1DB4F0C000F96F46\"\n               BuildableName = \"ProcedureKitNetwork.framework\"\n               BlueprintName = \"ProcedureKitNetwork\"\n               ReferencedContainer = \"container:ProcedureKit.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      enableThreadSanitizer = \"YES\"\n      enableUBSanitizer = \"YES\"\n      codeCoverageEnabled = \"YES\"\n      onlyGenerateCoverageForSpecifiedTargets = \"YES\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <CodeCoverageTargets>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"65ECB2CC1DB4F0C000F96F46\"\n            BuildableName = \"ProcedureKitNetwork.framework\"\n            BlueprintName = \"ProcedureKitNetwork\"\n            ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n         </BuildableReference>\n      </CodeCoverageTargets>\n      <Testables>\n         <TestableReference\n            skipped = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"65ECB2D41DB4F0C000F96F46\"\n               BuildableName = \"ProcedureKitNetworkTests.xctest\"\n               BlueprintName = \"ProcedureKitNetworkTests\"\n               ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n      </Testables>\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"65ECB2CC1DB4F0C000F96F46\"\n            BuildableName = \"ProcedureKitNetwork.framework\"\n            BlueprintName = \"ProcedureKitNetwork\"\n            ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"65ECB2CC1DB4F0C000F96F46\"\n            BuildableName = \"ProcedureKitNetwork.framework\"\n            BlueprintName = \"ProcedureKitNetwork\"\n            ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"65ECB2CC1DB4F0C000F96F46\"\n            BuildableName = \"ProcedureKitNetwork.framework\"\n            BlueprintName = \"ProcedureKitNetwork\"\n            ReferencedContainer = \"container:ProcedureKit.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": "ProcedureKit.xcodeproj/xcshareddata/xcschemes/ProcedureKitTV.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1020\"\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 = \"653C9FF21D609E650070B7A2\"\n               BuildableName = \"ProcedureKitTV.framework\"\n               BlueprintName = \"ProcedureKitTV\"\n               ReferencedContainer = \"container:ProcedureKit.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      enableThreadSanitizer = \"YES\"\n      enableUBSanitizer = \"YES\"\n      codeCoverageEnabled = \"YES\"\n      onlyGenerateCoverageForSpecifiedTargets = \"YES\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <CodeCoverageTargets>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"653C9FF21D609E650070B7A2\"\n            BuildableName = \"ProcedureKitTV.framework\"\n            BlueprintName = \"ProcedureKitTV\"\n            ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n         </BuildableReference>\n      </CodeCoverageTargets>\n      <Testables>\n         <TestableReference\n            skipped = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"653C9FFA1D609E660070B7A2\"\n               BuildableName = \"ProcedureKitTVTests.xctest\"\n               BlueprintName = \"ProcedureKitTVTests\"\n               ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n      </Testables>\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"653C9FF21D609E650070B7A2\"\n            BuildableName = \"ProcedureKitTV.framework\"\n            BlueprintName = \"ProcedureKitTV\"\n            ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"653C9FF21D609E650070B7A2\"\n            BuildableName = \"ProcedureKitTV.framework\"\n            BlueprintName = \"ProcedureKitTV\"\n            ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"653C9FF21D609E650070B7A2\"\n            BuildableName = \"ProcedureKitTV.framework\"\n            BlueprintName = \"ProcedureKitTV\"\n            ReferencedContainer = \"container:ProcedureKit.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": "ProcedureKit.xcodeproj/xcshareddata/xcschemes/Stress Tests.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1020\"\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 = \"65CFC5EF1D608A5500CAD875\"\n               BuildableName = \"ProcedureKit.framework\"\n               BlueprintName = \"ProcedureKit\"\n               ReferencedContainer = \"container:ProcedureKit.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      enableUBSanitizer = \"YES\"\n      codeCoverageEnabled = \"YES\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <CodeCoverageTargets>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"65CFC5EF1D608A5500CAD875\"\n            BuildableName = \"ProcedureKit.framework\"\n            BlueprintName = \"ProcedureKit\"\n            ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n         </BuildableReference>\n      </CodeCoverageTargets>\n      <Testables>\n         <TestableReference\n            skipped = \"NO\"\n            testExecutionOrdering = \"random\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"653CA0171D60A34E0070B7A2\"\n               BuildableName = \"ProcedureKitStressTests.xctest\"\n               BlueprintName = \"ProcedureKitStressTests\"\n               ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n      </Testables>\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"65CFC5EF1D608A5500CAD875\"\n            BuildableName = \"ProcedureKit.framework\"\n            BlueprintName = \"ProcedureKit\"\n            ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"65CFC5EF1D608A5500CAD875\"\n            BuildableName = \"ProcedureKit.framework\"\n            BlueprintName = \"ProcedureKit\"\n            ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"65CFC5EF1D608A5500CAD875\"\n            BuildableName = \"ProcedureKit.framework\"\n            BlueprintName = \"ProcedureKit\"\n            ReferencedContainer = \"container:ProcedureKit.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": "ProcedureKit.xcodeproj/xcshareddata/xcschemes/TestingProcedureKit.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1020\"\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 = \"65CFC6151D60900000CAD875\"\n               BuildableName = \"TestingProcedureKit.framework\"\n               BlueprintName = \"TestingProcedureKit\"\n               ReferencedContainer = \"container:ProcedureKit.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      enableThreadSanitizer = \"YES\"\n      enableUBSanitizer = \"YES\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <Testables>\n      </Testables>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"65CFC6151D60900000CAD875\"\n            BuildableName = \"TestingProcedureKit.framework\"\n            BlueprintName = \"TestingProcedureKit\"\n            ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"65CFC6151D60900000CAD875\"\n            BuildableName = \"TestingProcedureKit.framework\"\n            BlueprintName = \"TestingProcedureKit\"\n            ReferencedContainer = \"container:ProcedureKit.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": "ProcedureKit.xcodeproj/xcshareddata/xcschemes/iOS.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1020\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"NO\"\n            buildForArchiving = \"NO\"\n            buildForAnalyzing = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"65CFC5F81D608A5500CAD875\"\n               BuildableName = \"ProcedureKitTests.xctest\"\n               BlueprintName = \"ProcedureKitTests\"\n               ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"NO\"\n            buildForArchiving = \"NO\"\n            buildForAnalyzing = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"653CA0611D60AA990070B7A2\"\n               BuildableName = \"ProcedureKitCloudTests.xctest\"\n               BlueprintName = \"ProcedureKitCloudTests\"\n               ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"NO\"\n            buildForArchiving = \"NO\"\n            buildForAnalyzing = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"65A0E4A020B85169002D6C8C\"\n               BuildableName = \"ProcedureKitCoreDataTests.xctest\"\n               BlueprintName = \"ProcedureKitCoreDataTests\"\n               ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"NO\"\n            buildForArchiving = \"NO\"\n            buildForAnalyzing = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"659484251DAAA2B90028F83B\"\n               BuildableName = \"ProcedureKitLocationTests.xctest\"\n               BlueprintName = \"ProcedureKitLocationTests\"\n               ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"NO\"\n            buildForArchiving = \"NO\"\n            buildForAnalyzing = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"65ECB2D41DB4F0C000F96F46\"\n               BuildableName = \"ProcedureKitNetworkTests.xctest\"\n               BlueprintName = \"ProcedureKitNetworkTests\"\n               ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"NO\"\n            buildForArchiving = \"NO\"\n            buildForAnalyzing = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"653C9FC81D6097A40070B7A2\"\n               BuildableName = \"ProcedureKitMobileTests.xctest\"\n               BlueprintName = \"ProcedureKitMobileTests\"\n               ReferencedContainer = \"container:ProcedureKit.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      codeCoverageEnabled = \"YES\"\n      onlyGenerateCoverageForSpecifiedTargets = \"YES\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <CodeCoverageTargets>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"65CFC5EF1D608A5500CAD875\"\n            BuildableName = \"ProcedureKit.framework\"\n            BlueprintName = \"ProcedureKit\"\n            ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n         </BuildableReference>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"65A0E49820B85168002D6C8C\"\n            BuildableName = \"ProcedureKitCoreData.framework\"\n            BlueprintName = \"ProcedureKitCoreData\"\n            ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n         </BuildableReference>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"6594841D1DAAA2B90028F83B\"\n            BuildableName = \"ProcedureKitLocation.framework\"\n            BlueprintName = \"ProcedureKitLocation\"\n            ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n         </BuildableReference>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"653C9FC01D6097A40070B7A2\"\n            BuildableName = \"ProcedureKitMobile.framework\"\n            BlueprintName = \"ProcedureKitMobile\"\n            ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n         </BuildableReference>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"65ECB2CC1DB4F0C000F96F46\"\n            BuildableName = \"ProcedureKitNetwork.framework\"\n            BlueprintName = \"ProcedureKitNetwork\"\n            ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n         </BuildableReference>\n      </CodeCoverageTargets>\n      <Testables>\n         <TestableReference\n            skipped = \"NO\"\n            testExecutionOrdering = \"random\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"65CFC5F81D608A5500CAD875\"\n               BuildableName = \"ProcedureKitTests.xctest\"\n               BlueprintName = \"ProcedureKitTests\"\n               ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n         <TestableReference\n            skipped = \"NO\"\n            testExecutionOrdering = \"random\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"653CA0611D60AA990070B7A2\"\n               BuildableName = \"ProcedureKitCloudTests.xctest\"\n               BlueprintName = \"ProcedureKitCloudTests\"\n               ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n         <TestableReference\n            skipped = \"NO\"\n            testExecutionOrdering = \"random\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"65A0E4A020B85169002D6C8C\"\n               BuildableName = \"ProcedureKitCoreDataTests.xctest\"\n               BlueprintName = \"ProcedureKitCoreDataTests\"\n               ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n         <TestableReference\n            skipped = \"NO\"\n            testExecutionOrdering = \"random\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"659484251DAAA2B90028F83B\"\n               BuildableName = \"ProcedureKitLocationTests.xctest\"\n               BlueprintName = \"ProcedureKitLocationTests\"\n               ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n         <TestableReference\n            skipped = \"NO\"\n            testExecutionOrdering = \"random\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"65ECB2D41DB4F0C000F96F46\"\n               BuildableName = \"ProcedureKitNetworkTests.xctest\"\n               BlueprintName = \"ProcedureKitNetworkTests\"\n               ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n         <TestableReference\n            skipped = \"NO\"\n            testExecutionOrdering = \"random\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"653C9FC81D6097A40070B7A2\"\n               BuildableName = \"ProcedureKitMobileTests.xctest\"\n               BlueprintName = \"ProcedureKitMobileTests\"\n               ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n      </Testables>\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"65CFC5F81D608A5500CAD875\"\n            BuildableName = \"ProcedureKitTests.xctest\"\n            BlueprintName = \"ProcedureKitTests\"\n            ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"65CFC5F81D608A5500CAD875\"\n            BuildableName = \"ProcedureKitTests.xctest\"\n            BlueprintName = \"ProcedureKitTests\"\n            ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "ProcedureKit.xcodeproj/xcshareddata/xcschemes/tvOS.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1020\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"NO\"\n            buildForArchiving = \"NO\"\n            buildForAnalyzing = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"65CFC5F81D608A5500CAD875\"\n               BuildableName = \"ProcedureKitTests.xctest\"\n               BlueprintName = \"ProcedureKitTests\"\n               ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"NO\"\n            buildForArchiving = \"NO\"\n            buildForAnalyzing = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"653CA0611D60AA990070B7A2\"\n               BuildableName = \"ProcedureKitCloudTests.xctest\"\n               BlueprintName = \"ProcedureKitCloudTests\"\n               ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"NO\"\n            buildForArchiving = \"NO\"\n            buildForAnalyzing = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"65A0E4A020B85169002D6C8C\"\n               BuildableName = \"ProcedureKitCoreDataTests.xctest\"\n               BlueprintName = \"ProcedureKitCoreDataTests\"\n               ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"NO\"\n            buildForArchiving = \"NO\"\n            buildForAnalyzing = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"659484251DAAA2B90028F83B\"\n               BuildableName = \"ProcedureKitLocationTests.xctest\"\n               BlueprintName = \"ProcedureKitLocationTests\"\n               ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"NO\"\n            buildForArchiving = \"NO\"\n            buildForAnalyzing = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"65ECB2D41DB4F0C000F96F46\"\n               BuildableName = \"ProcedureKitNetworkTests.xctest\"\n               BlueprintName = \"ProcedureKitNetworkTests\"\n               ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"NO\"\n            buildForArchiving = \"NO\"\n            buildForAnalyzing = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"653C9FFA1D609E660070B7A2\"\n               BuildableName = \"ProcedureKitTVTests.xctest\"\n               BlueprintName = \"ProcedureKitTVTests\"\n               ReferencedContainer = \"container:ProcedureKit.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      codeCoverageEnabled = \"YES\"\n      onlyGenerateCoverageForSpecifiedTargets = \"YES\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <CodeCoverageTargets>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"65CFC5EF1D608A5500CAD875\"\n            BuildableName = \"ProcedureKit.framework\"\n            BlueprintName = \"ProcedureKit\"\n            ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n         </BuildableReference>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"653CA0591D60AA990070B7A2\"\n            BuildableName = \"ProcedureKitCloud.framework\"\n            BlueprintName = \"ProcedureKitCloud\"\n            ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n         </BuildableReference>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"65A0E49820B85168002D6C8C\"\n            BuildableName = \"ProcedureKitCoreData.framework\"\n            BlueprintName = \"ProcedureKitCoreData\"\n            ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n         </BuildableReference>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"6594841D1DAAA2B90028F83B\"\n            BuildableName = \"ProcedureKitLocation.framework\"\n            BlueprintName = \"ProcedureKitLocation\"\n            ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n         </BuildableReference>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"65ECB2CC1DB4F0C000F96F46\"\n            BuildableName = \"ProcedureKitNetwork.framework\"\n            BlueprintName = \"ProcedureKitNetwork\"\n            ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n         </BuildableReference>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"653C9FF21D609E650070B7A2\"\n            BuildableName = \"ProcedureKitTV.framework\"\n            BlueprintName = \"ProcedureKitTV\"\n            ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n         </BuildableReference>\n      </CodeCoverageTargets>\n      <Testables>\n         <TestableReference\n            skipped = \"NO\"\n            testExecutionOrdering = \"random\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"65CFC5F81D608A5500CAD875\"\n               BuildableName = \"ProcedureKitTests.xctest\"\n               BlueprintName = \"ProcedureKitTests\"\n               ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n         <TestableReference\n            skipped = \"NO\"\n            testExecutionOrdering = \"random\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"653CA0611D60AA990070B7A2\"\n               BuildableName = \"ProcedureKitCloudTests.xctest\"\n               BlueprintName = \"ProcedureKitCloudTests\"\n               ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n         <TestableReference\n            skipped = \"NO\"\n            testExecutionOrdering = \"random\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"65A0E4A020B85169002D6C8C\"\n               BuildableName = \"ProcedureKitCoreDataTests.xctest\"\n               BlueprintName = \"ProcedureKitCoreDataTests\"\n               ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n         <TestableReference\n            skipped = \"NO\"\n            testExecutionOrdering = \"random\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"659484251DAAA2B90028F83B\"\n               BuildableName = \"ProcedureKitLocationTests.xctest\"\n               BlueprintName = \"ProcedureKitLocationTests\"\n               ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n         <TestableReference\n            skipped = \"NO\"\n            testExecutionOrdering = \"random\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"65ECB2D41DB4F0C000F96F46\"\n               BuildableName = \"ProcedureKitNetworkTests.xctest\"\n               BlueprintName = \"ProcedureKitNetworkTests\"\n               ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n         <TestableReference\n            skipped = \"NO\"\n            testExecutionOrdering = \"random\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"653C9FFA1D609E660070B7A2\"\n               BuildableName = \"ProcedureKitTVTests.xctest\"\n               BlueprintName = \"ProcedureKitTVTests\"\n               ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n      </Testables>\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"65CFC5F81D608A5500CAD875\"\n            BuildableName = \"ProcedureKitTests.xctest\"\n            BlueprintName = \"ProcedureKitTests\"\n            ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"65CFC5F81D608A5500CAD875\"\n            BuildableName = \"ProcedureKitTests.xctest\"\n            BlueprintName = \"ProcedureKitTests\"\n            ReferencedContainer = \"container:ProcedureKit.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "README.md",
    "content": "![](https://raw.githubusercontent.com/ProcedureKit/ProcedureKit/development/header.png)\n\n[![Build status](https://badge.buildkite.com/4bc80b0824c6357ae071342271cb503b8994cf0cfa58645849.svg)](https://buildkite.com/procedurekit/procedurekit)\n[![Coverage Status](https://coveralls.io/repos/github/ProcedureKit/ProcedureKit/badge.svg?branch=swift%2F2.2)](https://coveralls.io/github/ProcedureKit/ProcedureKit?branch=swift%2F2.2)\n[![Documentation](http://procedure.kit.run/development/badge.svg)](http://procedure.kit.run/development)\n[![CocoaPods Compatible](https://img.shields.io/cocoapods/v/ProcedureKit.svg?style=flat)](https://cocoapods.org/pods/ProcedureKit)\n[![Platform](https://img.shields.io/cocoapods/p/ProcedureKit.svg?style=flat)](http://cocoadocs.org/docsets/ProcedureKit)\n[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)\n\n# ProcedureKit\n\nA Swift framework inspired by WWDC 2015 Advanced NSOperations session. Previously known as _Operations_, developed by [@danthorpe](https://github.com/danthorpe) with a lot of help from our fantastic community.\n\nResource | Where to find it\n---------|-----------------\nSession video | [developer.apple.com](https://developer.apple.com/videos/wwdc/2015/?id=226)\nOld but more complete reference documentation | [docs.danthorpe.me/operations](http://docs.danthorpe.me/operations/2.9.0/index.html)\nUpdated but not yet complete reference docs | [procedure.kit.run/development](http://procedure.kit.run/development/index.html)\nProgramming guide | [operations.readme.io](https://operations.readme.io)\n\n## Compatibility\n\nProcedureKit supports all current Apple platforms. The minimum requirements are:\n\n- iOS 9.0+\n- macOS 10.11+\n- watchOS 3.0+\n- tvOS 9.2+\n\nThe current released version of ProcedureKit (5.1.0) supports Swift 4.2+ and Xcode 10.1. The `development` branch is Swift 5 and Xcode 10.2 compatible.\n\n## Framework structure\n\n_ProcedureKit_ is a \"multi-module\" framework (don't bother Googling that, I just made it up). What I mean, is that the Xcode project has multiple targets/products each of which produces a Swift module. Some of these modules are cross-platform, others are dedicated, e.g. `ProcedureKitNetwork` vs `ProcedureKitMobile`.\n\n## Installing ProcedureKit\n\nSee the [Installing ProcedureKit](http://procedure.kit.run/development/installing-procedurekit.html) guide. \n\n## Usage\n\n`Procedure` is a `Foundation.Operation` subclass. It is an abstract class which _must_ be subclassed.\n\n```swift\nimport ProcedureKit\n\nclass MyFirstProcedure: Procedure {\n    override func execute() {\n        print(\"Hello World\")\n        finish()\n    }\n}\n\nlet queue = ProcedureQueue()\nlet myProcedure = MyFirstProcedure()\nqueue.add(procedure: myProcedure)\n```\n\nthe key points here are:\n\n1. Subclass `Procedure`\n2. Override `execute` but do not call `super.execute()`\n4. Always call `finish()` after the *work* is done, or if the procedure is cancelled. This could be done asynchronously.\n5. Add procedures to instances of `ProcedureQueue`.\n\n## Observers\n\nObservers are attached to a `Procedure` subclass. They receive callbacks when lifecycle events occur. The lifecycle events are: *did attach*, *will execute*, *did execute*, *did cancel*, *will add new operation*, *did add new operation*, *will finish* and *did finish*.\n\nThese methods are defined by a protocol, so custom classes can be written to conform to multiple events. However, block based methods exist to add observers more naturally. For example, to observe when a procedure finishes:\n\n```swift\nmyProcedure.addDidFinishBlockObserver { procedure, errors in \n    procedure.log.info(message: \"Yay! Finished!\")\n}\n```\n\nThe framework also provides `BackgroundObserver`, `TimeoutObserver` and `NetworkObserver`.\n\nSee the wiki on [[Observers|Observers]] for more information.\n\n## Conditions\n\nConditions are attached to a `Procedure` subclass. Before a procedure is ready to execute it will asynchronously *evaluate* all of its conditions. If any condition fails, it finishes with an error instead of executing. For example:\n\n```swift\nmyProcedure.add(condition: BlockCondition { \n    // procedure will execute if true\n    // procedure will be ignored if false\n    // procedure will fail if error is thrown\n    return trueOrFalse // or throw AnError()\n}\n``` \n\nConditions can be mutually exclusive. This is akin to a lock being held preventing other operations with the same exclusion being executed.\n\nThe framework provides the following conditions: `AuthorizedFor`, `BlockCondition`, `MutuallyExclusive`, `NegatedCondition`, `NoFailedDependenciesCondition`, `SilentCondition` and `UserConfirmationCondition` (in _ProcedureKitMobile_).\n\nSee the wiki on [[Conditions|Conditions]], or the old programming guide on [Conditions|](https://operations.readme.io/docs/conditions) for more information.\n\n## Capabilities\n\nA _capability_ represents the application’s ability to access device or user account abilities, or potentially any kind of gated resource. For example, location services, cloud kit containers, calendars etc or a webservice. The `CapabiltiyProtocol` provides a unified model to:\n \n1. Check the current authorization status, using `GetAuthorizationStatusProcedure`, \n2. Explicitly request access, using `AuthorizeCapabilityProcedure`\n3. Both of the above as a condition called `AuthorizedFor`. \n\nFor example:\n\n```swift\nimport ProcedureKit\nimport ProcedureKitLocation\n\nclass DoSomethingWithLocation: Procedure {\n    override init() {\n        super.init()\n        name = \"Location Operation\"\n        add(condition: AuthorizedFor(Capability.Location(.whenInUse)))\n    }\n   \n    override func execute() {\n        // do something with Location Services here\n        \n        \n        finish()\n    }\n}\n```\n\n_ProcedureKit_ provides the following capabilities: `Capability.CloudKit` and `Capability.Location`.\n\nIn _Operations_, (a previous version of this framework), more functionality existed (calendar, health, photos, address book, etc), and we are still considering how to offer these in _ProcedureKit_. \n\nSee the wiki on [[Capabilities|Capabilities]], or the old programming guide on [Capabilities](https://operations.readme.io/docs/capabilities) for more information.\n\n## Logging\n\n`Procedure` has its own internal logging functionality exposed via a `log` property:\n\n```swift\nclass LogExample: Procedure {\n   \n    override func execute() {\n        log.info(\"Hello World!\")\n        finish()\n    }\n}\n```\n\nSee the programming guide for more information on [logging](https://operations.readme.io/docs/logging) and [supporting 3rd party log frameworks](https://operations.readme.io/docs/custom-logging).\n\n## Dependency Injection\n\nOften, procedures will need dependencies in order to execute. As is typical with asynchronous/event based applications, these dependencies might not be known at creation time. Instead they must be injected after the procedure is initialised, but before it is executed. _ProcedureKit_ supports this via a set of protocols and types which work together. We think this pattern is great, as it encourages the composition of small single purpose procedures. These can be easier to test and potentially enable greater re-use. You will find dependency injection used and encouraged throughout this framework. \n\nAnyway, firstly, a value may be ready or pending. For example, when a procedure is initialised, it might not have all its dependencies, so they are in a pending state. Hopefully they become ready by the time it executes.\n\nSecondly, if a procedure is acquiring the dependency required by another procedure, it may succeed, or it may fail with an error. Therefore there is a simple _Result_ type which supports this.\n\nThirdly, there are protocols to define the `input` and `output` properties. \n\n`InputProcedure` associates an `Input` type. A `Procedure` subclass can conform to this to allow dependency injection. Note, that only one `input` property is supported, therefore, create intermediate struct types to contain multiple dependencies. Of course, the `input` property is a pending value type.\n\n`OutputProcedure` exposes the `Output` associated type via its `output` property, which is a pending result type.\n\nBringing it all together is a set of APIs on `InputProcedure` which allows chaining dependencies together. Like this:\n\n```swift\nimport ProcedureKitLocation\n\n// This class is part of the framework, it \n// conforms to OutputProcedure\nlet getLocation = UserLocationProcedure()\n\n// Lets assume we've written this, it\n// conforms to InputProcedure\nlet processLocation = ProcessUserLocation()\n\n// This line sets up dependency & injection\n// it automatically handles errors and cancellation\nprocessLocation.injectResult(from: getLocation)\n\n// Still need to add both procedures to the queue\nqueue.add(procedures: getLocation, processLocation)\n```\n\nIn the above, it is assumed that the `Input` type matched the `Output` type, in this case, `CLLocation`. However, it is also possible to use a closure to massage the output type to the required input type, for example:\n\n```swift\nimport ProcedureKitLocation\n\n// This class is part of the framework, it \n// conforms to OutputProcedure\nlet getLocation = UserLocationProcedure()\n\n// Lets assume we've written this, it\n// conforms to InputProcedure, and \n// requires a CLLocationSpeed value\nlet processSpeed = ProcessUserSpeed()\n\n// This line sets up dependency & injection\n// it automatically handles errors and cancellation\n// and the closure extracts the speed value\nprocessLocation.injectResult(from: getLocation) { $0.speed }\n\n// Still need to add both procedures to the queue\nqueue.add(procedures: getLocation, processLocation)\n```\n\nOkay, so what just happened? Well, the `injectResult` API has a variant which accepts a trailing closure. The closure receives the output value, and must return the input value (or throw an error). So, `{ $0.speed }` will return the speed property from the user's `CLLocation` instance.\n\nKey thing to note here is that this closure runs synchronously. So, it's best to not put anything onerous onto it. If you need to do more complex data mappings, check out [`TransformProcedure`](https://github.com/ProcedureKit/ProcedureKit/blob/development/Sources/ProcedureKit/Transform.swift#L7) and [`AsyncTransformProcedure`](https://github.com/ProcedureKit/ProcedureKit/blob/development/Sources/ProcedureKit/Transform.swift#L31). \n\nSee the programming guide on [Injecting Results](https://operations.readme.io/docs/injecting-results) for more information.\n"
  },
  {
    "path": "Sources/ProcedureKit/Any.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport Dispatch\n\nstruct ValueBox<Value> {\n\n    typealias Getter = () -> Value\n    typealias Setter = (Value) -> Void\n\n    private let setter: Setter\n    private let getter: Getter\n\n    var value: Value {\n        get {\n            return getter()\n        }\n        set {\n            setter(newValue)\n        }\n    }\n\n    init(getter: @escaping Getter, setter: @escaping Setter) {\n        self.getter = getter\n        self.setter = setter\n    }\n}\n\nenum ProcedureOutputBoxCreator {\n    static func outputBox<P: OutputProcedure>(for procedure: P) -> ValueBox<Pending<ProcedureResult<P.Output>>> {\n        let getter = { return procedure.output }\n        let setter = { procedure.output = $0 }\n        let valueBox = ValueBox(getter: getter, setter: setter)\n        return valueBox\n    }\n}\n\nenum ProcedureInputBoxCreator {\n    static func inputBox<P: InputProcedure>(for procedure: P) -> ValueBox<Pending<P.Input>> {\n        let getter = { return procedure.input }\n        let setter = { procedure.input = $0 }\n        let valueBox = ValueBox(getter: getter, setter: setter)\n        return valueBox\n    }\n}\n\npublic class AnyInputProcedure<Input>: GroupProcedure, InputProcedure {\n    private var inputBox: ValueBox<Pending<Input>>\n    public var input: Pending<Input> {\n        get {\n            return self.inputBox.value\n        }\n        set {\n            self.inputBox.value = newValue\n        }\n    }\n\n    public init<Base: Procedure>(dispatchQueue: DispatchQueue? = nil, _ base: Base) where Base: InputProcedure, Input == Base.Input {\n        self.inputBox = ProcedureInputBoxCreator.inputBox(for: base)\n        super.init(dispatchQueue: dispatchQueue, operations: [base])\n        self.log.enabled = false\n    }\n}\n\npublic class AnyOutputProcedure<Output>: GroupProcedure, OutputProcedure {\n    private var outputBox: ValueBox<Pending<ProcedureResult<Output>>>\n    public var output: Pending<ProcedureResult<Output>> {\n        get {\n            return self.outputBox.value\n        }\n        set {\n            self.outputBox.value = newValue\n        }\n    }\n\n    public init<Base: Procedure>(dispatchQueue: DispatchQueue? = nil, _ base: Base) where Base: OutputProcedure, Output == Base.Output {\n        self.outputBox = ProcedureOutputBoxCreator.outputBox(for: base)\n        super.init(dispatchQueue: dispatchQueue, operations: [base])\n        self.log.enabled = false\n    }\n}\n\npublic class AnyProcedure<Input, Output>: GroupProcedure, InputProcedure, OutputProcedure {\n    private var inputBox: ValueBox<Pending<Input>>\n    public var input: Pending<Input> {\n        get {\n            return self.inputBox.value\n        }\n        set {\n            self.inputBox.value = newValue\n        }\n    }\n\n    private var outputBox: ValueBox<Pending<ProcedureResult<Output>>>\n    public var output: Pending<ProcedureResult<Output>> {\n        get {\n            return self.outputBox.value\n        }\n        set {\n            self.outputBox.value = newValue\n        }\n    }\n\n    public init<Base: Procedure>(dispatchQueue: DispatchQueue? = nil, _ base: Base) where Base: InputProcedure & OutputProcedure, Output == Base.Output, Input == Base.Input {\n        self.inputBox = ProcedureInputBoxCreator.inputBox(for: base)\n        self.outputBox = ProcedureOutputBoxCreator.outputBox(for: base)\n        super.init(dispatchQueue: dispatchQueue, operations: [base])\n        self.log.enabled = false\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKit/AnyObserver.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport Foundation\n\nclass AnyObserverBox_<Procedure: ProcedureProtocol>: ProcedureObserver {\n    func didAttach(to procedure: Procedure) { _abstractMethod() }\n    func didSetInputReady(on procedure: Procedure) { _abstractMethod() }\n    func will(execute procedure: Procedure, pendingExecute: PendingExecuteEvent) { _abstractMethod() }\n    func did(execute procedure: Procedure) { _abstractMethod() }\n    func did(cancel procedure: Procedure, with: Error?) { _abstractMethod() }\n    func procedure(_ procedure: Procedure, willAdd newOperation: Operation) { _abstractMethod() }\n    func procedure(_ procedure: Procedure, didAdd newOperation: Operation) { _abstractMethod() }\n    func will(finish procedure: Procedure, with: Error?, pendingFinish: PendingFinishEvent) { _abstractMethod() }\n    func did(finish procedure: Procedure, with: Error?) { _abstractMethod() }\n    var eventQueue: DispatchQueueProtocol? { _abstractMethod(); return nil }\n}\n\nclass AnyObserverBox<Base: ProcedureObserver>: AnyObserverBox_<Base.Procedure> {\n    private var base: Base\n\n    init(_ base: Base) {\n        self.base = base\n    }\n\n    override func didAttach(to procedure: Base.Procedure) {\n        base.didAttach(to: procedure)\n    }\n\n    override func didSetInputReady(on procedure: Base.Procedure) {\n        base.didSetInputReady(on: procedure)\n    }\n\n    override func will(execute procedure: Base.Procedure, pendingExecute: PendingExecuteEvent) {\n        base.will(execute: procedure, pendingExecute: pendingExecute)\n    }\n\n    override func did(execute procedure: Base.Procedure) {\n        base.did(execute: procedure)\n    }\n\n    override func did(cancel procedure: Base.Procedure, with error: Error?) {\n        base.did(cancel: procedure, with: error)\n    }\n\n    override func procedure(_ procedure: Base.Procedure, willAdd newOperation: Operation) {\n        base.procedure(procedure, willAdd: newOperation)\n    }\n\n    override func procedure(_ procedure: Base.Procedure, didAdd newOperation: Operation) {\n        base.procedure(procedure, didAdd: newOperation)\n    }\n\n    override func will(finish procedure: Base.Procedure, with error: Error?, pendingFinish: PendingFinishEvent) {\n        base.will(finish: procedure, with: error, pendingFinish: pendingFinish)\n    }\n\n    override func did(finish procedure: Base.Procedure, with error: Error?) {\n        base.did(finish: procedure, with: error)\n    }\n\n    override var eventQueue: DispatchQueueProtocol? {\n        return base.eventQueue\n    }\n}\n\n/// Creates a ProcedureObserver that wraps another ProcedureObserver and transforms the input events from\n/// the input Procedure type (\"R\") to the wrapped ProcedureObserver's expected Procedure type (\"O\") (via a\n/// `procedureTransformBlock`).\n///\n/// This observer will fail at run-time if an event handler is called with a Procedure subclass that cannot\n/// be converted to the wrapped ProcedureObserver's expected Procedure type (via the transform block).\n///\n/// Failures are logged as warnings to the event's input Procedure.\ninternal class TransformObserver<O: ProcedureProtocol, R: ProcedureProtocol>: ProcedureObserver {\n    private typealias Erased = AnyObserverBox_<O>\n    public typealias Procedure = R\n\n    private var wrapped: Erased\n    private var procedureTransformBlock: (R) -> O?\n    init<Base: ProcedureObserver>(base: Base, procedureTransformBlock: @escaping (R) -> O? = { return $0 as? O }) where O == Base.Procedure {\n        wrapped = AnyObserverBox(base)\n        self.procedureTransformBlock = procedureTransformBlock\n    }\n\n    private enum Event {\n        case didAttach\n        case didSetInputReady\n        case willExecute\n        case didExecute\n        case didCancel\n        case willAdd\n        case didAdd\n        case willFinish\n        case didFinish\n\n        var string: String {\n            switch self {\n            case .didAttach: return \"didAttach\"\n            case .didSetInputReady: return \"didSetInputReady\"\n            case .willExecute: return \"willExecute\"\n            case .didExecute: return \"didExecute\"\n            case .didCancel: return \"didCancel\"\n            case .willAdd: return \"procedureWillAdd\"\n            case .didAdd: return \"procedureDidAdd\"\n            case .willFinish: return \"willFinish\"\n            case .didFinish: return \"didFinish\"\n            }\n        }\n    }\n\n    private func typedProcedure(_ procedure: R, event: Event) -> O? {\n        guard let typedProcedure = procedureTransformBlock(procedure) else {\n            procedure.log.warning.message(\"Observer will not receive event (\\(event.string)). Unable to convert \\(procedure) to the expected type \\\"\\(String(describing: O.self))\\\"\")\n            return nil\n        }\n        return typedProcedure\n    }\n\n    func didAttach(to procedure: Procedure) {\n        guard let baseProcedure = typedProcedure(procedure, event: .didAttach) else { return }\n        wrapped.didAttach(to: baseProcedure)\n    }\n\n    func didSetInputReady(on procedure: Procedure) {\n        guard let baseProcedure = typedProcedure(procedure, event: .didAttach) else { return }\n        wrapped.didSetInputReady(on: baseProcedure)\n    }\n\n    func will(execute procedure: Procedure, pendingExecute: PendingExecuteEvent) {\n        guard let baseProcedure = typedProcedure(procedure, event: .willExecute) else { return }\n        wrapped.will(execute: baseProcedure, pendingExecute: pendingExecute)\n    }\n\n    func did(execute procedure: Procedure) {\n        guard let baseProcedure = typedProcedure(procedure, event: .didExecute) else { return }\n        wrapped.did(execute: baseProcedure)\n    }\n\n    func did(cancel procedure: Procedure, with error: Error?) {\n        guard let baseProcedure = typedProcedure(procedure, event: .didCancel) else { return }\n        wrapped.did(cancel: baseProcedure, with: error)\n    }\n\n    func procedure(_ procedure: Procedure, willAdd newOperation: Operation) {\n        guard let baseProcedure = typedProcedure(procedure, event: .willAdd) else { return }\n        wrapped.procedure(baseProcedure, willAdd: newOperation)\n    }\n\n    func procedure(_ procedure: Procedure, didAdd newOperation: Operation) {\n        guard let baseProcedure = typedProcedure(procedure, event: .didAdd) else { return }\n        wrapped.procedure(baseProcedure, didAdd: newOperation)\n    }\n\n    func will(finish procedure: Procedure, with error: Error?, pendingFinish: PendingFinishEvent) {\n        guard let baseProcedure = typedProcedure(procedure, event: .willFinish) else { return }\n        wrapped.will(finish: baseProcedure, with: error, pendingFinish: pendingFinish)\n    }\n\n    func did(finish procedure: Procedure, with error: Error?) {\n        guard let baseProcedure = typedProcedure(procedure, event: .didFinish) else { return }\n        wrapped.did(finish: baseProcedure, with: error)\n    }\n\n    var eventQueue: DispatchQueueProtocol? {\n        return wrapped.eventQueue\n    }\n}\n\npublic struct AnyObserver<Procedure: ProcedureProtocol>: ProcedureObserver {\n    private typealias Erased = AnyObserverBox_<Procedure>\n\n    private var box: Erased\n\n    init<Base: ProcedureObserver>(base: Base) where Procedure == Base.Procedure {\n        box = AnyObserverBox(base)\n    }\n\n    public func didAttach(to procedure: Procedure) {\n        box.didAttach(to: procedure)\n    }\n\n    public func didSetInputReady(on procedure: Procedure) {\n        box.didSetInputReady(on: procedure)\n    }\n\n    public func will(execute procedure: Procedure, pendingExecute: PendingExecuteEvent) {\n        box.will(execute: procedure, pendingExecute: pendingExecute)\n    }\n\n    public func did(execute procedure: Procedure) {\n        box.did(execute: procedure)\n    }\n\n    public func did(cancel procedure: Procedure, with error: Error?) {\n        box.did(cancel: procedure, with: error)\n    }\n\n    public func procedure(_ procedure: Procedure, willAdd newOperation: Operation) {\n        box.procedure(procedure, willAdd: newOperation)\n    }\n\n    public func procedure(_ procedure: Procedure, didAdd newOperation: Operation) {\n        box.procedure(procedure, didAdd: newOperation)\n    }\n\n    public func will(finish procedure: Procedure, with error: Error?, pendingFinish: PendingFinishEvent) {\n        box.will(finish: procedure, with: error, pendingFinish: pendingFinish)\n    }\n\n    public func did(finish procedure: Procedure, with error: Error?) {\n        box.did(finish: procedure, with: error)\n    }\n\n    public var eventQueue: DispatchQueueProtocol? {\n        return box.eventQueue\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKit/Batch.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2018 ProcedureKit. All rights reserved.\n//\n\nimport Foundation\n\nopen class BatchProcedure<Transform: Procedure>: GroupProcedure, InputProcedure, OutputProcedure where Transform: InputProcedure, Transform: OutputProcedure {\n\n    public typealias Generator = () -> Transform\n\n    /// - returns: The pending input property\n    public var input: Pending<[Transform.Input]> = .pending\n\n    /// - returns: The pending output result property\n    public var output: Pending<ProcedureResult<[Transform.Output]>> = .pending\n\n    public let generator: Generator\n\n    public init(dispatchQueue: DispatchQueue? = nil, via generator: @escaping Generator) {\n        self.generator = generator\n        super.init(dispatchQueue: dispatchQueue, operations: [])\n        name = \"Batch<\\(Transform.self)>\"\n    }\n\n    open override func execute() {\n\n        defer { super.execute() }\n\n        guard let input = input.value else {\n            cancel(with: ProcedureKitError.requirementNotSatisfied())\n            return\n        }\n\n        let batch = input.map { i -> Transform in\n            let transform = generator()\n            transform.input = .ready(i)\n            transform.didSetInputReady()\n            return transform\n        }\n\n        let gathered = batch.gathered()\n        bind(from: gathered)\n\n        addChildren(batch)\n        addChild(gathered)\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKit/Block.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport Foundation\n\nopen class BlockProcedure: Procedure {\n\n    public typealias SelfBlock = (BlockProcedure) -> Void\n    public typealias ThrowingVoidBlock = () throws -> Void\n\n    enum BlockStorage {\n        case asSelf(SelfBlock)\n        case asVoid(ThrowingVoidBlock)\n    }\n\n    public static var defaultTimeoutInterval: TimeInterval = 3.0\n\n    let storage: BlockStorage\n\n    public init(block: @escaping SelfBlock) {\n        self.storage = .asSelf(block)\n        super.init()\n        addObserver(TimeoutObserver(by: BlockProcedure.defaultTimeoutInterval))\n    }\n\n    public init(block: @escaping ThrowingVoidBlock) {\n        self.storage = .asVoid(block)\n        super.init()\n    }\n\n    open override func execute() {\n        switch storage {\n        case let .asSelf(block):\n            block(self)\n        case let .asVoid(block):\n            do {\n                try block()\n                finish()\n            }\n            catch { finish(with: error) }\n        }\n    }\n\n    open override func procedureDidCancel(with error: Error?) {\n        if let procedureKitError = error as? ProcedureKitError {\n            if case .timedOut(.by(BlockProcedure.defaultTimeoutInterval)) = procedureKitError.context {\n                log.warning.message(\"Block not finished after \\(BlockProcedure.defaultTimeoutInterval) seconds. This is likely a mistake, check that this block calls .finish() on all code paths.\")\n            }\n        }\n    }\n}\n\n/*\n A block based procedure which execute the provided block on the UI/main thread.\n */\nopen class UIBlockProcedure: BlockProcedure {\n\n    public override init(block: @escaping ThrowingVoidBlock) {\n        super.init { (procedure) in\n\n            guard DispatchQueue.isMainDispatchQueue == false else {\n                do {\n                    try block()\n                    procedure.finish()\n                }\n                catch { procedure.finish(with: error) }\n                return\n            }\n\n            let sub = BlockProcedure(block: block)\n            sub.log.enabled = false\n\n            sub.addDidFinishBlockObserver { (_, error) in\n                if let error = error {\n                    procedure.finish(with: ProcedureKitError.dependency(finishedWithError: error))\n                } else {\n                    procedure.finish()\n                }\n            }\n\n            ProcedureQueue.main.addOperation(sub)\n        }\n    }\n}\n\n\n@available(*, deprecated, message: \"Use BlockProcedure directly and call .finish() on the block argument instead.\")\nopen class AsyncBlockProcedure: BlockProcedure {\n\n    public typealias Output = Void\n    public typealias FinishingBlock = (ProcedureResult<Output>) -> Void\n    public typealias Block = (@escaping FinishingBlock) -> Void\n\n    public init(block: @escaping Block) {\n        super.init { (procedure) in\n            block { result in\n                procedure.finish(with: result.error)\n            }\n        }\n    }\n}\n\n@available(*, deprecated, message: \"Use BlockProcedure directly and query the procedure argument inside your block.\")\nopen class CancellableBlockProcedure: BlockProcedure {\n\n    /// A block that receives a closure (that returns the current value of `isCancelled`\n    /// for the CancellableResultProcedure), and returns a value (which is set as the\n    /// CancellableResultProcedure's `output`).\n    public typealias ThrowingCancellableBlock = (() -> Bool) throws -> Void\n\n    public init(cancellableBlock: @escaping ThrowingCancellableBlock) {\n        super.init { (procedure) in\n            do {\n                try cancellableBlock { procedure.isCancelled }\n                procedure.finish()\n            }\n            catch { procedure.finish(with: error) }\n        }\n    }\n}\n\n"
  },
  {
    "path": "Sources/ProcedureKit/BlockCondition.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\npublic typealias ThrowingBoolBlock = () throws -> Bool\n\n/**\n A Condition which will be satisfied if the block returns true. If the\n block returns false, this will result in an ignored condition, i.e.\n it will not error, but the attached procedure will not execute either.\n Throwing an error from the block will result in a failed procedure.\n */\npublic final class BlockCondition: Condition {\n\n    let block: ThrowingBoolBlock\n\n    /**\n     Creates a condition with a supplied block.\n\n     - parameter block: a block which returns Bool, to indicate that the condition is satisfied.\n    */\n    public init(block: @escaping ThrowingBoolBlock) {\n        self.block = block\n        super.init()\n    }\n\n    public override func evaluate(procedure: Procedure, completion: @escaping (ConditionResult) -> Void) {\n        do {\n            completion(.success(try block()))\n        }\n        catch {\n            completion(.failure(ProcedureKitError.conditionFailed(with: error)))\n        }\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKit/BlockObservers.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport Foundation\n\npublic struct Observer<Procedure: ProcedureProtocol> {\n\n    public typealias VoidBlock = (Procedure) -> Void\n    public typealias ErrorBlock = (Procedure, Error?) -> Void\n    public typealias ProducerBlock = (Procedure, Operation) -> Void\n\n    public typealias DidAttach = VoidBlock\n    public typealias DidSetInputReady = VoidBlock\n    public typealias WillExecute = (Procedure, PendingExecuteEvent) -> Void\n    public typealias DidExecute = VoidBlock\n    public typealias DidCancel = ErrorBlock\n    public typealias WillAdd = ProducerBlock\n    public typealias DidAdd = ProducerBlock\n    public typealias WillFinish = (Procedure, Error?, PendingFinishEvent) -> Void\n    public typealias DidFinish = ErrorBlock\n\n    private init() { }\n}\n\npublic struct BlockObserver<Procedure: ProcedureProtocol>: ProcedureObserver {\n\n    /// - returns: the block which is called when the observer is attached to a procedure\n    public let didAttach: Observer<Procedure>.DidAttach?\n\n    /// - returns: the block which is called when the input value is set on an InputProcedure\n    public let didSetInputReady: Observer<Procedure>.DidSetInputReady?\n\n    /// - returns: the block which is called when the attached procedure will execute\n    public let willExecute: Observer<Procedure>.WillExecute?\n\n    /// - returns: the block which is called when the attached procedure did execute\n    public let didExecute: Observer<Procedure>.DidExecute?\n\n    /// - returns: the block which is called when the attached procedure did cancel\n    public let didCancel: Observer<Procedure>.DidCancel?\n\n    /// - returns: the block which is called when the attached procedure will add a new operation\n    public let willAdd: Observer<Procedure>.WillAdd?\n\n    /// - returns: the block which is called when the attached procedure did add a new operation\n    public let didAdd: Observer<Procedure>.DidAdd?\n\n    /// - returns: the block which is called when the attached procedure will finish\n    public let willFinish: Observer<Procedure>.WillFinish?\n\n    /// - returns: the block which is called when the attached procedure did finish\n    public let didFinish: Observer<Procedure>.DidFinish?\n\n    /// - returns: the queue onto which observer callbacks are dispatched\n    public let eventQueue: DispatchQueueProtocol?\n\n    /// Creates a new BlockObserver.\n    ///\n    /// - parameter synchronizedWith: a provider of the queue onto which observer callbacks are dispatched\n    /// - parameter didAttach:   the block which will execute when the observer is attached to a procedure\n    /// - parameter willExecute: the block which is called when the attached procedure will execute\n    /// - parameter didCancel:   the block which is called when the attached procedure did cancel\n    /// - parameter willAdd:     the block which is called when the attached procedure will add a new operation\n    /// - parameter didAdd:      the block which is called when the attached procedure did add a new operation\n    /// - parameter willFinish:  the block which is called when the attached procedure will finish\n    /// - parameter didFinish:   the block which is called when the attached procedure did finish\n    ///\n    /// - returns: an immutable BlockObserver\n    public init(\n        synchronizedWith queueProvider: QueueProvider? = nil,\n        didAttach: Observer<Procedure>.DidAttach? = nil,\n        didSetInputReady: Observer<Procedure>.DidSetInputReady? = nil,\n        willExecute: Observer<Procedure>.WillExecute? = nil,\n        didExecute: Observer<Procedure>.DidExecute? = nil,\n        didCancel: Observer<Procedure>.DidCancel? = nil,\n        willAdd: Observer<Procedure>.WillAdd? = nil,\n        didAdd: Observer<Procedure>.DidAdd? = nil,\n        willFinish: Observer<Procedure>.WillFinish? = nil,\n        didFinish: Observer<Procedure>.DidFinish? = nil) {\n            self.eventQueue = queueProvider?.providedQueue\n            self.didAttach = didAttach\n            self.didSetInputReady = didSetInputReady\n            self.willExecute = willExecute\n            self.didExecute = didExecute\n            self.didCancel = didCancel\n            self.willAdd = willAdd\n            self.didAdd = didAdd\n            self.willFinish = willFinish\n            self.didFinish = didFinish\n    }\n\n    public func didAttach(to procedure: Procedure) {\n        didAttach?(procedure)\n    }\n\n    public func didSetInputReady(on procedure: Procedure) {\n        didSetInputReady?(procedure)\n    }\n\n    public func will(execute procedure: Procedure, pendingExecute: PendingExecuteEvent) {\n        willExecute?(procedure, pendingExecute)\n    }\n\n    public func did(execute procedure: Procedure) {\n        didExecute?(procedure)\n    }\n\n    public func did(cancel procedure: Procedure, with error: Error?) {\n        didCancel?(procedure, error)\n    }\n\n    public func procedure(_ procedure: Procedure, willAdd newOperation: Operation) {\n        willAdd?(procedure, newOperation)\n    }\n\n    public func procedure(_ procedure: Procedure, didAdd newOperation: Operation) {\n        didAdd?(procedure, newOperation)\n    }\n\n    public func will(finish procedure: Procedure, with error: Error?, pendingFinish: PendingFinishEvent) {\n        willFinish?(procedure, error, pendingFinish)\n    }\n\n    public func did(finish procedure: Procedure, with error: Error?) {\n        didFinish?(procedure, error)\n    }\n}\n\n/// WillExecuteObserver is an observer which will execute a\n/// closure when the procedure starts (prior to the `execute()`\n/// method being called).\npublic struct WillExecuteObserver<Procedure: ProcedureProtocol>: ProcedureObserver {\n    private let block: Observer<Procedure>.WillExecute\n\n    /// - returns: a block which is called when the observer is attached to a procedure\n    public var didAttachToProcedure: Observer<Procedure>.DidAttach?\n\n    /// - returns: the queue onto which observer callbacks are dispatched\n    public let eventQueue: DispatchQueueProtocol?\n\n    /**\n     Initialize the observer with a block.\n\n     - parameter synchronizedWith: a provider of the queue onto which observer callbacks are dispatched\n     - parameter willExecute: the `Block`\n     - returns: an observer.\n     */\n    public init(synchronizedWith queueProvider: QueueProvider? = nil, willExecute: @escaping Observer<Procedure>.WillExecute) {\n        self.block = willExecute\n        self.eventQueue = queueProvider?.providedQueue\n    }\n\n    public func didAttach(to procedure: Procedure) {\n        didAttachToProcedure?(procedure)\n    }\n\n    /// Conforms to `WillExecuteProcedureObserver`, executes the block\n    public func will(execute procedure: Procedure, pendingExecute: PendingExecuteEvent) {\n        block(procedure, pendingExecute)\n    }\n}\n\n/// DidSetInputReadyObserver is an observer which will execute a\n/// closure when the input property of a procedure which conforms to\n/// InputProcedure is set to be ready.\npublic struct DidSetInputReadyObserver<Procedure: InputProcedure>: ProcedureObserver {\n    private let block: Observer<Procedure>.DidSetInputReady\n\n    /// - returns: a block which is called when the observer is attached to a procedure\n    public var didAttachToProcedure: Observer<Procedure>.DidAttach?\n\n    /// - returns: the queue onto which observer callbacks are dispatched\n    public let eventQueue: DispatchQueueProtocol?\n\n    /**\n     Initialize the observer with a block.\n\n     - parameter synchronizedWith: a provider of the queue onto which observer callbacks are dispatched\n     - parameter didSetInputReady: the `Block`\n     - returns: an observer.\n     */\n    public init(synchronizedWith queueProvider: QueueProvider? = nil, didSetInputReady: @escaping Observer<Procedure>.DidSetInputReady) {\n        self.block = didSetInputReady\n        self.eventQueue = queueProvider?.providedQueue\n    }\n\n    /// Conforms to ProcedureObserver\n    public func didAttach(to procedure: Procedure) {\n        didAttachToProcedure?(procedure)\n    }\n\n    /// Conforms to ProcedureObserver\n    public func didSetInputReady(on procedure: Procedure) {\n        block(procedure)\n    }\n}\n\n/// DidExecuteObserver is an observer which will execute a\n/// closure when the procedure starts.\n///\n/// - note: This observer will be invoked directly after the\n/// `execute` method of the procedure returns.\n///\n/// - warning: There are no guarantees about when this observer\n/// will be called, relative to the lifecycle of the procedure. It\n/// is entirely possible that the procedure will actually\n/// have already finished be the time the observer is invoked. See\n/// the conversation here which explains the reasoning behind it:\n/// https://github.com/ProcedureKit/ProcedureKit/pull/554\npublic struct DidExecuteObserver<Procedure: ProcedureProtocol>: ProcedureObserver {\n    private let block: Observer<Procedure>.DidExecute\n\n    /// - returns: a block which is called when the observer is attached to a procedure\n    public var didAttachToProcedure: Observer<Procedure>.DidAttach?\n\n    /// - returns: the queue onto which observer callbacks are dispatched\n    public let eventQueue: DispatchQueueProtocol?\n\n    /**\n     Initialize the observer with a block.\n\n     - parameter synchronizedWith: a provider of the queue onto which observer callbacks are dispatched\n     - parameter didExecute: the `Block`\n     - returns: an observer.\n     */\n    public init(synchronizedWith queueProvider: QueueProvider? = nil, didExecute: @escaping Observer<Procedure>.DidExecute) {\n        self.block = didExecute\n        self.eventQueue = queueProvider?.providedQueue\n    }\n\n    public func didAttach(to procedure: Procedure) {\n        didAttachToProcedure?(procedure)\n    }\n\n    /// Conforms to `DidExecuteProcedureObserver`, executes the block\n    public func did(execute procedure: Procedure) {\n        block(procedure)\n    }\n}\n\n/// DidCancelObserver is an observer which will execute a\n/// closure when the procedure cancels.\npublic struct DidCancelObserver<Procedure: ProcedureProtocol>: ProcedureObserver {\n    private let block: Observer<Procedure>.DidCancel\n\n    /// - returns: a block which is called when the observer is attached to a procedure\n    public var didAttachToProcedure: Observer<Procedure>.DidAttach?\n\n    /// - returns: the queue onto which observer callbacks are dispatched\n    public let eventQueue: DispatchQueueProtocol?\n\n    /// Initialize the observer with a block.\n    /// - parameter synchronizedWith: a provider of the queue onto which observer callbacks are dispatched\n    /// - parameter didCancel: the `Block`\n    /// - returns: an observer.\n    public init(synchronizedWith queueProvider: QueueProvider? = nil, didCancel: @escaping Observer<Procedure>.DidCancel) {\n        self.block = didCancel\n        self.eventQueue = queueProvider?.providedQueue\n    }\n\n    /// - parameter to: the procedure which is attached\n    public func didAttach(to procedure: Procedure) {\n        didAttachToProcedure?(procedure)\n    }\n\n    /// Observes when the attached procedure did cancel.\n    /// - parameter cancel: the procedure which is cancelled.\n    /// - parameter errors: the errors the procedure was cancelled with.\n    public func did(cancel procedure: Procedure, with error: Error?) {\n        block(procedure, error)\n    }\n}\n\n/// WillAddOperationObserver is an observer which will execute a\n/// closure when the procedure will add another operation.\npublic struct WillAddOperationObserver<Procedure: ProcedureProtocol>: ProcedureObserver {\n    private let block: Observer<Procedure>.WillAdd\n\n    /// - returns: a block which is called when the observer is attached to a procedure\n    public var didAttachToProcedure: Observer<Procedure>.DidAttach?\n\n    /// - returns: the queue onto which observer callbacks are dispatched\n    public let eventQueue: DispatchQueueProtocol?\n\n    /// Initialize the observer with a block.\n    /// - parameter synchronizedWith: a provider of the queue onto which observer callbacks are dispatched\n    /// - parameter willAdd: the `Block`\n    /// - returns: an observer.\n    public init(synchronizedWith queueProvider: QueueProvider? = nil, willAdd: @escaping Observer<Procedure>.WillAdd) {\n        self.block = willAdd\n        self.eventQueue = queueProvider?.providedQueue\n    }\n\n    /// - parameter to: the procedure which is attached\n    public func didAttach(to procedure: Procedure) {\n        didAttachToProcedure?(procedure)\n    }\n\n    /// Observes when the attached procedure will add another Operation.\n    /// - parameter procedure: the procedure which will add another Operation.\n    /// - parameter newOperation: the new Operation instance which will be added.\n    public func procedure(_ procedure: Procedure, willAdd newOperation: Operation) {\n        block(procedure, newOperation)\n    }\n}\n\n/// DidAddOperationObserver is an observer which will execute a\n/// closure when the procedure did add another operation.\npublic struct DidAddOperationObserver<Procedure: ProcedureProtocol>: ProcedureObserver {\n    private let block: Observer<Procedure>.DidAdd\n\n    /// - returns: a block which is called when the observer is attached to a procedure\n    public var didAttachToProcedure: Observer<Procedure>.DidAttach?\n\n    /// - returns: the queue onto which observer callbacks are dispatched\n    public let eventQueue: DispatchQueueProtocol?\n\n    /// Initialize the observer with a block.\n    /// - parameter synchronizedWith: a provider of the queue onto which observer callbacks are dispatched\n    /// - parameter didAdd: the `Block`\n    /// - returns: an observer.\n    public init(synchronizedWith queueProvider: QueueProvider? = nil, didAdd: @escaping Observer<Procedure>.DidAdd) {\n        self.block = didAdd\n        self.eventQueue = queueProvider?.providedQueue\n    }\n\n    /// - parameter to: the procedure which is attached\n    public func didAttach(to procedure: Procedure) {\n        didAttachToProcedure?(procedure)\n    }\n\n    /// Observes when the attached procedure did add another Operation.\n    /// - parameter procedure: the procedure which did add another Operation.\n    /// - parameter newOperation: the new Operation instance which was added.\n    public func procedure(_ procedure: Procedure, didAdd newOperation: Operation) {\n        block(procedure, newOperation)\n    }\n}\n\n/// WillFinishObserver is an observer which will execute a\n/// closure when the procedure is about to finish.\npublic struct WillFinishObserver<Procedure: ProcedureProtocol>: ProcedureObserver {\n    private let block: Observer<Procedure>.WillFinish\n\n    /// - returns: a block which is called when the observer is attached to a procedure\n    public var didAttachToProcedure: Observer<Procedure>.DidAttach?\n\n    /// - returns: the queue onto which observer callbacks are dispatched\n    public let eventQueue: DispatchQueueProtocol?\n\n    /// Initialize the observer with a block.\n    /// - parameter synchronizedWith: a provider of the queue onto which observer callbacks are dispatched\n    /// - parameter willFinish: the `Block`\n    /// - returns: an observer.\n    public init(synchronizedWith queueProvider: QueueProvider? = nil, willFinish: @escaping Observer<Procedure>.WillFinish) {\n        self.block = willFinish\n        self.eventQueue = queueProvider?.providedQueue\n    }\n\n    /// - parameter to: the procedure which is attached\n    public func didAttach(to procedure: Procedure) {\n        didAttachToProcedure?(procedure)\n    }\n\n    /// Observes when the attached procedure will finish.\n    /// - parameter procedure: the procedure which will finish.\n    /// - parameter errors: the errors the procedure will finish with\n    public func will(finish procedure: Procedure, with error: Error?, pendingFinish: PendingFinishEvent) {\n        block(procedure, error, pendingFinish)\n    }\n}\n\n/**\n DidFinishObserver is an observer which will execute a\n closure when the procedure did just finish.\n */\npublic struct DidFinishObserver<Procedure: ProcedureProtocol>: ProcedureObserver {\n    private let block: Observer<Procedure>.DidFinish\n\n    /// - returns: a block which is called when the observer is attached to a procedure\n    public var didAttachToProcedure: Observer<Procedure>.DidAttach?\n\n    /// - returns: the queue onto which observer callbacks are dispatched\n    public let eventQueue: DispatchQueueProtocol?\n\n    /// Initialize the observer with a block.\n    /// - parameter synchronizedWith: a provider of the queue onto which observer callbacks are dispatched\n    /// - parameter didFinish: the `Block`\n    /// - returns: an observer.\n    public init(synchronizedWith queueProvider: QueueProvider? = nil, didFinish: @escaping Observer<Procedure>.DidFinish) {\n        self.block = didFinish\n        self.eventQueue = queueProvider?.providedQueue\n    }\n\n    /// - parameter to: the procedure which is attached\n    public func didAttach(to procedure: Procedure) {\n        didAttachToProcedure?(procedure)\n    }\n\n    /// Observes when the attached procedure did finish.\n    /// - parameter procedure: the procedure which will finish.\n    /// - parameter errors: the errors the procedure will finish with\n    public func did(finish procedure: Procedure, with error: Error?) {\n        block(procedure, error)\n    }\n}\n\npublic extension ProcedureProtocol {\n\n    private var _currentEventQueue: DispatchQueueProtocol? {\n        get {\n            guard let queueProvider = self as? QueueProvider else {\n                return nil\n            }\n            return queueProvider.providedQueue\n        }\n    }\n\n    fileprivate func assertQueueProviderIsNotSelf(_ queueProvider: QueueProvider?, function: String = #function) {\n        assert(queueProvider == nil || queueProvider!.providedQueue !== _currentEventQueue, \"\\(function): Synchronizing with self is unnecessary for an observer added to self.\")\n    }\n\n    /// Adds a WillExecuteObserver to the receiver using a provided block\n    ///\n    /// - Parameter synchronizedWith: a QueueProvider that provides a queue onto which the observer callback will be dispatched (can be a Procedure, an EventQueue, or a DispatchQueue)\n    /// - Parameter block: the block which will be invoked before execute is called.\n    func addWillExecuteBlockObserver(synchronizedWith queueProvider: QueueProvider? = nil, block: @escaping Observer<Self>.WillExecute) {\n        assertQueueProviderIsNotSelf(queueProvider)\n        add(observer: WillExecuteObserver(synchronizedWith: queueProvider, willExecute: block))\n    }\n\n\n    /// Adds a DidExecuteObserver to the receiver using a provided block\n    ///\n    /// - Parameter synchronizedWith: a QueueProvider that provides a queue onto which the observer callback will be dispatched (can be a Procedure, an EventQueue, or a DispatchQueue)\n    /// - Parameter block: the block which will be invoked after execute is called.\n    func addDidExecuteBlockObserver(synchronizedWith queueProvider: QueueProvider? = nil, block: @escaping Observer<Self>.DidExecute) {\n        assertQueueProviderIsNotSelf(queueProvider)\n        add(observer: DidExecuteObserver(synchronizedWith: queueProvider, didExecute: block))\n    }\n\n    /// Adds a DidCancelObserver to the receiver using a provided block\n    ///\n    /// - Parameter synchronizedWith: a QueueProvider that provides a queue onto which the observer callback will be dispatched (can be a Procedure, an EventQueue, or a DispatchQueue)\n    /// - Parameter block: the block which will be invoked after the procedure cancels.\n    func addDidCancelBlockObserver(synchronizedWith queueProvider: QueueProvider? = nil, block: @escaping Observer<Self>.DidCancel) {\n        assertQueueProviderIsNotSelf(queueProvider)\n        add(observer: DidCancelObserver(synchronizedWith: queueProvider, didCancel: block))\n    }\n\n    /// Adds a WillAddOperationObserver to the receiver using a provided block\n    ///\n    /// - Parameter synchronizedWith: a QueueProvider that provides a queue onto which the observer callback will be dispatched (can be a Procedure, an EventQueue, or a DispatchQueue)\n    /// - Parameter block: the block which will be invoked before the procedure adds another operation.\n    func addWillAddOperationBlockObserver(synchronizedWith queueProvider: QueueProvider? = nil, block: @escaping Observer<Self>.WillAdd) {\n        assertQueueProviderIsNotSelf(queueProvider)\n        add(observer: WillAddOperationObserver(synchronizedWith: queueProvider, willAdd: block))\n    }\n\n    /// Adds a DidAddOperationObserver to the receiver using a provided block\n    ///\n    /// - Parameter synchronizedWith: a QueueProvider that provides a queue onto which the observer callback will be dispatched (can be a Procedure, an EventQueue, or a DispatchQueue)\n    /// - Parameter block: the block which will be invoked after the procedure adds another operation.\n    func addDidAddOperationBlockObserver(synchronizedWith queueProvider: QueueProvider? = nil, block: @escaping Observer<Self>.DidAdd) {\n        assertQueueProviderIsNotSelf(queueProvider)\n        add(observer: DidAddOperationObserver(synchronizedWith: queueProvider, didAdd: block))\n    }\n\n    /// Adds a WillFinishObserver to the receiver using a provided block\n    ///\n    /// - Parameter synchronizedWith: a QueueProvider that provides a queue onto which the observer callback will be dispatched (can be a Procedure, an EventQueue, or a DispatchQueue)\n    /// - Parameter block: the block which will be invoked before the procedure finishes.\n    func addWillFinishBlockObserver(synchronizedWith queueProvider: QueueProvider? = nil, block: @escaping Observer<Self>.WillFinish) {\n        assertQueueProviderIsNotSelf(queueProvider)\n        add(observer: WillFinishObserver(synchronizedWith: queueProvider, willFinish: block))\n    }\n\n    /// Adds a DidFinishObserver to the receiver using a provided block\n    ///\n    /// - Parameter synchronizedWith: a QueueProvider that provides a queue onto which the observer callback will be dispatched (can be a Procedure, an EventQueue, or a DispatchQueue)\n    /// - Parameter block: the block which will be invoked after the procedure has finished.\n    func addDidFinishBlockObserver(synchronizedWith queueProvider: QueueProvider? = nil, block: @escaping Observer<Self>.DidFinish) {\n        assertQueueProviderIsNotSelf(queueProvider)\n        add(observer: DidFinishObserver(synchronizedWith: queueProvider, didFinish: block))\n    }\n}\n\npublic extension InputProcedure {\n\n    /// Adds a WillExecuteObserver to the receiver using a provided block\n    ///\n    /// - Parameter synchronizedWith: a QueueProvider that provides a queue onto which the observer callback will be dispatched (can be a Procedure, an EventQueue, or a DispatchQueue)\n    /// - Parameter block: the block which will be invoked before execute is called.\n    func addDidSetInputReadyBlockObserver(synchronizedWith queueProvider: QueueProvider? = nil, block: @escaping Observer<Self>.DidSetInputReady) {\n        assertQueueProviderIsNotSelf(queueProvider)\n        add(observer: DidSetInputReadyObserver(synchronizedWith: queueProvider, didSetInputReady: block))\n    }\n}\n\n"
  },
  {
    "path": "Sources/ProcedureKit/Capability.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n/**\n Defines the authorization status of a capability. Typically\n this will be an enum, like CLAuthorizationStatus. Note\n that it is itself generic over the Requirement. This allows\n for another (or existing) types to be used to define granular\n levels of permissions. Use Void if not needed.\n */\npublic protocol AuthorizationStatus {\n\n    /// A generic type for the requirement\n    associatedtype Requirement\n\n    /**\n     Given the current authorization status (i.e. self)\n     this function should determine whether or not the\n     provided Requirement has been met or not. Therefore\n     this function should consider the overall authorization\n     state, and if *authorized* - whether the authorization\n     is enough for the Requirement.\n\n     - parameter requirement: the necessary Requirement\n     - returns: a Bool indicating whether or not the requirements are met.\n     */\n    func meets(requirement: Requirement?) -> Bool\n}\n\n/**\n This is the high level definition for device/user/system\n capabilities which typically would require the user's\n permission to access. For example, location, calendars,\n photos, health kit etc.\n\n However, it can also be used to abstract the business\n logic of custom login/auth too.\n */\npublic protocol CapabilityProtocol {\n\n    associatedtype Status: AuthorizationStatus\n\n    /**\n     A requirement of the capability. E.g. for Location this\n     might be acces \"when in use\" or \"always\"\n\n     - returns: the necessary Status.Requirement\n    */\n    var requirement: Status.Requirement? { get }\n\n    /**\n     Query the capability to see if it's available on the device.\n\n     - returns: true Bool value if the capability is available.\n     */\n    func isAvailable() -> Bool\n\n    /**\n     Get the current authorization status of the capability. This\n     can be performed asynchronously. The status is returns as the\n     argument to a completion block.\n\n     - parameter completion: a (Status) -> Void closure.\n     */\n    func getAuthorizationStatus(_ completion: @escaping (Status) -> Void)\n\n    /**\n     Request authorization with the requirement of the capability.\n\n     Again, this is designed to be performed asynchronously. More than\n     likely the registrar will present a dialog and wait for the user.\n     When control is returned, the completion block should be called.\n\n     - parameter completion: a () -> Void closure.\n     */\n    func requestAuthorization(withCompletion completion: @escaping () -> Void)\n}\n\n/**\n Capability is a namespace to nest as aliases the\n various device capability types.\n */\npublic struct Capability { }\n\nextension Capability {\n\n    /**\n     A capability might not have the need for\n     an authorization level, but still might not be available. For example\n     PassKit. In which case, use VoidStatus as the nested Status type.\n     */\n    public struct VoidStatus: AuthorizationStatus, Equatable {\n\n        public static func == (_: VoidStatus, _: VoidStatus) -> Bool {\n            return true\n        }\n\n        /// - returns: true, VoidStatus cannot fail to meet requirements.\n        public func meets(requirement: Void?) -> Bool {\n            return true\n        }\n    }\n}\n\n// MARK: - AnyCapability\n\n// swiftlint:disable generic_type_name\n\ninternal class AnyCapabilityBox_<_Status: AuthorizationStatus>: CapabilityProtocol {\n    typealias Status = _Status // Workaround for Swift 4: SR-5016\n    var requirement: Status.Requirement? { _abstractMethod(); return nil }\n    func isAvailable() -> Bool { _abstractMethod(); return false }\n    func getAuthorizationStatus(_ completion: @escaping (Status) -> Void) { _abstractMethod() }\n    func requestAuthorization(withCompletion completion: @escaping () -> Void) { _abstractMethod() }\n}\n\ninternal class AnyCapabilityBox<Base: CapabilityProtocol>: AnyCapabilityBox_<Base.Status> {\n\n    private var base: Base\n\n    init(_ base: Base) {\n        self.base = base\n    }\n\n    override var requirement: Base.Status.Requirement? { return base.requirement }\n    override func isAvailable() -> Bool {\n        return base.isAvailable()\n    }\n    override func getAuthorizationStatus(_ completion: @escaping (Base.Status) -> Void) {\n        base.getAuthorizationStatus(completion)\n    }\n    override func requestAuthorization(withCompletion completion: @escaping () -> Void) {\n        base.requestAuthorization(withCompletion: completion)\n    }\n}\n\npublic struct AnyCapability<_Status: AuthorizationStatus>: CapabilityProtocol {\n    public typealias Status = _Status // Workaround for Swift 4: SR-5016\n    private typealias Erased = AnyCapabilityBox_<Status>\n\n    private var box: Erased\n\n    init<Base: CapabilityProtocol>(_ base: Base) where Status == Base.Status {\n        box = AnyCapabilityBox(base)\n    }\n\n    public var requirement: Status.Requirement? { return box.requirement }\n    public func isAvailable() -> Bool {\n        return box.isAvailable()\n    }\n    public func getAuthorizationStatus(_ completion: @escaping (Status) -> Void) {\n        return box.getAuthorizationStatus(completion)\n    }\n    public func requestAuthorization(withCompletion completion: @escaping () -> Void) {\n        box.requestAuthorization(withCompletion: completion)\n    }\n}\n\n// swiftlint:enable generic_type_name\n\n// MARK: - Procedures\n\n/**\n A generic procedure which will get the current authorization\n status for AnyCapability<Status>.\n */\npublic class GetAuthorizationStatusProcedure<Status: AuthorizationStatus>: Procedure, OutputProcedure {\n\n    /// the StatusResponse is a tuple for the capabilities availability and status\n    public typealias StatusResponse = (Bool, Status)\n\n    /// the Completion is a closure which receives a StatusResponse\n    public typealias Completion = (StatusResponse) -> Void\n\n    /**\n     After the procedure has executed, this property will be set\n     to the result.\n\n     - returns: a StatusResponse\n     */\n    public var output: Pending<ProcedureResult<StatusResponse>> = .pending\n\n    fileprivate let capability: AnyCapability<Status>\n    fileprivate let completion: Completion?\n\n    /**\n     Initialize the operation with a base type which conforms to CapabilityProtocol\n     and an optional completion block.\n\n     - parameter capability: the Capability.\n     - parameter completion: an optional Completion closure.\n     */\n    public init<Base>(_ base: Base, completion block: Completion? = nil) where Base: CapabilityProtocol, Status == Base.Status {\n        capability = AnyCapability(base)\n        completion = block\n        super.init()\n    }\n\n    public override func execute() {\n        determineStatus { status in\n            self.output = .ready(.success(status))\n            self.completion?(status)\n            self.finish()\n        }\n    }\n\n    func determineStatus(completion: @escaping Completion) {\n        let isAvailable = capability.isAvailable()\n        capability.getAuthorizationStatus { status in\n            completion((isAvailable, status))\n        }\n    }\n}\n\n/// A generic procedure which will authorize a capability\npublic class AuthorizeCapabilityProcedure<Status: AuthorizationStatus>: GetAuthorizationStatusProcedure<Status> {\n\n    /**\n     Initialize the operation with a base type which conforms to CapabilityProtocol\n     and an optional completion block. This operation is mutually exclusive with\n     other AuthorizeCapabilityProcedures with the same base type CapabilityProtocol.\n\n     - parameter capability: the Capability.\n     - parameter completion: an optional Completion closure.\n     */\n    public override init<Base>(_ base: Base, completion block: Completion? = nil) where Base: CapabilityProtocol, Status == Base.Status {\n        super.init(base, completion: block)\n        addCondition(MutuallyExclusive<AuthorizeCapabilityProcedure>(category: \"AuthorizeCapabilityProcedure(\\(String(describing: type(of: base))))\"))\n    }\n\n    public override func execute() {\n        capability.requestAuthorization {\n            super.execute()\n        }\n    }\n}\n\n/**\n This is a Condition which can be used to allow or\n deny procedures to execute depending on the authorization status of a\n capability and its requirements.\n\n By default, the condition will add an Authorize operation as a dependency\n which means that potentially the user will be prompted to grant\n authorization. Suppress this from happening by wrapping in a SilentCondition.\n */\npublic class AuthorizedFor<Status: AuthorizationStatus>: Condition {\n\n    fileprivate let capability: AnyCapability<Status>\n\n    public init<Base>(_ base: Base, category: String? = nil) where Base: CapabilityProtocol, Status == Base.Status {\n        capability = AnyCapability(base)\n        super.init()\n        if let category = category {\n            addToAttachedProcedure(mutuallyExclusiveCategory: category)\n        }\n        produceDependency(AuthorizeCapabilityProcedure(base))\n    }\n\n    public override func evaluate(procedure: Procedure, completion: @escaping (ConditionResult) -> Void) {\n        guard capability.isAvailable() else {\n            completion(.failure(ProcedureKitError.capabilityUnavailable())); return\n        }\n\n        capability.getAuthorizationStatus { [requirement = self.capability.requirement] status in\n            if status.meets(requirement: requirement) {\n                completion(.success(true))\n            }\n            else {\n                completion(.failure(ProcedureKitError.capabilityUnauthorized()))\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKit/Collection+ProcedureKit.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport Foundation\n\nextension Collection where Iterator.Element: Operation {\n\n    internal var operationsAndProcedures: ([Operation], [Procedure]) {\n        // this for-in loop has considerably better performance characteristics than reduce()\n        var operations: [Operation] = []\n        var procedures: [Procedure] = []\n        for element in self {\n            if let procedure = element as? Procedure {\n                procedures.append(procedure)\n            }\n            else {\n                operations.append(element)\n            }\n        }\n        return (operations, procedures)\n    }\n\n    internal var conditions: [Condition] {\n        return compactMap { $0 as? Condition }\n    }\n    \n    @available(*, deprecated, message: \"Use underlying quality of service APIs instead.\")\n    internal var userIntent: UserIntent {\n        get { return .none }\n    }\n\n    internal func forEachProcedure(body: (Procedure) throws -> Void) rethrows {\n        try forEach {\n            if let procedure = $0 as? Procedure {\n                try body(procedure)\n            }\n        }\n    }\n\n    /**\n     Add the operations of the receiver as dependencies of each element of the argument sequence.\n     An Array of the receiver extended by the argument is returned.\n     - parameter operation: the Iterator.Element instance to add the receiver as a dependency.\n     - returns: an array of all operations operations.\n     */\n    public func then<S: Sequence>(do sequence: S) -> [Iterator.Element] where S.Iterator.Element == Iterator.Element {\n        var operations = Array(self)\n        for operation in self {\n            assert(!operation.isFinished, \"Cannot add a finished operation as a dependency.\")\n            sequence.forEach { $0.addDependency(operation) }\n        }\n        operations += sequence\n        return operations\n    }\n\n    /**\n     Add the operations of the receiver as dependencies of each element of the argument.\n     An Array of the receiver extended by the argument is returned.\n     - parameter operations: a variable argument of Iterator.Element instance(s) to\n         add the receiver as a dependency.\n     - returns: an array of all operations.\n     */\n    public func then(do operations: Iterator.Element...) -> [Iterator.Element] {\n        return then(do: operations)\n    }\n\n    /**\n     Add the result of a closure onto the receiver.\n     - parameter block: a throwing closure which returns an optional element\n     - returns: an array of all operations.\n     */\n    func then(do block: () throws -> Iterator.Element?) rethrows -> [Iterator.Element] {\n        guard let operations = try block() else { return Array(self) }\n        return then(do: operations)\n    }\n\n    /**\n     Adds the receiver to a ProcedureQueue.\n     - parameter queue: a ProcedureQueue, with a default argument\n    */\n    func enqueue(on queue: ProcedureQueue = ProcedureQueue()) {\n        queue.addOperations(self)\n    }\n}\n\n// MARK: - OutputProcedure & Gathering\n\nextension Collection where Iterator.Element: OutputProcedure {\n\n    /// Creates a new procedure which will flatmap the non-nil results of the receiver's procedures into a\n    /// new array. This new array is available as the result of the returned procedure.\n    ///\n    /// - Parameter transform: a throwing closure which receives the result from the receiver's procedure.\n    /// - Returns: a ResultProcedure<[T]> procedure.\n    public func flatMap<T>(transform: @escaping (Self.Iterator.Element.Output) throws -> T?) -> ResultProcedure<[T]> {\n\n        let mapped = ResultProcedure { try self.compactMap { $0.output.success }.compactMap(transform) }\n\n        forEach(mapped.addDependency)\n\n        return mapped\n    }\n\n    /// Creates a new procedure which will reduce the non-nil results of the receiver's procedures into a single type, using\n    /// and initial result, and combining closure.\n    ///\n    /// - Parameters:\n    ///   - initialResult: the initial result\n    ///   - nextPartialResult: a closure which receives the partial result, and next element (result) returns the next partial result.\n    /// - Returns: a ResultProcedure<ReducedResult> procedure\n    public func reduce<ReducedResult>(_ initialResult: ReducedResult, _ nextPartialResult: @escaping (ReducedResult, Self.Iterator.Element.Output) throws -> ReducedResult) -> ResultProcedure<ReducedResult> {\n\n        let result = ResultProcedure { try self.compactMap { $0.output.success }.reduce(initialResult, nextPartialResult) }\n\n        forEach(result.addDependency)\n\n        return result\n    }\n\n    /// Creates a new procedure which will gather the non-nil results of the receiver's procedures into a single array\n    ///\n    /// - Returns: a ResultProcedure<[Self.Iterator.Element.Result]> procedur\n    public func gathered() -> ResultProcedure<[Self.Iterator.Element.Output]> {\n        return flatMap(transform: { $0 })\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKit/Composed.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport Foundation\nimport Dispatch\n\n/**\n A `Procedure` which can be used to compose an Operation.\n It is designed to be subclassed or used directly.\n\n This can be useful for wrapping an (unmodifiable / system framework) Operation subclass inside\n a `Procedure`, gaining the advantages of a `Procedure` (such as Observers).\n\n - note: If you can modify the Operation subclass yourself, you may be better off migrating it\n to a `Procedure` subclass. In cases where you cannot modify the Operation subclass, such as when\n it's part of another framework for which you do not have the source code, ComposedProcedure can\n be used.\n\n - note: CloudKitProcedure internally uses a ComposedProcedure subclass (`CKProcedure`) to wrap\n CKOperation subclasses.\n */\nopen class ComposedProcedure<T: Operation>: GroupProcedure {\n\n    /// The composed operation (T)\n    public private(set) var operation: T\n\n    /// Initialize a ComposedProcedure to wrap a specified T (Operation subclass)\n    ///\n    /// - Parameter composed: the composed operation (T)\n    public convenience init(_ composed: T) {\n        self.init(operation: composed)\n    }\n\n    /// Initialize a ComposedProcedure to wrap a specified T (Operation subclass),\n    /// optionally specifying an underlying DispatchQueue.\n    ///\n    /// - Parameters:\n    ///   - dispatchQueue: the underlying DispatchQueue for the internal ProcedureQueue onto which the composed operation is submitted\n    ///   - operation: the composed operation (T)\n    public init(dispatchQueue: DispatchQueue? = nil, operation: T) {\n        self.operation = operation\n        super.init(dispatchQueue: dispatchQueue, operations: [operation])\n    }\n}\n\n/// Conformance for ComposedProcedure where T implements InputProcedure\nextension ComposedProcedure: InputProcedure where T: InputProcedure {\n\n    public typealias Input = T.Input\n\n    public var input: Pending<T.Input> {\n        get { return operation.input }\n        set { operation.input = newValue }\n    }\n}\n\n/// Conformance for ComposedProcedure where T implements OutputProcedure\nextension ComposedProcedure: OutputProcedure where T: OutputProcedure {\n\n    public typealias Output = T.Output\n\n    public var output: Pending<ProcedureResult<T.Output>> {\n        get { return operation.output }\n        set { operation.output = newValue }\n    }\n}\n\n/**\n A `Procedure` which composes an Operation, with a block.\n The block returns a boolean, and can be used for simple control flow.\n */\nopen class GatedProcedure<T: Operation>: ComposedProcedure<T> {\n\n    /// Initialize a GatedProcedure to wrap a specified Operation subclass T\n    ///\n    /// - Parameters:\n    ///   - composed: the composed Operation subclass T\n    ///   - gate: an escaping ThrowingBoolBlock\n    public convenience init(_ composed: T, gate: @escaping ThrowingBoolBlock) {\n        self.init(operation: composed, gate: gate)\n    }\n\n    /// Initialize a GatedProcedure to wrap a specified Operation subclass T\n    ///\n    /// - Parameters:\n    ///   - dispatchQueue: the underlying DispatchQueue for the internal ProcedureQueue onto which the composed operation is submitted\n    ///   - composed: the composed Operation subclass T\n    ///   - gate: an escaping ThrowingBoolBlock\n    public init(dispatchQueue: DispatchQueue? = nil, operation: T, gate: @escaping ThrowingBoolBlock) {\n        super.init(dispatchQueue: dispatchQueue, operation: operation)\n        addCondition(IgnoredCondition(BlockCondition(block: gate)))\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKit/Condition.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n// swiftlint:disable file_length\n\nimport Foundation\n\n/**\n ConditionResult encompasses 3 states:\n 1. `.success(true)`\n 2. `.success(false)`\n 3. `.failure(let error)`\n\n Generally:\n - If a Condition succeeds, return `.success(true)`.\n - If a Condition *fails*, return `.failure(error)` with a unique error\n defined for your Condition.\n\n In some situations, it can be beneficial for a Procedure to not collect an\n error if an attached condition fails. You can use `IgnoredCondition` to\n suppress the error associated with any Condition. This is generally\n preferred to returning `.success(false)` directly.\n */\npublic typealias ConditionResult = ProcedureResult<Bool>\n\npublic protocol ConditionProtocol: Hashable {\n\n    /// Dependencies to produce and wait on.\n    ///\n    /// The framework will automatically schedule these dependencies to run\n    /// after all dependencies on the attached Procedure, and will wait for\n    /// these dependencies to finish before the Condition's\n    /// `evaluate(procedure:completion:)` function is called.\n    ///\n    /// It is programmer error to add an Operation to the `producedDependencies`\n    /// this is already scheduled for execution or executing, or that will be\n    /// scheduled for execution elsewhere.\n    var producedDependencies: Set<Operation> { get }\n\n    /// Dependencies to wait on.\n    ///\n    /// The framework will wait for these dependencies to finish\n    /// before the Condition's `evaluate(procedure:completion:)`\n    /// function is called.\n    var dependencies: Set<Operation> { get }\n\n    /// Mutually exclusive categories to apply to the attached Procedure.\n    ///\n    /// Only one Procedure with a particular mutuallyExclusiveCategory may\n    /// execute at a time.\n    var mutuallyExclusiveCategories: Set<String> { get }\n\n    /// Called before a Condition is added to a Procedure.\n    ///\n    /// - Parameter procedure: the Procedure to which the Condition is being added\n    func willAttach(to procedure: Procedure)\n\n    /// Called to evaluate the Condition on a Procedure.\n    /// Must always call `completion` with the result.\n    func evaluate(procedure: Procedure, completion: @escaping (ConditionResult) -> Void)\n}\n\npublic extension ConditionProtocol {\n\n    var isMutuallyExclusive: Bool {\n        return !mutuallyExclusiveCategories.isEmpty\n    }\n}\n\n// MARK: Condition Errors\n\npublic extension ProcedureKitError {\n\n    struct FailedConditions: Error {\n        public let errors: [Error]\n\n        internal init(errors: [Error]) {\n            self.errors = errors\n        }\n\n        internal func append(error: Error) -> FailedConditions {\n            var errors = self.errors\n            if let failedConditions = error as? FailedConditions {\n                errors.append(contentsOf: failedConditions.errors)\n            }\n            else {\n                errors.append(error)\n            }\n            return FailedConditions(errors: errors)\n        }\n    }\n\n    struct FalseCondition: Error, Equatable {\n        public init() { }\n    }\n\n    struct ConditionEvaluationCancelled: Error {\n        public init() { }\n    }\n\n    struct ConditionDependenciesFailed: Error, Equatable, CustomStringConvertible {\n\n        public let condition: Condition\n\n        internal init(condition: Condition) {\n            self.condition = condition\n        }\n\n        public var description: String {\n            return \"ProcedureKitError.ConditionDependenciesFailed(condition: \\(condition))\"\n        }\n    }\n\n    struct ConditionDependenciesCancelled: Error, Equatable, CustomStringConvertible {\n\n        public let condition: Condition\n\n        internal init(condition: Condition) {\n            self.condition = condition\n        }\n\n        public var description: String {\n            return \"ProcedureKitError.ConditionDependenciesCancelled(condition: \\(condition))\"\n        }\n    }\n}\n\n/**\n Conditions are attached to a Procedure. Before a Procedure executes, it will\n asynchronously evaluate all of its conditions. If a condition fails, the\n Procedure cancels with an error instead of executing.\n\n For example:\n ```swift\n procedure.add(condition: BlockCondition {\n     // procedure will cancel instead of executing if this is false\n     return trueOrFalse\n })\n ```\n\n Conditions are evaluated after all of the Procedure's dependencies have finished.\n\n A Condition can also produce its own dependencies, which are executed after the\n Procedure's dependencies have finished, but _prior_ to evaluating the Condition.\n Thus, if a crucial detail must be set to satisfy the condition, it can be\n performed in its own Operation / Procedure.\n\n ProcedureKit has several built-in Conditions, like `BlockCondition` and\n `MutuallyExclusive<T>`. It is also easy to implement your own.\n\n ## Implementing a Custom Condition\n\n First, subclass `Condition`. Then, override `evaluate(procedure:completion:)`.\n Here is a simple example - a FalseCondition that always fails:\n\n ```swift\n public class FalseCondition: Condition {\n     public override func evaluate(procedure: Procedure, completion: @escaping (ConditionResult) -> Void) {\n        completion(.failure(ProcedureKitError.FalseCondition()))\n     }\n }\n ```\n\n ### Calling the Completion Block\n\n Your `evaluate(procedure:completion:)` override *must* eventually call the\n completion block with a `ConditionResult`. (Although it may, of course, be\n called asynchronously.)\n\n `ConditionResult` encompasses 3 states:\n 1. `.success(true)`\n 2. `.success(false)`\n 3. `.failure(let error: Error)`\n\n Generally:\n - If a Condition *succeeds*, return `.success(true)`.\n - If a Condition *fails*, return `.failure(error)` with a unique error\n defined for your Condition.\n\n In some situations, it can be beneficial for a Procedure to not collect an\n error if an attached condition fails. You can use `IgnoredCondition` to\n suppress the error associated with any Condition. This is generally\n preferred to returning `.success(false)` directly.\n */\nopen class Condition: ConditionProtocol, Hashable {\n\n    /// Requirements to be verified of all Condition dependencies once they are finished\n    /// (and before the Condition's evaluate method is called).\n    ///\n    /// Failures are evaluated before cancellations. Thus, if [.noFailed, .noCancelled] is specified:\n    /// 1. You will receive `ProcedureKitError.ConditionDependenciesFailed` if any Conditions finished\n    /// with errors (i.e. failed).\n    /// 2. If not, you will receive `ProcedureKitError.ConditionDependenciesCancelled` if any\n    /// dependencies are cancelled.\n    ///\n    /// - noFailed: Verifies that no dependencies have finished with errors. If any dependencies have, the Condition fails with a `ProcedureKitError.ConditionDependenciesFailed` error.\n    /// - ignoreFailedIfCancelled: Does not consider a dependency to have failed if it's cancelled. (To be used with .noFailed.)\n    ///\n    /// - noCancelled: Verifies that no dependencies are cancelled. If any dependencies are cancelled, the Condition fails with a `ProcedureKitError.ConditionDependenciesCancelled` error.\n    ///\n    /// - noFailedOrCancelled: [.noFailed, .noCancelled] (Verifies that no dependencies are failed nor cancelled.)\n    /// - none: Do not automatically verify any properties of the dependencies once they are finished.\n    public struct DependencyRequirements: OptionSet {\n        public let rawValue: UInt8\n        public init(rawValue: UInt8) { self.rawValue = rawValue }\n\n        public static let noFailed                  = DependencyRequirements(rawValue: 1 << 0)\n        public static let ignoreFailedIfCancelled   = DependencyRequirements(rawValue: 1 << 1)\n        public static let noCancelled               = DependencyRequirements(rawValue: 1 << 2)\n\n        public static let noFailedOrCancelled: DependencyRequirements = [.noFailed, .noCancelled]\n        public static let none: DependencyRequirements = []\n    }\n\n    fileprivate let stateLock = PThreadMutex()\n    private weak var _procedure: Procedure?\n    fileprivate var _name: String? // swiftlint:disable:this variable_name\n    private var _dependencyRequirements: DependencyRequirements = .none\n    fileprivate var _output: Pending<ConditionResult> = .pending // swiftlint:disable:this variable_name\n    private var _producedDependencies = Set<Operation>()\n    private var _dependencies = Set<Operation>()\n    private var _mutuallyExclusiveCategories = Set<String>()\n\n    fileprivate func synchronise<T>(block: () -> T) -> T {\n        return stateLock.withCriticalScope(block: block)\n    }\n\n    /// Dependencies to produce and wait on.\n    ///\n    /// The framework will automatically schedule these dependencies to run\n    /// after all dependencies on the attached `Procedure`, and will wait for\n    /// these dependencies to finish before the Condition's\n    /// `evaluate(procedure:completion:)` function is called.\n    ///\n    /// - IMPORTANT:\n    /// It is programmer error to add an Operation to the `producedDependencies`\n    /// that is already scheduled for execution or executing, or that will be\n    /// scheduled for execution elsewhere.\n    public var producedDependencies: Set<Operation> {\n        return synchronise { _producedDependencies }\n    }\n\n    /// Dependencies to wait on, added via `add(dependency:)`.\n    ///\n    /// The framework will wait for these dependencies to finish\n    /// before the Condition's `evaluate(procedure:completion:)`\n    /// function is called.\n    public var dependencies: Set<Operation> {\n        return synchronise { _dependencies }\n    }\n\n    /// Mutually exclusive categories to apply to the attached Procedure.\n    ///\n    /// Only one Procedure with a particular mutuallyExclusiveCategory may\n    /// execute at a time.\n    public var mutuallyExclusiveCategories: Set<String> {\n        return synchronise { _mutuallyExclusiveCategories }\n    }\n\n    /// A descriptive name for the Condition. (optional)\n    public var name: String? {\n        get { return synchronise { _name } }\n        set { synchronise { _name = newValue } }\n    }\n\n    /// Requirements that must be satisfied after all dependencies are finished, before\n    /// the Condition is evaluated by the framework.\n    ///\n    /// If the requirements fail, the Condition will fail. See `DependencyRequirements`.\n    ///\n    /// The default is \".none\", which performs no checks on the dependencies after they\n    /// are finished.\n    ///\n    /// - See: `DependencyRequirements`\n    public var dependencyRequirements: DependencyRequirements {\n        get { return synchronise { _dependencyRequirements } }\n        set {\n            synchronise {\n                debugAssertConditionNotAttachedToProcedure(\"Dependency requirement must be modified before the Condition is added to a Procedure.\")\n                _dependencyRequirements = newValue\n            }\n        }\n    }\n\n    /// The ConditionResult.\n    /// Will be Pending.ready(ConditionResult) once the Condition has been evaluated.\n    public var output: Pending<ConditionResult> {\n        return synchronise { _output }\n    }\n\n    public init() { }\n\n    /// Called before a Condition is added to a Procedure.\n    ///\n    /// - Parameter procedure: the Procedure to which the Condition is being added\n    public func willAttach(to procedure: Procedure) {\n        synchronise {\n            debugAssertConditionNotAttachedToProcedure(\"Cannot add a single Condition instance to multiple Procedures.\")\n            _procedure = procedure\n        }\n    }\n\n    // MARK: Mutual Exclusivity\n\n    /// Adds a mutually exclusive category to be applied to the attached Procedure.\n    ///\n    /// Only one Procedure with a particular mutuallyExclusiveCategory may execute at a time.\n    ///\n    /// - Parameter mutuallyExclusiveCategory: a String, which should be unique per category\n    final public func addToAttachedProcedure(mutuallyExclusiveCategory: String) {\n        synchronise {\n            debugAssertConditionNotAttachedToProcedure(\"Categories must be modified before the Condition is added to a Procedure.\")\n            _mutuallyExclusiveCategories.insert(mutuallyExclusiveCategory)\n        }\n    }\n\n    // MARK: Dependencies\n\n    /// Produce a dependency that the `Condition` runs before evaluation.\n    ///\n    /// Dependencies produced in this way are scheduled after all dependencies on\n    /// the attached `Procedure`, but prior to the `evaluate(procedure:completion)`\n    /// method being called.\n    ///\n    /// The Condition \"owns\" the dependency, and the framework will handle\n    /// scheduling and running the dependency at the appropriate time.\n    /// - IMPORTANT: Do *not* separately add the dependency to your own queue.\n    ///\n    /// If you want to add a dependency that has been or will be separately added\n    /// to a queue (or otherwise scheduled for execution), use `add(dependency:)` instead.\n    ///\n    /// - IMPORTANT:\n    /// It is a programmer error to produce the same Operation instance on more than\n    /// one `Condition` instance.\n    ///\n    /// - Parameter dependency: an Operation to be produced as a dependency\n    final public func produceDependency(_ dependency: Operation) {\n        assert(!dependency.isExecuting, \"Do not call produce(dependency:) with an Operation that is already executing.\")\n        assert(!dependency.isFinished, \"Do not call produce(dependency:) with an Operation that is already finished.\")\n        synchronise {\n            debugAssertConditionNotAttachedToProcedure(\"Dependencies must be modified before the Condition is added to a Procedure.\")\n            _producedDependencies.insert(dependency)\n        }\n    }\n\n    /// Adds a dependency, just like `Procedure.addDependency(_:)`.\n    ///\n    /// The framework will wait for the dependency to finish before the Condition's \n    /// `evaluate(procedure:completion:)` function is called.\n    ///\n    /// - IMPORTANT:\n    /// Does not schedule the dependency for execution. You must do this elsewhere by,\n    /// for example, adding it to an `OperationQueue` / `ProcedureQueue`.\n    ///\n    /// - Parameter dependency: an Operation to be added as a dependency\n    final public func addDependency(_ dependency: Operation) {\n        synchronise {\n            debugAssertConditionNotAttachedToProcedure(\"Dependencies must be modified before the Condition is added to a Procedure.\")\n            _dependencies.insert(dependency)\n        }\n    }\n\n    /// Add dependencies, just like `Procedure.addDependencies(_:)`.\n    ///\n    /// The framework will wait for the dependencies to finish before the Condition's\n    /// `evaluate(procedure:completion:)` function is called.\n    ///\n    /// - IMPORTANT:\n    /// Does not schedule the dependencies for execution. You must do this elsewhere by,\n    /// for example, adding it to an `OperationQueue` / `ProcedureQueue`.\n    ///\n    /// - Parameter dependencies: an array of Operations to be added as a dependencies\n    final public func addDependencies(_ dependencies: [Operation]) {\n        synchronise {\n            debugAssertConditionNotAttachedToProcedure(\"Dependencies must be modified before the Condition is added to a Procedure.\")\n            _dependencies.formUnion(dependencies)\n        }\n    }\n\n    final public func addDependencies(_ dependencies: Operation...) {\n        addDependencies(dependencies)\n    }\n\n    /// Removes a dependency.\n    ///\n    /// - Parameter dependency: an Operation to be removed from the `producedDependencies` and/or `dependencies`.\n    public func removeDependency(_ dependency: Operation) {\n        synchronise {\n            debugAssertConditionNotAttachedToProcedure(\"Dependencies must be modified before the Condition is added to a Procedure.\")\n            _dependencies.remove(dependency)\n            _producedDependencies.remove(dependency)\n        }\n    }\n\n    /// Removes dependencies.\n    ///\n    /// - Parameter dependencies: an array of Operations to be removed from the `producedDependencies` and/or `dependencies`.\n    public func removeDependencies(_ dependencies: [Operation]) {\n        synchronise {\n            debugAssertConditionNotAttachedToProcedure(\"Dependencies must be modified before the Condition is added to a Procedure.\")\n            dependencies.forEach {\n                _dependencies.remove($0)\n                _producedDependencies.remove($0)\n            }\n        }\n    }\n\n    public func removeDependencies(_ dependencies: Operation...) {\n        removeDependencies(dependencies)\n    }\n\n    // MARK: Evaluate\n\n    /// Must be overriden in Condition subclasses.\n    /// Must always call `completion` with the result.\n    open func evaluate(procedure: Procedure, completion: @escaping (ConditionResult) -> Void) {\n        let reason = \"Condition must be subclassed, and \\(#function) overridden.\"\n        let result: ConditionResult = .failure(ProcedureKitError.programmingError(reason: reason))\n        completion(result)\n    }\n\n    // MARK: Hashable\n\n    public static func == (lhs: Condition, rhs: Condition) -> Bool {\n        return lhs === rhs\n    }\n    \n    public func hash(into hasher: inout Hasher) {\n        hasher.combine(ObjectIdentifier(self).hashValue)\n    }\n\n\n    // MARK: Internal Implementation\n\n    internal func evaluate(procedure: Procedure, withContext context: ConditionEvaluationContext, completion: @escaping (ConditionResult) -> Void) {\n        // Default is to ignore the context, and simply call the overriden open evaluate method\n        evaluate(procedure: procedure, completion: completion)\n    }\n}\n\nextension Condition {\n\n    public var isMutuallyExclusive: Bool {\n        return !mutuallyExclusiveCategories.isEmpty\n    }\n}\n\ninternal extension Condition {\n    /// Set a descriptive name for the Condition.\n    ///\n    /// - Parameters:\n    ///   - name: the new name (String)\n    ///   - ifNotAlreadySet: if `true` (the default), the new name will only be set if the existing name is `nil`\n    /// - Returns: the resulting name for the Condition\n    func set(name: String, ifNotAlreadySet: Bool = true) -> String {\n        return synchronise {\n            if ifNotAlreadySet, let existingName = _name {\n                return existingName\n            }\n            _name = name\n            return name\n        }\n    }\n\n    // Set the output (once the Condition has been evaluated).\n    func set(output: ConditionResult) {\n        synchronise {\n            assert(_output.isPending, \"Trying to set output of Condition evaluation more than once.\")\n            _output = .ready(output)\n        }\n    }\n}\n\n// MARK: - Internal Extensions\n\ninternal extension Condition {\n\n    func debugAssertConditionNotAttachedToProcedure(_ message: String = \"Condition is already attached to a Procedure.\") {\n        #if DEBUG\n        guard _procedure == nil else {\n            assertionFailure(\"Dependencies must be modified before the Condition is added to a Procedure.\")\n            return\n        }\n        #endif\n    }\n}\n\n// MARK: - Deprecations\n\npublic extension Condition {\n\n    @available(*, deprecated, renamed: \"produceDependency(_:)\", message: \"This has been renamed to use Swift 3/4 naming conventions\")\n    final func produce(dependency: Operation) {\n        produceDependency(dependency)\n    }\n\n    @available(*, deprecated, renamed: \"addDependency(_:)\", message: \"This has been renamed to use Swift 3/4 naming conventions\")\n    final func add(dependency: Operation) {\n        addDependency(dependency)\n    }\n\n    @available(*, deprecated, renamed: \"addDependencies(_:)\", message: \"This has been renamed to use Swift 3/4 naming conventions\")\n    final func add(dependencies: [Operation]) {\n        addDependencies(dependencies)\n    }\n\n    @available(*, deprecated, renamed: \"addDependencies(_:)\", message: \"This has been renamed to use Swift 3/4 naming conventions\")\n    final func add(dependencies: Operation...) {\n        addDependencies(dependencies)\n    }\n\n    @available(*, deprecated, renamed: \"removeDependency(_:)\", message: \"This has been renamed to use Swift 3/4 naming conventions\")\n    func remove(dependency: Operation) {\n        removeDependency(dependency)\n    }\n\n    @available(*, deprecated, renamed: \"removeDependencies(_:)\", message: \"This has been renamed to use Swift 3/4 naming conventions\")\n    func remove(dependencies: [Operation]) {\n        removeDependencies(dependencies)\n    }\n\n    @available(*, deprecated, renamed: \"removeDependencies(_:)\", message: \"This has been renamed to use Swift 3/4 naming conventions\")\n    func remove(dependencies: Operation...) {\n        removeDependencies(dependencies)\n    }\n}\n\n// MARK: - Condition Subclasses\n\n/**\n A `Condition` subclass that always evaluates successfully.\n\n - seealso: `FalseCondition`\n */\npublic class TrueCondition: Condition {\n\n    public init(name: String = \"TrueCondition\", mutuallyExclusiveCategory: String? = nil) {\n        super.init()\n        self.name = name\n        if let category = mutuallyExclusiveCategory {\n            addToAttachedProcedure(mutuallyExclusiveCategory: category)\n        }\n    }\n\n    public override func evaluate(procedure: Procedure, completion: @escaping (ConditionResult) -> Void) {\n        completion(.success(true))\n    }\n}\n\n/**\n A `Condition` subclass that always fails.\n\n - seealso: `TrueCondition`\n */\npublic class FalseCondition: Condition {\n\n    public init(name: String = \"FalseCondition\", mutuallyExclusiveCategory: String? = nil) {\n        super.init()\n        self.name = name\n        if let category = mutuallyExclusiveCategory {\n            addToAttachedProcedure(mutuallyExclusiveCategory: category)\n        }\n    }\n\n    public override func evaluate(procedure: Procedure, completion: @escaping (ConditionResult) -> Void) {\n        completion(.failure(ProcedureKitError.FalseCondition()))\n    }\n}\n\n/**\n A Condition subclass that evaluates a sequence of Conditions according to the desired\n compound predicate. (\"&&\", \"||\")\n\n For example, if you have two Conditions and you'd like the attached Procedure to\n proceed if *either* of them evaluates successfully, you can use the \"orPredicate\"\n behavior:\n\n ```swift\n // assuming \"condition1\" and \"condition2\" were previously defined\n procedure.add(condition: CompoundCondition(orPredicateWith: [condition1, condition2]))\n ```\n\n You can also use the `AndCondition` and `OrCondition` subclasses of `CompoundCondition`,\n if you prefer:\n\n ```swift\n // equivalent to the prior example\n procedure.add(condition: OrCondition(condition1, condition2))\n ```\n\n - see: `AndCondition`, `OrCondition`\n */\nopen class CompoundCondition: Condition {\n\n    public let conditions: [Condition]\n\n    private var _currentEvaluationContext: ConditionEvaluationContext?\n    private var currentEvaluationContext: ConditionEvaluationContext? {\n        get { return stateLock.withCriticalScope { _currentEvaluationContext } }\n        set {\n            stateLock.withCriticalScope {\n                assert(_currentEvaluationContext == nil, \"Evaluating the same Condition twice is not supported.\")\n                _currentEvaluationContext = newValue\n            }\n        }\n    }\n\n    private enum Kind {\n        case andPredicate\n        case orPredicate\n\n        var resultAggregationBehavior: ConditionResultAggregationBehavior {\n            switch self {\n            case .andPredicate: return .andPredicate\n            case .orPredicate: return .orPredicate\n            }\n        }\n\n        var description: String {\n            switch self {\n            case .andPredicate: return \"&&\"\n            case .orPredicate: return \"||\"\n            }\n        }\n    }\n    private let kind: Kind\n\n    // NOTE: A CompoundCondition, unlike a ComposedCondition, does not inherit its \n    //       conditions dependencies / producedDependencies.\n    //\n    //       Internally, a CompoundCondition uses the Condition Collection extension\n    //       `evaluate(procedure:withAggregationBehavior:withQueue:completion)`\n    //       method which handles dependencies (while supporting short-cut evaluation).\n    //\n    //       This is the same method that the Procedure.EvaluateConditions operation uses.\n\n    // However, it's important to inherit mutually-exclusive categories from all the conditions,\n    // so they are applied to the Procedure to which this CompoundCondition is attached.\n    override public var mutuallyExclusiveCategories: Set<String> {\n        return super.mutuallyExclusiveCategories.union(conditions.mutuallyExclusiveCategories)\n    }\n\n    /// A descriptive name for the Condition. (optional)\n    ///\n    /// It may be expensive to generate a name for a CompoundCondition.\n    /// This override delays that generation until the name is first requested\n    /// (unless something else, like a subclass, explicitly sets a name).\n    override public var name: String? {\n        get {\n            if let name = super.name {\n                return name\n            }\n            else {\n                // generate and cache the CompoundCondition name\n                // if another name hasn't already been set\n                return set(name: computeName(), ifNotAlreadySet: true)\n            }\n        }\n        set {\n            super.name = newValue\n        }\n    }\n\n    override public func willAttach(to procedure: Procedure) {\n        conditions.forEach { $0.willAttach(to: procedure) }\n        super.willAttach(to: procedure)\n    }\n\n    // MARK: Init - AndPredicate\n\n    /// Initialize a CompoundCondition that evaluates to the logical \"&&\"\n    /// of all the supplied conditions.\n    ///\n    /// i.e. The CompoundCondition will only succeed if all the supplied\n    /// conditions succeed.\n    ///\n    /// - Parameter conditions: a Sequence of Conditions\n    public init<S: Sequence>(andPredicateWith conditions: S) where S.Iterator.Element == Condition {\n        self.conditions = conditions.filterDuplicates()\n        self.kind = .andPredicate\n        super.init()\n    }\n\n    /// Initialize a CompoundCondition that evaluates to the logical \"&&\"\n    /// of all the supplied conditions.\n    ///\n    /// i.e. The CompoundCondition will only succeed if all the supplied\n    /// conditions succeed.\n    ///\n    /// - Parameter conditions: a sequence of Conditions\n    convenience public init(andPredicateWith conditions: Condition...) {\n        self.init(andPredicateWith: conditions)\n    }\n\n    // MARK: Init - OrPredicate\n\n    /// Initialize a CompoundCondition that evaluates to the logical \"||\"\n    /// of all the supplied conditions.\n    ///\n    /// i.e. As soon as one of the supplied conditions evaluates successfully,\n    /// the CompoundCondition will return success.\n    ///\n    /// - Parameter conditions: a Sequence of Conditions\n    public init<S: Sequence>(orPredicateWith conditions: S) where S.Iterator.Element == Condition {\n        self.conditions = conditions.filterDuplicates()\n        self.kind = .orPredicate\n        super.init()\n    }\n\n    /// Initialize a CompoundCondition that evaluates to the logical \"||\"\n    /// of all the supplied conditions.\n    ///\n    /// i.e. As soon as one of the supplied conditions evaluates successfully,\n    /// the CompoundCondition will return success.\n    ///\n    /// - Parameter conditions: a sequence of Conditions\n    convenience public init(orPredicateWith conditions: Condition...) {\n        self.init(orPredicateWith: conditions)\n    }\n\n    // MARK: Evaluate Override\n\n    /// Override of public function\n    ///\n    /// If you subclass `CompoundCondition` and override this method, you must call\n    /// `super.evaluate(procedure: completion:)`.\n    public final override func evaluate(procedure: Procedure, completion: @escaping (ConditionResult) -> Void) {\n        // Create an evaluation sub-context (if a current evaluation context is present)\n        let context = currentEvaluationContext?.subContext(withBehavior: kind.resultAggregationBehavior) ?? ConditionEvaluationContext(behavior: kind.resultAggregationBehavior)\n\n        // Utilize the Condition Collection extension `evaluate` method to\n        // evaluate the conditions (while handling dependencies and\n        // short-cut evaluation).\n        conditions.evaluate(procedure: procedure, withContext: context, completion: completion)\n    }\n\n    /// Override of internal function\n    internal override func evaluate(procedure: Procedure, withContext context: ConditionEvaluationContext, completion: @escaping (ConditionResult) -> Void) {\n        currentEvaluationContext = context\n        super.evaluate(procedure: procedure, withContext: context, completion: completion)\n    }\n\n    // MARK: Private Implementation\n\n    private func computeName() -> String {\n        func makeConditionsString(kind: Kind, conditions: [Condition]) {\n            var output: String = \"\"\n            for condition in conditions {\n                guard !output.isEmpty else {\n                    output.append(\"\\(condition)\")\n                    continue\n                }\n                output.append(\"\\(kind.description) \\(condition)\")\n            }\n        }\n        return \"CompoundCondition(\\(makeConditionsString(kind: kind, conditions: conditions)))\"\n    }\n}\n\n/**\n A Condition subclass that evaluates a sequence of Conditions according to the \"&&\"\n compound predicate. i.e. All Conditions in the sequence must succeed for the AndCondition\n to succeed.\n\n A subclass of `CompoundCondition` that provides custom initializers (for convenience)\n for \"&&\" behavior.\n\n - see: `CompoundCondition`\n */\nopen class AndCondition: CompoundCondition {\n\n    /// Initialize an AndCondition that evaluates to the logical \"&&\"\n    /// of all the supplied conditions.\n    ///\n    /// - Parameter conditions: an array of `Condition`s\n    public init(_ conditions: [Condition]) {\n        super.init(andPredicateWith: conditions)\n    }\n\n    /// Initialize an AndCondition that evaluates to the logical \"&&\"\n    /// of all the supplied conditions.\n    ///\n    /// - Parameter conditions: an sequence of `Condition`s\n    public init<S: Sequence>(_ conditions: S) where S.Iterator.Element == Condition {\n        super.init(andPredicateWith: conditions)\n    }\n\n    /// Initialize an AndCondition that evaluates to the logical \"&&\"\n    /// of all the supplied conditions.\n    ///\n    /// - Parameter conditions: a variadic array of `Condition`s\n    convenience public init(_ conditions: Condition...) {\n        self.init(conditions)\n    }\n}\n\n/**\n A Condition subclass that evaluates a sequence of Conditions according to the \"||\"\n compound predicate. i.e. At least one Condition in the sequence must succeed for the\n OrCondition to succeed.\n\n A subclass of `CompoundCondition` that provides custom initializers (for convenience)\n for \"||\" behavior.\n\n - see: `CompoundCondition`\n */\nopen class OrCondition: CompoundCondition {\n\n    /// Initialize an OrCondition that evaluates to the logical \"||\"\n    /// of all the supplied conditions.\n    ///\n    /// - Parameter conditions: an array of `Condition`s\n    public init(_ conditions: [Condition]) {\n        super.init(orPredicateWith: conditions)\n    }\n\n    /// Initialize an OrCondition that evaluates to the logical \"||\"\n    /// of all the supplied conditions.\n    ///\n    /// - Parameter conditions: an sequence of `Condition`s\n    public init<S: Sequence>(_ conditions: S) where S.Iterator.Element == Condition {\n        super.init(orPredicateWith: conditions)\n    }\n\n    /// Initialize an OrCondition that evaluates to the logical \"||\"\n    /// of all the supplied conditions.\n    ///\n    /// - Parameter conditions: a variadic array of `Condition`s\n    convenience public init(_ conditions: Condition...) {\n        self.init(conditions)\n    }\n}\n\n/**\n Class which can be used to compose a Condition, it is designed to be subclassed.\n\n This can be useful to automatically manage the dependency and automatic\n injection of the composed condition result for evaluation inside your custom subclass.\n\n - see: `NegatedCondition`\n - see: `SilentCondition`\n */\nopen class ComposedCondition<C: Condition>: Condition {\n\n    /**\n     The composed condition.\n\n     - parameter condition: a the composed `Condition`\n     */\n    public let condition: C\n\n    private var _currentEvaluationContext: ConditionEvaluationContext?\n    private var currentEvaluationContext: ConditionEvaluationContext? {\n        get { return stateLock.withCriticalScope { _currentEvaluationContext } }\n        set {\n            stateLock.withCriticalScope {\n                assert(_currentEvaluationContext == nil, \"Evaluating the same Condition twice is not supported.\")\n                _currentEvaluationContext = newValue\n            }\n        }\n    }\n\n    override public var producedDependencies: Set<Operation> {\n        return super.producedDependencies.union(condition.producedDependencies)\n    }\n\n    override public var dependencies: Set<Operation> {\n        return super.dependencies.union(condition.dependencies)\n    }\n\n    override public var mutuallyExclusiveCategories: Set<String> {\n        return super.mutuallyExclusiveCategories.union(condition.mutuallyExclusiveCategories)\n    }\n\n    override public func willAttach(to procedure: Procedure) {\n        condition.willAttach(to: procedure)\n        super.willAttach(to: procedure)\n    }\n\n    /**\n     Initializer which receives a condition.\n\n     - parameter [unnamed]: a nested `Condition` type.\n     */\n    public init(_ condition: C) {\n        self.condition = condition\n        super.init()\n        name = condition.name\n    }\n\n    /// Override of public function\n    open override func evaluate(procedure: Procedure, completion: @escaping (ConditionResult) -> Void) {\n        // pass-through the Evaluation Context provided for the current evaluation (if present)\n        let context = currentEvaluationContext ?? ConditionEvaluationContext()\n\n        // evaluate the composed condition\n        condition.evaluate(procedure: procedure, withContext: context) { [weak self] result in\n            self?.condition.set(output: result)\n            // call the completion block with the composed condition's result\n            completion(result)\n        }\n    }\n\n    override public func removeDependency(_ dependency: Operation) {\n        condition.removeDependency(dependency)\n        super.removeDependency(dependency)\n    }\n\n    internal override func evaluate(procedure: Procedure, withContext context: ConditionEvaluationContext, completion: @escaping (ConditionResult) -> Void) {\n        currentEvaluationContext = context\n        super.evaluate(procedure: procedure, withContext: context, completion: completion)\n    }\n}\n\n/**\n A condition that treats failures from a composed condition as `.success(false)`.\n\n Thus, the only two possible ConditionResult outputs from an IgnoredCondition are:\n - `.success(true)`\n - `.success(false)`\n\n And any failure errors will not be propagated to the attached Procedure.\n */\npublic class IgnoredCondition<C: Condition>: ComposedCondition<C> {\n\n    /// Public override of initializer.\n    public override init(_ condition: C) {\n        super.init(condition)\n        name = condition.name.map { \"Ignored<\\($0)>\" }\n    }\n\n    /// Override of public function\n    public override func evaluate(procedure: Procedure, completion: @escaping (ConditionResult) -> Void) {\n        super.evaluate(procedure: procedure) { composedResult in\n            if case .failure(_) = composedResult {\n                completion(.success(false))\n            }\n            else {\n                completion(composedResult)\n            }\n        }\n    }\n}\n\n// MARK: - Condition Logical Operator Support\n\npublic func && (lhs: Condition, rhs: Condition) -> AndCondition {\n    return AndCondition([lhs, rhs])\n}\n\npublic func || (lhs: Condition, rhs: Condition) -> OrCondition {\n    return OrCondition([lhs, rhs])\n}\n\npublic prefix func !<T> (rhs: T) -> NegatedCondition<T> {\n    return NegatedCondition(rhs)\n}\n\n// MARK: - Internal Helpers\n\ninternal class ConditionEvaluationContext {\n    var procedureQueue: ProcedureQueue {\n        return stateLock.withCriticalScope { _procedureQueue }\n    }\n    var isCancelled: Bool {\n        return stateLock.withCriticalScope { _isCancelled }\n    }\n    fileprivate let underlyingQueue: DispatchQueue\n    fileprivate let aggregator: ConditionResultAggregator\n\n    init(queue: DispatchQueue = DispatchQueue(label: \"run.kit.procedure.ProcedureKit.ConditionEvaluationContext\", attributes: [.concurrent]), behavior: ConditionResultAggregationBehavior = .andPredicate) {\n        self.underlyingQueue = queue\n        self.aggregator = ConditionResultAggregator(behavior: behavior)\n    }\n\n    private var stateLock = PThreadMutex()\n    private var _isCancelled: Bool = false\n    private var _subContexts: [ConditionEvaluationContext] = []\n    private var _procedureQueue: ProcedureQueue {\n        if __procedureQueue == nil {\n            // Lazily create a ProcedureQueue the first time it's needed\n            __procedureQueue = ProcedureQueue()\n            __procedureQueue!.underlyingQueue = underlyingQueue\n        }\n        return __procedureQueue!\n    }\n    private var __procedureQueue: ProcedureQueue? // swiftlint:disable:this variable_name\n\n    func cancel() {\n        stateLock.withCriticalScope {\n            _isCancelled = true\n            if let procedureQueue = __procedureQueue {\n                procedureQueue.cancelAllOperations()\n            }\n            for subContext in _subContexts {\n                subContext.cancel()\n            }\n            aggregator.cancel(withResult: .failure(ProcedureKitError.ConditionEvaluationCancelled()))\n        }\n    }\n\n    func queueOperation(_ operation: Operation) -> ProcedureFuture {\n        return stateLock.withCriticalScope {\n            if _isCancelled { operation.cancel() }\n            return _procedureQueue.addOperation(operation)\n        }\n    }\n\n    func queueOperations<S>(_ operations: S) -> ProcedureFuture where S: Sequence, S.Iterator.Element: Operation {\n        return stateLock.withCriticalScope {\n            if _isCancelled { operations.forEach { $0.cancel() } }\n            return _procedureQueue.addOperations(operations)\n        }\n    }\n\n    func queueOperations<S>(_ operations: S...) where S: Sequence, S.Iterator.Element: Operation {\n        stateLock.withCriticalScope {\n            for operations in operations {\n                if _isCancelled { operations.forEach { $0.cancel() } }\n                _procedureQueue.addOperations(operations)\n            }\n        }\n    }\n\n    func subContext(withBehavior behavior: ConditionResultAggregationBehavior = .andPredicate) -> ConditionEvaluationContext {\n        return stateLock.withCriticalScope {\n            let newContext = ConditionEvaluationContext(queue: underlyingQueue, behavior: behavior)\n            if _isCancelled { newContext.cancel() }\n            _subContexts.append(newContext)\n            return newContext\n        }\n    }\n}\n\n/// The method of handling a new result for a particular ConditionResultAggregationBehavior.\n///\n/// - aggregate: Instructs the aggregator to aggregate the result.\n/// - finishWithResult: Instructs the aggregator to finish immediately with the supplied result.\ninternal enum ConditionResultAggregationResult {\n    case aggregate\n    case finishWithResult(ConditionResult)\n}\n\n/// ConditionResultAggregationBehavior provides two main behaviors:\n///\n/// - andPredicate: Aggregates results with logical behavior that matches \"&&\". Results are aggregated until one fails (i.e. does not return `.success(true)`), at which point the failure is treated as the final result.\n/// - orPredicate: Aggregates results with logical behavior that matches \"||\". Results are aggregated until one succeeds (i.e. returns `.success(true)`), at which point the success is treated as the final result. (If no results are successful, then all the failures are the result.)\ninternal enum ConditionResultAggregationBehavior {\n    case andPredicate\n    case orPredicate\n\n    func handle(newResult: ConditionResult) -> ConditionResultAggregationResult {\n        switch self {\n        case .andPredicate:\n            return andProcess(newResult: newResult)\n        case .orPredicate:\n            return orProcess(newResult: newResult)\n        }\n    }\n\n    private func andProcess(newResult: ConditionResult) -> ConditionResultAggregationResult {\n        switch newResult {\n        case .success: return .aggregate\n        default: return .finishWithResult(newResult)\n        }\n    }\n\n    private func orProcess(newResult: ConditionResult) -> ConditionResultAggregationResult {\n        switch newResult {\n        case .success(true): return .finishWithResult(newResult)\n        default: return .aggregate\n        }\n    }\n}\n\nfileprivate class ConditionResultAggregator {\n    enum Errors: Error {\n        case alreadyFinishedWithResult(ConditionResult)\n    }\n    private let stateLock = PThreadMutex()\n    private var _oustandingExpectations = 0\n    private var _aggregatedResults = [ConditionResult]()\n    private var _hasFinishedWithResult: ConditionResult?\n    private let resultAggregationBehavior: ConditionResultAggregationBehavior\n    private let group = DispatchGroup()\n\n    var aggregatedResults: [ConditionResult] {\n        return stateLock.withCriticalScope { _aggregatedResults }\n    }\n\n    var result: ConditionResult {\n        return stateLock.withCriticalScope {\n            guard let result = _hasFinishedWithResult else {\n                // no explicit result was set, so get the\n                // _aggregatedResults array and compute its result\n                return _aggregatedResults.conditionResult\n            }\n            return result\n        }\n    }\n\n    /// Initialize a ConditionResultAggregator with a ConditionResultAggregationBehavior.\n    ///\n    /// - Parameter behavior: A `ConditionResultAggregationBehavior`.\n    init(behavior: ConditionResultAggregationBehavior) {\n        resultAggregationBehavior = behavior\n    }\n\n    /// Call once before every expected call to `fulfill(result:)`.\n    ///\n    /// NOTE: If the `ConditionResultAggregationBehavior` specifies that the\n    /// aggregator should `.finishWithResult(ConditionResult)`, it is acceptable\n    /// to short-cut any remaining calls to `fulfill(result:)`.\n    ///\n    /// i.e. If a call to `expectResult()` throws `Errors.alreadyFinishedWithResult`\n    /// you are permitted to handle that result immediately, and do not have to make\n    /// any other remaining `fulfill(result:)` calls (to balance out earlier\n    /// `expectResult()` calls).\n    ///\n    /// - Throws: throws Errors.alreadyFinishedWithResult\n    func expectResult() throws {\n        let error: Error? = stateLock.withCriticalScope {\n            if let result = _hasFinishedWithResult {\n                // has already finished with result\n                // throw an error so the caller can handle this case\n                return Errors.alreadyFinishedWithResult(result)\n            }\n            if _oustandingExpectations == 0 {\n                group.enter()\n            }\n            _oustandingExpectations += 1\n            return nil\n        }\n        if let error = error {\n            throw error\n        }\n    }\n\n    /// For every call to `fulfill(result:)`, you must first call `expectResult()`.\n    ///\n    /// However, a `ConditionResultAggregator` may finish with a result before\n    /// all paired `fulfill(result:)` calls are made (depending on its\n    /// `ConditionResultAggregationBehavior`), in which case you are not required\n    /// to make further (remaining) `fulfill(result:)` calls.\n    ///\n    /// - Parameter result: A ConditionResult that is aggregated, based on the\n    ///                     aggregator's `ConditionResultAggregationBehavior`.\n    func fulfill(result: ConditionResult) {\n        stateLock.withCriticalScope {\n            guard _oustandingExpectations > 0 else {\n                fatalError(\"Mis-matched expectResult() / fulfill(result:) calls.\")\n            }\n            _oustandingExpectations -= 1\n            guard _hasFinishedWithResult == nil else { return }\n            switch resultAggregationBehavior.handle(newResult: result) {\n            case .aggregate:\n                _aggregatedResults.append(result)\n                guard _oustandingExpectations > 0 else {\n                    // no more outstanding expectations, decrease the group to 0\n                    group.leave()\n                    return\n                }\n            case .finishWithResult(let result):\n                // stop aggregating, and immediately trigger the completion with this result\n                _hasFinishedWithResult = result\n                group.leave()\n                return\n            }\n        }\n    }\n\n    func cancel(withResult result: ConditionResult) {\n        stateLock.withCriticalScope {\n            guard _hasFinishedWithResult == nil else { return }\n            // stop aggregating, and immediately trigger the completion with this result\n            _hasFinishedWithResult = result\n            guard _oustandingExpectations > 0 else { return }\n            group.leave()\n        }\n    }\n\n    func notify(queue: DispatchQueue, execute: @escaping (ConditionResult) -> Void) {\n        group.notify(queue: queue) {\n            execute(self.result)\n        }\n    }\n}\n\ninternal extension Condition {\n\n    enum DependencyVerificationResult {\n        case success\n        case dependencyFailed\n        case dependencyCancelled\n    }\n\n    // swiftlint:disable cyclomatic_complexity\n    func verifyDependencyRequirements() -> DependencyVerificationResult {\n        let dependencyRequirements = self.dependencyRequirements\n        guard !dependencyRequirements.isEmpty else { return .success }\n\n        let dependencies = self.dependencies.union(self.producedDependencies)\n\n        if dependencyRequirements.contains(.noFailed) {\n            // Verify that there are no failed dependencies\n            if dependencyRequirements.contains(.ignoreFailedIfCancelled) {\n                // Ignore failed dependencies that are cancelled\n                for dependency in dependencies {\n                    guard let procedure = dependency as? Procedure else { continue }\n                    guard !procedure.failed || procedure.isCancelled else { return .dependencyFailed }\n                }\n            }\n            else {\n                for dependency in dependencies {\n                    guard let procedure = dependency as? Procedure else { continue }\n                    guard !procedure.failed else { return .dependencyFailed }\n                }\n            }\n        }\n\n        if dependencyRequirements.contains(.noCancelled) {\n            // Verify that there are no cancelled dependencies\n            for dependency in dependencies {\n                guard !dependency.isCancelled else { return .dependencyCancelled }\n            }\n        }\n\n        return .success\n    }\n    // swiftlint:enable cyclomatic_complexity\n}\n\n// A Dummy Operation that only finishes once: \n// - something external calls `finishOnceStarted()` *and* it has been started by the queue\nfileprivate class DummyDependency: Operation {\n    private var stateLock = PThreadMutex()\n    private var _started: Bool = false\n    private var _shouldFinish: Bool = false\n    private var _isFinished: Bool = false\n    private var _isExecuting: Bool = false\n\n    override func start() {\n        isExecuting = true\n        main()\n    }\n    override func main() {\n        let canFinish: Bool = stateLock.withCriticalScope {\n            _started = true\n            return _shouldFinish\n        }\n        guard canFinish else { return }\n        finish()\n    }\n    func finishOnceStarted() {\n        let canFinish: Bool = stateLock.withCriticalScope {\n            _shouldFinish = true\n            return _started\n        }\n        guard canFinish else { return }\n        finish()\n    }\n    private func finish() {\n        isExecuting = false\n        isFinished = true\n    }\n    override var isFinished: Bool {\n        get { return stateLock.withCriticalScope { return _isFinished } }\n        set {\n            willChangeValue(forKey: .finished)\n            stateLock.withCriticalScope { _isFinished = newValue }\n            didChangeValue(forKey: .finished)\n        }\n    }\n    override var isExecuting: Bool {\n        get { return stateLock.withCriticalScope { return _isExecuting } }\n        set {\n            willChangeValue(forKey: .executing)\n            stateLock.withCriticalScope { _isExecuting = newValue }\n            didChangeValue(forKey: .executing)\n        }\n    }\n}\n\ninternal extension Collection where Iterator.Element == Condition {\n\n    var producedDependencies: Set<Operation> {\n        var result = Set<Operation>()\n        for condition in self {\n            result.formUnion(condition.producedDependencies)\n        }\n        return result\n    }\n\n    var dependencies: Set<Operation> {\n        var result = Set<Operation>()\n        for condition in self {\n            result.formUnion(condition.dependencies)\n        }\n        return result\n    }\n\n    var mutuallyExclusiveCategories: Set<String> {\n        var result = Set<String>()\n        for condition in self {\n            result.formUnion(condition.mutuallyExclusiveCategories)\n        }\n        return result\n    }\n\n    /// Evaluate a collection of Conditions on a Procedure, utilizing a context\n    /// containing a defined aggregation behavior to return an aggregated\n    /// ConditionResult as soon as it is known.\n    ///\n    /// For example, utilizing `.andPredicate` behavior ensures that the\n    /// ConditionResult aggregates successes, while returning immediately\n    /// for the first failure.\n    ///\n    /// The `ConditionResult` passed-in to the `completion` block is either\n    /// the final result determined by the aggregation behavior, or\n    /// (if the aggregation behavior does not instruct a final result)\n    /// the aggregate `ConditionResult` computed from the collection of\n    /// all results (once they are available).\n    ///\n    /// - Parameters:\n    ///   - procedure: a Procedure that is passed-in to every Condition's evaluate method\n    ///   - context: a ConditionEvaluationContext, containing parameters like the aggregation behavior\n    ///   - completion: the completion block that is called with a result as soon as it is known\n\n    func evaluate(procedure: Procedure, withContext context: ConditionEvaluationContext, completion: @escaping (ConditionResult) -> Void) {\n\n        let aggregator = context.aggregator\n        for condition in self {\n            do {\n                try aggregator.expectResult()\n            }\n            catch ConditionResultAggregator.Errors.alreadyFinishedWithResult(let result) {\n                // A result has been obtained (before all Conditions have been evaluated)\n\n                // Cancel the current evaluation context (since we have a result)\n                // (This cancels outstanding produced dependencies and dependent condition operations)\n                context.cancel()\n\n                // Immediately complete with the result\n                completion(result)\n\n                // Stop processing further conditions - return immediately\n                return\n            }\n            catch {\n                fatalError(\"Unexpected error: \\(error)\")\n            }\n\n            // Get any dependencies for this condition\n            let directDependencies = condition.dependencies\n            let producedDependencies = condition.producedDependencies\n            guard producedDependencies.isEmpty && directDependencies.isEmpty else {\n                // Must wait for dependencies to complete before evaluating the condition\n\n                // Create a new BlockOperation that wraps the call to `condition.evaluate`\n                let conditionEvaluateOperation = BlockOperation { [weak procedure, weak condition] in\n\n                    // Do not bother evaluating the Condition if the Procedure no longer exists\n                    guard let procedure = procedure else { return }\n                    guard let condition = condition else { return }\n\n                    // Check Dependencies (if required)\n                    switch condition.verifyDependencyRequirements() {\n                    case .success: break\n                    case .dependencyFailed:\n                        // one or more dependencies failed verification because they finished with errors\n                        // immediately fail this Condition\n                        aggregator.fulfill(result: .failure(ProcedureKitError.ConditionDependenciesFailed(condition: condition)))\n                        return\n                    case .dependencyCancelled:\n                        // one or more dependencies failed verification because they were cancelled\n                        // immediatelly fail this Condition\n                        aggregator.fulfill(result: .failure(ProcedureKitError.ConditionDependenciesCancelled(condition: condition)))\n                        return\n                    }\n\n                    // Evaluate the Condition\n                    condition.evaluate(procedure: procedure, withContext: context) { result in\n                        condition.set(output: result)\n                        aggregator.fulfill(result: result)\n                    }\n                }\n\n                // Set the conditionEvaluateOperation to be dependent on all the Condition dependencies\n                conditionEvaluateOperation.addDependencies(directDependencies.union(producedDependencies))\n\n                // Sanity-Check the producedDependencies\n                //\n                // An Operation instance must be produced by a single Condition instance.\n                // (i.e. Should only be added to a single Condition instance via a single\n                // `produce(dependency:)` call, and must not be scheduled for execution via\n                // any other means.)\n                assert(producedDependencies.filter { $0.isExecuting || $0.isFinished }.isEmpty, \"One or more produced dependencies are already executing or finished. Condition-produced dependencies must be produced by a single Condition instance, and not manually added to a queue, or executed, or produced by any other Condition instances. Problem Operations: \\(producedDependencies.filter { $0.isExecuting || $0.isFinished })\")\n\n                // Add the producedDependencies and the conditionEvaluateOperation to the procedureQueue\n                //\n                // IMPORTANT: To work around a rare race condition in NSOperation / NSOperationQueue,\n                //            the conditionEvaluateOperation must not have its isReady state transition to\n                //            `true` while it is being added to the queue.\n                //\n                //            Therefore: \n                //              1.) Add the `conditionEvaluateOperation` to the queue *before* its \n                //                  producedDependencies.\n                //              2.) If only directDependencies exist, create a \"dummy\" producedDependency,\n                //                  which is explicitly finished only after the queue add completes.\n                //\n                //            (Otherwise, it is possible for a conditionEvaluateOperation to get\n                //            \"stuck\" as ready but never executing if the dependencies all finish\n                //            while the conditionEvaluateOperation is being added to the underlying\n                //            NSOperationQueue.)\n                //\n                if !producedDependencies.isEmpty {\n                    // 1.) Add the `conditionEvaluateOperation` to the queue *before* its\n                    //     producedDependencies.\n                    context.queueOperations([conditionEvaluateOperation], producedDependencies)\n                }\n                else {\n                    // 2.) No produced dependencies (only direct dependencies)\n                    //     Create a \"dummy\" workaround produced dependency which is explicitly finished\n                    //     only after the queue add completes. \n                    //     (This ensures that the conditionEvaluateOperation will not become ready while\n                    //     being added to the queue.)\n                    let workaroundProducedDependency = DummyDependency()\n                    conditionEvaluateOperation.addDependency(workaroundProducedDependency)\n                    context.queueOperations([conditionEvaluateOperation, workaroundProducedDependency]).then(on: context.underlyingQueue) {\n                        workaroundProducedDependency.finishOnceStarted()\n                    }\n                }\n\n                // Skip to the next condition\n                continue\n            }\n\n            // Since this Condition has no dependencies, call the `evaluate` function directly\n            condition.evaluate(procedure: procedure, withContext: context) { result in\n                condition.set(output: result)\n                aggregator.fulfill(result: result)\n            }\n        }\n\n        aggregator.notify(queue: context.underlyingQueue) { result in\n            // Cancel the current evaluation context (since we have a result)\n            // (This cancels outstanding produced dependencies and dependent condition operations)\n            context.cancel()\n\n            // Call the completion block\n            completion(result)\n        }\n    }\n}\n\ninternal extension Collection where Iterator.Element == ConditionResult {\n\n    // Get a single conditionResult for a collection of results\n    var conditionResult: ConditionResult {\n        return self.reduce(.success(false)) { lhs, result in\n            // Unwrap the condition's output\n            let rhs = result\n\n            switch (lhs, rhs) {\n            // both results are failures\n            case let (.failure(error), .failure(anotherError)):\n                if let error = error as? ProcedureKitError.FailedConditions {\n                    return .failure(error.append(error: anotherError))\n                }\n                else if let anotherError = anotherError as? ProcedureKitError.FailedConditions {\n                    return .failure(anotherError.append(error: error))\n                }\n                else {\n                    return .failure(ProcedureKitError.FailedConditions(errors: [error, anotherError]))\n                }\n            // new condition failed - so return it\n            case (_, .failure):\n                return rhs\n            // first condition is ignored - so return the new one\n            case (.success(false), _):\n                return rhs\n            default:\n                return lhs\n            }\n        }\n    }\n\n    // Determine if any result in a collection of results is `.success(true)`\n    var hasSuccessfulConditionResult: Bool {\n        for result in self {\n            switch result {\n            case .success(true): return true\n            default: continue\n            }\n        }\n        return false\n    }\n}\n\ninternal extension Sequence where Iterator.Element: Hashable {\n\n    // - returns: an Array<Iterator.Element> that preserves the original sequence order, but in which only the first instance of a unique Element is preserved\n    func filterDuplicates() -> [Iterator.Element] {\n        var result: [Iterator.Element] = []\n        var added = Set<Iterator.Element>()\n        for element in self {\n            guard !added.contains(element) else { continue }\n            result.append(element)\n            added.insert(element)\n        }\n        return result\n    }\n}\n\n// MARK: - Unavailable\n\npublic extension Condition {\n\n    @available(*, unavailable, renamed: \"addToAttachedProcedure(mutuallyExclusiveCategory:)\")\n    var mutuallyExclusiveCategory: String? {\n        get { fatalError(\"Unavailable. Use `mutuallyExclusiveCategories` instead to query.\") }\n        set { fatalError(\"Unavailable. Use `addToAttachedProcedure(mutuallyExclusiveCategory:)` instead to set.\") }\n    }\n}\n\n// swiftlint:enable file_length\n"
  },
  {
    "path": "Sources/ProcedureKit/Decode.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2019 ProcedureKit. All rights reserved.\n//\n\nimport Foundation\n\n/// A generic Procedure to perfrom JSON decoding of any Decodable type from Data\npublic final class DecodeJSONProcedure<T: Decodable>: TransformProcedure<Data, T> {\n\n    /// Convenience initializer which allows optional configuration\n    /// of the JSONDecoder. All configurations are optional, with\n    /// default arguments of nil. Therefore the default behaviour\n    /// is that of JSONDecoder itself.\n    ///\n    /// - See: `JSONDecoder`\n    ///\n    /// - Parameters:\n    ///   - dateDecodingStrategy: an optional DateDecodingStrategy\n    ///   - dataDecodingStrategy: an optional DataDecodingStrategy\n    ///   - nonConformingFloatDecodingStrategy: an optional NonConformingFloatDecodingStrategy\n    ///   - keyDecodingStrategy: an optional KeyDecodingStrategy\n    ///   - userInfo: an optional [CodingUserInfoKey: Any]\n    public convenience init(\n        dateDecodingStrategy: JSONDecoder.DateDecodingStrategy? = nil,\n        dataDecodingStrategy: JSONDecoder.DataDecodingStrategy? = nil,\n        nonConformingFloatDecodingStrategy: JSONDecoder.NonConformingFloatDecodingStrategy? = nil,\n        keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy? = nil,\n        userInfo: [CodingUserInfoKey: Any]? = nil) {\n\n        let decoder = JSONDecoder()\n\n        if let strategy = dateDecodingStrategy {\n            decoder.dateDecodingStrategy = strategy\n        }\n\n        if let strategy = dataDecodingStrategy {\n            decoder.dataDecodingStrategy = strategy\n        }\n\n        if let strategy = nonConformingFloatDecodingStrategy {\n            decoder.nonConformingFloatDecodingStrategy = strategy\n        }\n\n        if let strategy = keyDecodingStrategy {\n            decoder.keyDecodingStrategy = strategy\n        }\n\n        if let userInfo = userInfo {\n            decoder.userInfo.merge(userInfo) { (_, new) in new }\n        }\n\n        self.init(decoder)\n    }\n\n    /// Initialize the procedure with a JSONDecoder instance\n    ///\n    /// - Parameter decoder: the JSONDecoder to use\n    public init(_ decoder: JSONDecoder) {\n        super.init { return try decoder.decode(T.self, from: $0) }\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKit/Delay.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport Foundation\nimport Dispatch\n\n/// `Delay` encapsulates different ways of specifying a delay.\n///\n/// - by: a `TimeInterval`\n/// - until: a `Date`\npublic enum Delay: Comparable {\n\n    public static func < (lhs: Delay, rhs: Delay) -> Bool {\n        switch (lhs, rhs) {\n        case let (.by(lhsBy), .by(rhsBy)):\n            return lhsBy < rhsBy\n        case let (.until(lhsUntil), .until(rhsUntil)):\n            return lhsUntil < rhsUntil\n        default: return false\n        }\n    }\n\n    case by(TimeInterval)\n    case until(Date)\n}\n\nextension Delay: CustomStringConvertible {\n\n    public var description: String {\n        switch self {\n        case .by(let _interval):\n            return \"for \\(_interval) seconds\"\n        case .until(let date):\n            return \"until \\(DateFormatter().string(from: date))\"\n        }\n    }\n}\n\ninternal extension Delay {\n\n    var interval: TimeInterval {\n        switch self {\n        case .by(let _interval):\n            return _interval\n        case .until(let date):\n            return date.timeIntervalSinceNow\n        }\n    }\n}\n\n/**\n `DelayProcedure` is a `Procedure` which waits until a given future\n date, or a time interval. If the interval is negative, or the date\n is in the past, the procedure finishes.\n\n - Note: This procedure efficiently uses\n [GCD](https://developer.apple.com/documentation/dispatch) so it does\n not block the thread on which it is called (i.e. it is asynchronous).\n\n Make an operation dependent on a `DelayProcedure` in order to\n make it execute after a timeout, or in a repeated fashion with a\n time-out.\n */\npublic class DelayProcedure: Procedure, InputProcedure {\n\n    public var input: Pending<Delay> = .pending\n\n    private let leeway: DispatchTimeInterval\n    private var _timer: DispatchSourceTimer?\n\n    /**\n     Initialize the `DelayProcedure` with a `Delay?` value.\n\n     - parameter delay: an optional `Delay`, defaults to nil. Use if\n         injecting the delay value after initilization.\n     - parameter leeway: an `DispatchTimeInterval` representing leeway\n     for the timer. This defaults to 1 milli-second accuracy.\n     This is partly from a energy standpoint as nanosecond\n     accuracy is costly.\n     */\n\n    public init(delay: Delay? = nil, leeway: DispatchTimeInterval = .milliseconds(1)) {\n        self.leeway = leeway\n        super.init()\n        if let delay = delay {\n            name = \"Delay \\(delay)\"\n            input = .ready(delay)\n        }\n        else {\n            name = \"Delay\"\n        }\n        addDidCancelBlockObserver { procedure, _ in\n            procedure._timer?.cancel()\n            procedure.finish()\n        }\n    }\n\n    /**\n     Initialize the `DelayProcedure` with a time interval.\n\n     - parameter by: a `TimeInterval`.\n     - parameter leeway: an `DispatchTimeInterval` representing leeway\n     for the timer. This defaults to 1 milli-second accuracy.\n     This is partly from a energy standpoint as nanosecond\n     accuracy is costly.\n     */\n    public convenience init(by interval: TimeInterval, leeway: DispatchTimeInterval = .milliseconds(1)) {\n        self.init(delay: .by(interval), leeway: leeway)\n    }\n\n    /**\n     Initialize the `DelayProcedure` with a date.\n\n     - parameter until: a `Date`.\n     - parameter leeway: an `DispatchTimeInterval` representing leeway\n     for the timer. This defaults to 1 milli-second accuracy.\n     This is partly from a energy standpoint as nanosecond\n     accuracy is costly.\n     */\n    public convenience init(until date: Date, leeway: DispatchTimeInterval = .milliseconds(1)) {\n        self.init(delay: .until(date), leeway: leeway)\n    }\n\n    /**\n     Executes the operation by using a DispatchSourceTimer to finish\n     the operation in the future, but only if the time interval is\n     greater than zero. (Otherwise it finishes immediately.)\n     */\n    public override func execute() {\n        guard let delay = input.value else {\n            cancel(with: ProcedureKitError.requirementNotSatisfied())\n            return\n        }\n        switch delay.interval {\n        case (let interval) where interval > 0.0:\n            guard !isCancelled else { return }\n            _timer = eventQueue.makeTimerSource()\n            _timer?.setEventHandler { [weak self] in\n                guard let strongSelf = self else { return }\n                if !strongSelf.isCancelled { strongSelf.finish() }\n            }\n            #if swift(>=4.0)\n                _timer?.schedule(deadline: .now() + interval, leeway: self.leeway)\n            #else\n                _timer?.scheduleOneshot(deadline: .now() + interval, leeway: self.leeway)\n            #endif\n            _timer?.resume()\n        default:\n            finish()\n        }\n    }\n}\n\n\n// MARK: - InputProcedure convenience methods\n\nextension InputProcedure where Self.Input == Delay {\n\n    @discardableResult\n    func injectDelay<Dependency: OutputProcedure>(from dependency: Dependency, by makeIntervalFrom: @escaping (Dependency.Output) throws -> TimeInterval) -> Self {\n        return injectResult(from: dependency) { try .by(makeIntervalFrom($0)) }\n    }\n\n    @discardableResult\n    func injectDelay<Dependency: OutputProcedure>(from dependency: Dependency, until makeDateFrom: @escaping (Dependency.Output) throws -> Date) -> Self {\n        return injectResult(from: dependency) { try .until(makeDateFrom($0)) }\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKit/DispatchQueue+ProcedureKit.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport Foundation\nimport Dispatch\n\n// MARK: - Queue\n\npublic extension DispatchQueue {\n\n    static var isMainDispatchQueue: Bool {\n        return mainQueueScheduler.isOnScheduledQueue\n    }\n\n    var isMainDispatchQueue: Bool {\n        return mainQueueScheduler.isScheduledQueue(self)\n    }\n\n    static var `default`: DispatchQueue {\n        return DispatchQueue.global(qos: DispatchQoS.QoSClass.default)\n    }\n\n    static var initiated: DispatchQueue {\n        return DispatchQueue.global(qos: DispatchQoS.QoSClass.userInitiated)\n    }\n\n    static var interactive: DispatchQueue {\n        return DispatchQueue.global(qos: DispatchQoS.QoSClass.userInteractive)\n    }\n\n    static var utility: DispatchQueue {\n        return DispatchQueue.global(qos: DispatchQoS.QoSClass.utility)\n    }\n\n    static var background: DispatchQueue {\n        return DispatchQueue.global(qos: DispatchQoS.QoSClass.background)\n    }\n\n    static func concurrent(label: String, qos: DispatchQoS = .default, autoreleaseFrequency: DispatchQueue.AutoreleaseFrequency = .inherit, target: DispatchQueue? = nil) -> DispatchQueue {\n        return DispatchQueue(label: label, qos: qos, attributes: [.concurrent], autoreleaseFrequency: autoreleaseFrequency, target: target)\n    }\n\n    static func onMain<T>(execute work: () throws -> T) rethrows -> T {\n        guard isMainDispatchQueue else {\n            return try DispatchQueue.main.sync(execute: work)\n        }\n        return try work()\n    }\n\n    static var currentQoSClass: DispatchQoS.QoSClass {\n        return DispatchQoS.QoSClass(rawValue: qos_class_self()) ?? .unspecified\n    }\n}\n\ninternal extension QualityOfService {\n\n    var qos: DispatchQoS {\n        switch self {\n        case .userInitiated: return DispatchQoS.userInitiated\n        case .userInteractive: return DispatchQoS.userInteractive\n        case .utility: return DispatchQoS.utility\n        case .background: return DispatchQoS.background\n        case .default: return DispatchQoS.default\n        @unknown default:\n            return DispatchQoS.default\n        }\n    }\n\n    var qosClass: DispatchQoS.QoSClass {\n        switch self {\n        case .userInitiated: return .userInitiated\n        case .userInteractive: return .userInteractive\n        case .utility: return .utility\n        case .background: return .background\n        case .default: return .default\n        @unknown default:\n            return .default\n        }\n    }\n}\n\nextension DispatchQoS.QoSClass: Comparable {\n\n    public static func < (lhs: DispatchQoS.QoSClass, rhs: DispatchQoS.QoSClass) -> Bool { // swiftlint:disable:this cyclomatic_complexity\n        switch lhs {\n        case .unspecified:\n            return rhs != .unspecified\n        case .background:\n            switch rhs {\n            case .unspecified, lhs: return false\n            default: return true\n            }\n        case .utility:\n            switch rhs {\n            case .default, .userInitiated, .userInteractive: return true\n            default: return false\n            }\n        case .default:\n            switch rhs {\n            case .userInitiated, .userInteractive: return true\n            default: return false\n            }\n        case .userInitiated:\n            return rhs == .userInteractive\n        case .userInteractive:\n            return false\n        @unknown default:\n            fatalError()\n        }\n    }\n}\n\nextension DispatchQoS: Comparable {\n    public static func < (lhs: DispatchQoS, rhs: DispatchQoS) -> Bool {\n        if lhs.qosClass < rhs.qosClass { return true }\n        else if lhs.qosClass > rhs.qosClass { return false }\n        else { // qosClass are equal\n            return lhs.relativePriority < rhs.relativePriority\n        }\n    }\n}\n\ninternal final class Scheduler {\n\n    var key: DispatchSpecificKey<UInt8>\n    var value: UInt8 = 1\n\n    init(queue: DispatchQueue) {\n        key = DispatchSpecificKey()\n        queue.setSpecific(key: key, value: value)\n    }\n\n    var isOnScheduledQueue: Bool {\n        guard let retrieved = DispatchQueue.getSpecific(key: key) else { return false }\n        return value == retrieved\n    }\n\n    func isScheduledQueue(_ queue: DispatchQueue) -> Bool {\n        guard let retrieved = queue.getSpecific(key: key) else { return false }\n        return value == retrieved\n    }\n}\n\ninternal let mainQueueScheduler = Scheduler(queue: DispatchQueue.main)\n"
  },
  {
    "path": "Sources/ProcedureKit/Encode.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2019 ProcedureKit. All rights reserved.\n//\n\nimport Foundation\n\n/// A generic Procedure to perfrom JSON encoding of any Encodable type to Data\npublic final class EncodeJSONProcedure<T: Encodable>: TransformProcedure<T,Data> {\n\n    /// Convenience initializer which allows optional configuration\n    /// of the JSONEncoder. All configurations are optional, with\n    /// default arguments of nil. Therefore the default behaviour\n    /// is that of JSONEncoder itself.\n    ///\n    /// - See: `JSONEncoder`\n    ///\n    /// - Parameters:\n    ///   - dateDecodingStrategy: an optional DateDecodingStrategy\n    ///   - dataDecodingStrategy: an optional DataDecodingStrategy\n    ///   - nonConformingFloatDecodingStrategy: an optional NonConformingFloatDecodingStrategy\n    ///   - keyDecodingStrategy: an optional KeyDecodingStrategy\n    ///   - userInfo: an optional [CodingUserInfoKey: Any]\n    public convenience init(\n        dateEncodingStrategy: JSONEncoder.DateEncodingStrategy? = nil,\n        dataEncodingStrategy: JSONEncoder.DataEncodingStrategy? = nil,\n        nonConformingFloatEncodingStrategy: JSONEncoder.NonConformingFloatEncodingStrategy? = nil,\n        keyEncodingStrategy: JSONEncoder.KeyEncodingStrategy? = nil,\n        userInfo: [CodingUserInfoKey: Any]? = nil) {\n\n        let encoder = JSONEncoder()\n\n        if let strategy = dateEncodingStrategy {\n            encoder.dateEncodingStrategy = strategy\n        }\n\n        if let strategy = dataEncodingStrategy {\n            encoder.dataEncodingStrategy = strategy\n        }\n\n        if let strategy = nonConformingFloatEncodingStrategy {\n            encoder.nonConformingFloatEncodingStrategy = strategy\n        }\n\n        if let strategy = keyEncodingStrategy {\n            encoder.keyEncodingStrategy = strategy\n        }\n\n        if let userInfo = userInfo {\n            encoder.userInfo.merge(userInfo) { (_, new) in new }\n        }\n\n        self.init(encoder)\n    }\n\n    /// Initialize the procedure with a JSONEncoder instance\n    ///\n    /// - Parameter encoder: the JSONEncoder to use\n    public init(_ encoder: JSONEncoder) {\n        super.init { return try encoder.encode($0) }\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKit/Errors.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n/// A type which has an associated error type\npublic protocol AssociatedErrorProtocol {\n\n    /// The type of associated error\n    associatedtype AssociatedError: Error\n}\n\npublic protocol ProcedureKitComponent {\n    var name: String { get }\n}\n\npublic struct ProcedureKitError: Error, Equatable, CustomStringConvertible {\n\n    public static func == (lhs: ProcedureKitError, rhs: ProcedureKitError) -> Bool {\n        return lhs.context == rhs.context\n    }\n\n    public enum CapabilityError: Error {\n        case unavailable, unauthorized\n    }\n\n    public enum Context: Equatable {\n\n        public static func == (lhs: Context, rhs: Context) -> Bool {\n            switch (lhs, rhs) {\n            case let (.capability(lhs), .capability(rhs)):\n                return lhs == rhs\n            case let (.component(lhs), .component(rhs)):\n                return lhs.name == rhs.name\n            case let (.programmingError(lhs), .programmingError(rhs)):\n                return lhs == rhs\n            case let (.timedOut(lhs), .timedOut(rhs)):\n                return lhs == rhs\n            case (.conditionFailed, .conditionFailed),\n                 (.dependenciesFailed, .dependenciesFailed),\n                 (.dependenciesCancelled, .dependenciesCancelled),\n                 (.dependencyFinishedWithError, .dependencyFinishedWithError),\n                 (.dependencyCancelledWithError, .dependencyCancelledWithError),\n                 (.noQueue, .noQueue),\n                 (.parentCancelledWithError, .parentCancelledWithError),\n                 (.requirementNotSatisfied, .requirementNotSatisfied),\n                 (.unknown, .unknown):\n                return true\n            default:\n                return false\n            }\n        }\n\n        case capability(CapabilityError)\n        case component(ProcedureKitComponent)\n        case conditionFailed\n        case dependenciesFailed\n        case dependenciesCancelled\n        case dependencyFinishedWithError\n        case dependencyCancelledWithError\n        case noQueue\n        case parentCancelledWithError\n        case programmingError(String)\n        case requirementNotSatisfied\n        case timedOut(Delay)\n        case unknown\n    }\n\n    public static func capabilityUnavailable() -> ProcedureKitError {\n        return ProcedureKitError(context: .capability(.unavailable), error: nil)\n    }\n\n    public static func capabilityUnauthorized() -> ProcedureKitError {\n        return ProcedureKitError(context: .capability(.unauthorized), error: nil)\n    }\n\n    public static func component(_ component: ProcedureKitComponent, error: Error?) -> ProcedureKitError {\n        return ProcedureKitError(context: .component(component), error: error)\n    }\n\n    public static func conditionFailed(with error: Error? = nil) -> ProcedureKitError {\n        return ProcedureKitError(context: .conditionFailed, error: error)\n    }\n\n    public static func dependenciesFailed() -> ProcedureKitError {\n        return ProcedureKitError(context: .dependenciesFailed, error: nil)\n    }\n\n    public static func dependenciesCancelled() -> ProcedureKitError {\n        return ProcedureKitError(context: .dependenciesCancelled, error: nil)\n    }\n\n    public static func dependency(finishedWithError error: Error?) -> ProcedureKitError {\n        return ProcedureKitError(context: .dependencyFinishedWithError, error: error)\n    }\n\n    public static func dependency(cancelledWithError error: Error?) -> ProcedureKitError {\n        return ProcedureKitError(context: .dependencyCancelledWithError, error: error)\n    }\n\n    public static func noQueue() -> ProcedureKitError {\n        return ProcedureKitError(context: .noQueue, error: nil)\n    }\n\n    public static func parent(cancelledWithError errors: Error?) -> ProcedureKitError {\n        return ProcedureKitError(context: .parentCancelledWithError, error: errors)\n    }\n\n    public static func programmingError(reason: String) -> ProcedureKitError {\n        return ProcedureKitError(context: .programmingError(reason), error: nil)\n    }\n\n    public static func requirementNotSatisfied() -> ProcedureKitError {\n        return ProcedureKitError(context: .requirementNotSatisfied, error: nil)\n    }\n\n    public static func timedOut(with delay: Delay) -> ProcedureKitError {\n        return ProcedureKitError(context: .timedOut(delay), error: nil)\n    }\n\n    public static let unknown = ProcedureKitError(context: .unknown, error: nil)\n\n    public let context: Context\n    public let error: Error?\n\n    // Swift 3.0 Leak Fix:\n    //\n    // As of Swift 3.0.1 & Xcode 8.1, ProcedureKitError leaks memory when converted to a string\n    // unless it conforms to CustomStringConvertible and provides its own `description`\n    // implementation.\n    //\n    // Symptoms: Malloc 48 byte leaks\n    //\n    public var description: String {\n        if let error = error {\n            return \"ProcedureKitError(context: \\(context), error: \\(error))\"\n        }\n        return \"ProcedureKitError(context: \\(context)\"\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKit/Filter.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nopen class FilterProcedure<Element>: ReduceProcedure<Element, Array<Element>> {\n\n    public init<S: Sequence>(source: S, isIncluded: @escaping (Element) throws -> Bool) where S.Iterator.Element == Element {\n        super.init(source: source, initial: []) { acc, element in\n            guard try isIncluded(element) else { return acc }\n            return acc + [element]\n        }\n    }\n\n    public convenience init(isIncluded block: @escaping (Element) throws -> Bool) {\n        self.init(source: [], isIncluded: block)\n    }\n}\n\npublic extension OutputProcedure where Self.Output: Sequence {\n\n    func filter(includeElement: @escaping (Output.Iterator.Element) throws -> Bool) -> FilterProcedure<Output.Iterator.Element> {\n        return FilterProcedure(isIncluded: includeElement).injectResult(from: self) { AnySequence(Array($0)) }\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKit/Group.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n// swiftlint:disable file_length\n\nimport Foundation\nimport Dispatch\n\n/**\n A `Procedure` subclass which enables the grouping\n of other procedures. Use `Group`s to associate\n related operations together, thereby creating higher\n levels of abstractions.\n */\nopen class GroupProcedure: Procedure {\n\n    public typealias TransformChildErrorBlockType = (Procedure, inout Error?) -> Void\n\n    internal let queue = ProcedureQueue()\n    internal var queueDelegate: GroupQueueDelegate!\n\n    fileprivate let initialChildren: [Operation]\n    fileprivate var groupCanFinish: CanFinishGroup!\n    fileprivate var groupStateLock = PThreadMutex()\n\n    @discardableResult\n    fileprivate func synchronise<T>(block: () -> T) -> T {\n        return groupStateLock.withCriticalScope(block: block)\n    }\n\n    // Protected private properties\n    fileprivate var _groupChildren: [Operation] // swiftlint:disable:this variable_name\n    fileprivate var _groupIsFinishing = false // swiftlint:disable:this variable_name\n    fileprivate var _groupIsSuspended = false // swiftlint:disable:this variable_name\n    fileprivate var _groupTransformChildErrorBlock: TransformChildErrorBlockType?\n\n    /// - returns: the operations which have been added to the queue\n    final public var children: [Operation] {\n        return synchronise { _groupChildren }\n    }\n\n    /**\n     The default service level to apply to the GroupProcedure and its child operations.\n     \n     This property specifies the service level applied to the GroupProcedure itself, and to\n     operation objects added to the GroupProcedure.\n     \n     If the added operation object has an explicit service level set, that value is used instead.\n     \n     For more, see the NSOperation and NSOperationQueue documentation for `qualityOfService`.\n     */\n    @available(OSX 10.10, iOS 8.0, tvOS 8.0, watchOS 2.0, *)\n    open override var qualityOfService: QualityOfService {\n        get { return queue.qualityOfService }\n        set {\n            super.qualityOfService = newValue\n            queue.qualityOfService = newValue\n        }\n    }\n\n    /**\n     - WARNING: Do not call `finish()` on a GroupProcedure or a GroupProcedure subclass.\n     A GroupProcedure finishes when all of its children finish.\n     It is an anti-pattern to call `finish()` directly on a GroupProcedure.\n\n     To cause a GroupProcedure to finish more quickly, without waiting for all of its \n     children to complete, call `cancel()`. The Group will then cancel all of its\n     children and finish as soon as they have handled cancellation / finished.\n    */\n    final public override func finish(with error: Error? = nil) {\n        assertionFailure(\"Do not call finish() on a GroupProcedure or a GroupProcedure subclass. GroupProcedure will automatically finish when all of its children finish.\")\n        // no-op\n    }\n\n    /**\n     Designated initializer for GroupProcedure. Create a GroupProcedure with\n     an array of Operation instances. Optionally provide the underlying dispatch\n     queue for the group's internal ProcedureQueue.\n\n     - parameter underlyingQueue: an optional DispatchQueue which defaults to nil, this\n     parameter is set as the underlying queue of the group's own ProcedureQueue.\n     - parameter operations: an array of Operation instances. Note that these do not\n     have to be Procedure instances - you can use `Foundation.Operation` instances\n     from other sources.\n    */\n    public init(dispatchQueue underlyingQueue: DispatchQueue? = nil, operations: [Operation]) {\n\n        assert(operations.filter({\n            if let procedure = $0 as? Procedure {\n                return procedure.isEnqueued\n            }\n            else {\n                return false\n            }\n        }).isEmpty,\n        \"Cannot initialize GroupProcedure with Procedures that have already been added to another queue / GroupProcedure: \\(operations.filter({ if let procedure = $0 as? Procedure { return procedure.isEnqueued } else { return false } }))\")\n\n        _groupChildren = operations\n        initialChildren = operations\n\n        /**\n         GroupProcedure is responsible for calling `finish()` on cancellation\n         once all of its childred have cancelled and finished, and its own\n         finishing operation has finished.\n\n         Therefore we disable `Procedure`'s automatic finishing mechanisms.\n        */\n        super.init(disableAutomaticFinishing: true)\n\n        queue.isSuspended = true\n        queue.underlyingQueue = underlyingQueue\n        queueDelegate = GroupQueueDelegate(self)\n        queue.delegate = queueDelegate\n        groupCanFinish = CanFinishGroup(group: self)\n    }\n\n    /// Create a GroupProcedure with a variadic array of Operation instances.\n    ///\n    /// - Parameter operations: a variadic array of `Operation` instances.\n    public convenience init(operations: Operation...) {\n        self.init(operations: operations)\n    }\n\n    deinit {\n        // To ensure that any remaining operations on the internal queue are released\n        // we must cancelAllOperations and also ensure the queue is not suspended.\n        queue.cancelAllOperations()\n        queue.isSuspended = false\n    }\n\n    // MARK: - Handling Cancellation\n\n    // GroupProcedure child cancellation can be safely handled without dispatching to the EventQueue.\n    //\n    // This function is called internally by the Group's .cancel() (Procedure.cancel())\n    // prior to dispatching DidCancel observers on the Group's EventQueue.\n    override func _procedureDidCancel(with error: Error?) {\n        guard let error = error else {\n            children.forEach { $0.cancel() }\n            return\n        }\n\n        let (operations, procedures) = children.operationsAndProcedures\n        operations.forEach { $0.cancel() }\n        procedures.forEach { $0.cancel(with: ProcedureKitError.parent(cancelledWithError: error)) }\n\n        // the GroupProcedure ensures that `finish()` is called once all the\n        // children have finished in its CanFinishGroup operation\n    }\n\n    // MARK: - Execute\n\n    /// Adds the GroupProcedure's initial child Operations to its internal queue (and other setup).\n    ///\n    /// If the Group is not suspended, the child Operations will execute once they are ready.\n    ///\n    /// - important: When overriding GroupProcedure's `execute()`, always call `super.execute()`.\n    open override func execute() {\n        // Add the initial children to the Group's internal queue.\n        // (This is delayed until execute to allow WillAdd/DidAdd observers set on the Group, post-init (but pre-execute),\n        // to receive the initial children.)\n        addAdditionalChildren(initialChildren, toOperationsArray: false, alreadyOnEventQueue: true)\n\n        // Add the CanFinishGroup (which is used to provide concurrency-safety for adding children post-execute).\n        add(canFinishGroup: groupCanFinish)\n\n        // Unsuspend the Group's internal queue (unless the user has suspended the Group)\n        groupStateLock.withCriticalScope {\n            if !_groupIsSuspended { queue.isSuspended = false }\n        }\n    }\n\n    // MARK: - GroupWillAddChild override\n\n    /**\n     This method is called when a child will be added to the Group.\n     (It is called on the Group's EventQueue.)\n     */\n    open func groupWillAdd(child: Operation) { /* no-op */ }\n\n    // MARK: - Customizing the Group's Child Error Handling\n\n    /**\n     This method is called when a child Procedure will finish (with / without an error).\n     (It is called on the Group's EventQueue.)\n\n     The default behavior is to append the child's errors, if any, to the Group's errors.\n\n     When subclassing GroupProcedure, you can override this method to execute custom\n     code in response to child Procedures finishing, or to override the default\n     error-aggregating behavior.\n\n     The child Procedure (and, thus, the Group) will not finish until this method returns.\n\n     - parameter child: the child Procedure which is finishing\n     - parameter errors: an [Error], the errors of the child Procedure\n    */\n    open func child(_ child: Procedure, willFinishWithError childError: Error?) {\n        assert(!child.isFinished, \"child(_:willFinishWithError:) called with a child that has already finished\")\n        guard let childError = childError else { return }\n\n        // Default GroupProcedure error-handling is to collect\n        // the first error related to a non-Procedure subclass.\n        setErrorOnce(childError)\n    }\n\n    final public func setErrorOnce(_ childError: Error) {\n        guard error == nil else { return }\n\n        error = childError\n    }\n\n    @available(*, deprecated, renamed: \"child(_:willFinishWithError:)\", message: \"Use child(_:,willFinishWithError:) instead.\")\n    open func child(_ childProcedure: Procedure, willFinishWithErrors errors: [Error]) {\n        assertionFailure(\"Use child(_:willFinishWithError:) instead.\")\n        child(childProcedure, willFinishWithError: errors.first)\n    }\n\n    /**\n     The transformChildErrorsBlock is called before the GroupProcedure handles child errors.\n     (It is called on the Group's EventQueue.)\n\n     The block is passed two parameters:\n        - Procedure: the child Procedure that will finish\n        - inout [Error]: the errors that the Group attributes to the child (on input: the errors that the child Procedure will finish with)\n\n     The array of errors is an `inout` parameter, and may be modified directly.\n\n     This enables the customization of the errors that the GroupProcedure (or GroupProcedure subclass) \n     attributes to the child and considers in its `child(_:willFinishWithErrors:)` function.\n\n     - IMPORTANT: This only affects the child errors that the GroupProcedure (or GroupProcedure subclass)\n     utilizes. It does not directly impact the child Procedure itself, nor the child Procedure's errors\n     (if obtained or read directly from the child).\n    */\n    final public var transformChildErrorBlock: TransformChildErrorBlockType? {\n        get { return synchronise { _groupTransformChildErrorBlock } }\n        set {\n            assert(!isExecuting, \"Do not modify the child errors block after the Group has started.\")\n            synchronise { _groupTransformChildErrorBlock = newValue }\n        }\n    }\n}\n\n// MARK: - GroupProcedure API\n\npublic extension GroupProcedure {\n\n    /**\n     Access the underlying queue of the GroupProcedure.\n\n     - returns: the underlying DispatchQueue of the groups private ProcedureQueue\n    */\n    final var dispatchQueue: DispatchQueue? {\n        return queue.underlyingQueue\n    }\n\n    /**\n     The maximum number of child operations that can execute at the same time.\n\n     The value in this property affects only the operations that the current GroupProcedure has\n     executing at the same time. Other operation queues and GroupProcedures can also execute\n     their maximum number of operations in parallel.\n\n     Reducing the number of concurrent operations does not affect any operations that are\n     currently executing.\n\n     Specifying the value NSOperationQueueDefaultMaxConcurrentOperationCount (which is recommended)\n     causes the system to set the maximum number of operations based on system conditions.\n\n     The default value of this property is NSOperationQueueDefaultMaxConcurrentOperationCount.\n     */\n    final var maxConcurrentOperationCount: Int {\n        get { return queue.maxConcurrentOperationCount }\n        set { queue.maxConcurrentOperationCount = newValue }\n    }\n\n    /**\n     A Boolean value indicating whether the GroupProcedure is actively scheduling operations for execution.\n\n     When the value of this property is false, the GroupProcedure actively starts child operations\n     that are ready to execute once the GroupProcedure has been executed.\n\n     Setting this property to true prevents the GroupProcedure from starting any child operations,\n     but already executing child operations continue to execute.\n\n     You may continue to add operations to a GroupProcedure that is suspended but those operations\n     are not scheduled for execution until you change this property to false.\n\n     The default value of this property is false.\n     */\n    final var isSuspended: Bool {\n        get {\n            return groupStateLock.withCriticalScope { _groupIsSuspended }\n        }\n        set {\n            groupStateLock.withCriticalScope {\n                log.verbose.message(\"isSuspended = \\(newValue), (old value: \\(_groupIsSuspended))\")\n                _groupIsSuspended = newValue\n                queue.isSuspended = newValue\n            }\n        }\n    }\n}\n\npublic extension GroupProcedure {\n\n    // MARK: - Add Child API\n\n    /**\n     Add a single child Operation instance to the group\n     - parameter child: an Operation instance\n    */\n    final func addChild(_ child: Operation, before pendingEvent: PendingEvent? = nil) {\n        addChildren(child, before: pendingEvent)\n    }\n\n    /**\n     Add children Operation instances to the group\n     - parameter children: a variable number of Operation instances\n     */\n    final func addChildren(_ children: Operation..., before pendingEvent: PendingEvent? = nil) {\n        addChildren(children, before: pendingEvent)\n    }\n\n    /**\n     Add a sequence of Operation instances to the group\n     - parameter children: a sequence of Operation instances\n     */\n    final func addChildren<Children: Collection>(_ children: Children, before pendingEvent: PendingEvent? = nil) where Children.Iterator.Element: Operation {\n        addAdditionalChildren(children, toOperationsArray: true, before: pendingEvent)\n    }\n\n    private func shouldAdd<Additional: Collection>(additional: Additional, toOperationsArray shouldAddToProperty: Bool) -> Bool where Additional.Iterator.Element: Operation {\n        return groupStateLock.withCriticalScope {\n\n            log.verbose.trace()\n\n            guard !_groupIsFinishing else {\n                assertionFailure(\"Cannot add new operations to a group after the group has started to finish.\")\n                return false\n            }\n\n            // Debug check whether any of the additional Procedures have already been added to another queue/Group.\n            assert(additional.filter({ if let procedure = $0 as? Procedure { return procedure.isEnqueued } else { return false } }).isEmpty, \"Cannot add Procedures to a GroupProcedure that have already been added to another queue / GroupProcedure: \\(additional.filter({ if let procedure = $0 as? Procedure { return procedure.isEnqueued } else { return false } }))\")\n\n            // Add the new children as a dependencies of the internal GroupCanFinish operation\n            groupCanFinish.addDependencies(additional)\n\n            // Add the new children to the Group's internal `children` array\n            if shouldAddToProperty {\n                let childrenToAdd: [Operation] = Array(additional)\n                _groupChildren.append(contentsOf: childrenToAdd)\n            }\n\n            return true\n        }\n    }\n\n    /**\n     Adds one or more operations to the Group.\n    */\n    final fileprivate func addAdditionalChildren<Additional: Collection>(_ additional: Additional, toOperationsArray shouldAddToProperty: Bool, before pendingEvent: PendingEvent? = nil, alreadyOnEventQueue: Bool = false) where Additional.Iterator.Element: Operation {\n\n        // Exit early if there are no children in the collection\n        guard !additional.isEmpty else { return }\n\n        // Check to see if should add child operations, depending on finishing state\n        // (Also enters the groupIsAddingOperations group)\n        guard shouldAdd(additional: additional, toOperationsArray: shouldAddToProperty) else {\n            let message = !isFinished ? \"started to finish\" : \"completed\"\n            assertionFailure(\"Cannot add new children to a group after the group has \\(message).\")\n            return\n        }\n\n        log.verbose.trace()\n        log.verbose.message(\"is adding \\(additional.count) child operations to the queue.\")\n\n        // If the Group is cancelled, cancel the additional operations\n        if isCancelled {\n            additional.forEach { if !$0.isCancelled { $0.cancel() } }\n        }\n\n        // Step 2:\n        guard alreadyOnEventQueue else {\n            dispatchEvent {\n                self.addOperation_step2(additional: additional, before: pendingEvent)\n            }\n            return\n        }\n        addOperation_step2(additional: additional, before: pendingEvent)\n    }\n\n    fileprivate func addOperation_step2<Additional: Collection>(additional: Additional, before pendingEvent: PendingEvent?) where Additional.Iterator.Element: Operation {\n\n        eventQueue.debugAssertIsOnQueue()\n\n        log.verbose.trace()\n\n        // groupWillAdd(child:) override\n        additional.forEach { self.groupWillAdd(child: $0) }\n\n        // WillAddOperation observers\n        let willAddObserversGroup = self.dispatchObservers(pendingEvent: PendingEvent.addOperation) { observer, _ in\n            additional.forEach {\n                observer.procedure(self, willAdd: $0)\n            }\n        }\n\n        optimizedDispatchEventNotify(group: willAddObserversGroup) {\n\n            // Add to queue\n            self.queue.addOperations(additional, withContext: self.queueAddContext).then(on: self) {\n\n                if let pendingEvent = pendingEvent {\n                    pendingEvent.doBeforeEvent {\n                        self.log.verbose.message(\"Children (\\(additional)) added prior to (\\(pendingEvent)).\")\n                    }\n                }\n\n                // DidAddOperation observers\n                let didAddObserversGroup = self.dispatchObservers(pendingEvent: PendingEvent.postDidAdd) { observer, _ in\n                    additional.forEach {\n                        observer.procedure(self, didAdd: $0)\n                    }\n                }\n\n                self.optimizedDispatchEventNotify(group: didAddObserversGroup) {\n                    self.log.verbose.message(\"finished adding child operations to the queue.\")\n                }\n            }\n        }\n    }\n}\n\n// MARK: - GroupProcedure Private Queue Delegate\n\ninternal extension GroupProcedure {\n\n    /**\n     The group utilizes a GroupQueueDelegate to effectively act as its own delegate for its own\n     internal queue, while keeping this implementation detail private.\n\n     When an operation is added to the queue, assuming that the group is not yet finishing or \n     finished, then we add the operation as a dependency to an internal \"barrier\" operation that\n     separates executing from finishing state.\n\n     This serves to keep the internal operation as a final child operation that executes when\n     there are no more operations in the group operation, safely handling the transition\n     of group operation state.\n     */\n\n    class GroupQueueDelegate: ProcedureQueueDelegate {\n\n        private weak var group: GroupProcedure?\n\n        init(_ group: GroupProcedure) {\n            self.group = group\n        }\n\n        func procedureQueue(_ queue: ProcedureQueue, willAddOperation operation: Operation, context: Any?) -> ProcedureFuture? {\n            guard let strongGroup = group else { return nil }\n            guard queue === strongGroup.queue else { return nil }\n\n            return strongGroup.willAdd(operation: operation, context: context)\n        }\n\n        func procedureQueue(_ queue: ProcedureQueue, willAddProcedure procedure: Procedure, context: Any?) -> ProcedureFuture? {\n            guard let strongGroup = group else { return nil }\n            guard queue === strongGroup.queue else { return nil }\n\n            return strongGroup.willAdd(operation: procedure, context: context)\n        }\n\n        public func procedureQueue(_ queue: ProcedureQueue, willFinishProcedure procedure: Procedure, with error: Error?) -> ProcedureFuture? {\n            guard let strongGroup = group else { return nil }\n            guard queue === strongGroup.queue else { return nil }\n\n            /// If the group is cancelled, exit early\n            guard !strongGroup.isCancelled else { return nil }\n\n            let promise = ProcedurePromise()\n            strongGroup.dispatchEvent {\n\n                defer { promise.complete() }\n\n                var childError: Error? = error\n\n                defer { strongGroup.child(procedure, willFinishWithError: childError) }\n\n                guard let transformChildError = strongGroup.transformChildErrorBlock else { return }\n\n                transformChildError(procedure, &childError)\n\n                strongGroup.log.verbose.message(\"Child error for <\\(procedure.operationName)> was transformed.\")\n            }\n            return promise.future\n        }\n    }\n\n    private func shouldAdd(operation: Operation) -> Bool {\n        return groupStateLock.withCriticalScope {\n            guard !_groupIsFinishing else {\n                assertionFailure(\"Cannot add new operations to a group after the group has started to finish.\")\n                return false\n            }\n\n            // Add the new child as a dependency of the internal GroupCanFinish operation\n            groupCanFinish.addDependency(operation)\n\n            // Add the new child to the Group's internal children array\n            _groupChildren.append(operation)\n            return true\n        }\n    }\n\n    /**\n     - returns: a `ProcedureFuture` that is signaled once the Group has fully prepared for the operation to be added\n                to its internal queue (including notifying all WillAdd observers)\n     */\n    private func willAdd(operation: Operation, context: Any?) -> ProcedureFuture? {\n\n        if let context = context as? ProcedureQueueContext, context === queueAddContext {\n            // The Procedure adding the operation to the Group's private queue is the Group itself\n            //\n            // which means it could only have come from:\n            //      - self.add(child:)  (and convenience overloads)\n            //\n            // which will handle the setup-work for this operation in the context of the Group\n            // (asynchronously) so there is nothing to do here - exit early\n\n            return nil\n        }\n\n        // The Procedure adding the operation to the Group's private queue is *not* the Group.\n        //\n        // It could have come from:\n        //      - a child.produce(operation:)\n        //      - an Operation (NSOperation) subclass calling OperationQueue.current.addOperation()\n        //        (which is not at all recommended, but is possible from an Operation subclass)\n        //\n        // In either case, the operation has not yet been handled in the context of the Group\n        // (i.e. adding it as a child, adding it as a dependency on finishing, notifying Group\n        // Will/DidAddOperation observers) thus it must be handled here:\n        //\n\n        assert(!isFinished, \"Cannot add new operations to a group after the group has completed.\")\n\n        guard shouldAdd(operation: operation) else { return nil }\n\n        let promise = ProcedurePromise()\n\n        // If the Group is already cancelled, ensure that the new child is cancelled.\n        if isCancelled && !operation.isCancelled {\n            operation.cancel()\n        }\n\n        // Dispatch the next step (observers, etc) asynchronously on the Procedure EventQueue\n        dispatchEvent {\n            self.willAdd_step2(operation: operation, promise: promise)\n        }\n\n        return promise.future\n    }\n\n    private func willAdd_step2(operation: Operation, promise: ProcedurePromise) {\n        eventQueue.debugAssertIsOnQueue()\n\n        // groupWillAdd(child:) override\n        groupWillAdd(child: operation)\n\n        // WillAddOperation observers\n        let willAddObserversGroup = dispatchObservers(pendingEvent: PendingEvent.addOperation) { observer, _ in\n            observer.procedure(self, willAdd: operation)\n        }\n\n        optimizedDispatchEventNotify(group: willAddObserversGroup) {\n\n            // Complete the promise\n            promise.complete()\n\n            // DidAddOperation observers\n            _ = self.dispatchObservers(pendingEvent: PendingEvent.postDidAdd) { observer, _ in\n                    observer.procedure(self, didAdd: operation)\n            }\n\n            // Note: no need to wait on DidAddOperation observers - nothing left to do.\n        }\n    }\n}\n\n// MARK: - Finishing\n\nfileprivate extension GroupProcedure {\n\n    final class CanFinishGroup: Operation {\n\n        private weak var group: GroupProcedure?\n        private var _isFinished = false\n        private var _isExecuting = false\n        private let stateLock = PThreadMutex()\n\n        init(group: GroupProcedure) {\n            self.group = group\n            super.init()\n        }\n\n        fileprivate override func start() {\n\n            // Override Operation.start() because this operation may have to\n            // finish asynchronously (if it has to register to be notified when\n            // operations are no longer being added concurrently).\n            //\n            // Since we override start(), it is important to send Operation\n            // isExecuting / isFinished KVO notifications.\n            //\n            // (Otherwise, the operation may not be released, there may be\n            // problems with dependencies, with the queue's handling of\n            // maxConcurrentOperationCount, etc.)\n\n            isExecuting = true\n\n            main()\n        }\n\n        override func main() {\n            execute()\n        }\n\n        func execute() {\n\n            if let group = group {\n                group.log.verbose.trace()\n                group.log.verbose.message(\"executing can finish group operation.\")\n\n                // All operations that were added as a side-effect of anything up to\n                // WillFinishObservers of prior operations should have been executed.\n                //\n                // Handle an edge case caused by concurrent calls to Group.add(children:)\n\n                enum GroupCanFinishResult {\n                    case canFinishNow\n                    case waitingOnNewChildren(CanFinishGroup, [Operation])\n                }\n\n                let isWaiting: GroupCanFinishResult = group.groupStateLock.withCriticalScope {\n\n                    // Check whether new children were added prior to the lock\n                    // (i.e. after the queue decided to start the CanFinish operation)\n                    // by checking for child operations that are not finished.\n\n                    let active = group._groupChildren.filter({ !$0.isFinished })\n                    if !active.isEmpty {\n\n                        // Children were added after this CanFinishOperation became\n                        // ready, but before it executed or before the lock could be acquired.\n\n                        group.log.verbose.message(\"cannot finish now, as there are children still active.\")\n\n                        // The GroupProcedure should wait for these children to finish\n                        // before finishing. Add the oustanding children as\n                        // dependencies to a new CanFinishGroup, and add that as the\n                        // Group's new CanFinishGroup.\n\n                        let newCanFinishGroup = GroupProcedure.CanFinishGroup(group: group)\n                        group.groupCanFinish = newCanFinishGroup\n                        return .waitingOnNewChildren(newCanFinishGroup, active)\n                    }\n                    else {\n                        // There are no additional children to handle.\n                        // Ensure that no new operations can be added.\n\n                        group.log.verbose.message(\"can now finish.\")\n\n                        group._groupIsFinishing = true\n\n                        return .canFinishNow\n                    }\n                } // End of isWaiting\n\n                switch isWaiting {\n                case .canFinishNow:\n                    // trigger an immediate finish of the parent Group\n                    group._finishGroup()\n                case .waitingOnNewChildren(let newCanFinishGroup, let newChildrenToWaitOn):\n                    // add the new children as dependencies to the newCanFinishGroup,\n                    // (which is already set as the `group.groupCanFinish` inside the lock\n                    // above) and then add the newCanFinishGroup to the group's internal queue\n                    newCanFinishGroup.addDependencies(newChildrenToWaitOn)\n                    group.add(canFinishGroup: newCanFinishGroup)\n                    // continue on to finish this CanFinishGroup operation\n                    // (the newCanFinishGroup takes over responsibility)\n                    break\n                }\n            }\n\n            isExecuting = false\n            isFinished = true\n        }\n\n        override private(set) var isExecuting: Bool {\n            get { return stateLock.withCriticalScope { _isExecuting } }\n            set {\n                willChangeValue(forKey: .executing)\n                stateLock.withCriticalScope { _isExecuting = newValue }\n                didChangeValue(forKey: .executing)\n            }\n        }\n\n        override private(set) var isFinished: Bool {\n            get { return stateLock.withCriticalScope { _isFinished } }\n            set {\n                willChangeValue(forKey: .finished)\n                stateLock.withCriticalScope { _isFinished = newValue }\n                didChangeValue(forKey: .finished)\n            }\n        }\n    }\n\n    func add(canFinishGroup: CanFinishGroup) {\n        queue.add(canFinishGroup: canFinishGroup)\n    }\n}\n\nfileprivate extension GroupProcedure {\n\n    func _finishGroup() {\n        super.finish()\n        queue.isSuspended = true\n    }\n}\n\nfileprivate extension ProcedureQueue {\n\n    func add(canFinishGroup: GroupProcedure.CanFinishGroup) {\n        // Do not add observers (not needed - CanFinishGroup is an implementation detail of Group)\n        // Do not add conditions (CanFinishGroup has none)\n        // Call OperationQueue.addOperation() directly\n        super.addOperation(canFinishGroup)\n    }\n}\n\n// MARK: - Deprecations Unavailable\n\npublic extension GroupProcedure {\n\n    @available(*, unavailable, renamed: \"children\")\n    var operations: [Operation] { return children }\n\n    @available(*, unavailable, renamed: \"isSuspended\")\n    final var suspended: Bool { return isSuspended }\n\n    @available(*, unavailable, renamed: \"addChild(_:before:)\")\n    func addOperation(operation: Operation) { }\n\n    @available(*, unavailable, renamed: \"add(children:)\")\n    func addOperations(operations: Operation...) { }\n\n    @available(*, unavailable, renamed: \"add(children:)\")\n    func addOperations(additional: [Operation]) { }\n\n    @available(*, unavailable, message: \"GroupProcedure child error handling customization has been re-worked. Consider overriding child(_:willFinishWithError:).\")\n    final func childDidRecoverFromErrors(_ child: Operation) { }\n\n    @available(*, unavailable, message: \"GroupProcedure child error handling customization has been re-worked. Consider overriding child(_:willFinishWithError:).\")\n    final func childDidNotRecoverFromErrors(_ child: Operation) { }\n\n    @available(*, unavailable, message: \"GroupProcedure no longer collects all the child errors within itself\")\n    final func append(fatalError error: Error) { }\n\n    @available(*, unavailable, message: \"GroupProcedure no longer collects all the child errors within itself\")\n    final func append(fatalErrors errors: [Error]) { }\n\n    @available(*, unavailable, message: \"GroupProcedure no longer collects all the child errors within itself\")\n    final func append(error: Error, fromChild child: Operation? = nil) { }\n\n    @available(*, unavailable, message: \"GroupProcedure no longer collects all the child errors within itself\")\n    final func append(errors: [Error], fromChild child: Operation? = nil) { }\n\n    @available(*, deprecated, renamed: \"addChild(_:before:)\", message: \"This has been renamed to use Swift 3/4 naming conventions\")\n    final func add(child: Operation, before pendingEvent: PendingEvent? = nil) {\n        addChild(child, before: pendingEvent)\n    }\n\n    @available(*, deprecated, renamed: \"addChildren(_:before:)\", message: \"This has been renamed to use Swift 3/4 naming conventions\")\n    final func add(children: Operation..., before pendingEvent: PendingEvent? = nil) {\n        addChildren(children, before: pendingEvent)\n    }\n\n    @available(*, deprecated, renamed: \"addChildren(_:before:)\", message: \"This has been renamed to use Swift 3/4 naming conventions\")\n    final func add<Children: Collection>(children: Children, before pendingEvent: PendingEvent? = nil) where Children.Iterator.Element: Operation {\n        addChildren(children, before: pendingEvent)\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKit/Identity.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport Foundation\n\n/// `Identifiable` is a generic protocol for defining property based identity.\npublic protocol Identifiable {\n    associatedtype Identity: Hashable\n\n    /// An identifier\n    var identity: Identity { get }\n}\n\npublic func ==<T: Identifiable> (lhs: T, rhs: T) -> Bool {\n    return lhs.identity == rhs.identity\n}\n\npublic func ==<T, V> (lhs: T, rhs: V) -> Bool where T: Identifiable, V: Identifiable, T.Identity == V.Identity {\n    return lhs.identity == rhs.identity\n}\n\nextension Procedure: Identifiable {\n\n    public struct Identity: Identifiable, Hashable {\n\n        public let identity: ObjectIdentifier\n        public let name: String?\n\n        public var description: String {\n            return name.map { \"\\($0) #\\(identity)\" } ?? \"Unnamed Procedure #\\(identity)\"\n        }\n\n        public func hash(into hasher: inout Hasher) {\n            hasher.combine(identity)\n        }\n    }\n\n    /// A Procedure's identity (often used for debugging purposes) provides a unique identifier\n    /// for a `Procedure` instance, comprised of the Procedure's `name` and a `UUID`.\n    public var identity: Identity {\n        return Identity(identity: ObjectIdentifier(self), name: name)\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKit/IgnoreErrors.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2016-2018 ProcedureKit. All rights reserved.\n//\n\nimport Foundation\n\n/**\n Compose another `Procedure` subclass to ignore any errors that it generates.\n*/\nfinal public class IgnoreErrorsProcedure<T: Procedure>: ComposedProcedure<T> {\n\n    /// Override to supress errors from the composed procedure\n    override public func child(_ child: Procedure, willFinishWithError error: Error?) {\n        assert(!child.isFinished, \"child(_:willFinishWithErrors:) called with a child that has already finished\")\n\n        // No errors - call the super.\n        guard let e = error else {\n            super.child(child, willFinishWithError: error)\n            return\n        }\n\n        // If there are errors, just log them.\n        log.warning.message(\"Ignoring \\(e) errors from \\(child.operationName).\")\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKit/Logging.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport Foundation\nimport Dispatch\nimport os\n\ninternal struct CurrentProcessInfo {\n\n    static var name: String {\n        return shared.name\n    }\n\n    static var ID: Int32 {\n        return shared.ID\n    }\n\n    private static let shared = CurrentProcessInfo()\n\n    private let name: String\n    private let ID: Int32\n\n    private init() {\n        let process = ProcessInfo.processInfo\n        name = process.processName\n        ID = process.processIdentifier\n    }\n}\n\npublic class Log {\n\n    public enum Severity: Int, Comparable {\n\n        public static func < (lhs: Severity, rhs: Severity) -> Bool {\n            return lhs.rawValue < rhs.rawValue\n        }\n\n        /// Reserved for chatty ProcedureKit framework level logging\n        case verbose = 0\n\n        /// Used by ProcedureKit for lifecycle level logging\n        /// in non-production builds. Available to framework users\n        case info\n\n        /// Reserved for user activity events\n        case event\n\n        /// Reserved for caveman debugging\n        case debug\n\n        /// Errors are happening, but maybe recoverable\n        case warning\n\n        /// Everything is on fire\n        case fatal\n    }\n\n    public struct Entry: CustomStringConvertible {\n\n        public enum Payload: CustomStringConvertible {\n\n            case trace\n            case message(String)\n            case value(Any?)\n\n            public var description: String {\n                switch self {\n                case .trace:\n                    return \"\"\n                case .message(let text):\n                    return text\n                case .value(let value):\n                    if let value = value {\n                        return \"\\(value)\"\n                    }\n                    return \"<nil-value>\"\n                }\n            }\n        }\n\n        public let payload: Payload\n\n        public let formattedMetadata: String?\n\n        public let severity: Severity\n\n        public let file: String\n\n        public let function: String\n\n        public let line: Int\n\n        public let threadID: UInt64\n\n        public let timestamp: Date\n\n        public let processName: String\n\n        public let processID: Int32\n\n        public var description: String {\n            guard let metadata = formattedMetadata else {\n                return payload.description\n            }\n            return \"\\(metadata) \\(payload.description)\"\n        }\n\n        public var message: String? {\n            switch payload {\n            case let .message(message):\n                return message\n            default:\n                return nil\n            }\n        }\n\n        public init(payload: Payload, formattedMetadata: String? = nil, severity: Log.Severity, file: String, function: String, line: Int, threadID: UInt64, timestamp: Date = Date()) {\n            self.payload = payload\n            self.formattedMetadata = formattedMetadata\n            self.severity = severity\n            self.file = file\n            self.function = function\n            self.line = line\n            self.threadID = threadID\n            self.timestamp = timestamp\n            self.processName = CurrentProcessInfo.name\n            self.processID = CurrentProcessInfo.ID\n        }\n\n        func append(formattedMetadata newFormattedMetadata: String?) -> Log.Entry {\n            guard let newFormattedMetadata = newFormattedMetadata?.trimmingCharacters(in: .whitespacesAndNewlines) else { return self }\n            guard false == newFormattedMetadata.isEmpty else { return self }\n\n            let new: String\n            if let old = formattedMetadata, !old.isEmpty {\n                new = \"\\(old) \\(newFormattedMetadata)\"\n            }\n            else {\n                new = newFormattedMetadata\n            }\n            return Log.Entry(payload: payload, formattedMetadata: new, severity: severity, file: file, function: function, line: line, threadID: threadID, timestamp: timestamp)\n        }\n    }\n\n    // MARK: - Static Properties\n\n    internal static var shared: LogChannel = Log.Channel<Log>(enabled: true, severity: .info, writer: Log.Writers.standard, formatter: Log.Formatters.standard)\n\n    // MARK: - Instance Properties\n\n    private let queue = DispatchQueue(label: \"run.kit.procedure.ProcedureKit.Logger\", qos: .utility)\n\n    private let stateLock = PThreadMutex()\n\n    private init() { }\n}\n\npublic protocol LogSettings {\n\n    static var enabled: Bool { get set }\n\n    static var severity: Log.Severity { get set }\n\n    static var channel: LogChannel { get set }\n\n    static var writer: LogWriter { get set }\n\n    static var formatter: LogFormatter { get set }\n}\n\npublic protocol LogWriter {\n\n    func write(entry: Log.Entry)\n}\n\npublic protocol LogFormatter {\n\n    func format(entry: Log.Entry) -> Log.Entry\n}\n\npublic protocol LogChannel {\n\n    var enabled: Bool { get set }\n\n    var severity: Log.Severity { get set }\n\n    var writer: LogWriter { get set }\n\n    var formatter: LogFormatter { get set }\n}\n\npublic protocol LogChannels {\n\n    var verbose: LogChannel { get }\n\n    var info: LogChannel { get }\n\n    var event: LogChannel { get }\n\n    var debug: LogChannel { get }\n\n    var warning: LogChannel { get }\n\n    var fatal: LogChannel { get }\n\n    var current: LogChannel { get }\n}\n\npublic typealias ProcedureLog = LogChannels & LogChannel\n\n// MARK: - Protocol Exensions\n\npublic extension LogChannel {\n\n    func shouldWrite(severity: Log.Severity) -> Bool {\n        return enabled && Log.enabled && (self.severity >= Log.severity) && (severity >= self.severity)\n    }\n\n    func write(entry: Log.Entry) {\n        writer.write(entry: formatter.format(entry: entry))\n    }\n\n    func trace(_ file: String = #file, function: String = #function, line: Int = #line) {\n        guard shouldWrite(severity: severity) else { return }\n        var threadID: UInt64 = 0\n        pthread_threadid_np(nil, &threadID)\n        let entry = Log.Entry(payload: .trace, severity: severity, file: file, function: function, line: line, threadID: threadID)\n        write(entry: entry)\n    }\n\n    func message(_ msg: @autoclosure () -> String, file: String = #file, function: String = #function, line: Int = #line) {\n        guard shouldWrite(severity: severity) else { return }\n        var threadID: UInt64 = 0\n        pthread_threadid_np(nil, &threadID)\n        let entry = Log.Entry(payload: .message(msg()), severity: severity, file: file, function: function, line: line, threadID: threadID)\n        write(entry: entry)\n    }\n\n    func value(_ value: @autoclosure () -> Any?, file: String = #file, function: String = #function, line: Int = #line) {\n        guard shouldWrite(severity: severity) else { return }\n        var threadID: UInt64 = 0\n        pthread_threadid_np(nil, &threadID)\n        let entry = Log.Entry(payload: .value(value()), severity: severity, file: file, function: function, line: line, threadID: threadID)\n        write(entry: entry)\n    }\n}\n\npublic extension LogChannels {\n\n    var channels: [LogChannel] {\n        return [verbose, info, event, debug, warning, fatal]\n    }\n}\n\n// MARK: - Protocol Conformance\n\nextension Log: LogSettings {\n\n    public static var channel: LogChannel {\n        get { return shared }\n        set { shared = newValue }\n    }\n\n    public static var enabled: Bool {\n        get { return channel.enabled }\n        set { channel.enabled = newValue }\n    }\n\n    public static var severity: Severity {\n        get { return channel.severity }\n        set { channel.severity = newValue }\n    }\n\n    public static var writer: LogWriter {\n        get { return channel.writer }\n        set { channel.writer = newValue }\n    }\n\n    public static var formatter: LogFormatter {\n        get { return channel.formatter }\n        set { channel.formatter = newValue }\n    }\n\n    @available(iOS 10.0, iOSApplicationExtension 10.0, tvOS 10.0, tvOSApplicationExtension 10.0, OSX 10.12, OSXApplicationExtension 10.12, *)\n    public static func setWriterUsingOSLog(_ log: OSLog) {\n        writer = Log.Writers.OSLogWriter(log: log)\n    }\n\n}\n\n// MARK: - Log Channel\n\npublic extension Log {\n\n    class Channel<Settings: LogSettings>: LogChannel {\n\n        private let stateLock = PThreadMutex()\n\n        private var _enabled: Bool\n        private var _severity: Severity\n        private var _writer: LogWriter\n        private var _formatter: LogFormatter\n\n        public init(enabled: Bool = Settings.enabled, severity: Log.Severity = Settings.severity, writer: LogWriter = Settings.writer, formatter: LogFormatter = Settings.formatter) {\n            _enabled = enabled\n            _severity = severity\n            _writer = writer\n            _formatter = formatter\n        }\n\n        @discardableResult\n        private func synchronise<T>(block: () -> T) -> T {\n            return stateLock.withCriticalScope(block: block)\n        }\n\n        public var enabled: Bool {\n            get { return synchronise { _enabled } }\n            set { synchronise { _enabled = newValue } }\n        }\n\n        public var severity: Severity {\n            get { return synchronise { _severity } }\n            set { synchronise { _severity = newValue } }\n        }\n\n        public var writer: LogWriter {\n            get { return synchronise { _writer } }\n            set { synchronise { _writer = newValue } }\n        }\n\n        public var formatter: LogFormatter {\n            get { return synchronise { _formatter } }\n            set { synchronise { _formatter = newValue } }\n        }\n    }\n}\n\n// MARK: - Log Channels\n\nextension Log {\n\n    public class Channels<Settings: LogSettings>: Log.Channel<Settings>, LogChannels {\n\n        public private(set) var verbose: LogChannel\n\n        public private(set) var info: LogChannel\n\n        public private(set) var event: LogChannel\n\n        public private(set) var debug: LogChannel\n\n        public private(set) var warning: LogChannel\n\n        public private(set) var fatal: LogChannel\n\n        public var current: LogChannel {\n            switch severity {\n            case .verbose: return verbose\n            case .info: return info\n            case .event: return event\n            case .debug: return debug\n            case .warning: return warning\n            case .fatal: return fatal\n            }\n        }\n\n        public override var enabled: Bool {\n            didSet {\n                for var channel in channels {\n                    channel.enabled = enabled\n                }\n            }\n        }\n\n        public override var writer: LogWriter {\n            didSet {\n                for var channel in channels {\n                    channel.writer = writer\n                }\n            }\n        }\n\n        public override var formatter: LogFormatter {\n            didSet {\n                for var channel in channels {\n                    channel.formatter = formatter\n                }\n            }\n        }\n\n        override public init(enabled: Bool = Settings.enabled, severity: Log.Severity = Settings.severity, writer: LogWriter = Settings.writer, formatter: LogFormatter = Settings.formatter) {\n            verbose = Log.Channel<Settings>(enabled: enabled, severity: .verbose, writer: writer, formatter: formatter)\n            info = Log.Channel<Settings>(enabled: enabled, severity: .info, writer: writer, formatter: formatter)\n            event = Log.Channel<Settings>(enabled: enabled, severity: .event, writer: writer, formatter: formatter)\n            debug = Log.Channel<Settings>(enabled: enabled, severity: .debug, writer: writer, formatter: formatter)\n            warning = Log.Channel<Settings>(enabled: enabled, severity: .warning, writer: writer, formatter: formatter)\n            fatal = Log.Channel<Settings>(enabled: enabled, severity: .fatal, writer: writer, formatter: formatter)\n            super.init(enabled: enabled, severity: severity, writer: writer, formatter: formatter)\n        }\n    }\n}\n\n// MARK: - Log Writers\n\npublic extension Log {\n\n    struct Writers {\n\n        public static let standard: LogWriter = {\n            if #available(iOS 10.0, iOSApplicationExtension 10.0, tvOS 10.0, tvOSApplicationExtension 10.0, OSX 10.12, OSXApplicationExtension 10.12, *) {\n                return OSLogWriter(log: .procedure)\n            }\n            else {\n                return PrintLogWriter()\n            }\n        }()\n\n        public static let system: LogWriter = {\n            if #available(iOS 10.0, iOSApplicationExtension 10.0, tvOS 10.0, tvOSApplicationExtension 10.0, OSX 10.12, OSXApplicationExtension 10.12, *) {\n                return Log.Writers.OSLogWriter(log: .procedure)\n            }\n            else {\n                return Log.Writers.PrintLogWriter()\n            }\n        }()\n    }\n}\n\n// MARK: - Log Formatters\n\npublic extension Log {\n\n    struct Formatters {\n\n        public static let standard: LogFormatter = Concatenating([SeverityFormatter(), CallsiteFormatter()])\n\n        public static func makeProcedureLogFormatter(operationName name: String) -> LogFormatter {\n            return Log.Formatters.Concatenating([\n                Log.Formatters.CallsiteFormatter(),\n                Log.Formatters.SeverityFormatter(),\n                Log.Formatters.StaticStringFormatter(name)])\n        }\n    }\n}\n\npublic extension Log.Formatters {\n\n    class Concatenating: LogFormatter {\n\n        public let formatters: [LogFormatter]\n\n        public init(_ formatters: [LogFormatter]) {\n            self.formatters = formatters\n        }\n\n        public func format(entry: Log.Entry) -> Log.Entry {\n            return formatters.reduce(entry) { $1.format(entry: $0) }\n        }\n    }\n\n    class SeverityFormatter: LogFormatter {\n\n        public func format(entry: Log.Entry) -> Log.Entry {\n            return entry.append(formattedMetadata: entry.severity.description)\n        }\n    }\n\n    class StaticStringFormatter: LogFormatter {\n\n        public let text: String\n\n        public init(_ text: String) {\n            self.text = text\n        }\n\n        public func format(entry: Log.Entry) -> Log.Entry {\n            return entry.append(formattedMetadata: text)\n        }\n    }\n\n    class CallsiteFormatter: LogFormatter {\n\n        public func format(entry: Log.Entry) -> Log.Entry {\n            guard false == entry.file.contains(\"ProcedureKit\") else { return entry }\n            let filename = (entry.file as NSString).pathComponents.last ?? \"redacted\"\n            return entry.append(formattedMetadata: \"\\(filename):\\(entry.line)\")\n        }\n    }\n\n}\n\nextension Log.Severity: CustomStringConvertible {\n\n    public var description: String {\n        switch self {\n        case .verbose:\n            return \"▪️\"\n        case .info:\n            return \"🔷\"\n        case .event:\n            return \"🔶\"\n        case .debug:\n            return \"◽️\"\n        case .warning:\n            return \"⚠️\"\n        case .fatal:\n            return \"❌\"\n        }\n    }\n}\n\n\n\n\n// MARK: - Log Writer\n\n\n// MARK: - OSLog Writer\n\n@available(iOS 10.0, iOSApplicationExtension 10.0, tvOS 10.0, tvOSApplicationExtension 10.0, OSX 10.12, OSXApplicationExtension 10.12, *)\npublic extension Log.Severity {\n\n    var logType: OSLogType {\n        switch self {\n        case .verbose, .debug:\n            return .debug\n        case .info, .event:\n            return .info\n        case .warning:\n            return .default\n        case .fatal:\n            return .error\n        }\n    }\n}\n\nextension Log.Writers {\n\n    @available(iOS 10.0, iOSApplicationExtension 10.0, tvOS 10.0, tvOSApplicationExtension 10.0, OSX 10.12, OSXApplicationExtension 10.12, *)\n    public class OSLogWriter: LogWriter {\n\n        public let log: OSLog\n\n        public init(log: OSLog) {\n            self.log = log\n        }\n\n        public func write(entry: Log.Entry) {\n            os_log(\"%{public}@\", log: log, type: entry.severity.logType, entry.description)\n        }\n    }\n}\n\n@available(iOS 10.0, iOSApplicationExtension 10.0, tvOS 10.0, tvOSApplicationExtension 10.0, OSX 10.12, OSXApplicationExtension 10.12, *)\ninternal extension OSLog {\n\n    static let procedure = OSLog(subsystem: \"run.kit.procedure\", category: \"ProcedureKit\")\n}\n\n// MARK: - Print Log Writer\nextension Log.Writers {\n\n    public class PrintLogWriter: LogWriter {\n\n        public func write(entry: Log.Entry) {\n            print(entry)\n        }\n    }\n}\n\nextension Log.Writers {\n\n    public class Redirecting: LogWriter {\n\n        public let writers: [LogWriter]\n\n        public init(writers: [LogWriter]) {\n            self.writers = writers\n        }\n\n        public func write(entry: Log.Entry) {\n            writers.forEach { $0.write(entry: entry) }\n        }\n    }\n}\n\n// MARK: - Procedure Log\n\n\n// MARK: - Deprecations\n\npublic extension LogChannel {\n\n    @available(*, deprecated, renamed: \"info.message\", message: \"The .notice severity has been deprecated use .info, .event or .debug instead\")\n    func notice(message: @autoclosure () -> String, file: String = #file, function: String = #function, line: Int = #line) {\n        self.message(message(), file: file, function: function, line: line)\n    }\n}\n\n"
  },
  {
    "path": "Sources/ProcedureKit/Map.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nopen class MapProcedure<Element, U>: ReduceProcedure<Element, Array<U>> {\n\n    public init<S: Sequence>(source: S, transform: @escaping (Element) throws -> U) where S.Iterator.Element == Element {\n        super.init(source: source, initial: Array<U>()) { acc, element in\n            var accumulator = acc\n            try accumulator.append(transform(element))\n            return accumulator\n        }\n    }\n\n    public convenience init(transform: @escaping (Element) throws -> U) {\n        self.init(source: [], transform: transform)\n    }\n}\n\npublic extension OutputProcedure where Self.Output: Sequence {\n\n    func map<U>(transform: @escaping (Output.Iterator.Element) throws -> U) -> MapProcedure<Output.Iterator.Element, U> {\n        return MapProcedure(transform: transform).injectResult(from: self) { AnySequence(Array($0)) }\n    }\n}\n\nopen class FlatMapProcedure<Element, U>: ReduceProcedure<Element, Array<U>> {\n\n    public init<S: Sequence>(source: S, transform: @escaping (Element) throws -> U?) where S.Iterator.Element == Element {\n        super.init(source: source, initial: Array<U>()) { acc, element in\n            guard let u = try transform(element) else { return acc }\n            return acc + [u]\n        }\n    }\n\n    public convenience init(transform: @escaping (Element) throws -> U?) {\n        self.init(source: [], transform: transform)\n    }\n}\n\npublic extension OutputProcedure where Self.Output: Sequence {\n\n    func flatMap<U>(transform: @escaping (Output.Iterator.Element) throws -> U?) -> FlatMapProcedure<Output.Iterator.Element, U> {\n        return FlatMapProcedure(transform: transform).injectResult(from: self) { AnySequence(Array($0)) }\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKit/MutualExclusion.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport Foundation\nimport Dispatch\n\n/**\n A generic condition for describing operations that\n cannot be allowed to execute concurrently.\n */\npublic final class MutuallyExclusive<T>: Condition {\n\n    /// Public constructor\n    public init(category: String = \"MutuallyExclusive<\\(T.self)>\") {\n        super.init()\n        name = \"MutuallyExclusive<\\(T.self)>\"\n        addToAttachedProcedure(mutuallyExclusiveCategory: category)\n    }\n\n    /// Required public override, but there is no evaluation, so it just completes with `.Satisfied`.\n    public override func evaluate(procedure: Procedure, completion: @escaping (ConditionResult) -> Void) {\n        completion(.success(true))\n    }\n}\n\n/// Manages Exclusivity locks. A single shared instance (per-process) is used by the framework.\n///\n/// - NOTE: You should not interact with ExclusivityManager directly.\n/// Instead, add `MutuallyExclusive` Conditions to Procedures.\n///\n/// - see: `MutuallyExclusive`\nfinal public class ExclusivityManager {\n\n    static let sharedInstance = ExclusivityManager()\n\n    fileprivate let queue = DispatchQueue(label: \"run.kit.procedure.ProcedureKit.Exclusivity\", qos: DispatchQoS.userInitiated) // serial dispatch queue\n\n    fileprivate let completeLocksQueue = DispatchQueue(label: \"run.kit.procedure.ProcedureKit.ExclusivityCompleteLocks\", qos: DispatchQoS.userInitiated, attributes: [.concurrent])\n    fileprivate var categoryQueues: [String: [DispatchGroup]] = [:]\n\n    private init() {\n        // A private initalizer prevents any other part of the app\n        // from creating an instance.\n    }\n\n    /// Asynchronously requests a lock for a set of categories, and calls the completion block\n    /// once it is acquired.\n    ///\n    /// The set of categories must not be empty.\n    ///\n    /// The completion block is *always* called asynchronously.\n    ///\n    /// - Parameters:\n    ///   - categories: a Set of Strings - each String is treated as a unique lock identifier\n    ///   - completion: a block called once the lock on every category is acquired\n    internal func requestLock(for categories: Set<String>, completion: @escaping () -> Void) {\n        guard !categories.isEmpty else {\n            // No categories requested\n            fatalError(\"A request for Mutual Exclusivity locks was made with no categories specified. This request is unnecessary.\") // ProcedureKit internal programmer error\n        }\n\n        queue.async { self._requestLock(for: categories, completion: completion) }\n    }\n\n    private func _requestLock(for categories: Set<String>, completion: @escaping () -> Void) {\n        assert(!categories.isEmpty)\n\n        // Create a new dispatch group for this lock request\n        let categoriesGroup = DispatchGroup()\n\n        var unavailableCategories = 0\n        // Add the procedure to each category's queue\n        for category in categories {\n            switch _requestLock(forCategory: category, withGroup: categoriesGroup) {\n            case .immediatelyAvailable:\n                // Do nothing - continue directly to the next category\n                break\n            case .waitingForLock:\n                unavailableCategories += 1\n            }\n        }\n\n        // If the lock was immediately acquired for all categories:\n        if unavailableCategories == 0 {\n            // call completion now\n            //            completeLocksQueue.async {\n            completion()\n            //            }\n        }\n        else {\n            // Otherwise, wait on the DispatchGroup created for this lock request\n\n            // Enter it once for every category on which we must wait\n            (0..<unavailableCategories).forEach { _ in categoriesGroup.enter() }\n\n            // Schedule a notification when the lock for all those categories has been acquired\n            categoriesGroup.notify(queue: completeLocksQueue) {\n                completion()\n            }\n        }\n    }\n\n    private enum RequestLockResult {\n        case immediatelyAvailable\n        case waitingForLock\n    }\n    private func _requestLock(forCategory category: String, withGroup group: DispatchGroup) -> RequestLockResult {\n        var queueForThisCategory = categoryQueues[category] ?? []\n        let isFrontOfTheQueueForThisCategory = queueForThisCategory.isEmpty\n        queueForThisCategory.append(group)\n        categoryQueues[category] = queueForThisCategory\n\n        return (isFrontOfTheQueueForThisCategory) ? .immediatelyAvailable : .waitingForLock\n    }\n\n    internal func unlock(categories: Set<String>) {\n        queue.async { self._unlock(categories: categories) }\n    }\n\n    private func _unlock(categories: Set<String>) {\n        for category in categories {\n            _unlock(category: category)\n        }\n    }\n\n    internal func _unlock(category: String) {\n        guard var queueForThisCategory = categoryQueues[category] else { return }\n        // Remove the first item in the queue for this category\n        // (which should be the procedure that currently has the lock).\n        assert(!queueForThisCategory.isEmpty)\n        _ = queueForThisCategory.removeFirst()\n\n        // If another operation is waiting on this particular lock\n        if let nextOperationForLock = queueForThisCategory.first {\n            // Leave its DispatchGroup (i.e. it \"acquires\" the lock for this category)\n            nextOperationForLock.leave()\n        }\n\n        if !queueForThisCategory.isEmpty {\n            categoryQueues[category] = queueForThisCategory\n        }\n        else {\n            categoryQueues.removeValue(forKey: category)\n        }\n    }\n}\n\npublic extension ExclusivityManager {\n\n    /// This should only be used as part of the unit testing\n    /// - WARNING: This immediately frees up any oustanding mutual exclusion.\n    static func __tearDownForUnitTesting() {\n        sharedInstance.__tearDownForUnitTesting()\n    }\n\n    /// This should only be used as part of the unit testing\n    fileprivate func __tearDownForUnitTesting() {\n        queue.sync {\n            for (_, dispatchGroups) in categoryQueues {\n                // Skip the first item in the category, because\n                // it's the one that currently holds the lock.\n                for group in dispatchGroups.suffix(from: 1) {\n                    group.leave()\n                }\n            }\n            categoryQueues.removeAll()\n        }\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKit/NegatedCondition.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n/**\n A Condition that negates the result from a composed Condition.\n\n Thus:\n - If the composed Condition returns `.success(true)`, the `NegatedCondition` returns `.failure(ProcedureKitError.conditionFailed())`\n - Otherwise, the `NegatedCondition` returns `.success(true)`\n\n */\npublic final class NegatedCondition<C: Condition>: ComposedCondition<C> {\n\n    /// Public override of initializer.\n    public override init(_ condition: C) {\n        super.init(condition)\n        name = condition.name.map { \"Not<\\($0)>\" }\n    }\n\n    /// Override of public function\n    public override func evaluate(procedure: Procedure, completion: @escaping (ConditionResult) -> Void) {\n        super.evaluate(procedure: procedure) { composedResult in\n            switch composedResult {\n            case .success(true):\n                completion(.failure(ProcedureKitError.conditionFailed()))\n            case .success(false), .failure:\n                completion(.success(true))\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKit/NetworkObserver.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport Foundation\nimport Dispatch\n\npublic protocol NetworkActivityIndicatorProtocol {\n    #if swift(>=3.2)\n        var isNetworkActivityIndicatorVisible: Bool { get set }\n    #else // Swift < 3.2 (Xcode 8.x)\n        var networkActivityIndicatorVisible: Bool { get set }\n    #endif\n}\n\npublic class NetworkActivityController {\n\n    let interval: TimeInterval\n    private(set) var indicator: NetworkActivityIndicatorProtocol\n\n    private var count = 0\n    private var delayedHide: DispatchWorkItem?\n\n    private let queue = DispatchQueue(label: \"run.kit.procedure.ProcedureKit.NetworkActivityController\", qos: .userInteractive)\n\n    /// Initialize a NetworkActivityController\n    ///\n    /// - Parameters:\n    ///   - timerInterval: How long to wait after observed network activity stops before\n    ///                    the network activity indicator is set to false.\n    ///                    (This helps reduce flickering if you rapidly create procedures\n    ///                    with attached NetworkObservers.)\n    ///   - indicator:     Conforms to `NetworkActivityIndicatorProtocol`.\n    ///                    The `indicator`'s `networkActivityIndicatorVisible` property\n    ///                    is queried/set by the NetworkActivityController.\n    ///                    (NOTE: NetworkActivityController always accesses the indicator's\n    ///                    `networkActivityIndicatorVisible` property on the main queue.)\n    ///\n    public init(timerInterval: TimeInterval = 1.0, indicator: NetworkActivityIndicatorProtocol) {\n        self.interval = timerInterval\n        self.indicator = indicator\n    }\n\n    /// start() is thread-safe\n    func start() {\n        queue.async {\n            self.count += 1\n            self.update()\n        }\n    }\n\n    /// stop() is thread-safe\n    func stop() {\n        queue.async {\n            self.count -= 1\n            self.update()\n        }\n    }\n\n    private func update() {\n        if count > 0 {\n            updateIndicator(withVisibility: true)\n        }\n        else if count == 0 {\n            let workItem = DispatchWorkItem(block: {\n                self.updateIndicator(withVisibility: false)\n            })\n            delayedHide = workItem\n            queue.asyncAfter(deadline: .now() + interval, execute: workItem)\n        }\n    }\n\n    private func updateIndicator(withVisibility visibility: Bool) {\n        delayedHide?.cancel()\n        delayedHide = nil\n        DispatchQueue.main.async {\n            // only set the visibility if it has changed\n            #if swift(>=3.2)\n                if self.indicator.isNetworkActivityIndicatorVisible != visibility {\n                    self.indicator.isNetworkActivityIndicatorVisible = visibility\n                }\n            #else // Swift < 3.2 (Xcode 8.x)\n                if self.indicator.networkActivityIndicatorVisible != visibility {\n                    self.indicator.networkActivityIndicatorVisible = visibility\n                }\n            #endif\n        }\n    }\n}\n\npublic class NetworkObserver: ProcedureObserver {\n\n    private let networkActivityController: NetworkActivityController\n\n    /// Initialize a NetworkObserver with a supplied NetworkActivityController.\n    public init(controller: NetworkActivityController) {\n        networkActivityController = controller\n    }\n\n    public func will(execute procedure: Procedure, pendingExecute: PendingExecuteEvent) {\n        networkActivityController.start()\n    }\n\n    public func did(finish procedure: Procedure, with error: Error?) {\n        networkActivityController.stop()\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKit/NoFailedDependenciesCondition.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\npublic class NoFailedDependenciesCondition: Condition {\n\n    /// Options on how to handle cancellation\n    enum CancellationOptions {\n\n        /// Indicates that cancelled dependencies\n        /// would trigger a failed condition\n        case fail\n\n        /// Indicates that cancelled dependencies\n        /// would trigger an ignored condition\n        case ignore\n    }\n\n    let cancellationOptions: CancellationOptions\n\n    public init(ignoreCancellations: Bool = false) {\n        cancellationOptions = ignoreCancellations ? .ignore : .fail\n        super.init()\n        name = \"No Failed Dependencies\"\n    }\n\n    /**\n     Evaluates the procedure with respect to the finished status of its dependencies.\n\n     The condition first checks if any dependencies were cancelled, in which case it\n     fails with an `ProcedureKitError.dependenciesCancelled`. Then\n     it checks to see if any dependencies failed due to errors, in which case it\n     fails with an `ProcedureKitError.dependenciesFailed`.\n\n\n     - parameter procedure: the `Procedure` which the condition is attached to.\n     - parameter completion: the completion block which receives a `ConditionResult`.\n     */\n    public override func evaluate(procedure: Procedure, completion: @escaping (ConditionResult) -> Void) {\n        let dependencies = procedure.dependencies\n        let cancelled = dependencies.filter { $0.isCancelled }\n        let failures = dependencies.filter {\n            guard let procedure = $0 as? Procedure else { return false }\n            return procedure.failed\n        }\n\n        switch cancellationOptions {\n        case _ where !failures.isEmpty:\n            completion(.failure(ProcedureKitError.dependenciesFailed()))\n        case .fail where !cancelled.isEmpty:\n            completion(.failure(ProcedureKitError.dependenciesCancelled()))\n        case .ignore where !cancelled.isEmpty:\n            completion(.success(false))\n        default:\n            completion(.success(true))\n        }\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKit/Operation+ProcedureKit.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport Foundation\n\ninternal extension Operation {\n\n    enum KeyPath: String {\n        case cancelled = \"isCancelled\"\n        case executing = \"isExecuting\"\n        case finished = \"isFinished\"\n    }\n\n    func willChangeValue(forKey key: KeyPath) {\n        willChangeValue(forKey: key.rawValue)\n    }\n\n    func didChangeValue(forKey key: KeyPath) {\n        didChangeValue(forKey: key.rawValue)\n    }\n}\n\npublic extension Operation {\n\n    /**\n     Returns a non-optional `String` to use as the name\n     of an Operation. If the `name` property is not\n     set, this resorts to the class description.\n     */\n    var operationName: String {\n        return name ?? \"Unnamed Operation\"\n    }\n\n    /**\n     Returns a non-optional `String` to use as the name\n     of an Operation. If the `name` property is not\n     set, this resorts to the class description.\n     */\n    var procedureName: String {\n        return operationName\n    }\n\n    func addCompletionBlock(block: @escaping () -> Void) {\n        if let existing = completionBlock {\n            completionBlock = {\n                existing()\n                block()\n            }\n        }\n        else {\n            completionBlock = block\n        }\n    }\n\n    /**\n     Adds dependencies to the operation, using Swift 3 API style\n     - parameter dependencies: a sequencey of Operation instances\n     */\n    func addDependencies<Operations: Sequence>(_ dependencies: Operations) where Operations.Iterator.Element: Operation {\n        dependencies.forEach(addDependency)\n    }\n\n    /**\n     Adds dependencies to the operation, using Swift 3 API style\n     - parameter dependencies: a variable number of Operation instances\n     */\n    func addDependencies(_ dependencies: Operation...) {\n        addDependencies(dependencies)\n    }\n\n    /**\n     Removes dependencies to the operation, using Swift 3 API style\n     - parameter dependencies: a sequencey of Operation instances\n     */\n    func removeDependencies<Operations: Sequence>(_ dependencies: Operations) where Operations.Iterator.Element: Operation {\n        dependencies.forEach(removeDependency)\n    }\n\n    /// Removes all dependencies from the operation\n    func removeAllDependencies() {\n        addDependencies(dependencies)\n    }\n\n    /**\n     Add self as a dependency of a new operation and return both operations\n     - parameter operation: the Operation instance to add the receiver as a dependency\n     - returns: an array of both operations.\n    */\n    func then(do operation: Operation) -> [Operation] {\n        assert(!isFinished, \"Cannot add a finished operation as a dependency.\")\n        operation.addDependency(self)\n        return [self, operation]\n    }\n\n    /**\n     Add self as a dependency of a new operation via a throwing closure and return both operations\n     - parameter block: a throwing closure which returns an optional Operation\n     - returns: an array of both operations.\n     */\n    func then(do block: () throws -> Operation?) rethrows -> [Operation] {\n        guard let operation = try block() else { return [self] }\n        return then(do: operation)\n    }\n}\n\n\npublic extension Operation {\n\n    @available(*, deprecated, renamed: \"addDependencies(_:)\", message: \"This has been renamed to use Swift 3/4 naming conventions\")\n    func add<Operations: Sequence>(dependencies: Operations) where Operations.Iterator.Element: Operation {\n        addDependencies(dependencies)\n    }\n\n    @available(*, deprecated, renamed: \"addDependencies(_:)\", message: \"This has been renamed to use Swift 3/4 naming conventions\")\n    func add(dependencies: Operation...) {\n        addDependencies(dependencies)\n    }\n\n    @available(*, deprecated, renamed: \"addDependency(_:)\", message: \"This has been removed.\")\n    func add(dependency: Operation) {\n        addDependency(dependency)\n    }\n\n    @available(*, deprecated, renamed: \"addDependencies(_:)\", message: \"This has been renamed to use Swift 3/4 naming conventions\")\n    func remove<Operations: Sequence>(dependencies: Operations) where Operations.Iterator.Element: Operation {\n        removeDependencies(dependencies)\n    }\n\n    @available(*, deprecated, renamed: \"removeDependency(_:)\", message: \"This has been removed.\")\n    func remove(dependency: Operation) {\n        removeDependency(dependency)\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKit/PendingEvent.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport Foundation\nimport Dispatch\n\n/// `PendingEvent` encapsulates a reference to a future `Procedure` event, and can be used\n/// to ensure that asynchronous tasks are executed to completion *before* the future event.\n///\n/// While a reference to the `PendingEvent` exists, the event will not occur.\n///\n/// You cannot instantiate your own `PendingEvent` instances - only the framework\n/// itself creates and provides (in certain circumstances) PendingEvents.\n///\n/// A common use-case is when handling a WillExecute or WillFinish observer callback.\n/// ProcedureKit will provide your observer with a `PendingExecuteEvent` or a `PendingFinishEvent`.\n///\n/// If you must dispatch an asynchronous task from within your observer, but want to\n/// ensure that the observed `Procedure` does not execute / finish until your asynchronous task\n/// completes, you can use the Pending(Execute/Finish)Event like so:\n///\n/// ```swift\n/// procedure.addWillFinishObserver { procedure, errors, pendingFinish in\n///     DispatchQueue.global().async {\n///         pendingFinish.doBeforeEvent {\n///             // do something asynchronous\n///             // this block is guaranteed to complete before the procedure finishes\n///         }\n//      }\n/// }\n/// ```\n///\n/// Some of the built-in `Procedure` functions take an optional \"before:\" parameter,\n/// to which a `PendingEvent` can be directly passed. For example:\n///\n/// ```swift\n/// procedure.addWillFinishObserver { procedure, errors, pendingFinish in\n///     // produce a new operation before the procedure finishes\n///     procedure.produce(BlockOperation { /* do something */ }, before: pendingFinish)\n/// }\n/// ```\n///\nfinal public class PendingEvent: CustomStringConvertible {\n    public enum Kind: CustomStringConvertible {\n        case postDidAttach\n        case addOperation\n        case postDidAddOperation\n        case execute\n        case postDidExecute\n        case postDidCancel\n        case finish\n        case postDidFinish\n\n        public var description: String {\n            switch self {\n            case .postDidAttach: return \"PostDidAttach\"\n            case .addOperation: return \"AddOperation\"\n            case .postDidAddOperation: return \"PostAddOperation\"\n            case .execute: return \"Execute\"\n            case .postDidExecute: return \"PostExecute\"\n            case .postDidCancel: return \"PostDidCancel\"\n            case .finish: return \"Finish\"\n            case .postDidFinish: return \"PostFinish\"\n            }\n        }\n    }\n\n    internal let event: Kind\n    internal let group: DispatchGroup\n    fileprivate let procedure: ProcedureProtocol\n    private let isDerivedEvent: Bool\n    internal init(forProcedure procedure: ProcedureProtocol, withGroup group: DispatchGroup = DispatchGroup(), withEvent event: Kind) {\n        self.group = group\n        self.procedure = procedure\n        self.event = event\n        self.isDerivedEvent = false\n        group.enter()\n    }\n\n    // Ensures that a block is executed prior to the event described by the `PendingEvent`\n    public func doBeforeEvent(block: () -> Void) {\n        group.enter()\n        block()\n        group.leave()\n    }\n\n    // Ensures that the call to this function will occur prior to the event described by the `PendingEvent`\n    public func doThisBeforeEvent() {\n        group.enter()\n        group.leave()\n    }\n\n    deinit {\n        debugProceed()\n        group.leave()\n    }\n\n    private func debugProceed() {\n        (procedure as? Procedure)?.log.verbose.message(\"(\\(self)) is ready to proceed\")\n    }\n\n    public var description: String {\n        return \"Pending\\(event.description) for: \\(procedure.procedureName)\"\n    }\n}\n\ninternal extension PendingEvent {\n    static let postDidAttach: (Procedure) -> PendingEvent = { PendingEvent(forProcedure: $0, withEvent: .postDidAttach) }\n    static let addOperation: (Procedure) -> PendingEvent = { PendingEvent(forProcedure: $0, withEvent: .addOperation) }\n    static let postDidAdd: (Procedure) -> PendingEvent = { PendingEvent(forProcedure: $0, withEvent: .postDidAddOperation) }\n    static let execute: (Procedure) -> PendingEvent = { PendingEvent(forProcedure: $0, withEvent: .execute) }\n    static let postDidExecute: (Procedure) -> PendingEvent = { PendingEvent(forProcedure: $0, withEvent: .postDidExecute) }\n    static let postDidCancel: (Procedure) -> PendingEvent = { PendingEvent(forProcedure: $0, withEvent: .postDidCancel) }\n    static let finish: (Procedure) -> PendingEvent = { PendingEvent(forProcedure: $0, withEvent: .finish) }\n    static let postFinish: (Procedure) -> PendingEvent = { PendingEvent(forProcedure: $0, withEvent: .postDidFinish) }\n\n}\n\npublic typealias PendingExecuteEvent = PendingEvent\npublic typealias PendingFinishEvent = PendingEvent\npublic typealias PendingAddOperationEvent = PendingEvent\n"
  },
  {
    "path": "Sources/ProcedureKit/Procedure.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n// swiftlint:disable file_length\n// swiftlint:disable type_body_length\n\nimport Foundation\nimport os\n\ninternal struct ProcedureKit {\n\n    fileprivate enum FinishingFrom: CustomStringConvertible {\n        case main, finish\n        var description: String {\n            switch self {\n            case .main: return \"main()\"\n            case .finish: return \"finish()\"\n            }\n        }\n    }\n\n    fileprivate enum State: Int, Comparable {\n\n        static func < (lhs: State, rhs: State) -> Bool {\n            return lhs.rawValue < rhs.rawValue\n        }\n\n        case initialized\n        case willEnqueue\n        case pending\n        case started\n        case executing\n        case finishing\n        case finished\n\n        func canTransition(to other: State, whenCancelled isCancelled: Bool) -> Bool {\n            switch (self, other) {\n            case (.initialized, .willEnqueue),\n                 (.willEnqueue, .pending),\n                 (.pending, .started),\n                 (.started, .executing),\n                 (.executing, .finishing),\n                 (.finishing, .finished):\n                return true\n\n            case (.started, .finishing):\n                // Once a Procedure has started, it can go direct to finishing.\n                return true\n\n            default:\n                return false\n            }\n        }\n    }\n\n    @available(iOS 12.0, tvOS 12.0, watchOS 5.0, OSX 10.14, *)\n    internal struct Signposts {\n\n        internal static let procedure: OSLog = {\n            return OSLog(subsystem: \"run.kit.procedure\", category: \"ProcedureKit\")\n        }()\n    }\n\n    private init() { }\n}\n\npublic enum ProcedureStatus: String {\n    case pending, executing, cancelled, failed, finished\n}\n\n\n/**\n Type to express the intent of the user in regards to executing an Operation instance\n\n - see: https://developer.apple.com/library/ios/documentation/Performance/Conceptual/EnergyGuide-iOS/PrioritizeWorkWithQoS.html#//apple_ref/doc/uid/TP40015243-CH39\n */\n@available(*, deprecated, message: \"Use underlying quality of service APIs instead.\")\n@objc public enum UserIntent: Int {\n    case none = 0, sideEffect, initiated\n\n    internal var qualityOfService: QualityOfService {\n        switch self {\n        case .initiated, .sideEffect:\n            return .userInitiated\n        default:\n            return .default\n        }\n    }\n}\n\n\n/**\n Procedure is an Operation subclass. It is an abstract class which should be subclassed.\n\n ```swift\n import ProcedureKit\n\n class MyFirstProcedure: Procedure {\n     override func execute() {\n         guard !isCancelled else { return }\n         print(\"Hello World\")\n         finish()\n     }\n }\n\n let queue = ProcedureQueue()\n let myProcedure = MyFirstProcedure()\n queue.addOperation(myProcedure)\n ```\n\n The key points here are:\n\n 1. Subclass `Procedure`\n 2. Override `execute` but do not call `super.execute()`\n 3. Check the `isCancelled` property before starting any work.\n 4. If not cancelled, always call `finish()` after the work is done. This could be done asynchronously.\n 5. Add procedures to instances of `ProcedureQueue`.\n\n ### Built-in Procedures\n\n ProcedureKit includes a number of built-in Procedure subclasses, such as `GroupProcedure`,\n `RetryProcedure`, `RepeatProcedure`. Many of these built-in subclasses can be used as-is\n (without subclassing them). See their documentation for information on what they do and\n how to utilize them.\n\n ### Cancellation\n\n Once you add a Procedure to a ProcedureQueue, the queue takes over and handles the\n scheduling of the task at some point in the future (based on dependencies, and\n qualityOfService, etc).\n\n If you later decide that you do not want to execute the procedure after all, you can cancel\n the procedure to prevent it from running needlessly. You do this by calling the `cancel()`\n method on the Procedure instance itself.\n\n Cancelling a Procedure before it has been started by the queue will cause the queue to:\n    - Ignore any unfinished dependencies\n    - Automatically finish the Procedure (without calling your `execute()` override)\n\n This helps clear the cancelled Procedure from the queue as quickly as possible. Since it\n hasn't yet started to execute, the framework can help handle this case for you.\n\n However, cancelling a Procedure that has already been started by the queue will *not*\n automatically stop it from executing. It is the responsibility of your Procedure subclass,\n once it has started to execute, to check its cancelled state and respond to cancellation\n by finishing as quickly as possible.\n\n You can implement this via two different methods:\n    1. Checking `isCancelled` periodically (for example, in your `execute()` override)\n    2. Adding a DidCancel observer or overriding `produceDidCancel(withErrors:)`, which will be called after your Procedure is cancelled.\n\n Which method you should use is likely determined by how your Procedure performs the\n bulk of its task (synchronously - in its `execute()` override - or asynchronously, for\n which a DidCancel observer may be more useful).\n */\nopen class Procedure: Operation, ProcedureProtocol {\n\n    private var _isTransitioningToExecuting = false\n    private var _isHandlingCancel = false\n    private var _isCancelled = false  // should always be set by .cancel()\n    private var _isHandlingFinish: Bool = false\n\n    fileprivate let isAutomaticFinishingDisabled: Bool\n\n    // A strong reference to the ProcedureQueue onto which this Procedure was added\n    // This is cleared when the Procedure finishes\n    private var _queue: ProcedureQueue?\n\n    fileprivate var procedureQueue: ProcedureQueue? {\n        get { return stateLock.withCriticalScope { _queue } }\n    }\n\n    // Stored pending finish information\n    // (used if a Procedure is cancelled and finish() is called prior to the queue\n    // starting the Procedure - see `shouldFinish`)\n    fileprivate struct FinishingInfo {\n        var error: Error?\n        var source: ProcedureKit.FinishingFrom\n    }\n    private var _pendingFinish: FinishingInfo?\n\n    // only accessed from within the EventQueue\n    private var pendingAutomaticFinish: FinishingInfo?\n    private var finishedHandlingCancel: Bool = false\n\n    // The Procedure's EventQueue\n    // A serial FIFO queue onto which all Procedure Events that call user code are dispatched.\n    // (ex. `execute()` overrides, observer callbacks, etc.)\n    public let eventQueue = EventQueue(label: \"run.kit.procedure.ProcedureKit.Procedure.EventQueue\")\n\n    /**\n     Expresses the user intent in regards to the execution of this Procedure.\n\n     Setting this property will set the appropriate quality of service parameter\n     on the parent Operation.\n\n     - requires: self must not have started yet. i.e. either hasn't been added\n     to a queue, or is waiting on dependencies.\n     */\n    @available(*, deprecated, message: \"Use underlying quality of service APIs instead.\")\n    public var userIntent: UserIntent = .none\n\n    @available(OSX 10.10, iOS 8.0, tvOS 8.0, watchOS 2.0, *)\n    open override var qualityOfService: QualityOfService {\n        get { return super.qualityOfService }\n        set {\n            super.qualityOfService = newValue\n            eventQueue.qualityOfService = newValue.qos\n        }\n    }\n\n    open override var name: String? {\n        didSet {\n            synchronise {\n                let formatter = Log.Formatters.makeProcedureLogFormatter(operationName: operationName)\n                protectedProperties.log.formatter = formatter\n                protectedProperties.log.formatter = formatter\n            }\n        }\n    }\n\n    internal let uuid = UUID()\n\n    internal var typeDescription: String {\n        return String(describing: type(of: self))\n    }\n\n    internal class ProcedureQueueContext { }\n    internal let queueAddContext = ProcedureQueueContext()\n\n    deinit {\n        // ensure that any EvaluateConditions operation is cancelled\n        evaluateConditionsProcedure?.cancel()\n\n        // ensure that the Protected Properies are deinitialized within the lock\n        stateLock.withCriticalScope {\n            self.protectedProperties = nil\n            _evaluateConditionsProcedure = nil\n        }\n    }\n\n    // MARK: - State\n\n    fileprivate let stateLock = PThreadMutex()\n\n    @discardableResult\n    fileprivate func synchronise<T>(block: () -> T) -> T {\n        return stateLock.withCriticalScope(block: block)\n    }\n\n    // the state variable to be used *within* the stateLock\n    fileprivate var _state = ProcedureKit.State.initialized { // swiftlint:disable:this variable_name\n        willSet(newState) {\n            assert(_state.canTransition(to: newState, whenCancelled: _isCancelled), \"Attempting to perform illegal cyclic state transition, \\(_state) -> \\(newState) for operation: \\(identity). Ensure that Procedure instances are added to a ProcedureQueue not an OperationQueue.\")\n        }\n    }\n\n    // the state variable to be used *outside* the stateLock\n    fileprivate private(set) var state: ProcedureKit.State {\n        get {\n            return synchronise { _state }\n        }\n        set(newState) {\n            synchronise { _state = newState }\n        }\n    }\n\n    /// Boolean indicator for whether the Procedure has been enqueued\n    final public var isEnqueued: Bool {\n        return synchronise { _isEnqueued }\n    }\n\n    /// Boolean indicator for whether the Procedure is pending\n    final public var isPending: Bool {\n        return synchronise { _isPending }\n    }\n\n    /// Boolean indicator for whether the Procedure is currently executing or not\n    final public override var isExecuting: Bool {\n        return synchronise { _isExecuting }\n    }\n\n    /// Boolean indicator for whether the Procedure has finished or not\n    final public override var isFinished: Bool {\n        return synchronise { _isFinished }\n    }\n\n    public var status: ProcedureStatus {\n        return synchronise {\n            switch (_isPending, _isExecuting, _isFinished, _isCancelled, (_error != nil)) {\n            case (true, _, _, _, _):\n                return .pending\n            case (_, true, _, _, _):\n                return .executing\n            case (_, _, true, _, _):\n                return .finished\n            case (_, _, _, true, _):\n                return .cancelled\n            case (_, _, _, _, true):\n                return .failed\n            default:\n                return .finished\n            }\n        }\n    }\n\n    private var _mutuallyExclusiveCategories: Set<String>?\n    private var mutuallyExclusiveCategories: Set<String>? {\n        get { return synchronise { _mutuallyExclusiveCategories } }\n        set { synchronise { _mutuallyExclusiveCategories = newValue } }\n    }\n    private var _mutualExclusivityTicket: ProcedureQueue.ExclusivityLockTicket?\n    private var mutualExclusivityTicket: ProcedureQueue.ExclusivityLockTicket? {\n        get { return synchronise { _mutualExclusivityTicket } }\n        set { synchronise { _mutualExclusivityTicket = newValue } }\n    }\n\n    // Only called by the ConditionEvaluator\n    fileprivate func request(mutuallyExclusiveCategories: Set<String>, completion: @escaping (Bool) -> Void) {\n        // On the internal EventQueue\n        dispatchEvent {\n            guard self.state < .started else {\n                // If the Procedure has already started or finished, it's too late to acquire mutual\n                // exclusivity locks. This can occur, normally, if a Procedure is cancelled (and then\n                // finished) at just the right time.\n                guard self.isCancelled else {\n                    fatalError(\"Procedure started prior to acquiring mutual exclusivity locks, but is not cancelled.\")\n                }\n\n                // Immediately call the completion block, with false\n                completion(false)\n                return\n            }\n            guard let procedureQueue = self.procedureQueue else {\n                fatalError(\"procedureQueue is nil\")\n            }\n\n            // Store the mutually-exclusive categories for later release (when the Procedure is finished).\n            assert(self.mutuallyExclusiveCategories == nil, \"Mutually exclusive locks were requested more than once.\")\n            self.mutuallyExclusiveCategories = mutuallyExclusiveCategories\n\n            // Request a lock via the ProcedureQueue\n            procedureQueue.requestLock(for: mutuallyExclusiveCategories) { lockTicket in\n                // Once a lock ticket is acquired, store the lockTicket\n                // (which must be claimed once the Procedure starts)\n\n                self.mutualExclusivityTicket = lockTicket\n\n                // and call the completion block\n                completion(true)\n            }\n        }\n    }\n\n    /// Boolean indicator for whether the Procedure is cancelled or not\n    ///\n    /// Canceling a Procedure does not actively stop the Procedure's code from executing.\n    ///\n    /// An executing Procedure is responsible for checking its own cancellation status,\n    /// and stopping and moving to the finished state as quickly as possible.\n    ///\n    /// Built-in Procedure subclasses in ProcedureKit (like GroupProcedure and CloudKitProcedure)\n    /// handle responding to cancellation as appropriate.\n    ///\n    final public override var isCancelled: Bool {\n        return synchronise { _isCancelled }\n    }\n\n    /// The Boolean indicators to be used *within* the stateLock\n    private var _isEnqueued: Bool {\n        return _state >= .pending\n    }\n    private var _isPending: Bool {\n        return _state == .pending\n    }\n    private var _isExecuting: Bool {\n        return _state == .executing\n    }\n    private var _isFinished: Bool {\n        return _state == .finished\n    }\n\n    // MARK: - Protected Internal Properties\n\n    fileprivate var _evaluateConditionsProcedure: EvaluateConditions? // swiftlint:disable:this variable_name\n\n    // Grouped in a class to allow for easily deinitializing in `deinit`.\n    fileprivate class ProtectedProperties {\n        var log: ProcedureLog = Log.Channels<Log>()\n        var error: Error? = nil\n        var observers = [AnyObserver<Procedure>]()\n        var directDependencies = Set<Operation>()\n        var conditions = Set<Condition>()\n    }\n\n    fileprivate var protectedProperties: ProtectedProperties! = ProtectedProperties() // see deinit\n\n    // the errors variable to be used *within* the stateLock\n    private var _error: Error? {\n        return protectedProperties.error\n    }\n\n    // MARK: - Errors\n\n    final public var error: Error? {\n        get { return synchronise { _error } }\n        set {\n            synchronise {\n                guard _state <= .executing else {\n                    assertionFailure(\"Cannot append errors to Procedure that is finishing or finished.\")\n                    return\n                }\n                protectedProperties.error = newValue\n            }\n        }\n    }\n\n    // MARK: - Log\n\n    /**\n     Access the logger for this Operation\n\n     The `log` property can be used as the interface to access the logger.\n     e.g. to output a message with `LogSeverity.Info` from inside\n     the `Procedure`, do this:\n\n     ```swift\n     log.info(\"This is my message\")\n     ```\n\n     To adjust the instance severity of the LoggerType for the\n     `Procedure`, access it via this property too:\n\n     ```swift\n     log.severity = .Verbose\n     ```\n\n     The logger is a very simple type, and all it does beyond\n     manage the enabled status and severity is send the String to\n     a block on a dedicated serial queue. Therefore to provide custom\n     logging, set the `logger` property:\n\n     ```swift\n     log.logger = { message in sendMessageToAnalytics(message) }\n     ```\n\n     By default, the Logger's logger block is the same as the global\n     LogManager. Therefore to use a custom logger for all Operations:\n\n     ```swift\n     LogManager.logger = { message in sendMessageToAnalytics(message) }\n     ```\n\n     */\n    final public var log: ProcedureLog {\n        get { return synchronise { protectedProperties.log } }\n        set { synchronise { protectedProperties.log = newValue } }\n    }\n\n    // MARK: - Observers\n\n    final internal var observers: [AnyObserver<Procedure>] {\n        get { return synchronise { protectedProperties.observers } }\n    }\n\n    // MARK: - Dependencies & Conditions\n\n    internal var directDependencies: Set<Operation> {\n        get { return synchronise { protectedProperties.directDependencies } }\n    }\n\n    /// - returns conditions: the Set of Condition instances attached to the operation\n    public var conditions: Set<Condition> {\n        get { return synchronise { protectedProperties.conditions } }\n    }\n\n    /// Internal for testing.\n    internal var evaluateConditionsProcedure: EvaluateConditions? {\n        return synchronise { _evaluateConditionsProcedure }\n    }\n\n    // MARK: - Initialization\n\n    public override init() {\n        isAutomaticFinishingDisabled = false\n        super.init()\n        name = String(describing: type(of: self))\n\n        // Add a signpost observer to every procedure        \n        if #available(iOS 12.0, tvOS 12.0, watchOS 5.0, OSX 10.14, *) {\n            addObserver(SignpostObserver())\n        }\n    }\n\n    // MARK: - Disable Automatic Finishing\n\n    /**\n     Ability to override Procedure's built-in finishing behavior, if a\n     subclass requires full control over when `finish()` is called.\n\n     Used for GroupProcedure to implement proper .Finished state-handling\n     (only finishing after all child operations have finished).\n\n     The default behavior of Procedure is to automatically call `finish()`\n     when:\n     (a) the Procedure is cancelled prior to it starting\n         (in which case, the Procedure will skip calling `execute()`)\n     (b) when willExecuteObservers log errors\n\n     To ensure that a Procedure subclass does not finish until the\n     subclass calls `finish()`:\n     call `super.init(disableAutomaticFinishing: true)` in the init.\n\n     - Important: If `disableAutomaticFinishing == TRUE`, the subclass is\n     responsible for calling `finish()` in **ALL** cases, including when the\n     Procedure is cancelled.\n\n     You can react to cancellation using a `DidCancelObserver` and/or\n     checking periodically during `execute()` with something like:\n\n     ```swift\n     guard !cancelled else {\n        // do any necessary clean-up\n        finish()    // always call finish if automatic finishing is disabled\n        return\n     }\n     ```\n\n     */\n    public init(disableAutomaticFinishing: Bool) {\n        isAutomaticFinishingDisabled = disableAutomaticFinishing\n        super.init()\n        name = String(describing: type(of: self))\n        if #available(iOS 12.0, tvOS 12.0, watchOS 5.0, OSX 10.14, *) {\n            addObserver(SignpostObserver())\n        }\n    }\n\n    // MARK: - Execution\n\n    /// Called by the framework before a Procedure is added to a ProcedureQueue.\n    ///\n    /// - warning: Do *NOT* call this function directly.\n    ///\n    /// - Parameter queue: the ProcedureQueue onto which the Procedure will be added\n    public final func willEnqueue(on queue: ProcedureQueue) {\n        synchronise {\n            _state = .willEnqueue\n            _queue = queue\n        }\n    }\n\n    /// Called by the framework before a Procedure is added to a ProcedureQueue, but *after*\n    /// the ProcedureQueue delegate's `procedureQueue(_:willAddProcedure:context:)` is called.\n    ///\n    /// - warning: Do *NOT* call this function directly.\n    public final func pendingQueueStart() {\n        let optionalConditionEvaluator: EvaluateConditions? = synchronise {\n            _state = .pending\n\n            // After the state has been set to `.willEnqueue` (via an earlier call\n            // to `willEnqueue(on:)`), Procedure conditions cannot be modified.\n            //\n            // `pendingQueueStart()` is called *after* the ProcedureQueue\n            // delegate's `procedureQueue(_:willAddProcedure:context:)` is called,\n            // but *before* the Procedure is actually added to the queue. Thus:\n            //  - the delegate's willAdd method has had a chance to add any dependencies to\n            //    the Procedure (which _must_ be picked up and added as dependencies to the\n            //    EvaluateConditions operation)\n            //  - the Procedure will not be executed by the queue until this method returns\n            //\n            // Thus, construct the EvaluateConditions procedure now (if needed).\n            guard !protectedProperties.conditions.isEmpty else { return nil }\n\n            // If the Procedure is cancelled, there is no point to evaluating Conditions\n            guard !_isCancelled else { return nil }\n\n            // Create the EvaluateConditions operation\n            let evaluator = EvaluateConditions(procedure: self)\n            evaluator.name = \"\\(operationName) Evaluate Conditions\"\n\n            // Add the direct dependencies of the procedure as direct dependencies of the evaluator\n            // (to ensure that conditions are evaluated after all of the Procedure's dependencies)\n            let directDependencies = protectedProperties.directDependencies\n            evaluator.addDependencies(directDependencies)\n\n            // Store the evaluator in the Procedure\n            // (the Procedure maintains a strong reference to the EvaluateConditions operation)\n            assert(_evaluateConditionsProcedure == nil)\n            _evaluateConditionsProcedure = evaluator\n\n            return evaluator\n        }\n\n        guard let evaluator = optionalConditionEvaluator else { return }\n\n        // The Procedure must be dependent on its condition evaluator.\n        // Call super.addDependency so the evaluator isn't added to the visible\n        // `directDependencies`, but *is* treated as a dependency by the underlying\n        // Operation.\n        super.addDependency(evaluator)\n    }\n\n    /// Called by the framework after a Procedure is added to a ProcedureQueue.\n    /// The Procedure may have already been scheduled for / started executing.\n    /// This is only used to manage when it's safe to begin evaluating conditions.\n    internal final func postQueueAdd() {\n        guard let evaluateConditionsProcedure = evaluateConditionsProcedure else { return }\n\n        // If this Procedure has a condition evaluator, the condition evaluator must not\n        // finish prior to the return of the internal OperationQueue.addOperation() call\n        // in ProcedureQueue that adds this Procedure to the ProcedureQueue's underlying\n        // OperationQueue.\n        //\n        // (If the EvaluateConditions operation finishes while the underlying OperationQueue\n        // implementation is in the process of adding the operation, a rare race condition may\n        // be triggered with NSOperationQueue's handling of the Operation isReady state for\n        // the Procedure. This can result in a situation in which a Procedure with, for\n        // example, failing conditions ends up cancelled + ready but never finishes.)\n        //\n        // To accomplish this, signal to the EvaluateConditions operation that it is now safe \n        // (post-add) to begin evaluating conditions (assuming it is otherwise ready).\n\n        evaluateConditionsProcedure.parentProcedureHasBeenAddedToQueue()\n    }\n\n    /// Starts the Procedure, correctly managing the cancelled state. Cannot be over-ridden\n    ///\n    /// - warning: Do not call `start()` directly on a Procedure. Add the Procedure to a `ProcedureQueue`.\n    public final override func start() {\n        // Don't call super.start\n\n        assert(state >= .pending, \"Calling start() manually on a Procedure is unsupported. Instead, add the Procedure to a ProcedureQueue.\") // Do not check for < .started here; _start() does that.\n        assert(procedureQueue != nil, \"The Procedure's associated procedureQueue is nil. If you are adding the Procedure to a ProcedureQueue, this should never happen.\")\n\n        // Dispatch the innards of start() on the EventQueue,\n        // inheriting the current QoS level (i.e. the Qos that\n        // the ProcedureQueue decided to use to call start()).\n\n        let currentQoS = DispatchQoS(qosClass: DispatchQueue.currentQoSClass, relativePriority: 0)\n\n        eventQueue.dispatchEventBlockInternal(minimumQoS: currentQoS) {\n            self._start()\n        }\n    }\n\n    private final func _start() {\n\n        debugAssertIsOnEventQueue() // should only be executed on the EventQueue\n\n        // NOTE: The EventQueue handles ensuring proper autoreleasepool behavior,\n        // so there is no need for an explicit autoreleasepool here.\n\n        assert(state < .started, \"A Procedure cannot be started more than once.\")\n\n        let hasPendingFinish = synchronise { () -> FinishingInfo? in\n            _state = .started\n            return _pendingFinish\n        }\n\n        if let pendingFinish = hasPendingFinish {\n            assert(isCancelled)\n            // A call to finish occurred prior to the Procedure starting (but after it was cancelled)\n            // Handle this pending finish now, and skip processing execute\n            _finish(withInfo: pendingFinish)\n            return\n        }\n\n        guard !isCancelled || isAutomaticFinishingDisabled else {\n            queueAutomaticFinish(from: .main)\n            return\n        }\n\n        _main()\n    }\n\n    /// - warning: Do not call `main()` directly on a Procedure. Add the Procedure to a `ProcedureQueue`.\n    public final override func main() {\n        assertionFailure(\"Do not call main() directly on a Procedure. Add the Procedure to a ProcedureQueue.\")\n    }\n\n    /// Triggers execution of the operation's task, correctly managing errors and the cancelled state. Cannot be over-ridden\n    private final func _main() {\n\n        debugAssertIsOnEventQueue()\n\n        assert(state >= .started, \"Procedure.main() is being called when Procedure.start() has not been called. Do not call main() directly. Add the Procedure to a ProcedureQueue.\")\n\n        if let mutualExclusivityTicket = mutualExclusivityTicket {\n            // Mutual Exclusivity has been requested for this Procedure\n            // Proceed only once the ticket has been claimed via the ProcedureQueue\n\n            guard let procedureQueue = procedureQueue else {\n                fatalError(\"Procedure has a nil procedureQueue\") // ProcedureKit internal programmer error\n            }\n\n            // Store the current QoS level\n            let originalQoS = DispatchQoS(qosClass: DispatchQueue.currentQoSClass, relativePriority: 0)\n\n            // Now that the Procedure has started, claim the mutual exclusivity lock\n            procedureQueue.procedureClaimLock(withTicket: mutualExclusivityTicket) {\n                // Mutual Exclusivity lock has been claimed - can now proceed with executing\n\n                // Dispatch the innards of main() on the EventQueue,\n                // inheriting the original QoS level (i.e. the Qos that\n                // the ProcedureQueue decided to use to call start()).\n\n                self.eventQueue.dispatchEventBlockInternal(minimumQoS: originalQoS) {\n                    self._main_step1()\n                }\n            }\n        }\n        else {\n            // No Mutual Exclusivity required - proceed immediately with the next steps of executing\n            _main_step1()\n        }\n    }\n\n    private final func _main_step1() {\n\n        debugAssertIsOnEventQueue()\n\n        log.verbose.trace()\n        log.verbose.message(\"[observers]: WillExecute\")\n\n        // Call the WillExecute observers\n        let willExecuteObserversGroup = dispatchObservers(pendingEvent: PendingEvent.execute) { observer, pendingEvent in\n            observer.will(execute: self, pendingExecute: pendingEvent)\n        }\n\n        // After the WillExecute observers have all completed, proceed to Step 2 of main()\n        // Inherit the current QoS level to ensure that the QoS level of start() persists through to execute()\n        optimizedDispatchEventNotify(group: willExecuteObserversGroup, inheritQoS: true) {\n            self._main_step2()\n        }\n    }\n\n    private final func _main_step2() { // swiftlint:disable:this function_body_length\n\n        debugAssertIsOnEventQueue()\n\n        // Prevent concurrent execution\n        func getNextState() -> ProcedureKit.State? {\n            return synchronise {\n\n                // Check to see if the procedure is already attempting to execute\n                assert(!_isExecuting, \"Procedure is attempting to execute, but is already executing.\")\n                guard !_isTransitioningToExecuting else {\n                    assertionFailure(\"Procedure is attempting to execute twice, concurrently.\")\n                    return nil\n                }\n\n                // Check to see if the procedure has now been finished\n                // by an observer (or anything else)\n                guard _state <= .started else { return nil }\n                guard !_isHandlingFinish else {\n                    // a finish is pending, simply exit from processing execute\n                    return nil\n                }\n\n                // Check to see if the procedure has now been cancelled\n                // by an observer\n                guard ((_error == nil) && !_isCancelled) || isAutomaticFinishingDisabled else {\n                    return .finishing\n                }\n\n                // Transition to the .isExecuting state, and explicitly send the required KVO change notifications\n                _isTransitioningToExecuting = true\n                return .executing\n            }\n        }\n\n        // Check the state again, as it could have changed in another queue via finish\n        func getNextStateAgain() -> (ProcedureKit.State?, ProcedureQueue?) {\n            return synchronise {\n                guard _state <= .started else { return (nil, nil) }\n\n                guard !_isHandlingFinish else {\n                    // a finish is pending, simply exit from processing execute\n                    return (nil, nil)\n                }\n\n                if _isCancelled && !isAutomaticFinishingDisabled && !_isHandlingFinish {\n                    // Procedure was cancelled, and automatic finishing is enabled.\n                    // Because execute() has not yet been called, handle finish here.\n                    return (.finishing, nil)\n                }\n\n                _state = .executing\n                _isTransitioningToExecuting = false\n\n                return (.executing, _queue)\n            }\n        }\n\n        log.verbose.trace()\n        log.verbose.message(\"[event]: Continue Pending Execute\")\n\n        // Determine the next Procedure state (prepare to set to executing, if possible)\n        let nextState = getNextState()\n\n        guard nextState != .finishing else {\n            // The Procedure should transition to finishing\n            // (for example, if cancelled prior to execute())\n            queueAutomaticFinish(from: .main)\n            return\n        }\n\n        guard nextState == .executing else { return }\n\n        willChangeValue(forKey: .executing)\n\n        // Set the state to executing (unless something, like cancellation, has happened concurrently)\n        let (nextState2, queue) = getNextStateAgain()\n\n        didChangeValue(forKey: .executing)\n\n        guard nextState2 != .finishing else {\n            // The Procedure should transition to finishing\n            // (for example, if cancelled prior to execute())\n            queueAutomaticFinish(from: .main)\n            return\n        }\n\n        guard nextState2 == .executing else { return }\n\n        log.verbose.message(\"Will Execute\")\n\n        // Call the execute() function (which should be overriden in Procedure subclasses)\n        if let underlyingQueue = queue?.underlyingQueue {\n            // The Procedure was enqueued on a ProcedureQueue that specifies an `underlyingQueue`.\n            //\n            // Explicitly call the `execute()` function on the underlyingQueue, while also\n            // pausing dispatch of any new blocks on the Procedure's EventQueue until the call\n            // to `execute()` returns, to ensure that `execute()` occurs on the underlyingQueue\n            // *and* non-concurrently with this Procedure's EventQueue.\n\n            eventQueue.dispatchSynchronizedBlock(onOtherQueue: underlyingQueue) {\n                // This block is now synchronized with *both* queues:\n                //  - the Procedure's EventQueue\n                //  - the underlyingQueue of the ProcedureQueue on which the Procedure is scheduled to execute\n                // and is *on* the underlyingQueue of said ProcedureQueue.\n\n                // Call the `execute()` function on the underlyingQueue\n                self.execute()\n\n                // Dispatch async back to the Procedure's EventQueue to\n                // process DidExecute observers.\n                self.dispatchEvent {\n                    self._handleDidExecute()\n                }\n            }\n            return\n        }\n\n        execute()\n        _handleDidExecute()\n    }\n\n    private func _handleDidExecute() {\n\n        debugAssertIsOnEventQueue()\n\n        // Dispatch DidExecute observers\n        log.verbose.trace()\n        log.verbose.message(\"[observers]: DidExecute\")\n        _ = dispatchObservers(pendingEvent: PendingEvent.postDidExecute) { observer, _ in\n            observer.did(execute: self)\n        }\n\n        // Log that execute() has returned\n        log.info.message(\"Did Execute\")\n    }\n\n    /// Procedure subclasses must override `execute()`.\n    /// - important: Do not call `super.execute()` when subclassing `Procedure` directly.\n    open func execute() {\n        log.warning.message(\"\\(self) must override `execute()`.\")\n        finish()\n    }\n\n    /// Adds an operation to the same queue as target.\n    ///\n    /// - Precondition: Target must already be added to a queue / `GroupProcedure`.\n    /// - Parameters:\n    ///   - operation: The operation to add to the same queue as target.\n    ///   - pendingEvent: (optional) A PendingEvent. The operation will be added prior to the PendingEvent.\n    /// - Returns: A `ProcedureFuture` that is completed once the operation has been added to the queue.\n    /// - Throws: `ProcedureKitError.noQueue` if the target has not yet been added to a queue / `GroupProcedure`.\n    @discardableResult public final func produce(operation: Operation, before pendingEvent: PendingEvent? = nil) throws -> ProcedureFuture {\n        precondition(state > .initialized, \"Cannot add operation which is not being scheduled on a queue\")\n        guard let queue = synchronise(block: { return _queue }) else {\n            throw ProcedureKitError.noQueue()\n        }\n\n        let promise = ProcedurePromise()\n\n        log.verbose.trace()\n        log.verbose.message(\".produce() | Will add \\(operation.operationName)\")\n\n        // Dispatch the innards of produce() onto the EventQueue\n        dispatchEvent {\n            self._produce(operation: operation, onQueue: queue, before: pendingEvent, promise: promise)\n        }\n\n        return promise.future\n    }\n\n    private func _produce(operation: Operation, onQueue queue: ProcedureQueue, before pendingEvent: PendingEvent? = nil, promise: ProcedurePromise) {\n        debugAssertIsOnEventQueue()\n\n        log.verbose.trace()\n        log.verbose.message(\".produce() | [observers]: WillAddOperation(\\(operation.operationName))\")\n\n        // Dispatch WillAddOperation observers\n        let willAddObserversGroup = dispatchObservers(pendingEvent: PendingEvent.addOperation) { observer, _ in\n            observer.procedure(self, willAdd: operation)\n        }\n\n        // After the WillAddOperation observers have all completed\n        optimizedDispatchEventNotify(group: willAddObserversGroup) {\n            // Proceed to step 2 of handling produce()\n            self._produce_step2(operation: operation, onQueue: queue, before: pendingEvent, promise: promise)\n        }\n    }\n\n    private func _produce_step2(operation: Operation, onQueue queue: ProcedureQueue, before pendingEvent: PendingEvent? = nil, promise: ProcedurePromise) {\n        debugAssertIsOnEventQueue()\n\n        log.verbose.trace()\n        log.verbose.message(\".produce() | [event]: AddOperation(\\(operation.operationName)) to queue.\")\n\n        // Add the new produced operation to the ProcedureQueue on which this Procedure was added\n        queue.addOperation(operation, withContext: queueAddContext).then(on: self) {\n\n            // After adding to the queue completes, proceed to step 3 of handling produce()\n            self._produce_step3(operation: operation, onQueue: queue, before: pendingEvent, promise: promise)\n        }\n    }\n\n    private func _produce_step3(operation: Operation, onQueue queue: ProcedureQueue, before pendingEvent: PendingEvent? = nil, promise: ProcedurePromise) {\n\n        log.verbose.trace()\n\n        if let pendingEvent = pendingEvent {\n            // Ensure that the PendingEvent occurs sometime after this point\n            pendingEvent.doBeforeEvent {\n                log.verbose.message(\"ProcedureQueue.add(\\(operation.operationName)) called prior to (\\(pendingEvent)).\")\n            }\n        }\n\n        log.info.message(\".produce() | Did add \\(operation.operationName)\")\n\n        log.verbose.message(\".produce() | [observers]: DidAddOperation(\\(operation.operationName))\")\n\n        // Complete the promise, since the produced operation has been added to the queue\n        promise.complete()\n\n        // Dispatch DidAddOperation observers\n        _ = self.dispatchObservers(pendingEvent: PendingEvent.postDidAdd) { observer, _ in\n            observer.procedure(self, didAdd: operation)\n        }\n        // no follow-up events to wait on the didAdd observers\n    }\n\n    // MARK: - Cancellation\n\n    /**\n     By default, cancelling a Procedure simply sets the `isCancelled` flag to true.\n\n     It is the responsibility of the Procedure subclass to handle cancellation,\n     as appropriate.\n\n     For example, GroupProcedure handles cancellation by cancelling all of its\n     children.\n\n     You can react to cancellation using a DidCancelObserver\n     and/or checking periodically during execute with something like:\n\n     ```swift\n     guard !isCancelled else {\n        // do any necessary clean-up\n        finish()    // always call finish when your Procedure is done\n        return\n     }\n     ```\n\n     */\n\n    open func procedureDidCancel(with error: Error?) {\n        // no-op\n    }\n\n    public final override func cancel() {\n        _cancel(with: nil)\n    }\n\n    public final func cancel(with error: Error?) {\n        _cancel(with: error)\n    }\n\n    // Micro-optimaization used by GroupProcedure to bypass dispatching to the event queue for its cancellation handling\n    internal func _procedureDidCancel(with error: Error?) {\n        // no-op\n    }\n\n    private enum ShouldCancelResult {\n        case shouldCancel\n        case alreadyFinishingOrFinished\n        case alreadyCancelling\n        case alreadyCancelled\n    }\n\n    private var shouldCancel: ShouldCancelResult {\n        return synchronise {\n            // Do not cancel if already finished or finishing, or if finish has already been called\n            guard _state <= .executing && !_isHandlingFinish else { return .alreadyFinishingOrFinished }\n            // Do not cancel if already cancelled\n            guard !_isCancelled else { return .alreadyCancelled }\n            // Only a single call to cancel should continue\n            guard !_isHandlingCancel else { return .alreadyCancelling }\n            _isHandlingCancel = true\n            return .shouldCancel\n        }\n    }\n\n    private final func _cancel(with error: Error?, promise: ProcedurePromise? = nil) {\n\n        log.verbose.trace()\n\n        let shouldCancel = self.shouldCancel\n\n        guard shouldCancel == .shouldCancel else {\n            promise?.complete()//(withFailure: shouldCancel.error ?? ProcedureKitError.unknown)\n            return\n        }\n\n        // Immediately (and possibly concurrently with the EventQueue) set the `isCancelled`\n        // state of the Procedure to true, sending appropriate KVO.\n\n        willChangeValue(forKey: .cancelled)\n\n        let resultingError = synchronise { () -> Error? in\n            protectedProperties.error = error ?? protectedProperties.error\n            _isCancelled = true\n            return protectedProperties.error\n        }\n\n        if let error = resultingError {\n            log.verbose.message(\"Will cancel with error: \\(error).\")\n        }\n        else {\n            log.verbose.message(\"Will cancel without error.\")\n        }\n\n        didChangeValue(forKey: .cancelled)\n\n        // Call super to trigger .isReady state change on cancel as well as isReady KVO notification\n        super.cancel()\n\n        // Micro-optimization for built-in Procedures that can safely handle cancellation off the EventQueue\n        _procedureDidCancel(with: error)\n\n        // Cancel the EvaluateConditions operation (in case the Procedure is cancelled\n        // before its dependencies have finished, and the EvaluateConditions operation\n        // is still waiting on those dependencies).\n        //\n        // If the Procedure is cancelled before it is added to a queue, the\n        // EvaluateConditions operation will not yet exist, and so must be handled\n        // later.\n        evaluateConditionsProcedure?.cancel()\n\n        // Trigger DidCancel function & observers on the event queue\n        dispatchEvent {\n\n            // procedureDidCancel(withErrors:) override\n            self.procedureDidCancel(with: resultingError)\n\n            // DidCancel observers\n            self.log.verbose.message(\"[observers]: DidCancel\")\n            let didCancelObserversGroup = self.dispatchObservers(pendingEvent: PendingEvent.postDidCancel) { observer, _ in\n                observer.did(cancel: self, with: resultingError)\n            }\n\n            // After the DidCancel observers have all completed\n            self.optimizedDispatchEventNotify(group: didCancelObserversGroup) {\n                // Process the pending automatic finish (from main) if present\n\n                self.finishedHandlingCancel = true\n\n                if let pendingAutomaticFinish = self.pendingAutomaticFinish {\n                    // Pass the pending automatic finish to finish()\n                    // finish() will handle ensuring that only the first call to finish succeeds\n                    // (i.e. if a DidCancel observer has already called finish, that call is the one\n                    // that succeeds)\n                    self.finish(with: pendingAutomaticFinish.error, from: pendingAutomaticFinish.source)\n\n                    // Ensure that the EvaluateConditions operation is cancelled\n                    self.evaluateConditionsProcedure?.cancel()\n                }\n            }\n\n            promise?.complete()\n        }\n    }\n\n    // MARK: - Finishing\n\n    open func procedureWillFinish(with error: Error?) { }\n\n    open func procedureDidFinish(with error: Error?) { }\n\n    /**\n     Finish method which must be called eventually after an operation has\n     begun executing (even if cancelled).\n\n     This method may not be overridden. To handle finishing, override\n     `procedureWillFinish(withErrors:)` or `procedureDidFinish(withErrors:)`\n     or use a WillFinish / DidFinish observer.\n\n     - parameter errors: an array of `Error`, which defaults to empty.\n     */\n    public func finish(with error: Error? = nil) {\n        finish(with: error, from: .finish)\n    }\n\n    // Used to queue an automatic finish from Procedure.start()/main()\n    // (i.e. if a Procedure should automatically finish prior to executing if, for example,\n    // it is cancelled prior to executing)\n    private func queueAutomaticFinish(from source: ProcedureKit.FinishingFrom) {\n\n        debugAssertIsOnEventQueue() // only ever called from a block on the EventQueue\n        assert(pendingAutomaticFinish == nil)\n        assert(state < .executing)\n\n        if finishedHandlingCancel {\n            // DidCancel observers have already been run, and given a chance to call finish() themselves.\n            // Thus, it is safe to call finish() directly here (which will queue a finish attempt at the\n            // end of the EventQueue):\n            finish(with: nil, from: source)\n        }\n        else {\n            // DidCancel observers have not yet been run.\n            // They may or may not be queued on the event queue yet (queuing may happen concurrently).\n            // The only guarantee is that they will be queued and run at some point after this\n            // current event.\n            //\n            // Thus, it is *not* safe to simply queue (async) a finishing block to execute on the\n            // EventQueue - we cannot guarantee it will be queued prior to the DidCancel event block.\n            //\n            // Instead, store the pendingAutomaticFinish for processing in the DidCancel observer block\n            // (whenever it is executed):\n            pendingAutomaticFinish = FinishingInfo(error: nil, source: source)\n        }\n    }\n\n    private final func shouldFinish(with receivedError: Error?, from source: ProcedureKit.FinishingFrom) -> FinishingInfo? {\n        return synchronise {\n            // Do not finish is already finishing or finished\n            guard _state <= .finishing else { return nil }\n            // Do not finish if not yet started - unless cancelled\n            var queueFinishForStart = false\n            if _state < .started {\n                guard _isCancelled else {\n                    assertionFailure(\"Cannot finish Procedure prior to it being started (unless cancelled).\")\n                    return nil\n                }\n                // if the Procedure is cancelled, we can queue the finish for after\n                // start() is called\n                queueFinishForStart = true\n            }\n            // Only a single call to _finish should continue\n            guard !_isHandlingFinish else { return nil }\n            _isHandlingFinish = true\n\n            guard !queueFinishForStart else {\n                // Calls to finish() prior to the Procedure starting are\n                // queued to be executed once the queue has started the Procedure.\n                // (As long as the Procedure is cancelled first.)\n                //\n                // (It's an error for an Operation added to an OperationQueue to\n                // set isFinished to true prior to the queue starting the Operation.)\n                _pendingFinish = FinishingInfo(error: receivedError, source: source)\n                return nil\n            }\n\n            return FinishingInfo(error: receivedError, source: source)\n        }\n    }\n\n    private final func finish(with receivedError: Error?, from source: ProcedureKit.FinishingFrom) {\n\n        log.verbose.trace()\n\n        guard let finishingInfo = shouldFinish(with: receivedError, from: source) else {\n            log.verbose.message(\"An earlier call to finish \\((isFinished) ? \"has already succeeded.\" : \"is pending. The Procedure will finish from the first call.\") This call will have no effect: finish(with: \\(receivedError.debugDescription)\")\n            return\n        }\n\n        _finish(withInfo: finishingInfo)\n    }\n\n    private final func _finish(withInfo info: FinishingInfo) {\n        dispatchEvent {\n            self._finish_onEventQueue(withInfo: info)\n        }\n    }\n\n    private final func _finish_onEventQueue(withInfo info: FinishingInfo) {\n\n        debugAssertIsOnEventQueue()\n        debugSynchronizedAssertIsExecuting()\n\n        log.verbose.trace()\n\n        // Obtain a local strong reference to the Procedure queue\n        guard let strongProcedureQueue = procedureQueue else {\n            // NOTE: For the mutual exclusivity implementation to work properly,\n            // a strong reference to the ProcedureQueue must exist through finish.\n            //\n            // Procedure is supposed to hold onto its own strong reference\n            // to the ProcedureQueue onto which it was added.\n            fatalError(\"Procedure hasn't finished, but procedureQueue is nil\") // ProcedureKit internal programmer error\n        }\n\n        // NOTE:\n        // - The stateLock should only be held when necessary, and should not\n        //   be held when notifying observers (whether via KVO or Operation's\n        //   observers) or deadlock can result.\n\n        // Determine whether the `isExecuting` state is changing.\n        // (If the Procedure is finishing from a state other than .executing, `isExecuting` will\n        // not transition from `true` -> `false`, and no KVO is necessary.)\n        let changedExecutingState = isExecuting\n\n        if changedExecutingState {\n            willChangeValue(forKey: .executing)\n        }\n\n        // Change the state to .finishing and set & retrieve the final resulting array of errors\n        let resultingError: Error? = synchronise {\n            protectedProperties.error = protectedProperties.error ?? info.error\n            _state = .finishing\n            return protectedProperties.error\n        }\n\n        if changedExecutingState {\n            didChangeValue(forKey: .executing)\n        }\n\n        if let error = resultingError {\n            log.verbose.message(\"Will finish with error: \\(error).\")\n        }\n        else {\n            log.verbose.message(\"Will finish with no errors.\")\n        }\n\n        procedureWillFinish(with: resultingError)\n\n        let willFinishObserversGroup = dispatchObservers(pendingEvent: PendingEvent.finish) {\n            $0.will(finish: self, with: resultingError, pendingFinish: $1)\n        }\n\n        optimizedDispatchEventNotify(group: willFinishObserversGroup) {\n            // Once all the WillFinishObservers have completed, continue processing finish\n\n            self.log.verbose.message(\"[event]: Resuming pending finish\")\n\n            // Change the state to .finished and signal `isFinished` KVO.\n            //\n            // IMPORTANT: willChangeValue and didChangeValue *must* occur\n            // on the same *thread*.\n            //\n            // Thus, both are executed below (in the same block on the EventQueue),\n            // as delaying didChangeValue to another block on the queue (for example,\n            // after the DidFinishObservers) may not result in it executing on the\n            // same _thread_ as the earlier call to willChangeValue.\n            //\n            self.willChangeValue(forKey: .finished)\n            self.synchronise {\n                // Set the state to .finished\n                self._state = .finished\n                // Clear the internal Procedure strong reference to its ProcedureQueue\n                //\n                // A separate strong reference (strongProcedureQueue) exists for use\n                // in cleanup (unlocking) tasks below\n                self._queue = nil\n            }\n            self.didChangeValue(forKey: .finished)\n\n            // Call the Procedure.procedureDidFinish(withErrors:) override\n            self.procedureDidFinish(with: resultingError)\n\n            // If mutually exclusive categories were locked, unlock\n            if let mutuallyExclusiveCategories = self.mutuallyExclusiveCategories {\n                strongProcedureQueue.unlock(mutuallyExclusiveCategories: mutuallyExclusiveCategories)\n            }\n\n            // Dispatch the DidFinishObservers\n            let didFinishObserversGroup = self.dispatchObservers(pendingEvent: PendingEvent.postFinish) { observer, _ in\n                observer.did(finish: self, with: resultingError)\n            }\n\n            self.optimizedDispatchEventNotify(group: didFinishObserversGroup) {\n                // Once all the DidFinishObservers have completed, log a final notice\n\n                if let error = resultingError {\n                    self.log.warning.message(\"Did finish with error: \\(error).\")\n                }\n                else {\n                    self.log.info.message(\"Did finish without errors.\")\n                }\n            }\n        }\n    }\n\n    // MARK: - Observers\n\n    /**\n     Add an observer to the procedure.\n\n     - parameter observer: type conforming to protocol `ProcedureObserver`.\n     */\n    open func addObserver<Observer>(_ observer: Observer) where Observer: ProcedureObserver, Observer.Procedure: Procedure {\n        assert(self as? Observer.Procedure != nil, \"add(observer:) passed an Observer with an invalid expected Procedure type. The Observer will not receive any events from this Procedure. (Observer expects a Procedure of type \\\"\\(String(describing: Observer.Procedure.self))\\\", but `self` is a \\\"\\(typeDescription)\\\" and cannot be converted.)\")\n\n        addAnyObserver(AnyObserver(base: TransformObserver<Observer.Procedure, Procedure>(base: observer)))\n    }\n\n    // Internal function used to add AnyObserver<Procedure> to the Procedure's internal array of observers.\n    internal func addAnyObserver(_ observer: AnyObserver<Procedure>) {\n        debugSynchronizedAssertIsPending(\"Adding observers to a Procedure after it has been added to a queue is an inherent race condition, and risks missing events.\")\n\n        dispatchEvent {\n\n            self.debugAssertIsOnEventQueue()\n\n            // Add the observer to the internal observers array\n            self.synchronise {\n                self.protectedProperties.observers.append(observer)\n            }\n\n            // Dispatch the DidAttach event to the observer\n            if let observerEventQueue = observer.eventQueue, observerEventQueue !== self.eventQueue {\n                // This observer has a desired eventQueue onto which all observer\n                // callbacks should be synchronized.\n                //\n                // Dispatch the observer callback block onto the observer's event queue\n                self.eventQueue.dispatchSynchronizedBlock(onOtherQueue: observerEventQueue) {\n                    // this block is now synchronized with *both* queues\n                    //observerEventQueue.debugAssertIsOnQueue()\n\n                    // process observer block on Observer's event queue\n                    observer.didAttach(to: self)\n                }\n                return\n            }\n            else {\n                // The observer lacks a desired eventQueue, so just execute the block directly on the\n                // Procedure's EventQueue.\n                observer.didAttach(to: self)\n            }\n        }\n    }\n\n    /// Appropriately dispatch an observer call (using the provided block) for every observer.\n    ///\n    /// - IMPORTANT: Only call this if already on the eventQueue.\n    ///\n    /// - Parameters:\n    ///   - pendingEvent: the Procedure's PendingEvent that occurs after all the observers have completed their work\n    ///   - block: a block that will be called for every observer, on the appropriate queue/thread\n    /// - Returns: a DispatchGroup that will be signaled (ready) when the PendingEvent is ready (i.e. when\n    ///            all of the observers have completed their work)\n    @discardableResult\n    internal func dispatchObservers(pendingEvent: (Procedure) -> PendingEvent, block: @escaping (AnyObserver<Procedure>, PendingEvent) -> Void) -> DispatchGroup {\n        debugAssertIsOnEventQueue() // This function should only be called if already on the EventQueue\n\n        let iterator = observers.makeIterator()\n        let pendingEvent = pendingEvent(self)\n\n        processObservers(iterator: iterator, futureEvent: pendingEvent, block: block)\n        return pendingEvent.group\n    }\n\n    typealias ObserverIterator = IndexingIterator<[AnyObserver<Procedure>]>\n    private func processObservers(iterator: ObserverIterator, futureEvent: PendingEvent, block: @escaping (AnyObserver<Procedure>, PendingEvent) -> Void) {\n        debugAssertIsOnEventQueue() // This function should only be called if already on the EventQueue\n\n        var modifiableIterator = iterator\n        while let observer = modifiableIterator.next() {\n\n            if let observerEventQueue = observer.eventQueue, observerEventQueue !== eventQueue {\n                // This observer has a desired eventQueue onto which all observer\n                // callbacks should be synchronized.\n                //\n                // Dispatch the observer callback block onto the observer's event queue,\n                // and chain an async dispatch back to this Procedure's event queue\n                // to continue processing any remaining observers once this observer's\n                // callback has returned.\n                //\n                let originalQoS = DispatchQoS(qosClass: DispatchQueue.currentQoSClass, relativePriority: 0)\n                eventQueue.dispatchSynchronizedBlock(onOtherQueue: observerEventQueue) {\n                    // This block is now synchronized with *both* queues:\n                    //  - the parent Procedure's EventQueue\n                    //  - the observer's queue\n                    // and is *on* the observer's queue.\n\n                    // Process the observer block on Observer's event queue\n                    block(observer, futureEvent)\n\n                    // Dispatch async back to the Procedure's EventQueue to\n                    // continue processing observers.\n                    self.dispatchEvent(minimumQoS: originalQoS) {\n                        self.processObservers(iterator: modifiableIterator, futureEvent: futureEvent, block: block)\n                    }\n                }\n                return\n            }\n            else {\n                block(observer, futureEvent)\n            }\n        }\n    }\n}\n\n// MARK: - Dependencies\n\npublic extension Procedure {\n\n    final func addDependency<Dependency: ProcedureProtocol>(_ dependency: Dependency) {\n        guard let op = dependency as? Operation else {\n            assertionFailure(\"Adding dependencies which do not subclass Foundation.Operation is not supported.\")\n            return\n        }\n        addDependency(op)\n    }\n}\n\n// MARK: - Event Queue\n\ninternal extension Procedure {\n\n    /// Asynchronously dispatches an event for execution on the Procedure's EventQueue.\n    ///\n    /// - Parameters:\n    ///   - block: a block to execute on the EventQueue\n    func dispatchEvent(minimumQoS: DispatchQoS? = nil, block: @escaping () -> Void) {\n        eventQueue.dispatchEventBlockInternal(minimumQoS: minimumQoS, block: block)\n    }\n\n    // Only to be called when already on the eventQueue\n    func optimizedDispatchEventNotify(group: DispatchGroup, inheritQoS: Bool = false, block: @escaping () -> Void) {\n        debugAssertIsOnEventQueue()\n\n        if group.wait(timeout: .now()) == .success {\n            // no need to dispatch notify, just execute block directly\n            // (optimal path when the DispatchGroup is already finished)\n            block()\n        }\n        else {\n            // must wait on group to execute the block on the eventQueue\n\n            // use either the QoS of the Procedure, or the current QoS\n            let minimumQoS = (!inheritQoS) ? qualityOfService.qos : DispatchQoS(qosClass: DispatchQueue.currentQoSClass, relativePriority: 0)\n\n            eventQueue.dispatchNotify(withGroup: group, minimumQoS: minimumQoS, block: block)\n        }\n    }\n\n    func debugAssertIsOnEventQueue() {\n        eventQueue.debugAssertIsOnQueue()\n    }\n}\n\n// MARK: - Conditions\n\nextension Procedure {\n\n    // A custom internal operation subclass that handles evaluating Conditions for a Procedure.\n    final class EvaluateConditions: Operation {\n\n        private enum State: Int, Comparable { // swiftlint:disable:this nesting\n\n            static func < (lhs: State, rhs: State) -> Bool {\n                return lhs.rawValue < rhs.rawValue\n            }\n\n            case waiting\n            case dispatchedStart\n            case started\n            case executingMain\n        }\n\n        let queue: DispatchQueue\n        weak var procedure: Procedure?\n        let context: ConditionEvaluationContext\n\n        init(procedure: Procedure) {\n            self.procedure = procedure\n            let queue = DispatchQueue(label: \"run.kit.procedure.ProcedureKit.EvaluateConditions\", qos: procedure.qualityOfService.qos, attributes: [.concurrent])\n            self.queue = queue\n            self.context = ConditionEvaluationContext(queue: queue, behavior: .andPredicate)\n            super.init()\n        }\n\n        func parentProcedureHasBeenAddedToQueue() {\n            // Only once the parent Procedure has been fully added to the ProcedureQueue\n            // (OperationQueue) is it safe to begin evaluating conditions (if otherwise isReady).\n\n            dispatchStartOnce(source: .parentProcedureHasBeenAddedToQueue)\n        }\n\n        private var _isFinished: Bool = false\n        private var _isExecuting: Bool = false\n        private let stateLock = PThreadMutex()\n        private var _state: State = .waiting\n        private var _parentProcedureHasBeenAddedToQueue: Bool = false\n\n        override var isFinished: Bool {\n            get { return stateLock.withCriticalScope { return _isFinished } }\n            set {\n                willChangeValue(forKey: .finished)\n                stateLock.withCriticalScope { _isFinished = newValue }\n                didChangeValue(forKey: .finished)\n            }\n        }\n        override var isExecuting: Bool {\n            get { return stateLock.withCriticalScope { return _isExecuting } }\n            set {\n                willChangeValue(forKey: .executing)\n                stateLock.withCriticalScope { _isExecuting = newValue }\n                didChangeValue(forKey: .executing)\n            }\n        }\n\n        final override var isReady: Bool {\n            let superIsReady = super.isReady\n            if superIsReady {\n                // If super.isReady == true, dispatch start *once*\n                dispatchStartOnce(source: .isReady)\n            }\n            return superIsReady\n        }\n\n        private enum StartSource { // swiftlint:disable:this nesting\n\n            case isReady\n            case parentProcedureHasBeenAddedToQueue\n        }\n\n        final private func dispatchStartOnce(source: StartSource) {\n            // dispatch start() once\n            let shouldDispatchStart: Bool = stateLock.withCriticalScope {\n                guard _state < .dispatchedStart else { return false } // already started evaluating\n                switch source {\n                case .isReady:\n                    // if isReady, can proceed to .dispatchedStart *if* _parentProcedureHasBeenAddedToQueue\n                    guard _parentProcedureHasBeenAddedToQueue else {\n                        // isReady, but the parent procedure hasn't yet been added\n                        // to the queue - do not proceed\n                        return false\n                    }\n                case .parentProcedureHasBeenAddedToQueue:\n                    assert(!_parentProcedureHasBeenAddedToQueue)\n                    _parentProcedureHasBeenAddedToQueue = true\n                    // can proceed to .dispatchedStart *if* otherwise isReady\n                    guard super.isReady else { return false }\n                }\n                _state = .dispatchedStart\n                return true\n            }\n            guard shouldDispatchStart else { return }\n\n            guard let procedure = procedure else {\n                // the Procedure went away - finish immediately\n                finish()\n                return\n            }\n            guard let procedureQueue = procedure.procedureQueue else {\n                fatalError(\"The Condition Evaluator's Procedure has a nil associated ProcedureQueue.\")\n            }\n            procedureQueue.requestEvaluation(of: self)\n        }\n        final fileprivate func dispatchStartOnce() {\n            dispatchStartOnce(source: .isReady)\n        }\n\n        final override func cancel() {\n            // If the EvaluateConditions operation is cancelled\n            // Ensure that the attached Procedure is cancelled\n            procedure?.cancel()\n            super.cancel()\n            // Cancel the context to ensure that any concurrent\n            // evaluation of Conditions rapidly stops.\n            context.cancel()\n        }\n\n        /// Should only be called by ProcedureQueue\n        /// (see: the call to `procedureQueue.requestEvaluation(of: self)` above)\n        override func start() {\n            isExecuting = true\n            main()\n        }\n\n        /// Should only be called by start()\n        override func main() {\n            // This should only be executed once\n            let shouldContinue: Bool = stateLock.withCriticalScope {\n                guard _state < .executingMain else { return false }\n                _state = .executingMain\n                return true\n            }\n            guard shouldContinue else { return }\n\n            guard let procedure = procedure else {\n                // the Procedure went away - finish immediately\n                finish()\n                return\n            }\n            guard !isCancelled else {\n                // this EvaluateConditions operation has been cancelled\n                // ensure that the dependent Procedure is cancelled\n                procedure.cancel()\n                // then finish immediately\n                finish()\n                return\n            }\n\n            let conditions = procedure.conditions\n            conditions.evaluate(procedure: procedure, withContext: context) { result in\n\n                // Determine whether the Procedure can proceed to execution\n                switch result {\n                case .success(true):\n                    // All conditions were successful - the Procedure may execute\n                    // Continue on\n                    break\n                case .success(false):\n                    // One or more conditions failed (with an ignored error)\n                    procedure.log.verbose.message(\"Condition(s) failed.\")\n                    // Cancel the Procedure without errors\n                    procedure.cancel()\n                    // Finish this EvaluateConditions operation immediately\n                    self.finish()\n                    return\n                case let .failure(error):\n                    procedure.log.verbose.message(\"Condition(s) failed with error: \\(error).\")\n                    procedure.cancel(with: error)\n                    // Finish this EvaluateConditions operation immediately\n                    self.finish()\n                    return\n                }\n\n                // If the parent Procedure wasn't cancelled\n                // by something else\n                guard !procedure.isCancelled else {\n                    // Finish this EvaluateConditions operation immediately\n                    self.finish()\n                    return\n                }\n\n                // Check for any mutually exclusive categories\n                // to apply to the Procedure\n                let mutuallyExclusiveCategories = conditions.mutuallyExclusiveCategories\n                guard !mutuallyExclusiveCategories.isEmpty else {\n                    // No mutually-exclusive categories to acquire - finish immediately\n                    self.finish()\n                    return\n                }\n\n                // Acquire the mutually-exclusive categories (locks) for the Procedure\n                // before allowing it to execute.\n\n                procedure.request(mutuallyExclusiveCategories: mutuallyExclusiveCategories) { _ in\n                    // Exclusivity locks have been acquired, or the request did not succeed\n                    // (but for valid cancellation/timing reasons).\n                    //\n                    // Regardless, it is now safe to finish the EvaluateConditions operation\n                    // and trigger the parent Procedure (if it hasn't already cancelled + finished).\n                    self.finish()\n                }\n            }\n        }\n        func finish() {\n            isExecuting = false\n            isFinished = true\n        }\n    }\n\n    func addDirectDependency(_ directDependency: Operation) {\n        precondition(state < .started, \"Dependencies cannot be modified after a Procedure has started, current state: \\(state).\")\n        stateLock.withCriticalScope { () -> Void in\n            protectedProperties.directDependencies.insert(directDependency)\n\n            // occurs inside the stateLock to prevent any double-adds of dependencies\n            // to the EvaluateConditions operation\n            assert(!((_evaluateConditionsProcedure?.isExecuting ?? false) || (_evaluateConditionsProcedure?.isFinished ?? false)), \"Conditions are already being evaluated (or have already finished being evaluated). It is too late to add a dependency and have it properly affect the Procedure. Instead, consider adding dependencies before adding the Procedure to a queue, or adding dependencies before all other existing dependencies have finished (for example: from a WillFinish observer on a dependency).\")\n            _evaluateConditionsProcedure?.addDependency(directDependency)\n        }\n        super.addDependency(directDependency)\n    }\n\n    func removeDirectDependency(_ directDependency: Operation) {\n        precondition(state < .started, \"Dependencies cannot be modified after a Procedure has started, current state: \\(state).\")\n        stateLock.withCriticalScope { () -> Void in\n            protectedProperties.directDependencies.remove(directDependency)\n\n            // occurs inside the stateLock to ensure that every removed dependency is\n            // removed from the EvaluateConditions operation\n            _evaluateConditionsProcedure?.removeDependency(directDependency)\n        }\n        super.removeDependency(directDependency)\n    }\n\n    public final override var dependencies: [Operation] {\n        return Array(directDependencies)\n    }\n\n    /**\n     Add another `Operation` as a dependency. It is a programmatic error to call\n     this method after the receiver has already started executing. Therefore, best\n     practice is to add dependencies before adding them to operation queues.\n\n     - requires: self must not have started yet. i.e. either hasn't been added\n     to a queue, or is waiting on dependencies.\n     - parameter operation: a `Operation` instance.\n     */\n    public final override func addDependency(_ operation: Operation) {\n        precondition(state < .started, \"Dependencies cannot be modified after a Procedure has started, current state: \\(state).\")\n        addDirectDependency(operation)\n    }\n\n    /**\n     Remove another `Operation` as a dependency. It is a programmatic error to call\n     this method after the receiver has already started executing. Therefore, best\n     practice is to manage dependencies before adding them to operation\n     queues.\n\n     - requires: self must not have started yet. i.e. either hasn't been added\n     to a queue, or is waiting on dependencies.\n     - parameter operation: a `Operation` instance.\n     */\n    public final override func removeDependency(_ operation: Operation) {\n        precondition(state < .started, \"Dependencies cannot be modified after a Procedure has started, current state: \\(state).\")\n        removeDirectDependency(operation)\n    }\n\n    /**\n     Add a condition to the procedure. It is a programmatic error to call this method\n     after the receiver has been added to a ProcedureQueue. Therefore, best practice\n     is to manage conditions before adding a Procedure to a queue.\n\n     - parameter condition: a `Condition` which must be satisfied for the procedure to be executed.\n     */\n    public final func addCondition(_ condition: Condition) {\n        assert(state < .willEnqueue, \"Cannot modify conditions after a Procedure has been added to a queue, current state: \\(state).\")\n        synchronise { () -> Void in\n            protectedProperties.conditions.insert(condition)\n        }\n    }\n}\n\n// MARK: - Internal Extensions\n\ninternal extension Procedure {\n\n    func debugSynchronizedAssertIsExecuting(_ message: String = \"Procedure is not yet finishing or finished.\") {\n        #if DEBUG\n        synchronise {\n            guard _state <= .executing else {\n                assertionFailure(message)\n                return\n            }\n        }\n        #endif\n    }\n\n    /// Internal Assertions\n    func debugSynchronizedAssertIsPending(_ message: String = \"Procedure is no longer pending.\") {\n        #if DEBUG\n        synchronise {\n            guard _state <= .pending else {\n                assertionFailure(message)\n                return\n            }\n        }\n        #endif\n    }\n}\n\n// MARK: - Deprecations\n\npublic extension Procedure {\n\n    @available(*, deprecated, renamed: \"addObserver(_:)\", message: \"This has been renamed to use Swift 3/4 naming conventions\")\n    func add<Observer>(observer: Observer) where Observer: ProcedureObserver, Observer.Procedure: Procedure {\n        addObserver(observer)\n    }\n\n    @available(*, deprecated, renamed: \"addObserver(_:)\", message: \"This has been renamed to use Swift 3/4 naming conventions\")\n    internal func add(anyObserver observer: AnyObserver<Procedure>) {\n        addAnyObserver(observer)\n    }\n\n    @available(*, deprecated, renamed: \"addDependency(_:)\", message: \"This has been renamed to use Swift 3/4 naming conventions\")\n    final func add<Dependency: ProcedureProtocol>(dependency: Dependency) {\n        addDependency(dependency)\n    }\n\n    @available(*, deprecated, renamed: \"addDirectDependency(_:)\", message: \"This has been renamed to use Swift 3/4 naming conventions\")\n    func add(directDependency: Operation) {\n        addDirectDependency(directDependency)\n    }\n\n    @available(*, deprecated, renamed: \"removeDirectDependency(_:)\", message: \"This has been renamed to use Swift 3/4 naming conventions\")\n    func remove(directDependency: Operation) {\n        removeDirectDependency(directDependency)\n    }\n\n    @available(*, deprecated, renamed: \"addCondition(_:)\", message: \"This has been renamed to use Swift 3/4 naming conventions\")\n    final func add(condition: Condition) {\n        addCondition(condition)\n    }\n}\n\n// swiftlint:enable type_body_length\n\n// swiftlint:enable file_length\n"
  },
  {
    "path": "Sources/ProcedureKit/ProcedureEventQueue.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport Foundation\nimport Dispatch\n\n// MARK: - EventQueue\n\n/**\n An EventQueue is used to wrap some additional logic around a serial DispatchQueue for internal use in ProcedureKit.\n Blocks can be dispatched asynchronously onto an EventQueue, and are executed in a serial FIFO manner.\n \n (Only asynchronous dispatch methods are available.)\n*/\npublic class EventQueue {\n    fileprivate let queue: DispatchQueue\n    #if DEBUG\n    private let key: DispatchSpecificKey<UInt8>\n    private let value: UInt8 = 1\n    #endif\n    fileprivate let eventQueueLock = PThreadMutex()\n    internal var qualityOfService: DispatchQoS = .default // is updated by Procedure\n\n    public init(label: String, qos: DispatchQoS = .default) {\n        // The internal DispatchQueue is created as a serial queue with no specified QoS level\n        // to permit the setting of any desired minimum QoS level for a block later.\n        self.queue = DispatchQueue(label: label)\n        self.qualityOfService = qos\n        #if DEBUG\n            key = DispatchSpecificKey()\n            queue.setSpecific(key: key, value: value)\n        #endif\n    }\n\n    internal func debugAssertIsOnQueue() {\n        #if DEBUG\n            assert(isOnQueue, \"Not on expected EventQueue.\")\n        #endif\n        // does nothing if not compiled in Debug mode\n    }\n\n    #if DEBUG\n    internal var isOnQueue: Bool {\n        guard let retrieved = DispatchQueue.getSpecific(key: key) else { return false }\n        return value == retrieved\n    }\n    internal func debugBestowTemporaryEventQueueStatusOn(queue: DispatchQueueProtocol) {\n        queue.pk_setSpecific(key: key, value: value)\n    }\n    internal func debugClearTemporaryEventQueueStatusFrom(queue: DispatchQueueProtocol) {\n        queue.pk_setSpecific(key: key, value: nil)\n    }\n    #endif\n\n    /// Asynchronously dispatches a block for execution on the EventQueue.\n    ///\n    /// - Parameters:\n    ///   - block: a block to execute on the EventQueue\n    public func dispatch(block: @escaping () -> Void) {\n        dispatchEventBlockInternal(minimumQoS: nil, block: block)\n    }\n\n    /// Asynchronously dispatches a block for execution on the EventQueue as a DispatchWorkItem (which it returns).\n    ///\n    /// - Parameters:\n    ///   - block: a block to execute on the EventQueue\n    /// - Returns: the DispatchWorkItem that is scheduled for executing on the EventQueue\n    public func dispatchAsWorkItem(block: @escaping () -> Void) -> DispatchWorkItem {\n        return dispatchEventBlockInternal(minimumQoS: nil, block: block)\n    }\n\n    /// Schedules a block to be submitted to the EventQueue when a DispatchGroup has completed.\n    ///\n    /// - Parameters:\n    ///   - group: the DispatchGroup which signals completion\n    ///   - block: a block to execute on the EventQueue\n    public func dispatchNotify(withGroup group: DispatchGroup, block: @escaping () -> Void) {\n        group.notify(queue: queue, execute: {\n            self.eventQueueLock.withCriticalScope {\n                autoreleasepool {\n                    block()\n                }\n            }\n        })\n    }\n}\n\ninternal extension EventQueue {\n\n    /// Asynchronously dispatches an event for execution on the Procedure's EventQueue\n    /// (optionally specifying a minimumQoS level).\n    ///\n    /// If no minimumQoS level is specified, the qualityOfService level of the EventQueue\n    /// itself will be used. (For custom-created EventQueues, this is the value assigned\n    /// at init(). For Procedure.eventQueue, this value is updated when the\n    /// Procedure.qualityOfService is updated.)\n    ///\n    /// - NOTE: Just because a block has a specified QoS level does not guarantee the block\n    /// will execute with that exact QoS level. Promotional QoS and other factors can come\n    /// into play and result in a higher QoS level.\n    ///\n    /// - Parameters:\n    ///   - minimumQoS: a minimum QoS level for the submitted block\n    ///   - block: a block to execute on the EventQueue\n    @discardableResult\n    func dispatchEventBlockInternal(minimumQoS: DispatchQoS? = nil, block: @escaping () -> Void) -> DispatchWorkItem {\n        let resultingQoS = minimumQoS ?? qualityOfService\n\n        let workItem = DispatchWorkItem(qos: resultingQoS, flags: [DispatchWorkItemFlags.enforceQoS]) {\n            self.eventQueueLock.withCriticalScope {\n                autoreleasepool {\n                    block()\n                }\n            }\n        }\n        queue.async(execute: workItem)\n        return workItem\n    }\n\n    func dispatchNotify(withGroup group: DispatchGroup, minimumQoS: DispatchQoS? = nil, block: @escaping () -> Void) {\n        let resultingQoS = minimumQoS ?? qualityOfService\n\n        group.notify(qos: resultingQoS, flags: [DispatchWorkItemFlags.enforceQoS], queue: queue, execute: {\n            self.eventQueueLock.withCriticalScope {\n                autoreleasepool {\n                    block()\n                }\n            }\n        })\n    }\n\n    /// - IMPORTANT: MUST be called when executing on the receiver EventQueue itself.\n    ///\n    /// Dispatches a block to be executed on another queue (EventQueue, DispatchQueue, etc)\n    /// non-concurrently with the receiver (i.e. the current EventQueue). No further blocks\n    /// from the receiver EventQueue will be executed until the block submitted to the otherQueue\n    /// completes.\n    ///\n    /// If you call this method, you should return from the block that is executing on the receiver\n    /// EventQueue as quickly as possible - the block scheduled on the otherQueue will only execute\n    /// after the receiver EventQueue's block returns.\n    ///\n    /// Internally, this pauses the receiver EventQueue, to ensure that no threads are blocked waiting\n    /// on the otherQueue to asynchronously handle the submitted block. After the otherQueue handles\n    /// the submitted block, the receiver EventQueue is resumed.\n    ///\n    /// The block on the otherQueue is submitted with a QoS level promoted to at least the level of\n    /// the calling thread. (Although never less than the QoS of the otherQueue itself.)\n    ///\n    /// - Parameters:\n    ///   - otherQueue: another queue (EventQueue, DispatchQueue) onto which to asynchronously submit the block\n    ///   - block: the block that is asynchronously submitted to the otherQueue\n    func dispatchSynchronizedBlock(onOtherQueue otherQueue: DispatchQueueProtocol, block: @escaping () -> Void) {\n        debugAssertIsOnQueue()\n        assert(otherQueue !== self, \"Cannot dispatch synchronized block onOtherQueue if otherQueue is self.\")\n\n        // acquire the QoS class of the current block on the receiver queue\n        let originalQueueQoS = DispatchQoS(qosClass: DispatchQueue.currentQoSClass, relativePriority: 0)\n\n        // suspend the current queue so no additional scheduled async blocks will be executed\n        // after the calling code returns (preventing blocked threads)\n        queue.suspend()\n\n        // dispatch async to the other queue\n        //\n        // the original queue, since it is also synchronized with the block, will not schedule\n        // any additional blocks to be executed after the current block returns (i.e. the block\n        // that called dispatchSynchronizedBlock(onOtherQueue:))\n        //\n        // the caller should ideally return quickly after this function returns so that the current \n        // eventQueueLock is released and can be acquired in the otherQueue\n        //\n        otherQueue.asyncDispatch(minimumQoS: originalQueueQoS) { [originalQueue = self] in\n\n            // on the other queue, aquire the event lock from the original queue\n            // to ensure that all blocks on the original queue are done executing\n\n            originalQueue.eventQueueLock.withCriticalScope {\n\n                #if DEBUG\n                    // For Debug purposes, treat the otherQueue at this point as if it were *also* the EventQueue\n                    // (Since the actual EventQueue is paused and no longer executing blocks until this finishes.)\n                    //\n                    // This ensures that if the code inside the block calls `eventQueue.debugAssertIsOnQueue()`,\n                    // it will (properly) succeed.\n                    originalQueue.debugBestowTemporaryEventQueueStatusOn(queue: otherQueue)\n                    assert(originalQueue.isOnQueue)\n                #endif\n\n                // This block should be synchronized with *both* queues\n                block()\n\n                #if DEBUG\n                    originalQueue.debugClearTemporaryEventQueueStatusFrom(queue: otherQueue)\n                    assert(!originalQueue.isOnQueue)\n                #endif\n            }\n\n            // after the block is complete, resume the original queue\n            originalQueue.queue.resume()\n        }\n    }\n}\n\npublic extension EventQueue {\n    func makeTimerSource(flags: DispatchSource.TimerFlags = []) -> DispatchSourceTimer {\n        return DispatchSource.makeTimerSource(flags: flags, queue: queue)\n    }\n}\n\n// MARK: - QueueProvider\n\n/**\n A QueueProvider provides a queue conforming to DispatchQueueProtocol.\n \n Dispatch.DispatchQueue and ProcedureKit.EventQueue both provide themselves.\n ProcedureKit.Procedure provides its EventQueue.\n \n Several methods in ProcedureKit can take a QueueProvider. For example,\n ProcedureProtocol's `add*BlockObserver(synchronizedWith:block:)` methods take\n a QueueProvider for the `synchronizedWith` parameter. This can be a\n DispatchQueue, a ProcedureKit.EventQueue, or a Procedure.\n \n */\npublic protocol QueueProvider {\n    var providedQueue: DispatchQueueProtocol { get }\n}\n\nextension DispatchQueue: QueueProvider {\n    public var providedQueue: DispatchQueueProtocol { return self }\n}\n\nextension EventQueue: QueueProvider {\n    public var providedQueue: DispatchQueueProtocol { return self }\n}\n\nextension Procedure: QueueProvider {\n    public var providedQueue: DispatchQueueProtocol { return eventQueue }\n}\n\n// MARK: - DispatchQueueProtocol\n\npublic protocol DispatchQueueProtocol: class {\n    @discardableResult func asyncDispatch(block: @escaping () -> Void) -> DispatchWorkItem\n    @discardableResult func asyncDispatch(minimumQoS: DispatchQoS, block: @escaping () -> Void) -> DispatchWorkItem\n    func dispatchNotify(withGroup group: DispatchGroup, block: @escaping () -> Void)\n    #if DEBUG\n    func pk_setSpecific<T>(key: DispatchSpecificKey<T>, value: T?)\n    #endif\n}\n\nextension DispatchQueue: DispatchQueueProtocol {\n    @discardableResult public func asyncDispatch(block: @escaping () -> Void) -> DispatchWorkItem {\n        let workItem = DispatchWorkItem(block: block)\n        self.async(execute: workItem)\n        return workItem\n    }\n    @discardableResult public func asyncDispatch(minimumQoS: DispatchQoS, block: @escaping () -> Void) -> DispatchWorkItem {\n        let workItem = DispatchWorkItem(qos: minimumQoS, flags: [DispatchWorkItemFlags.enforceQoS], block: block)\n        self.async(execute: workItem)\n        return workItem\n    }\n    public func dispatchNotify(withGroup group: DispatchGroup, block: @escaping () -> Void) {\n        group.notify(queue: self, execute: block)\n    }\n    #if DEBUG\n    public func pk_setSpecific<T>(key: DispatchSpecificKey<T>, value: T?) {\n        #if swift(>=3.2)\n            setSpecific(key: key, value: value)\n        #else // Swift < 3.2 (Xcode 8.x)\n            if let value = value {\n                setSpecific(key: key, value: value)\n            }\n            else {\n                pk_clearSpecific(key: key)\n            }\n        #endif\n    }\n    #endif\n}\n\n// Swift 3.x\nfileprivate extension DispatchQueue {\n    // Swift 3.x (Xcode 8.x) is missing the ability to clear specific keys from DispatchQueues\n    // via DispatchQueue.setSpecific(key:value:) because it does not take an optional.\n    //\n    // A fix was merged into apple/swift in: https://github.com/apple/swift/commit/5accebf556f40ea104a7440ff0353f9e4f7f1ac2\n    // And is available in Swift 4+.\n    //\n    // For compatibility with Xcode < 9 and Swift 3, this custom clearSpecific(key:)\n    // function is provided.\n    func pk_clearSpecific<T>(key: DispatchSpecificKey<T>) {\n        let k = Unmanaged.passUnretained(key).toOpaque()\n        __dispatch_queue_set_specific(self, k, nil, nil)\n    }\n}\n\nextension EventQueue: DispatchQueueProtocol {\n    @discardableResult public func asyncDispatch(block: @escaping () -> Void) -> DispatchWorkItem {\n        return self.dispatchEventBlockInternal(block: block)\n    }\n    @discardableResult public func asyncDispatch(minimumQoS: DispatchQoS, block: @escaping () -> Void) -> DispatchWorkItem {\n        let desiredQoS = max(minimumQoS, qualityOfService)\n        return self.dispatchEventBlockInternal(minimumQoS: desiredQoS, block: block)\n    }\n    #if DEBUG\n    public func pk_setSpecific<T>(key: DispatchSpecificKey<T>, value: T?) {\n        queue.pk_setSpecific(key: key, value: value)\n    }\n    #endif\n}\n"
  },
  {
    "path": "Sources/ProcedureKit/ProcedureFuture.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport Foundation\nimport Dispatch\n\n// MARK: - ProcedurePromise & ProcedureFuture\n\n/**\n A `ProcedurePromise` provides a `ProcedureFuture` that is signaled when the promise is completed.\n \n Create a `ProcedurePromise` and retrieve the future from the promise:\n \n ```swift\n let promise = ProcedurePromise()\n let future = promise.future // retrieve the future from the promise\n ```\n \n then after your asynchronous task is complete, complete the promise like so:\n \n ```swift\n promise.complete()\n ```\n \n and anything scheduled using the `ProcedureFuture` will occur after the promise has been completed.\n \n A simple example is:\n \n ```swift\n func myAsyncFunction() -> ProcedureFuture {\n     let promise = ProcedurePromise()\n     // dispatch an asynchronous task\n     DispatchQueue.global().async {\n         // do something\n         // then complete the promise when done\n         promise.complete()\n     }\n     return promise.future\n }\n \n myAsyncFunction().then(on: DispatchQueue.global()) {\n    // execute this block after myAsyncFunction's promise completes, on DispatchQueue.global()\n }\n ```\n \n A `ProcedurePromise` / `ProcedureFuture` does not return a value - it merely allows you to execute\n a block when a promise is complete.\n \n To return a future value, use `ProcedurePromiseResult` (and `ProcedureFutureResult`).\n */\npublic class ProcedurePromise {\n\n    /// The `ProcedureFuture` associated with the Promise.\n    public let future = ProcedureFuture()\n    #if DEBUG\n    private var _didComplete = false\n    private var lock = PThreadMutex()\n    #endif\n\n    #if DEBUG\n    // In Debug builds, verify and fail if a promise is not completed before it is deinited\n    // (this slightly impacts performance)\n    deinit {\n        let didComplete = lock.withCriticalScope { _didComplete }\n        guard didComplete else {\n            fatalError(\"Did not complete ProcedurePromise (\\(self)) before deinit. All promises must eventually be completed.\")\n        }\n    }\n    #endif\n\n    /// Complete the ProcedurePromise, signaling the future to dispatch any waiting blocks\n    ///\n    /// - IMPORTANT: Only call `complete()` **once** on a ProcedurePromise.\n    func complete() {\n        #if DEBUG\n        lock.withCriticalScope {\n            assert(!_didComplete, \"Called complete() more than once on a ProcedurePromise.\")\n            _didComplete = true\n        }\n        #endif\n        future.complete()\n    }\n}\n\n/**\n A `ProcedureFuture` can be used to schedule a following block of code after it is signaled (in the future).\n \n You cannot create a `ProcedureFuture` directly. Instead, create a `ProcedurePromise` and retrieve the future\n from the promise:\n \n ```swift\n let promise = ProcedurePromise()\n let future = promise.future // retrieve the future from the promise\n ```\n \n then after your asynchronous task is complete, complete the promise like so:\n \n ```swift\n promise.complete()\n ```\n \n and anything scheduled using the `ProcedureFuture` will occur after the promise has been completed.\n\n A simple example is:\n \n ```swift\n func myAsyncFunction() -> ProcedureFuture {\n    let promise = ProcedurePromise()\n    // dispatch an asynchronous task\n    DispatchQueue.global().async {\n        // do something\n        // then complete the promise when done\n        promise.complete()\n    }\n    return promise.future\n }\n \n myAsyncFunction().then(on: DispatchQueue.global()) {\n    // execute this block after myAsyncFunction's promise completes, on DispatchQueue.global()\n }\n ```\n \n A `ProcedureFuture` / `ProcedurePromise` does not return a value - it merely allows you to execute\n a block when a promise is complete.\n \n To return a future value, use `ProcedurePromiseResult` (and `ProcedureFutureResult`).\n*/\npublic class ProcedureFuture {\n    internal let group: DispatchGroup\n\n    internal init(group: DispatchGroup = DispatchGroup()) {\n        self.group = group\n        group.enter()\n    }\n\n    /// Schedules a block for execution after the ProcedureFuture completes.\n    ///\n    /// - Parameters:\n    ///   - on: a queue [DispatchQueue, EventQueue, Procedure (which schedules it on its internal event queue)]\n    ///   - block: The block to be scheduled after the ProcedureFuture completes.\n    public func then(on eventQueueProvider: QueueProvider, block: @escaping () -> Void) {\n\n        let eventQueue = eventQueueProvider.providedQueue\n        eventQueue.dispatchNotify(withGroup: group, block: block)\n    }\n}\n\n// Used by ProcedurePromise\nfileprivate extension ProcedureFuture {\n\n    func complete() {\n        group.leave()\n    }\n}\n\n// Used by ProcedureFutureGroup\nfileprivate extension ProcedureFuture {\n    // If the future is immediately available, execute the block synchronously on the current thread\n    // otherwise, queue a future dispatch onto the QueueProvider's queue.\n    @discardableResult\n    func thenOnSelfOrLater(on eventQueueProvider: QueueProvider, block: @escaping () -> Void) -> ProcedureFuture {\n        let promise = ProcedurePromise()\n        let eventQueue = eventQueueProvider.providedQueue\n        if group.wait(timeout: .now()) == .success {\n            // future is immediately available, execute the block synchronously on the current thread\n            block()\n            promise.complete()\n        }\n        else {\n            // future is not immediately available, so queue an asynchrous dispatch when it is on the\n            // provided queue\n            eventQueue.dispatchNotify(withGroup: group) {\n                block()\n                promise.complete()\n            }\n        }\n        return promise.future\n    }\n}\n\nextension Collection where Iterator.Element: ProcedureFuture {\n\n    /// Retrieve a future for a collection of ProcedureFutures that is signaled once\n    /// all the futures in the collection are signaled.\n    ///\n    /// ```swift\n    /// let futures: [ProcedureFuture] = ... // multiple ProcedureFutures\n    /// futures.future.then(on: DispatchQueue.global()) {\n    ///     // execute this block when all the futures have completed\n    /// }\n    /// ```\n    ///\n    /// - returns: a ProcedureFuture that is signaled once all ProcedureFutures in the collection are signaled\n    var future: ProcedureFuture {\n        let future = ProcedureFuture()\n        let group = DispatchGroup()\n        self.forEach {\n            group.enter()\n            $0.thenOnSelfOrLater(on: DispatchQueue.global()) {\n                group.leave()\n            }\n        }\n        group.notify(queue: DispatchQueue.global()) {\n            future.complete()\n        }\n        return future\n    }\n}\n\n// MARK: - ProcedurePromiseResult\n\n/**\n A `ProcedurePromiseResult<T>`, is much like a `ProcedurePromise`, except it returns a\n `ProcedureFutureResult<T>` that provides a `ProcedureResult<T>` when the promise is completed.\n\n Create a `ProcedurePromiseResult` and retrieve the future from the promise:\n \n ```swift\n let promise = ProcedurePromiseResult<Bool>()\n let future = promise.future // retrieve the future from the promise\n ```\n \n then after your asynchronous task is complete, complete the promise like so:\n \n ```swift\n promise.complete(withResult: true)\n ```\n \n and anything scheduled using the `ProcedureFutureResult` will occur after the promise has been completed.\n \n A simple example is:\n \n ```swift\n func myAsyncFunction() -> ProcedureFutureResult<Bool> {\n     let promise = ProcedurePromiseResult<Bool>()\n     // dispatch an asynchronous task\n     DispatchQueue.global().async {\n         // do something that returns a result\n         let result = true\n         // then complete the promise when done\n         promise.complete(withResult: result)\n     }\n     return promise.future\n }\n \n myAsyncFunction().then(on: DispatchQueue.global()) { result in\n     // execute this block after myAsyncFunction's promise completes, on DispatchQueue.global()\n     // the result of the promise is passed-in to the block as a ProcedureResult<T>\n     guard let value = result.value else {\n        // error\n        print(\"The result is error: \\(result.error)\")\n     }\n     print(\"The result is: \\(value)\")\n }\n ```\n\n If you do not need to return a value, use `ProcedurePromise` (and `ProcedureFuture`) instead.\n */\npublic class ProcedurePromiseResult<T> {\n\n    /// The `ProcedureFutureResult` associated with the Promise.\n    public let future = ProcedureFutureResult<T>()\n\n    deinit {\n        assert(future.hasResult, \"Did not complete ProcedureResultPromise (\\(self)) before deinit. All promises must eventually be completed.\")\n        guard future.hasResult else {\n            future.complete(withFailure: ProcedureKitError.UnfulfilledPromise())\n            return\n        }\n    }\n\n    /// Complete the `ProcedurePromiseResult` with a result of type T, signaling the\n    /// future to dispatch any waiting blocks.\n    ///\n    /// The blocks will receive a `ProcedureResult<T>.success(result)`.\n    /// - See: `ProcedureResult`\n    ///\n    /// - IMPORTANT: Only call `complete` **once** on a ProcedurePromiseResult.\n    func complete(withResult success: T) {\n        future.complete(withResult: success)\n    }\n\n    /// Complete the `ProcedurePromiseResult` with a failure Error, signaling the\n    /// future to dispatch any waiting blocks\n    ///\n    /// The blocks will receive a `ProcedureResult<T>.failure(error)`.\n    /// - See: `ProcedureResult`\n    ///\n    /// - IMPORTANT: Only call `complete` **once** on a ProcedurePromiseResult.\n    func complete(withFailure failure: Error) {\n        future.complete(withFailure: failure)\n    }\n}\n\npublic class ProcedureFutureResult<Result> {\n    private var _result = Pending<ProcedureResult<Result>>(nil)\n    private var group = DispatchGroup()\n    private var resultLock = PThreadMutex()\n    private var result: Pending<ProcedureResult<Result>> {\n        get { return resultLock.withCriticalScope { _result } }\n        set {\n            resultLock.withCriticalScope {\n                _result = newValue\n            }\n        }\n    }\n\n    fileprivate init() {\n        group.enter()\n    }\n\n    public func then(on eventQueueProvider: QueueProvider, block: @escaping (ProcedureResult<Result>) -> Void) {\n\n        let eventQueue = eventQueueProvider.providedQueue\n        eventQueue.dispatchNotify(withGroup: group) {\n            guard let value = self.result.value else { fatalError(\"Notify triggered before result is available.\") }\n            block(value)\n        }\n    }\n\n    // MARK: - Private Implementation used by ProcedurePromiseResult\n\n    fileprivate func complete(withResult value: Result) {\n        setResult(.success(value))\n    }\n\n    fileprivate func complete(withFailure error: Error) {\n        setResult(.failure(error))\n    }\n\n    private func setResult(_ result: ProcedureResult<Result>) {\n        let setResult = resultLock.withCriticalScope { () -> Bool in\n            guard _result.isPending else {\n                assertionFailure(\"Cannot set the result of a ProcedureFuture more than once.\")\n                return false\n            }\n            _result = .ready(result)\n            return true\n        }\n        guard setResult else { return }\n        group.leave()\n    }\n\n    fileprivate var hasResult: Bool {\n        return resultLock.withCriticalScope { !_result.isPending }\n    }\n}\n\npublic extension ProcedureKitError {\n\n    struct UnfulfilledPromise: Error {\n        internal init() { }\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKit/ProcedureObserver.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport Foundation\n\n/**\n Types which conform to this protocol, can be attached to `Procedure` subclasses to receive\n events at state transitions.\n */\npublic protocol ProcedureObserver {\n\n    associatedtype Procedure: ProcedureProtocol\n\n    /**\n     Observer gets notified when it is attached to a procedure.\n\n     - parameter procedure: the observed procedure, P.\n     */\n    func didAttach(to procedure: Procedure)\n\n    /**\n     Observer gets notified when the attached InputProcedure has\n     it's input value set ready.\n\n     - parameter procedure: the observed procedure, P\n     */\n    func didSetInputReady(on procedure: Procedure)\n\n    /**\n     The procedure will execute.\n\n     - parameter procedure: the observed `Procedure`.\n     */\n    func will(execute procedure: Procedure, pendingExecute: PendingExecuteEvent)\n\n    /**\n     The procedure did execute.\n\n     - note: This observer will be invoked directly after the\n     `execute` method of the procedure returns.\n\n     - warning: There are no guarantees about when this observer\n     will be called, relative to the lifecycle of the procedure. It\n     is entirely possible that the procedure will actually\n     have already finished be the time the observer is invoked. See\n     the conversation here which explains the reasoning behind it:\n     https://github.com/ProcedureKit/ProcedureKit/pull/554\n\n     - parameter procedure: the observed `Procedure`.\n     */\n    func did(execute procedure: Procedure)\n\n    /**\n     The procedure did cancel.\n\n     - parameter procedure: the observed `Procedure`.\n     */\n    func did(cancel procedure: Procedure, with error: Error?)\n\n    /**\n     The procedure will add a new `Operation` instance to the\n     queue. Note that this isn't necessarily a `Procedure`, so be careful, if you\n     intend to automatically start observing it.\n\n     - parameter procedure: the observed `Procedure`.\n     - parameter newOperation: the `Operation` which will be added\n     */\n    func procedure(_ procedure: Procedure, willAdd newOperation: Operation)\n\n    /**\n     The procedure did add a new `Operation` instance to the\n     queue. Note that this isn't necessarily a `Procedure`, so be careful, if you\n     intend to automatically start observing it.\n\n     - parameter procedure: the observed `Procedure`.\n     - parameter newOperation: the `Operation` which has been added to the queue\n     */\n    func procedure(_ procedure: Procedure, didAdd newOperation: Operation)\n\n    /**\n     The procedure will finish. Any errors that were encountered are collected here.\n\n     - parameter procedure: the observed `Procedure`.\n     - parameter errors: an Error.\n     */\n    func will(finish procedure: Procedure, with error: Error?, pendingFinish: PendingFinishEvent)\n\n    /**\n     The procedure did finish. Any errors that were encountered are collected here.\n\n     - parameter procedure: the observed `Procedure`.\n     - parameter error: an Error.\n     */\n    func did(finish procedure: Procedure, with error: Error?)\n\n    /**\n     Provide a queue onto which observer callbacks will be dispatched.\n    */\n    var eventQueue: DispatchQueueProtocol? { get }\n}\n\npublic extension ProcedureObserver {\n    // MARK: - Unavailable/renamed observer callbacks\n    @available(*, unavailable, renamed: \"will(execute:pendingExecute:)\")\n    func will(execute procedure: Procedure) { }\n\n    @available(*, unavailable, renamed: \"will(finish:withErrors:pendingFinish:)\")\n    func will(finish procedure: Procedure, withErrors: [Error]) { }\n\n    @available(*, deprecated, renamed: \"did(cancel:with:)\", message: \"Use did(cancel:with:) instead.\")\n    func did(cancel procedure: Procedure, withErrors errors: [Error]) {\n        did(cancel: procedure, with: errors.first)\n    }\n\n    @available(*, deprecated, renamed: \"will(finish:with:pendingFinish:)\", message: \"Use will(finish:with:pendingFinish:) instead.\")\n    func will(finish procedure: Procedure, withErrors errors: [Error], pendingFinish: PendingFinishEvent) {\n        will(finish: procedure, with: errors.first, pendingFinish: pendingFinish)\n    }\n\n    @available(*, deprecated, renamed: \"did(finish:with:)\", message: \"Use did(finish:with:) instead.\")\n    func did(finish procedure: Procedure, withErrors errors: [Error]) {\n        did(finish: procedure, with: errors.first)\n    }\n}\n\npublic extension ProcedureObserver {\n\n    /// Do nothing.\n    func didAttach(to procedure: Procedure) { }\n\n    /// Do nothing\n    func didSetInputReady(on procedure: Procedure) { }\n\n    /// Do nothing.\n    func will(execute procedure: Procedure, pendingExecute: PendingExecuteEvent) { }\n\n    /// Do nothing.\n    func did(execute procedure: Procedure) { }\n\n    /// Do nothing.\n    func did(cancel procedure: Procedure, with error: Error?) { }\n\n    /// Do nothing.\n    func procedure(_ procedure: Procedure, willAdd newOperation: Operation) { }\n\n    /// Do nothing.\n    func procedure(_ procedure: Procedure, didAdd newOperation: Operation) { }\n\n    /// Do nothing.\n    func will(finish procedure: Procedure, with error: Error?, pendingFinish: PendingFinishEvent) { }\n\n    /// Do nothing.\n    func did(finish procedure: Procedure, with error: Error?) { }\n\n    /// - Returns: nil\n    var eventQueue: DispatchQueueProtocol? { return nil }\n}\n\n// MARK: - Unavilable & Renamed\n\n@available(*, unavailable, renamed: \"ProcedureObserver\")\npublic protocol OperationObserverType { }\n\n@available(*, unavailable, renamed: \"ProcedureObserver\")\npublic protocol OperationWillExecuteObserver { }\n\n@available(*, unavailable, renamed: \"ProcedureObserver\")\npublic protocol OperationWillCancelObserver { }\n\n@available(*, unavailable, renamed: \"ProcedureObserver\")\npublic protocol OperationDidCancelObserver { }\n\n@available(*, unavailable, renamed: \"ProcedureObserver\")\npublic protocol OperationDidProduceOperationObserver { }\n\n@available(*, unavailable, renamed: \"ProcedureObserver\")\npublic protocol OperationWillFinishObserver { }\n\n@available(*, unavailable, renamed: \"ProcedureObserver\")\npublic protocol OperationDidFinishObserver { }\n\n@available(*, unavailable, renamed: \"ProcedureObserver\")\npublic protocol OperationObserver { }\n"
  },
  {
    "path": "Sources/ProcedureKit/ProcedureProcotol.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport Foundation\n\npublic protocol ProcedureProtocol: class {\n\n    var procedureName: String { get }\n\n    var status: ProcedureStatus { get }\n\n    var isExecuting: Bool { get }\n\n    var isFinished: Bool { get }\n\n    var isCancelled: Bool { get }\n\n    var error: Error? { get }\n\n    var log: ProcedureLog { get }\n\n    // Execution\n\n    func willEnqueue(on: ProcedureQueue)\n\n    func pendingQueueStart()\n\n    func execute()\n\n    @discardableResult func produce(operation: Operation, before: PendingEvent?) throws -> ProcedureFuture\n\n    // Cancelling\n\n    func cancel(with error: Error?)\n\n    func procedureDidCancel(with error: Error?)\n\n    // Finishing\n\n    func finish(with error: Error?)\n\n    func procedureWillFinish(with error: Error?)\n\n    func procedureDidFinish(with error: Error?)\n\n    // Observers\n\n    func add<Observer: ProcedureObserver>(observer: Observer) where Observer.Procedure == Self\n\n    // Dependencies\n\n    func add<Dependency: ProcedureProtocol>(dependency: Dependency)\n\n\n    // Deprecations\n\n    @available(*, deprecated, message: \"Use cancel(with:) instead. This API will now just use the first error.\")\n    func cancel(withErrors: [Error])\n\n    @available(*, deprecated, message: \"Use procedureDidCancel(with:) instead. This API will now just use the first error.\")\n    func procedureDidCancel(withErrors: [Error])\n\n    @available(*, deprecated, message: \"Use finish(with:) instead. This API will now just use the first error.\")\n    func finish(withErrors: [Error])\n\n    @available(*, deprecated, message: \"Use procedureWillFinish(with:) instead. This API will now just receive a single error.\")\n    func procedureWillFinish(withErrors: [Error])\n\n    @available(*, deprecated, message: \"Use procedureDidFinish(with:) instead. This API will now just receive a single error.\")\n    func procedureDidFinish(withErrors: [Error])\n}\n\n\n/// Default ProcedureProtocol implementations\npublic extension ProcedureProtocol {\n\n    /// Boolean indicator for whether the Procedure finished with an error\n    var failed: Bool {\n        return error != nil\n    }\n\n    func procedureDidCancel(with error: Error?) { }\n\n    func procedureWillFinish(with error: Error?) { }\n\n    func procedureDidFinish(with error: Error?) { }\n\n    // Deprecations\n\n    func cancel(withErrors errors: [Error]) {\n        cancel(with: errors.first)\n    }\n\n    func procedureDidCancel(withErrors errors: [Error]) {\n        procedureDidCancel(with: errors.first)\n    }\n\n    func finish(withErrors errors: [Error]) {\n        finish(with: errors.first)\n    }\n\n    func procedureWillFinish(withErrors errors: [Error]) {\n        procedureWillFinish(with: errors.first)\n    }\n\n    func procedureDidFinish(withErrors errors: [Error]) {\n        procedureDidFinish(with: errors.first)\n    }\n\n}\n"
  },
  {
    "path": "Sources/ProcedureKit/ProcedureQueue.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport Foundation\n\n/**\n A protocol which the `ProcedureQueue`'s delegate must conform to. The delegate is informed\n when the queue is about to add an operation/procedure, and when they finish. Because it is a\n delegate protocol, conforming types must be classes, as the queue weakly owns it.\n \n There are slight differences depending on whether an Operation subclass or a Procedure subclass\n is being added to a ProcedureQueue.\n \n For an Operation subclass, the delegate callbacks are:\n \n    - procedureQueue(_:, willAddOperation:, context:)\n    - procedureQueue(_:, didAddOperation:, context:)\n    - procedureQueue(_:, didFinishOperation:)\n \n If you get the first, you are guaranteed* to get the other two callbacks once the Operation\n finishes (*unless you later modify the completionBlock - which is a bad idea - or your Operation\n never finishes - which is also a bad idea).\n \n For a Procedure subclass, the delegate callbacks are:\n \n    - procedureQueue(_:, willAddProcedure:, context:)\n    - procedureQueue(_:, didAddProcedure:, context:)\n    - procedureQueue(_:, willFinishProcedure:)\n    - procedureQueue(_:, didFinishProcedure:)\n \n You will (eventually) receive all 4 delegate callbacks for a Procedure (assuming it finishes).\n \n The `context` parameter provided to the will/didAdd delegate callbacks is the same `context`\n parameter that was passed into the call to `ProcedureQueue.add(operation:context:)`.\n \n For both adding and finishing, the \"will\" delegate will be called before the respective \"did\" delegate\n method. However, you should be aware of the following additional guidelines:\n \n    - `willAddOperation` / `willAddProcedure` is always guaranteed to be called before any other delegate\n      methods for an Operation / Procedure instance\n    - `willFinishProcedure` is always guaranteed to be called before `didFinishProcedure` for a\n      Procedure instance\n    - No other ordering (or non-concurrency) is guaranteed\n \n Delegate callbacks may occur concurrently and on any thread.\n \n Examples:\n    - It is possible for `didAddOperation` / `didAddProcedure` to be called concurrently with\n    `didFinishOperation` / `will/didFinishProcedure` for an Operation / Procedure instance.\n    - It is possible for `didAddOperation` to be called concurrently for two different Operation\n    instances added to a ProcedureQueue simultaneously. (i.e. Once for each Operation.)\n \n */\npublic protocol ProcedureQueueDelegate: class {\n\n    // MARK: - Operations\n\n    /**\n     The procedure queue will add a new operation. This is for information only, the\n     delegate cannot affect whether the operation is added, or other control flow.\n\n     - parameter queue: the `ProcedureQueue`.\n     - parameter operation: the `Operation` instance about to be added.\n     - parameter context: the context, if any, passed into the call to ProcedureQueue.add(operation:context:) that triggered the delegate callback\n     - returns: (optional) a `ProcedureFuture` (signaled when handling of the delegate callback is complete), or nil (if there is no need for the `ProcedureQueue` to wait to add the operation)\n     */\n    func procedureQueue(_ queue: ProcedureQueue, willAddOperation operation: Operation, context: Any?) -> ProcedureFuture?\n\n    /**\n     The procedure queue did add a new operation. This is for information only.\n\n     - parameter queue: the `ProcedureQueue`.\n     - parameter operation: the `Operation` instance which was added.\n     - parameter context: the context, if any, passed into the call to ProcedureQueue.add(operation:context:) that triggered the delegate callback\n     */\n    func procedureQueue(_ queue: ProcedureQueue, didAddOperation operation: Operation, context: Any?)\n\n    /**\n     An operation has finished on the queue.\n\n     - parameter queue: the `ProcedureQueue`.\n     - parameter operation: the `Operation` instance which finished.\n     - parameter errors: an array of `Error`s.\n     */\n    func procedureQueue(_ queue: ProcedureQueue, didFinishOperation operation: Operation)\n\n    // MARK: - Procedures\n\n    /**\n     The procedure queue will add a new Procedure. This is for information only, the\n     delegate cannot affect whether the Procedure is added, or other control flow.\n     \n     - parameter queue: the `ProcedureQueue`.\n     - parameter procedure: the `Procedure` instance about to be added.\n     - parameter context: the context, if any, passed into the call to ProcedureQueue.add(operation:context:) that triggered the delegate callback\n     - returns: (optional) a `ProcedureFuture` (signaled when handling of the delegate callback is complete), or nil (if there is no need for the `ProcedureQueue` to wait to add the operation)\n     */\n    func procedureQueue(_ queue: ProcedureQueue, willAddProcedure procedure: Procedure, context: Any?) -> ProcedureFuture?\n\n    /**\n     The procedure queue did add a new Procedure. This is for information only.\n     \n     - parameter queue: the `ProcedureQueue`.\n     - parameter procedure: the `Procedure` instance which was added.\n     - parameter context: the context, if any, passed into the call to ProcedureQueue.add(operation:context:) that triggered the delegate callback\n     */\n    func procedureQueue(_ queue: ProcedureQueue, didAddProcedure procedure: Procedure, context: Any?)\n\n    /**\n     A Procedure will finish on the queue.\n     \n     - parameter queue: the `ProcedureQueue`.\n     - parameter procedure: the `Procedure` instance which finished.\n     - parameter errors: an array of `Error`s.\n     - returns: (optional) a `ProcedureFuture` (signaled when handling of the delegate callback is complete), or nil (if there is no need for the `ProcedureQueue` to temporarily block the Procedure from finishing)\n     */\n    func procedureQueue(_ queue: ProcedureQueue, willFinishProcedure procedure: Procedure, with error: Error?) -> ProcedureFuture?\n\n    /**\n     A Procedure has finished on the queue.\n     \n     - parameter queue: the `ProcedureQueue`.\n     - parameter procedure: the `Procedure` instance which finished.\n     - parameter errors: an array of `Error`s.\n     */\n    func procedureQueue(_ queue: ProcedureQueue, didFinishProcedure procedure: Procedure, with error: Error?)\n}\n\npublic extension ProcedureQueueDelegate {\n\n    // Operations\n\n    /// Default - do nothing.\n    func procedureQueue(_ queue: ProcedureQueue, willAddOperation operation: Operation, context: Any?) -> ProcedureFuture? { /* default no-op */ return nil }\n\n    /// Default - do nothing.\n    func procedureQueue(_ queue: ProcedureQueue, didAddOperation operation: Operation, context: Any?) { /* default no-op */ }\n\n    /// Default - do nothing.\n    func procedureQueue(_ queue: ProcedureQueue, didFinishOperation operation: Operation) { /* default no-op */ }\n\n    // Procedures\n\n    /// Default - do nothing.\n    func procedureQueue(_ queue: ProcedureQueue, willAddProcedure procedure: Procedure, context: Any?) -> ProcedureFuture? { /* default no-op */ return nil }\n\n    /// Default - do nothing.\n    func procedureQueue(_ queue: ProcedureQueue, didAddProcedure procedure: Procedure, context: Any?) { /* default no-op */ }\n\n    /// Default - do nothing.\n    func procedureQueue(_ queue: ProcedureQueue, willFinishProcedure procedure: Procedure, with error: Error?) -> ProcedureFuture? { /* default no-op */ return nil }\n\n    /// Default - do nothing.\n    func procedureQueue(_ queue: ProcedureQueue, didFinishProcedure procedure: Procedure, with error: Error?) { /* default no-op */ }\n}\n\n/**\n An `OperationQueue` subclass which supports the features of ProcedureKit. All functionality\n is achieved via the overridden functionality of `addOperation`.\n */\nopen class ProcedureQueue: OperationQueue {\n\n    private class MainProcedureQueue: ProcedureQueue {\n        override init() {\n            super.init()\n            underlyingQueue = DispatchQueue.main\n            maxConcurrentOperationCount = 1\n        }\n    }\n\n    private static let sharedMainQueue = MainProcedureQueue()\n\n    fileprivate let dispatchQueue = DispatchQueue(label: \"run.kit.procedure.ProcedureKit.ProcedureQueue\"/*, qos: DispatchQoS.userInteractive*/, attributes: [.concurrent])\n\n    // Events that are queued until the ProcedureQueue is un-suspended\n    fileprivate var queuedConditionEvaluators: [Procedure.EvaluateConditions] = [] // must be accessed within the suspendLock\n    fileprivate var queuedProcedureLockRequests: [ExclusivityLockRequest] = [] // must be accessed within the suspendLock\n    fileprivate var unclaimedExclusivityLockTickets = Set<ExclusivityLockTicket>() // must be accessed within the suspendLock\n    fileprivate let suspendLock = PThreadMutex()\n\n    /**\n     Override OperationQueue's main to return the main queue as an ProcedureQueue\n\n     - returns: The main queue\n     */\n    open override class var main: ProcedureQueue {\n        return sharedMainQueue\n    }\n\n    /**\n     The queue's delegate, helpful for reporting activity.\n\n     - parameter delegate: a weak `ProcedureQueueDelegate?`\n     */\n    open weak var delegate: ProcedureQueueDelegate?\n\n    /**\n     Adds the operation to the queue. Subclasses which override this method must call this\n     implementation as it is critical to how ProcedureKit functions.\n\n     - parameter op: an `Operation` instance.\n     - parameter context: an optional parameter that is passed-through to the Will/DidAdd delegate callbacks\n     - returns: a `ProcedureFuture` that is signaled once the operation has been added to the `ProcedureQueue`\n     */\n    @discardableResult open func addOperation(_ operation: Operation, withContext context: Any? = nil) -> ProcedureFuture {\n\n        let promise = ProcedurePromise()\n\n        // Execute the first internal implementation function on the current thread.\n        // This will ensure that willAddOperation/Procedure delegate callbacks are called\n        // prior to returning.\n        //\n        // If those delegate callbacks return a future, additional steps may be executed \n        // asynchronously on the ProcedureQueue's internal DispatchQueue.\n        //\n        // Thus, when this function returns:\n        //  - it is guaranteed that the `willAddOperation` / `willAddProcedure` delegate callbacks\n        //    have been called\n        //  - the operation may not have been added to the queue yet, but *will* be (if not)\n        //\n        _addOperation(operation, withContext: context, promise: promise)\n\n        return promise.future\n    }\n\n    /**\n     Adds the operations to the queue.\n\n     - parameter ops: an array of `NSOperation` instances.\n     - parameter wait: a Bool flag which is ignored.\n\n     - IMPORTANT:\n       Unlike `Foundation.OperationQueue`, `ProcedureQueue` ignores the\n       `waitUntilFinished` parameter.\n     */\n    open override func addOperations(_ ops: [Operation], waitUntilFinished wait: Bool) {\n        ops.forEach { addOperation($0) }\n    }\n\n    /// Overrides and wraps the Swift 3 interface\n    open override func addOperation(_ operation: Operation) {\n        addOperation(operation, withContext: nil)\n    }\n\n    /**\n     Override of OperationQueue's `isSuspended`. Functions the same (with some additional support for\n     ProcedureKit internal functionality).\n     */\n    open override var isSuspended: Bool {\n        get { return super.isSuspended }\n        set (newIsSuspended) {\n            suspendLock.withCriticalScope {\n                guard newIsSuspended != super.isSuspended else { return } // nothing changed\n                super.isSuspended = newIsSuspended\n                if !newIsSuspended {\n                    // When resuming a ProcedureQueue:\n                    // 1.) Process all queuedProcedureLockRequests\n                    for lockRequest in queuedProcedureLockRequests {\n                        _requestLockAsync(for: lockRequest.mutuallyExclusiveCategories, completion: lockRequest.completion)\n                    }\n                    queuedProcedureLockRequests.removeAll()\n                    // 2.) Process all queued condition evaluators\n                    for conditionEvaluator in queuedConditionEvaluators {\n                        conditionEvaluator.queue.async {\n                            conditionEvaluator.start()\n                        }\n                    }\n                    queuedConditionEvaluators.removeAll()\n                }\n                else {\n                    // When suspending a ProcedureQueue:\n                    // 1.) Invalidate all unclaimedExclusivityLockTickets (releasing the locks)\n                    for ticket in unclaimedExclusivityLockTickets {\n                        ExclusivityManager.sharedInstance.unlock(categories: ticket.mutuallyExclusiveCategories)\n                    }\n                    unclaimedExclusivityLockTickets.removeAll()\n                }\n            }\n        }\n    }\n\n    // MARK: - Private Implementation\n\n    private func _addOperation(_ operation: Operation, withContext context: Any?, promise: ProcedurePromise) {\n\n        // Stage 1: Add observers / completion block,\n        //          willEnqueue(on: self)\n        //          Call async WillAdd delegate method, .then(onQueue: )\n\n        guard let procedure = operation as? Procedure else {\n\n            // Operation (non-Procedure) subclasses are handled differently:\n            //  - They receive the following delegate callbacks: \n            //      willAddOperation, didAddOperation, didFinishOperation\n            //    (There is no willFinishOperation callback fired for non-Procedure Operation subclasses,\n            //    and no error information is automatically available when finished.)\n\n            // Add a completion block to invoke the did finish delegate method\n            operation.addCompletionBlock { [weak self, weak operation] in\n                if let queue = self, let operation = operation {\n                    queue.delegate?.procedureQueue(queue, didFinishOperation: operation)\n                }\n            }\n\n            if let delegate = delegate {\n\n                // WillAddOperation delegate\n                (delegate.procedureQueue(self, willAddOperation: operation, context: context) ?? _SyncAlreadyAvailableFuture()).then(on: dispatchQueue) {\n\n                    super.addOperation(operation)\n\n                    delegate.procedureQueue(self, didAddOperation: operation, context: context)\n\n                    promise.complete()\n                }\n            }\n            else {\n                super.addOperation(operation)\n\n                promise.complete()\n            }\n\n            return\n        }\n\n        // Procedure subclass\n\n        procedure.log.verbose.message(\"Adding to queue\")\n\n        /// Add an observer to invoke the will finish delegate method\n        procedure.addWillFinishBlockObserver { [weak self] procedure, error, pendingFinish in\n            if let queue = self {\n                queue.delegate?.procedureQueue(queue, willFinishProcedure: procedure, with: error)?.then(on: queue.dispatchQueue) {\n                    // ensure that the observed procedure does not finish prior to the\n                    // willFinishProcedure delegate completing\n                    pendingFinish.doThisBeforeEvent()\n                }\n            }\n        }\n\n        /// Add an observer to invoke the did finish delegate method\n        procedure.addDidFinishBlockObserver { [weak self] procedure, error in\n            if let queue = self {\n                queue.delegate?.procedureQueue(queue, didFinishProcedure: procedure, with: error)\n            }\n        }\n\n        // Indicate to the operation that it is to be enqueued\n        procedure.willEnqueue(on: self)\n\n        if let delegate = delegate {\n\n            // WillAddProcedure delegate\n            (delegate.procedureQueue(self, willAddProcedure: procedure, context: context) ?? _SyncAlreadyAvailableFuture()).then(on: dispatchQueue) {\n\n                // Step 2:\n                self._add_step2(procedure: procedure, context: context, promise: promise)\n            }\n        }\n        else {\n\n            // if no delegate, proceed to Step 2 directly:\n            _add_step2(procedure: procedure, context: context, promise: promise)\n        }\n    }\n\n    // Step 2: pendingQueueStart()\n    //         super.addOperation()\n    //         Call async DidAdd delegate method, .then(onQueue: )\n    //\n    private func _add_step2(procedure: Procedure, context: Any?, promise: ProcedurePromise) {\n\n        // Indicate to the Procedure that it will be added to the queue\n        // and is waiting for the queue to start it\n        procedure.pendingQueueStart()\n\n        super.addOperation(procedure)\n\n        procedure.postQueueAdd()\n\n        // DidAddProcedure delegate\n        delegate?.procedureQueue(self, didAddProcedure: procedure, context: context)\n\n        promise.complete()\n    }\n\n    // MARK: Mutual Exclusivity\n\n    fileprivate struct ExclusivityLockRequest {\n        let mutuallyExclusiveCategories: Set<String>\n        let completion: (ExclusivityLockTicket) -> Void\n    }\n\n    internal class ExclusivityLockTicket: Hashable {\n        let mutuallyExclusiveCategories: Set<String>\n        fileprivate init(mutuallyExclusiveCategories: Set<String>)\n        {\n            self.mutuallyExclusiveCategories = mutuallyExclusiveCategories\n        }\n        static func ==(lhs: ExclusivityLockTicket, rhs: ExclusivityLockTicket) -> Bool {\n            return ObjectIdentifier(lhs) == ObjectIdentifier(rhs)\n        }\n        \n        func hash(into hasher: inout Hasher) {\n            hasher.combine(ObjectIdentifier(self).hashValue)\n        }\n    }\n\n    /// Requests a Mutual Exclusivity lock for a set of categories, taking into account\n    /// the ProcedureQueue's `isSuspended` status.\n    ///\n    /// If the ProcedureQueue is suspended, the request is queued until the ProcedureQueue is resumed.\n    /// If the ProcedureQueue is running, the lock request is processed (asynchronously).\n    ///\n    /// Once the lock request is granted (asynchronously), this function again checks whether the\n    /// ProcedureQueue is suspended. If it is, the lock is immediately released and a future attempt\n    /// is queued for when the ProcedureQueue is resumed.\n    ///\n    /// The completion block is provided an `ExclusivityLockTicket`. Once the Procedure has started,\n    /// it *must* internally call ProcedureQueue's `procedureClaimLock(withTicket:completion:)`\n    /// to officially \"claim\" the lock to ensure that Mutual Exclusivity is, in fact, enforced.\n    /// (This mechanic allows the ProcedureQueue to safely handle various tricky situations\n    /// caused by the asynchronous nature of suspending vs. when/how Foundation.Operation\n    /// internally decides to start Operations on the queue.)\n    ///\n    /// - Parameters:\n    ///   - mutuallyExclusiveCategories: a Set of mutually exclusive categories (Strings)\n    ///   - completion: a block called once a ExclusivityLockTicket has been granted by the ProcedureQueue\n    internal func requestLock(for mutuallyExclusiveCategories: Set<String>, completion: @escaping (ExclusivityLockTicket) -> Void) {\n\n        assert(!mutuallyExclusiveCategories.isEmpty, \"requestLock called with an empty set of categories\")\n\n        let proceed: Bool = suspendLock.withCriticalScope {\n            guard !super.isSuspended else {\n                // The ProcedureQueue is currently suspended\n                // Queue a future lock request attempt (once the queue is resumed)\n                queuedProcedureLockRequests.append(\n                    ExclusivityLockRequest(mutuallyExclusiveCategories: mutuallyExclusiveCategories, completion: completion)\n                )\n                return false\n            }\n            return true\n        }\n        guard proceed else { return }\n\n        _requestLockAsync(for: mutuallyExclusiveCategories, completion: completion)\n    }\n\n    fileprivate func _requestLockAsync(for mutuallyExclusiveCategories: Set<String>, completion: @escaping (ExclusivityLockTicket) -> Void) {\n\n        assert(!mutuallyExclusiveCategories.isEmpty, \"requestLock called with an empty set of categories\")\n\n        // Request a lock from the ExclusivityManager.\n        ExclusivityManager.sharedInstance.requestLock(for: mutuallyExclusiveCategories) {\n            // Once the lock is acquired\n            let optionalTicket: ExclusivityLockTicket? = self.suspendLock.withCriticalScope {\n                guard !super.isSuspended else {\n                    // If by the time the lock request is granted the Procedure is suspended,\n                    // immediately release the lock and queue a future lock request attempt\n                    // (once the ProcedureQueue is resumed)\n                    ExclusivityManager.sharedInstance.unlock(categories: mutuallyExclusiveCategories)\n                    self.queuedProcedureLockRequests.append(\n                        ExclusivityLockRequest(mutuallyExclusiveCategories: mutuallyExclusiveCategories, completion: completion)\n                    )\n                    return nil\n                }\n                // If by the time the lock request succeeds the ProcedureQueue is not suspended,\n                // return an ExclusivityLockTicket (which is recorded within the ProcedureQueue)\n                let ticket = ExclusivityLockTicket(mutuallyExclusiveCategories: mutuallyExclusiveCategories)\n                self.unclaimedExclusivityLockTickets.insert(ticket)\n                return ticket\n            }\n\n            guard let ticket = optionalTicket else { return }\n            completion(ticket)\n        }\n    }\n\n    /// Called by a Procedure, *once the ProcedureQueue has started the Procedure*,\n    /// to claim an outstanding Exclusivity Lock\n    ///\n    /// If the ProcedureQueue has released the lock in the interim (for example, if\n    /// it was suspended), this function issues a new lock request on behalf of\n    /// the Procedure.\n    internal func procedureClaimLock(withTicket ticket: ExclusivityLockTicket, completion: @escaping () -> Void) {\n        let claimedLock: Bool = suspendLock.withCriticalScope {\n            guard unclaimedExclusivityLockTickets.remove(ticket) != nil else {\n                //\n                // The ticket is no longer valid (likely because the ProcedureQueue was suspended\n                // and released the exclusivity lock in the interim)\n                //\n                // Initiate a new async lock request on behalf of the Procedure\n                //\n                // NOTE: Since the Procedure has *already been started* by the ProcedureQueue,\n                // there is no point in trying to delay its execution further if the\n                // ProcedureQueue is now suspended.\n                //\n                // Foundation.OperationQueue already only guarantees that:\n                //   \"Setting [isSuspended] to true prevents the queue from starting any queued\n                //    operations, but already executing operations continue to execute.\"\n                // https://developer.apple.com/documentation/foundation/operationqueue/1415909-issuspended\n                //\n                // Therefore, instead of calling the *ProcedureQueue's* `requestLock` function,\n                // (which *would* delay requesting a lock if the ProcedureQueue is suspended),\n                // we use the ExclusivityManager directly here.\n                //\n\n                ExclusivityManager.sharedInstance.requestLock(for: ticket.mutuallyExclusiveCategories, completion: completion)\n                return false\n            }\n            return true\n        }\n        guard claimedLock else { return }\n\n        // Lock was successfully claimed - call the completion block\n        completion()\n    }\n\n    internal func unlock(mutuallyExclusiveCategories categories: Set<String>) {\n        ExclusivityManager.sharedInstance.unlock(categories: categories)\n    }\n\n    // MARK: Condition Evaluation\n\n    // When a Procedure's EvaluateConditions Operation is ready to begin (i.e. when all dependencies\n    // have finished), it calls requestEvaluation(of: self) to ask the ProcedureQueue associated\n    // with its Procedure to begin its evaluation.\n    //\n    // If the ProcedureQueue is suspended, it queues the request until it the queue is un-suspended.\n    // If the ProcedureQueue is running, the condition evaluation is started (asynchronously).\n    internal func requestEvaluation(of conditionEvaluator: Procedure.EvaluateConditions) {\n        let dispatchEvaluator: Bool = suspendLock.withCriticalScope {\n            guard !super.isSuspended else {\n                // The ProcedureQueue is currently suspended\n                // Queue a future dispatch of the condition evaluator (once the queue is resumed)\n                queuedConditionEvaluators.append(conditionEvaluator)\n                return false\n            }\n            return true\n        }\n        guard dispatchEvaluator else { return }\n\n        // Since the ProcedureQueue wasn't suspended, dispatch condition evaluation\n        conditionEvaluator.queue.async {\n            conditionEvaluator.start()\n        }\n    }\n}\n\npublic extension ProcedureQueue {\n    /**\n     Add operations to the queue as an array\n     \n     - parameter operations: a sequence of `Operation` instances.\n     - parameter context: an optional parameter that is passed-through to the Will/DidAdd delegate callbacks\n     - returns: a `ProcedureFuture` that is signaled once the operations have been added to the `ProcedureQueue`\n     */\n    @discardableResult final func addOperations<S: Sequence>(_ operations: S, withContext context: Any? = nil) -> ProcedureFuture where S.Iterator.Element: Operation {\n\n        let futures = operations.map {\n            addOperation($0, withContext: context)\n        }\n\n        return futures.future\n    }\n\n    /**\n     Add operations to the queue as a variadic parameter\n\n     - parameter operations: a variadic array of `Operation` instances.\n     - parameter context: an optional parameter that is passed-through to the Will/DidAdd delegate callbacks\n     - returns: a `ProcedureFuture` that is signaled once the operations have been added to the `ProcedureQueue`\n     */\n    @discardableResult final func addOperations(_ operations: Operation..., withContext context: Any? = nil) -> ProcedureFuture {\n        return addOperations(operations, withContext: context)\n    }\n}\n\n/// Public extensions on OperationQueue\npublic extension OperationQueue {\n\n    /**\n     Add operations to the queue as an array\n     - parameter operations: a array of `Operation` instances.\n     */\n    final func addOperations<S>(_ operations: S) where S: Sequence, S.Iterator.Element: Operation {\n        addOperations(Array(operations), waitUntilFinished: false)\n    }\n\n    /**\n     Add operations to the queue as a variadic parameter\n     - parameter operations: a variadic array of `Operation` instances.\n     */\n    final func addOperations(_ operations: Operation...) {\n        addOperations(operations)\n    }\n}\n\n/// A ProcedureFuture that is used internally to shortcut dispatching async when no waiting is required.\nfileprivate class _SyncAlreadyAvailableFuture: ProcedureFuture {\n    internal init() { }\n\n    deinit {\n        group.leave()\n    }\n\n    public override func then(on eventQueueProvider: QueueProvider, block: @escaping () -> Void) {\n        block()\n    }\n}\n\n// MARK: - Unavilable & Renamed\n\n@available(*, unavailable, renamed: \"ProcedureQueueDelegate\")\npublic protocol OperationQueueDelegate: class { }\n\npublic extension ProcedureQueue {\n\n    @available(*, deprecated, renamed: \"addOperation(_:withContext:)\", message: \"This has been renamed to use Swift 3/4 naming conventions\")\n    @discardableResult func add(operation: Operation, withContext context: Any? = nil) -> ProcedureFuture {\n        return addOperation(operation, withContext: context)\n    }\n\n    @available(*, deprecated, renamed: \"addOperations(_:withContext:)\", message: \"This has been renamed to use Swift 3/4 naming conventions\")\n    @discardableResult final func add<S: Sequence>(operations: S, withContext context: Any? = nil) -> ProcedureFuture where S.Iterator.Element: Operation {\n        return addOperations(operations, withContext: context)\n    }\n\n    @available(*, deprecated, renamed: \"addOperations(_:withContext:)\", message: \"This has been renamed to use Swift 3/4 naming conventions\")\n    final func add(operations: Operation..., withContext context: Any? = nil) -> ProcedureFuture {\n        return addOperations(operations, withContext: context)\n    }\n}\n\npublic extension OperationQueue {\n\n    @available(*, deprecated, renamed: \"addOperations(_:)\", message: \"This has been renamed to use Swift 3/4 naming conventions\")\n    final func add<S>(operations: S) where S: Sequence, S.Iterator.Element: Operation {\n        addOperations(operations)\n    }\n\n    @available(*, deprecated, renamed: \"addOperations(_:)\", message: \"This has been renamed to use Swift 3/4 naming conventions\")\n    final func add(operations: Operation...) {\n        addOperations(operations)\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKit/ProcedureResult.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\npublic enum Pending<T> {\n\n    case pending\n    case ready(T)\n\n    public var isPending: Bool {\n        guard case .pending = self else { return false }\n        return true\n    }\n\n    public var value: T? {\n        guard case let .ready(value) = self else { return nil }\n        return value\n    }\n\n    public init(_ value: T?) {\n        self = value.pending\n    }\n}\n\nextension Pending: Equatable where T: Equatable {\n\n    public static func == (lhs: Pending<T>, rhs: Pending<T>) -> Bool {\n        switch (lhs, rhs) {\n        case (.pending, .pending):\n            return true\n        case let (.ready(lhsValue), .ready(rhsValue)):\n            return lhsValue == rhsValue\n        default:\n            return false\n        }\n    }\n}\n\npublic extension Optional {\n\n    var pending: Pending<Wrapped> {\n        switch self {\n        case .none:\n            return .pending\n        case let .some(value):\n            return .ready(value)\n        }\n    }\n}\n\npublic protocol ProcedureResultProtocol {\n    associatedtype Value\n\n    var value: Value? { get }\n\n    var error: Error? { get }\n}\n\nextension Pending: ProcedureResultProtocol where T: ProcedureResultProtocol {\n\n    public var success: T.Value? {\n        return value?.value\n    }\n\n    public var error: Error? {\n        return value?.error\n    }\n}\n\npublic enum ProcedureResult<T>: ProcedureResultProtocol {\n\n    case success(T)\n    case failure(Error)\n\n    public var value: T? {\n        guard case let .success(value) = self else { return nil }\n        return value\n    }\n\n    public var error: Error? {\n        guard case let .failure(error) = self else { return nil }\n        return error\n    }\n}\n\nextension ProcedureResult: Equatable where T: Equatable {\n\n    public static func == (lhs: ProcedureResult<T>, rhs: ProcedureResult<T>) -> Bool {\n        switch (lhs, rhs) {\n        case let (.success(lhsValue), .success(rhsValue)):\n            return lhsValue == rhsValue\n        default:\n            return false\n        }\n    }\n}\n\npublic protocol InputProcedure: ProcedureProtocol {\n\n    associatedtype Input\n\n    var input: Pending<Input> { get set }\n}\n\npublic protocol OutputProcedure: ProcedureProtocol {\n\n    associatedtype Output\n\n    var output: Pending<ProcedureResult<Output>> { get set }\n}\n\npublic let pendingVoid: Pending<Void> = .ready(())\npublic let success: ProcedureResult<Void> = .success(())\npublic let pendingVoidResult: Pending<ProcedureResult<Void>> = .ready(success)\n\n// MARK: - Extensions\n\npublic extension OutputProcedure {\n\n    func finish(withResult result: ProcedureResult<Output>) {\n        output = .ready(result)\n        finish(with: output.error)\n    }\n}\n\nprivate enum InjectionResult<Dependency: OutputProcedure> {\n    case success(Dependency.Output)\n    case cancel(Error)\n}\n\npublic extension ProcedureProtocol {\n\n    /**\n     Access the completed dependency Procedure before `self` is\n     started. This can be useful for transfering results/data between\n     Procedures.\n\n     - parameter dependency: any `Procedure` subclass.\n     - parameter block: a closure which receives `self`, the dependent\n     operation, and an array of `ErrorType`, and returns Void.\n     (The closure is automatically dispatched on the EventQueue\n     of the receiver, if the receiver is a Procedure or supports the\n     QueueProvider protocol).\n     - returns: `self` - so that injections can be chained together.\n     */\n    @discardableResult func inject<Dependency: ProcedureProtocol>(dependency: Dependency, block: @escaping (Self, Dependency, Error?) -> Void) -> Self {\n        precondition(dependency !== self, \"Cannot inject result of self into self.\")\n\n        dependency.addWillFinishBlockObserver(synchronizedWith: (self as? QueueProvider)) { [weak self] dependency, error, _ in\n            guard let this = self else { return }\n            block(this, dependency, error)\n        }\n\n        dependency.addDidCancelBlockObserver { [weak self] _, error in\n            guard let this = self else { return }\n            if let dependencyError = error {\n                this.cancel(with: ProcedureKitError.dependency(cancelledWithError: dependencyError))\n            }\n            else {\n                this.cancel(with: ProcedureKitError.dependenciesCancelled())\n            }\n        }\n\n        add(dependency: dependency)\n\n        return self\n    }\n\n    @discardableResult func injectResult<Dependency: OutputProcedure>(from dependency: Dependency, block: @escaping (Self, Dependency.Output) -> Void) -> Self {\n\n        func injectionResultGiven(_ pendingResult: Pending<ProcedureResult<Dependency.Output>>, and error: Error?) -> InjectionResult<Dependency> {\n\n            if let error = error {\n                return .cancel(ProcedureKitError.dependency(finishedWithError: error))\n            }\n\n            switch pendingResult {\n\n            case .pending:\n                return .cancel(ProcedureKitError.requirementNotSatisfied())\n\n            case let .ready(.failure(error)):\n                return .cancel(ProcedureKitError.dependency(finishedWithError: error))\n\n            case let .ready(.success(output)):\n                return .success(output)\n            }\n        }\n\n        return inject(dependency: dependency) { procedure, dependency, error in\n\n            switch injectionResultGiven(dependency.output, and: error) {\n            case let .cancel(e):\n                procedure.cancel(with: e)\n            case let .success(output):\n                block(procedure, output)\n            }\n        }\n    }\n}\n\npublic extension InputProcedure {\n\n    /// Notifies observers that the input was set .ready\n    func didSetInputReady() {\n        guard !input.isPending, let procedure = self as? Procedure else { return }\n        procedure.eventQueue.dispatch {\n            procedure.dispatchObservers(pendingEvent: PendingEvent.execute) { (observer, event) in\n                observer.didSetInputReady(on: procedure)\n            }\n        }\n    }\n\n    @discardableResult func injectResult<Dependency: OutputProcedure>(from dependency: Dependency, via block: @escaping (Dependency.Output) throws -> Input) -> Self {\n\n        return injectResult(from: dependency) { (procedure, output) in\n            do {\n                procedure.input = .ready(try block(output))\n\n                procedure.didSetInputReady()\n            }\n            catch {\n                procedure.cancel(with: error)\n            }\n        }\n    }\n\n    @discardableResult func injectResult<Dependency: OutputProcedure>(from dependency: Dependency) -> Self where Dependency.Output == Input {\n        return injectResult(from: dependency, via: { $0 })\n    }\n\n    @discardableResult func injectResult<Dependency: OutputProcedure>(from dependency: Dependency) -> Self where Dependency.Output == Optional<Input> {\n        return injectResult(from: dependency) { output in\n            guard let output = output else {\n                throw ProcedureKitError.requirementNotSatisfied()\n            }\n            return output\n        }\n    }\n}\n\n// MARK: - Bindings\n\npublic extension InputProcedure {\n\n    func bind<T: InputProcedure>(to target: T) where T.Input == Self.Input {\n        addDidSetInputReadyBlockObserver { (procedure) in\n            target.input = procedure.input\n        }\n    }\n}\n\npublic extension OutputProcedure {\n\n    func bind<T: OutputProcedure>(from source: T) where T.Output == Self.Output {\n        source.addWillFinishBlockObserver { [weak self] (source, _, _) in\n            guard let strongSelf = self else { return }\n            strongSelf.output = source.output\n        }\n    }\n}\n\n\n\n"
  },
  {
    "path": "Sources/ProcedureKit/Profiler.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport Foundation\n\npublic enum ProcedureEvent: Int {\n    case attached = 0, started, cancelled, produced, finished\n}\n\nextension ProcedureEvent: CustomStringConvertible {\n    public var description: String {\n        switch self {\n        case .attached: return \"Attached\"\n        case .started: return \"Started\"\n        case .cancelled: return \"Cancelled\"\n        case .produced: return \"Produced\"\n        case .finished: return \"Finished\"\n        }\n    }\n}\n\n// MARK: - ProcedureProfilerReporter\npublic protocol ProcedureProfilerReporter {\n    func finishedProfiling(withResult result: ProfileResult)\n}\n\n// MARK: - ProfileResult\npublic struct ProfileResult {\n    public let identity: Procedure.Identity\n    public let created: TimeInterval\n    public let attached: TimeInterval\n    public let started: TimeInterval\n    public let cancelled: TimeInterval?\n    public let finished: TimeInterval?\n    public let children: [ProfileResult]\n}\n\n// MARK: - PendingResult\nstruct PendingProfileResult {\n\n    let created: TimeInterval\n    let identity: Pending<Procedure.Identity>\n    let attached: Pending<TimeInterval>\n    let started: Pending<TimeInterval>\n    let cancelled: Pending<TimeInterval>\n    let finished: Pending<TimeInterval>\n    let children: [ProfileResult]\n\n    var isPending: Bool {\n        return identity.isPending || attached.isPending || started.isPending || (cancelled.isPending && finished.isPending)\n    }\n\n    func createResult() -> ProfileResult? {\n        guard !isPending, let\n            identity = identity.value,\n            let attached = attached.value,\n            let started = started.value\n        else { return nil }\n\n        return ProfileResult(identity: identity, created: created, attached: attached, started: started, cancelled: cancelled.value, finished: finished.value, children: children)\n    }\n\n    func set(identity newIdentity: Procedure.Identity) -> PendingProfileResult {\n        guard identity.isPending else { return self }\n        return PendingProfileResult(created: created, identity: .ready(newIdentity), attached: attached, started: started, cancelled: cancelled, finished: finished, children: children)\n    }\n\n    func attach(now: TimeInterval = CFAbsoluteTimeGetCurrent() as TimeInterval) -> PendingProfileResult {\n        guard attached.isPending else { return self }\n        return PendingProfileResult(created: created, identity: identity, attached: .ready(now - created), started: started, cancelled: cancelled, finished: finished, children: children)\n    }\n\n    func start(now: TimeInterval = CFAbsoluteTimeGetCurrent() as TimeInterval) -> PendingProfileResult {\n        guard started.isPending else { return self }\n        return PendingProfileResult(created: created, identity: identity, attached: attached, started: .ready(now - created), cancelled: cancelled, finished: finished, children: children)\n    }\n\n    func cancel(now: TimeInterval = CFAbsoluteTimeGetCurrent() as TimeInterval) -> PendingProfileResult {\n        guard cancelled.isPending else { return self }\n        return PendingProfileResult(created: created, identity: identity, attached: attached, started: started, cancelled: .ready(now - created), finished: finished, children: children)\n    }\n\n    func finish(now: TimeInterval = CFAbsoluteTimeGetCurrent() as TimeInterval) -> PendingProfileResult {\n        guard finished.isPending else { return self }\n        return PendingProfileResult(created: created, identity: identity, attached: attached, started: started, cancelled: cancelled, finished: .ready(now - created), children: children)\n    }\n\n    func add(child: ProfileResult) -> PendingProfileResult {\n        var newChildren = children\n        newChildren.append(child)\n        return PendingProfileResult(created: created, identity: identity, attached: attached, started: started, cancelled: cancelled, finished: finished, children: newChildren)\n    }\n}\n\n// MARK: ProcedureProfiler\n\npublic final class ProcedureProfiler: Identifiable, Equatable {\n\n    public let identity = UUID()\n\n    enum Reporter {\n        case parent(ProcedureProfiler)\n        case reporters([ProcedureProfilerReporter])\n    }\n\n    let queue = DispatchQueue(label: \"run.kit.ProcedureKit.Profiler\")\n    let reporter: Reporter\n\n    var result = PendingProfileResult(created: CFAbsoluteTimeGetCurrent() as TimeInterval, identity: .pending, attached: .pending, started: .pending, cancelled: .pending, finished: .pending, children: [])\n    var children: [Procedure.Identity] = []\n    var finishedOrCancelled = false\n\n    var pending: Bool {\n        return result.isPending || (children.count > 0)\n    }\n\n    public convenience init(reporters: [ProcedureProfilerReporter]) {\n        self.init(reporter: .reporters(reporters))\n    }\n\n    convenience init(parent: ProcedureProfiler) {\n        self.init(reporter: .parent(parent))\n    }\n\n    init(reporter: Reporter) {\n        self.reporter = reporter\n    }\n\n    func addMetric(now: TimeInterval = CFAbsoluteTimeGetCurrent() as TimeInterval, forEvent event: ProcedureEvent) {\n        queue.sync { [weak self] in\n            guard let strongSelf = self else { return }\n            switch event {\n                case .attached:\n                    strongSelf.result = strongSelf.result.attach(now: now)\n                case .started:\n                    strongSelf.result = strongSelf.result.start(now: now)\n                case .cancelled:\n                    strongSelf.result = strongSelf.result.cancel(now: now)\n                    strongSelf.finishedOrCancelled = true\n                case .finished:\n                    strongSelf.result = strongSelf.result.finish(now: now)\n                    strongSelf.finishedOrCancelled = true\n                default:\n                    break\n            }\n            strongSelf.finish()\n        }\n    }\n\n    func addChild(operation: Operation, now: TimeInterval = CFAbsoluteTimeGetCurrent() as TimeInterval) {\n        if let procedure = operation as? Procedure {\n            let profiler = ProcedureProfiler(parent: self)\n            procedure.addObserver(profiler)\n            queue.sync { [weak self] in\n                self?.children.append(procedure.identity)\n            }\n        }\n    }\n\n    func finish() {\n        guard finishedOrCancelled && !pending, let result = result.createResult() else { return }\n        reporter.finishedProfiling(withResult: result)\n    }\n}\n\nextension ProcedureProfiler.Reporter: ProcedureProfilerReporter {\n\n    func finishedProfiling(withResult result: ProfileResult) {\n        switch self {\n        case .parent(let parent):\n            parent.finishedProfiling(withResult: result)\n        case .reporters(let reporters):\n            reporters.forEach { $0.finishedProfiling(withResult: result)  }\n        }\n    }\n}\n\nextension ProcedureProfiler: ProcedureProfilerReporter {\n\n    public func finishedProfiling(withResult result: ProfileResult) {\n        queue.sync { [weak self] in\n            guard let strongSelf = self else { return }\n            if let index = strongSelf.children.firstIndex(of: result.identity) {\n                strongSelf.result = strongSelf.result.add(child: result)\n                strongSelf.children.remove(at: index)\n            }\n            strongSelf.finish()\n        }\n    }\n}\n\nextension ProcedureProfiler: ProcedureObserver {\n\n    public func didAttach(to procedure: Procedure) {\n        queue.sync { [unowned self] in\n            self.result = self.result.set(identity: procedure.identity)\n        }\n        addMetric(forEvent: .attached)\n    }\n\n    public func will(execute procedure: Procedure, pendingExecute: PendingExecuteEvent) {\n        addMetric(forEvent: .started)\n    }\n\n    public func did(cancel procedure: Procedure) {\n        addMetric(forEvent: .cancelled)\n    }\n\n    public func did(finish procedure: Procedure, with error: Error?) {\n        addMetric(forEvent: .finished)\n    }\n\n    public func procedure(_ procedure: Procedure, willAdd newOperation: Operation) {\n        addChild(operation: newOperation)\n    }\n}\n\n// MARK: - Reporters\nstruct PrintableProfileResult: CustomStringConvertible {\n    let indentation: Int\n    let spacing: Int\n    let result: ProfileResult\n\n    func addRow(withInterval interval: TimeInterval, text: String) -> String {\n        return \"\\(createIndentation())+\\(interval)\\(createSpacing())\\(text)\\n\"\n    }\n\n    func addRow(withInterval interval: TimeInterval, forEvent event: ProcedureEvent) -> String {\n        return addRow(withInterval: interval, text: event.description)\n    }\n\n    var description: String {\n        get {\n            var output = \"\"\n            output += addRow(withInterval: result.attached, forEvent: .attached)\n            output += addRow(withInterval: result.started, forEvent: .started)\n\n            for child in result.children {\n                output += \"\\(createIndentation())-> Spawned \\(child.identity) with profile results\\n\"\n                output += \"\\(PrintableProfileResult(indentation: indentation + 2, spacing: spacing, result: child))\"\n            }\n\n            if let cancelled = result.cancelled {\n                output += addRow(withInterval: cancelled, forEvent: .cancelled)\n            }\n\n            if let finished = result.finished {\n                output += addRow(withInterval: finished, forEvent: .finished)\n            }\n\n            return output\n        }\n    }\n\n    init(indentation: Int = 0, spacing: Int = 1, result: ProfileResult) {\n        self.indentation = indentation\n        self.spacing = spacing\n        self.result = result\n    }\n\n    func createIndentation() -> String {\n        return String(repeating: \"\", count: indentation)\n    }\n\n    func createSpacing() -> String {\n        return String(repeating: \"\", count: spacing)\n    }\n}\n\npublic class _ProcedureProfileLogger<Settings: LogSettings>: Log.Channels<Settings>, ProcedureProfilerReporter {\n\n    public func finishedProfiling(withResult result: ProfileResult) {\n        formatter = Log.Formatters.makeProcedureLogFormatter(operationName: result.identity.description)\n        current.message(\"finished profiling with results:\\n\\(PrintableProfileResult(result: result))\")\n    }\n}\n\npublic typealias ProcedureProfileLogger = _ProcedureProfileLogger<Log>\n\npublic extension ProcedureProfiler {\n\n    convenience init(_ reporter: ProcedureProfilerReporter = ProcedureProfileLogger()) {\n        self.init(reporters: [reporter])\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKit/Reachability.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n#if !os(watchOS)\n\nimport Foundation\nimport Dispatch\nimport SystemConfiguration\n\n// MARK: - Public APIs\n\npublic struct Reachability {\n\n    public enum Connectivity {\n        case any, wwan, wifi\n    }\n\n    public enum NetworkStatus: Equatable {\n        case notReachable\n        case reachable(Connectivity)\n    }\n\n    public typealias ObserverBlock = (NetworkStatus) -> Void\n\n    public struct Observer {\n        public let connectivity: Connectivity\n        public let didConnectBlock: () -> Void\n\n        public init(connectivity: Connectivity, didConnectBlock: @escaping () -> Void) {\n            self.connectivity = connectivity\n            self.didConnectBlock = didConnectBlock\n        }\n    }\n}\n\npublic enum ReachabilityError: Error {\n    case failedToCreateDefaultRouteReachability\n    case failedToSetNotifierCallback\n    case failedToSetNotifierDispatchQueue\n}\n\npublic protocol NetworkReachabilityDelegate: class {\n\n    func didChangeReachability(flags: SCNetworkReachabilityFlags)\n}\n\npublic protocol NetworkReachability {\n\n    var delegate: NetworkReachabilityDelegate? { get set }\n\n    func startNotifier(onQueue queue: DispatchQueue) throws\n\n    func stopNotifier()\n\n    //func reachabilityFlags(of: URL) -> SCNetworkReachabilityFlags?\n}\n\npublic protocol SystemReachability {\n\n    func whenReachable(via: Reachability.Connectivity, block: @escaping () -> Void)\n\n    func reachability(of: URL, block: @escaping (Reachability.NetworkStatus) -> Void)\n}\n\n// MARK: Conformance\n\npublic extension Reachability.NetworkStatus {\n\n    init(flags: SCNetworkReachabilityFlags) {\n        switch flags {\n        case _ where flags.isReachableViaWiFi:\n            self = .reachable(.wifi)\n        case _ where flags.isReachableViaWWAN:\n            #if os(iOS)\n                self = .reachable(.wwan)\n            #else\n                self = .reachable(.any)\n            #endif\n        default:\n            self = .notReachable\n        }\n    }\n\n    func isConnected(via connectivity: Reachability.Connectivity) -> Bool {\n        switch (self, connectivity) {\n        case (.notReachable, _), (.reachable(.wwan), .wifi):\n            return false\n        default:\n            return true\n        }\n    }\n}\n\npublic extension SCNetworkReachabilityFlags {\n\n    var isReachable: Bool {\n        return contains(.reachable)\n    }\n\n    var isConnectionRequired: Bool {\n        return contains(.connectionRequired)\n    }\n\n    var isInterventionRequired: Bool {\n        return contains(.interventionRequired)\n    }\n\n    var isConnectionOnTraffic: Bool {\n        return contains(.connectionOnTraffic)\n    }\n\n    var isConnectionOnDemand: Bool {\n        return contains(.connectionOnDemand)\n    }\n\n    var isTransientConnection: Bool {\n        return contains(.transientConnection)\n    }\n\n    var isALocalAddress: Bool {\n        return contains(.isLocalAddress)\n    }\n\n    var isDirectConnection: Bool {\n        return contains(.isDirect)\n    }\n\n    var isConnectionOnTrafficOrDemand: Bool {\n        return isConnectionOnTraffic || isConnectionOnDemand\n    }\n\n    var isConnectionRequiredOrTransient: Bool {\n        return isConnectionRequired || isTransientConnection\n    }\n\n    var isConnected: Bool {\n        return isReachable && !isConnectionRequired\n    }\n\n    var isOnWWAN: Bool {\n        #if os(iOS)\n            return contains(.isWWAN)\n        #else\n            return false\n        #endif\n    }\n\n    var isReachableViaWWAN: Bool {\n        #if os(iOS)\n            return isConnected && isOnWWAN\n        #else\n            return isReachable\n        #endif\n    }\n\n    var isReachableViaWiFi: Bool {\n        #if os(iOS)\n            return isConnected && !isOnWWAN\n        #else\n            return isConnected\n        #endif\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Sources/ProcedureKit/Reduce.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nopen class ReduceProcedure<Element, U>: TransformProcedure<AnySequence<Element>, U> {\n\n    public init<S: Sequence>(source: S, initial: U, nextPartialResult block: @escaping (U, Element) throws -> U) where S.Iterator.Element == Element {\n        super.init { try $0.reduce(initial, block) }\n        self.input = .ready(AnySequence(source))\n        self.output = .ready(.success(initial))\n    }\n\n    public convenience init(initial: U, nextPartialResult block: @escaping (U, Element) throws -> U) {\n        self.init(source: [], initial: initial, nextPartialResult: block)\n    }\n}\n\npublic extension OutputProcedure where Self.Output: Sequence {\n\n    func reduce<U>(_ initial: U, nextPartialResult: @escaping (U, Output.Iterator.Element) throws -> U) -> ReduceProcedure<Output.Iterator.Element, U> {\n        return ReduceProcedure(initial: initial, nextPartialResult: nextPartialResult).injectResult(from: self) { AnySequence(Array($0)) }\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKit/Repeat.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport Foundation\nimport Dispatch\n\n/// Struct to hold the values necessary for each\n/// iteration of a RepeatProcedure. It is generic\n/// over the Operation type (i.e. the type being\n/// iterated). However, it also holds an optional\n/// Delay property, and an optional ConfigureBlock.\npublic struct RepeatProcedurePayload<T: Operation> {\n    public typealias ConfigureBlock = (T) -> Void\n\n    /// - returns: the operation value\n    public let operation: T\n    /// - returns: the optional Delay\n    public let delay: Delay?\n    /// - returns: the optional ConfigureBlock\n    public let configure: ConfigureBlock?\n\n    /// Initializes a payload struct.\n    ///\n    /// - Parameters:\n    ///   - operation: an instance of an Operation subclass T\n    ///   - delay: an optional Delay value, which defaults to nil\n    ///   - configure: an optional closure which receives the operation, and which defaults to nil\n    public init(operation: T, delay: Delay? = nil, configure: ConfigureBlock? = nil) {\n        self.operation = operation\n        self.delay = delay\n        self.configure = configure\n    }\n\n    /// Sets the delay property.\n    ///\n    /// - Parameter newDelay: the new Delay property\n    /// - Returns: a new RepeatProcedurePayload value.\n    public func set(delay newDelay: Delay?) -> RepeatProcedurePayload {\n        return RepeatProcedurePayload(operation: operation, delay: newDelay, configure: configure)\n    }\n}\n\n/// RepeatProcedure is a GroupProcedure subclass which can be used to create\n/// polling or repeating procedures. Each child procedure is a new instance\n/// of the same Operation subclass T. For example `RepeatProcedure<MyOperation>`\n/// will create and execute instances of MyOperation repeatedly, and we say\n/// that the RepeatProcedure is generic over T, which in this case is\n/// MyOperation.\n///\n/// While RepeatProcedure can be initialized in a variety of ways, it helps\n/// to understand that it works by using an Iterator. The iterator's payload\n/// is a structure which holds an instance of the Operation subclass (`T`),\n/// and optional Delay value, and an optional configuration block. The block\n/// receives the instance, and can be used to prepare the operation before\n/// it is executed.\n///\n/// All of the initializers available will ultimately create the underlying\n/// iterator.\nopen class RepeatProcedure<T: Operation>: GroupProcedure {\n\n    public typealias Payload = RepeatProcedurePayload<T>\n\n    static func create<V>(withMax max: Int? = nil, andIterator base: V) -> (T, AnyIterator<Payload>) where V: IteratorProtocol, V.Element == Payload {\n\n        var base = base\n        guard let payload = base.next() else { preconditionFailure(\"Payload Iterator must return an instance initially.\") }\n\n        if let max = max {\n            return (payload.operation, AnyIterator(FiniteIterator(base, limit: max - 1)))\n        }\n        return (payload.operation, AnyIterator(base))\n    }\n\n    static func create<D, V>(withMax max: Int? = nil, andDelay delay: D, andIterator base: V) -> (T, AnyIterator<Payload>) where D: IteratorProtocol, D.Element == Delay, V: IteratorProtocol, V.Element == T {\n        let tmp = MapIterator(PairIterator(primary: base, secondary: delay)) { Payload(operation: $0.0, delay: $0.1) }\n        return create(withMax: max, andIterator: tmp)\n    }\n\n    private let _repeatStateLock = PThreadMutex()\n\n    @discardableResult\n    fileprivate func synchronise<T>(block: () -> T) -> T {\n        return _repeatStateLock.withCriticalScope(block: block)\n    }\n\n    private var _iterator: AnyIterator<Payload>\n\n    private var _previous: T?\n\n    /// - returns: the previous executing operation instance of T\n    public internal(set) var previous: T? {\n        get { return synchronise { _previous } }\n        set { synchronise { _previous = newValue } }\n    }\n\n    private var _current: T\n\n    /// - returns: the currently executing operation instance of T\n    public internal(set) var current: T {\n        get { return synchronise { _current } }\n        set { synchronise { _current = newValue } }\n    }\n\n    private var _count: Int = 1\n\n    /// - returns: the number of operation instances\n    public var count: Int {\n        return synchronise { _count }\n    }\n\n    private var _configure: Payload.ConfigureBlock = { _ in }\n    internal var configure: Payload.ConfigureBlock {\n        return synchronise { _configure }\n    }\n\n    /// Initialize RepeatProcedure with an iterator, the element of the iterator a `RepeatProcedurePayload<T>`.\n    /// Other arguments allow for specific dispatch queues, and a maximum count of iteratations.\n    ///\n    /// - Parameters:\n    ///   - dispatchQueue: an optional DispatchQueue, which defaults to nil\n    ///   - max: an optional Int, which defaults to nil.\n    ///   - iterator: a generic IteratorProtocol type, with a Payload Element type\n    public init<PayloadIterator>(dispatchQueue: DispatchQueue? = nil, max: Int? = nil, iterator: PayloadIterator) where PayloadIterator: IteratorProtocol, PayloadIterator.Element == Payload {\n        (_current, _iterator) = RepeatProcedure.create(withMax: max, andIterator: iterator)\n        super.init(dispatchQueue: dispatchQueue, operations: [])\n    }\n\n    /// Initialize RepeatProcedure with two iterators, the first one has `Delay` elements, the\n    /// second has `T` elements - i.e. the Operation subclass to be repeated.\n    /// Other arguments allow for specific dispatch queues, and a maximum count of iteratations.\n    ///\n    /// - Parameters:\n    ///   - dispatchQueue: an optional DispatchQueue, which defaults to nil\n    ///   - max: an optional Int, which defaults to nil.\n    ///   - delay: a generic IteratorProtocol type, with a Delay Element type\n    ///   - iterator: a generic IteratorProtocol type, with a T Element type\n    public init<OperationIterator, DelayIterator>(dispatchQueue: DispatchQueue? = nil, max: Int? = nil, delay: DelayIterator, iterator: OperationIterator) where OperationIterator: IteratorProtocol, DelayIterator: IteratorProtocol, OperationIterator.Element == T, DelayIterator.Element == Delay {\n        (_current, _iterator) = RepeatProcedure.create(withMax: max, andDelay: delay, andIterator: iterator)\n        super.init(dispatchQueue: dispatchQueue, operations: [])\n    }\n\n    /// Initialize RepeatProcedure with a WaitStrategy and an iterator, which has `T` type\n    /// elements - i.e. the Operation subclass to be repeated.\n    /// Other arguments allow for specific dispatch queues, and a maximum count of iteratations.\n    ///\n    /// - Parameters:\n    ///   - dispatchQueue: an optional DispatchQueue, which defaults to nil\n    ///   - max: an optional Int, which defaults to nil.\n    ///   - wait: a WaitStrategy value, which defaults to .immediate\n    ///   - iterator: a generic IteratorProtocol type, with a T Element type\n    public init<OperationIterator>(dispatchQueue: DispatchQueue? = nil, max: Int? = nil, wait: WaitStrategy = .immediate, iterator: OperationIterator) where OperationIterator: IteratorProtocol, OperationIterator.Element == T {\n        (_current, _iterator) = RepeatProcedure.create(withMax: max, andDelay: Delay.iterator(wait.iterator), andIterator: iterator)\n        super.init(dispatchQueue: dispatchQueue, operations: [])\n    }\n\n    /// Initialize RepeatProcedure with a WaitStrategy and a closure. The closure returns\n    /// an optional instance of T, i.e. the Operation subclass to be repeated.\n    /// Other arguments allow for specific dispatch queues, and a maximum count of iteratations.\n    ///\n    /// This is the most convenient initializer, you can use it like this:\n    /// ```swift\n    ///    let procedure = RepeatProcedure { MyOperation() }\n    ///    let procedure = RepeatProcedure(dispatchQueue: target) { MyOperation() }\n    ///    let procedure = RepeatProcedure(dispatchQueue: target, max: 5) { MyOperation() }\n    ///    let procedure = RepeatProcedure(dispatchQueue: target, max: 5, wait: .constant(10)) { MyOperation() }\n    /// ```\n    ///\n    /// - Parameters:\n    ///   - dispatchQueue: an optional DispatchQueue, which defaults to nil\n    ///   - max: an optional Int, which defaults to nil.\n    ///   - wait: a WaitStrategy value, which defaults to .immediate\n    ///   - body: an espacing closure which returns an optional T\n    public init(dispatchQueue: DispatchQueue? = nil, max: Int? = nil, wait: WaitStrategy = .immediate, body: @escaping () -> T?) {\n        (_current, _iterator) = RepeatProcedure.create(withMax: max, andDelay: Delay.iterator(wait.iterator), andIterator: AnyIterator(body))\n        super.init(dispatchQueue: dispatchQueue, operations: [])\n    }\n\n    /// Public override of `execute()` which configures and adds the first operation\n    ///\n    /// - IMPORTANT: If subclassing `RepeatProcedure` and overriding this method, consider\n    /// carefully whether / when / how you should call `super.execute()`.\n    open override func execute() {\n        let current = _repeatStateLock.withCriticalScope { () -> T in\n            _configure(_current)\n            return _current\n        }\n        addChild(current)\n        super.execute()\n    }\n\n    /// Handle child willFinish event\n    ///\n    /// This is used by RepeatProcedure to trigger adding the next Procedure,\n    /// and calls `super.child(_:willFinishWithErrors:)` to get the default\n    /// GroupProcedure error-handling behavior.\n    ///\n    /// - IMPORTANT: If subclassing RepeatProcedure and overriding this method, consider\n    /// carefully whether / when / how you should call `super.child(_:willFinishWithErrors:)`.\n    open override func child(_ child: Procedure, willFinishWithError error: Error?) {\n        eventQueue.debugAssertIsOnQueue()\n        _addNextOperation(child === self.current)\n        super.child(child, willFinishWithError: error) // default GroupProcedure error-handling\n    }\n\n    /// Adds the next payload from the iterator to the queue.\n    ///\n    /// - parameter shouldAddNext: must evaluate true to get the next payload. Defaults to true.\n    ///\n    /// - returns: whether or not there was a next payload added.\n    @discardableResult\n    final public func addNextOperation(_ shouldAddNext: @escaping @autoclosure () -> Bool = true) -> ProcedureFutureResult<Bool> {\n        assert(!isFinished, \"Cannot add next operation after the procedure has finished.\")\n        let promise = ProcedurePromiseResult<Bool>()\n        dispatchEvent {\n            let result = self._addNextOperation(shouldAddNext())\n            promise.complete(withResult: result)\n        }\n        return promise.future\n    }\n\n    @discardableResult\n    final internal func _addNextOperation(_ shouldAddNext: @escaping @autoclosure () -> Bool = true) -> Bool {\n        eventQueue.debugAssertIsOnQueue() // Must always be called on the EventQueue.\n\n        guard !isCancelled else { return false }\n\n        guard shouldAddNext(), let payload = _next() else { return false }\n\n        log.verbose.trace()\n        log.info.message(\"Will add next operation.\")\n\n        _repeatStateLock.withCriticalScope {\n            if let newConfigureBlock = payload.configure {\n                _replace(configureBlock: newConfigureBlock)\n            }\n\n            _configure(payload.operation)\n\n            _count += 1\n            _previous = _current\n            _current = payload.operation\n        }\n\n        if let delay = payload.delay.map({ DelayProcedure(delay: $0) }) {\n            payload.operation.addDependency(delay)\n            addChildren(delay, payload.operation)\n        }\n        else {\n            addChild(payload.operation)\n        }\n\n        return true\n    }\n\n    /// Returns the next operation from the generator. This is here to\n    /// allow subclasses to override and configure the operation\n    /// further before it is added.\n    ///\n    /// - returns: an optional Payload future\n    final public func next() -> ProcedureFutureResult<Payload?> {\n        let promise = ProcedurePromiseResult<Payload?>()\n        dispatchEvent {\n            let next = self._next()\n            promise.complete(withResult: next)\n        }\n        return promise.future\n    }\n\n    /// Appends a configuration block to the current block. This\n    /// can be used to configure every instance of the operation\n    /// before it is added to the queue.\n    ///\n    /// - NOTE: The configuration blocks are executed in FIFO order,\n    /// so it is possible to overwrite previous configurations.\n    ///\n    /// - parameter block: a block which receives an instance of T\n    final public func append(configureBlock block: @escaping Payload.ConfigureBlock) {\n        _repeatStateLock.withCriticalScope {\n            let config = _configure\n            _configure = { operation in\n                config(operation)\n                block(operation)\n            }\n        }\n    }\n\n    /// - See: `append(configureBlock:)`\n    final public func appendConfigureBlock(block: @escaping Payload.ConfigureBlock) {\n        append(configureBlock: block)\n    }\n\n    /// Replaces the current configuration block\n    ///\n    /// If the payload returns a configure block, it replaces using\n    /// this API, before configuring\n    ///\n    /// - parameter block: a block which receives an instance of T\n    final public func replace(configureBlock block: @escaping Payload.ConfigureBlock) {\n        _repeatStateLock.withCriticalScope {\n            _replace(configureBlock: block)\n        }\n    }\n\n    /// - See: `replace(configureBlock:)`\n    final public func replaceConfigureBlock(block: @escaping Payload.ConfigureBlock) {\n        replace(configureBlock: block)\n    }\n\n    // MARK: - Private Implementation\n\n    // This method must be called on the Procedure's EventQueue.\n    private func _next() -> Payload? {\n        eventQueue.debugAssertIsOnQueue()\n        return _iterator.next()\n    }\n\n    // This method is not thread-safe, and must be called within an aquisition\n    // of the _repeatStateLock.\n    private func _replace(configureBlock block: @escaping Payload.ConfigureBlock) {\n        _configure = block\n        log.verbose.trace()\n        log.verbose.message(\"did replace configure block.\")\n    }\n}\n\n// MARK: - Repeatable\n\n/// Repeatable protocol is a very simple protocol which allows\n/// `Operation` subclasses to determine whether they should\n/// trigger another repeated value. In other words, the current\n/// just finished instance determines whether a new instance is\n/// executed next, or the repeating finishes.\n@available(*, deprecated, message: \"Use RepeatProcedure or RetryProcedure instead\")\npublic protocol Repeatable {\n\n    /// Determines whether or not a subsequent instance of the\n    /// receiver should be executed.\n    ///\n    /// - Parameter count: an Int, the number of instances executes thus far\n    /// - Returns: a Bool, true to indicate that another instance should be executed.\n    func shouldRepeat(count: Int) -> Bool\n}\n\n@available(*, deprecated, message: \"Use RepeatProcedure or RetryProcedure instead\")\nextension RepeatProcedure where T: Repeatable {\n\n    /// Initialize RepeatProcedure with a WaitStrategy and a closure. The closure returns\n    /// an optional instance of T which conform to the `Repeatable` protocol.\n    /// i.e. T is the Operation subclass to be repeated.\n    /// Other arguments allow for specific dispatch queues, and a maximum count of iteratations.\n    ///\n    /// This is the most convenient initializer, you can use it like this:\n    /// ```swift\n    ///    let procedure = RepeatProcedure { MyRepeatableOperation() }\n    ///    let procedure = RepeatProcedure(dispatchQueue: target) { MyRepeatableOperation() }\n    ///    let procedure = RepeatProcedure(dispatchQueue: target, max: 5) { MyRepeatableOperation() }\n    ///    let procedure = RepeatProcedure(dispatchQueue: target, max: 5, wait: .constant(10)) { MyRepeatableOperation() }\n    /// ```\n    ///\n    /// - Parameters:\n    ///   - dispatchQueue: an optional DispatchQueue, which defaults to nil\n    ///   - max: an optional Int, which defaults to nil.\n    ///   - wait: a WaitStrategy value, which defaults to .immediate\n    ///   - body: an espacing closure which returns an optional T\n    @available(*, deprecated, message: \"Use RepeatProcedure or RetryProcedure instead\")\n    public convenience init(dispatchQueue: DispatchQueue? = nil, max: Int? = nil, wait: WaitStrategy = .immediate, body: @escaping () -> T?) {\n        self.init(dispatchQueue: dispatchQueue, max: max, wait: wait, iterator: RepeatableGenerator(AnyIterator(body)))\n    }\n}\n\n// MARK: - Extensions\n\nextension RepeatProcedure: InputProcedure where T: InputProcedure {\n\n    public typealias Input = T.Input\n\n    /// - returns: the pending input value where T conforms to InputProcedure\n    public var input: Pending<T.Input> {\n        get { return current.input }\n        set {\n            current.input = newValue\n            appendConfigureBlock { $0.input = newValue }\n        }\n    }\n\n    /// MARK: Result Injection APIs\n\n    @discardableResult func injectResult<Dependency: OutputProcedure>(from dependency: Dependency, via block: @escaping (Dependency.Output) throws -> T.Input) -> Self {\n\n        return injectResult(from: dependency) { (procedure, output) in\n            do {\n                procedure.input = .ready(try block(output))\n            }\n            catch {\n                procedure.cancel(with: ProcedureKitError.dependency(finishedWithError: error))\n            }\n        }\n    }\n\n    @discardableResult func injectResult<Dependency: OutputProcedure>(from dependency: Dependency) -> Self where Dependency.Output == T.Input {\n        return injectResult(from: dependency, via: { $0 })\n    }\n\n    @discardableResult func injectResult<Dependency: OutputProcedure>(from dependency: Dependency) -> Self where Dependency.Output == Optional<T.Input> {\n        return injectResult(from: dependency) { output in\n            guard let output = output else {\n                throw ProcedureKitError.requirementNotSatisfied()\n            }\n            return output\n        }\n    }\n}\n\nextension RepeatProcedure: OutputProcedure where T: OutputProcedure {\n\n    public typealias Output = T.Output\n\n    /// - returns: the pending output result value where T conforms to OutputProcedure\n    public var output: Pending<ProcedureResult<T.Output>> {\n        get { return current.output }\n        set {\n            current.output = newValue\n            appendConfigureBlock { $0.output = newValue }\n        }\n    }\n}\n\n// MARK: - Iterators\n\n@available(*, deprecated, message: \"Use RepeatProcedure or RetryProcedure instead\")\ninternal struct RepeatableGenerator<Element: Repeatable>: IteratorProtocol {\n\n    private var iterator: CountingIterator<Element>\n    private var latest: Element?\n\n    init<I: IteratorProtocol>(_ base: I) where I.Element == Element {\n        let mutatingBaseIterator = AnyIterator(base)\n        iterator = CountingIterator { _ in return mutatingBaseIterator.next() }\n    }\n\n    mutating func next() -> Element? {\n        if let latest = latest {\n            guard latest.shouldRepeat(count: iterator.count) else { return nil }\n        }\n        latest = iterator.next()\n        return latest\n    }\n}\n\npublic struct CountingIterator<Element>: IteratorProtocol {\n\n    private let body: (Int) -> Element?\n    public private(set) var count: Int = 0\n\n    public init(_ body: @escaping (Int) -> Element?) {\n        self.body = body\n    }\n\n    public mutating func next() -> Element? {\n        defer { count = count + 1 }\n        return body(count)\n    }\n}\n\npublic func arc4random<T: ExpressibleByIntegerLiteral>(_ type: T.Type) -> T {\n    var r: T = 0\n    arc4random_buf(&r, Int(MemoryLayout<T>.size))\n    return r\n}\n\npublic struct RandomFailIterator<Element>: IteratorProtocol {\n\n    private var iterator: AnyIterator<Element>\n    private let shouldNotFail: () -> Bool\n\n    public let probability: Double\n\n    public init<I: IteratorProtocol>(_ iterator: I, probability prob: Double = 0.1) where I.Element == Element {\n        self.iterator = AnyIterator(iterator)\n        self.shouldNotFail = {\n            let r = (Double(arc4random(UInt64.self)) / Double(UInt64.max))\n            return r > prob\n        }\n        self.probability = prob\n    }\n\n    public mutating func next() -> Element? {\n        guard shouldNotFail() else { return nil }\n        return iterator.next()\n    }\n}\n\npublic struct FibonacciIterator: IteratorProtocol {\n    var currentValue = 0, nextValue = 1\n\n    public mutating func next() -> Int? {\n        let result = currentValue\n        currentValue = nextValue\n        nextValue += result\n        return result\n    }\n}\n\npublic struct FiniteIterator<Element>: IteratorProtocol {\n\n    private var iterator: CountingIterator<Element>\n\n    public init<I: IteratorProtocol>(_ iterator: I, limit: Int = 10) where I.Element == Element {\n        var mutable = iterator\n        self.iterator = CountingIterator { count in\n            guard count < limit else { return nil }\n            return mutable.next()\n        }\n    }\n\n    public mutating func next() -> Element? {\n        return iterator.next()\n    }\n}\n\npublic struct MapIterator<T, V>: IteratorProtocol {\n\n    private let transform: (T) -> V\n    private var iterator: AnyIterator<T>\n\n    public init<I: IteratorProtocol>(_ iterator: I, transform: @escaping (T) -> V) where T == I.Element {\n        self.iterator = AnyIterator(iterator)\n        self.transform = transform\n    }\n\n    public mutating func next() -> V? {\n        return iterator.next().map(transform)\n    }\n}\n\npublic struct PairIterator<T, V>: IteratorProtocol {\n\n    private var primary: AnyIterator<T>\n    private var secondary: AnyIterator<V>\n\n    public init<Primary: IteratorProtocol, Secondary: IteratorProtocol>(primary: Primary, secondary: Secondary) where Primary.Element == T, Secondary.Element == V {\n        self.primary = AnyIterator(primary)\n        self.secondary = AnyIterator(secondary)\n    }\n\n    public mutating func next() -> (T, V?)? {\n        return primary.next().map { ($0, secondary.next()) }\n    }\n}\n\n// MARK: - IntervalIterator\n\npublic struct IntervalIterator {\n\n    public static let immediate = AnyIterator { TimeInterval(0) }\n\n    public static func constant(_ constant: TimeInterval = 1.0) -> AnyIterator<TimeInterval> {\n        return AnyIterator { constant }\n    }\n\n    public static func random(withMinimum min: TimeInterval = 0.0, andMaximum max: TimeInterval = 10.0) -> AnyIterator<TimeInterval> {\n        return AnyIterator {\n            let r = (Double(arc4random(UInt64.self)) / Double(UInt64.max))\n            return (r * (max - min)) + min\n        }\n    }\n\n    public static func incrementing(from initial: TimeInterval = 0.0, by increment: TimeInterval = 1.0) -> AnyIterator<TimeInterval> {\n        return AnyIterator(CountingIterator { count in\n            let interval = initial + (increment * TimeInterval(count))\n            return max(0, interval)\n        })\n    }\n\n    public static func fibonacci(withPeriod period: TimeInterval = 1.0, andMaximum maximum: TimeInterval = TimeInterval(Int.max)) -> AnyIterator<TimeInterval> {\n        return AnyIterator(MapIterator(FibonacciIterator()) { fib in\n            let interval = period * TimeInterval(fib)\n            return max(0, min(maximum, interval))\n        })\n    }\n\n    public static func exponential(power: Double = 2.0, withPeriod period: TimeInterval = 1.0, andMaximum maximum: TimeInterval = TimeInterval(Int.max)) -> AnyIterator<TimeInterval> {\n        return AnyIterator(CountingIterator { count in\n            let interval = period * pow(power, Double(count))\n            return max(0, min(maximum, interval))\n        })\n    }\n}\n\npublic extension Delay {\n\n    static func iterator(_ iterator: AnyIterator<TimeInterval>) -> AnyIterator<Delay> {\n        return AnyIterator(MapIterator(iterator) { Delay.by($0) })\n    }\n\n    struct Iterator {\n\n        static func iterator(_ iterator: AnyIterator<TimeInterval>) -> AnyIterator<Delay> {\n            return Delay.iterator(iterator)\n        }\n\n        public static let immediate: AnyIterator<Delay> = iterator(IntervalIterator.immediate)\n\n        public static func constant(_ constant: TimeInterval = 1.0) -> AnyIterator<Delay> {\n            return iterator(IntervalIterator.constant(constant))\n        }\n\n        public static func random(withMinimum min: TimeInterval = 0.0, andMaximum max: TimeInterval = 10.0) -> AnyIterator<Delay> {\n            return iterator(IntervalIterator.random(withMinimum: min, andMaximum: max))\n        }\n\n        public static func incrementing(from initial: TimeInterval = 0.0, by increment: TimeInterval = 1.0) -> AnyIterator<Delay> {\n            return iterator(IntervalIterator.incrementing(from: initial, by: increment))\n        }\n\n        public static func fibonacci(withPeriod period: TimeInterval = 1.0, andMaximum maximum: TimeInterval = TimeInterval(Int.max)) -> AnyIterator<Delay> {\n            return iterator(IntervalIterator.fibonacci(withPeriod: period, andMaximum: maximum))\n        }\n\n        public static func exponential(power: Double = 2.0, withPeriod period: TimeInterval = 1.0, andMaximum maximum: TimeInterval = TimeInterval(Int.max)) -> AnyIterator<Delay> {\n            return iterator(IntervalIterator.exponential(power: power, withPeriod: period, andMaximum: maximum))\n        }\n    }\n}\n\npublic enum WaitStrategy {\n    case immediate\n    case constant(TimeInterval)\n    case random(minimum: TimeInterval, maximum: TimeInterval)\n    case incrementing(initial: TimeInterval, increment: TimeInterval)\n    case fibonacci(period: TimeInterval, maximum: TimeInterval)\n    case exponential(power: Double, period: TimeInterval, maximum: TimeInterval)\n\n    public var iterator: AnyIterator<TimeInterval> {\n        switch self {\n        case .immediate:\n            return IntervalIterator.immediate\n        case let .constant(constant):\n            return IntervalIterator.constant(constant)\n        case let .random(minimum: min, maximum: max):\n            return IntervalIterator.random(withMinimum: min, andMaximum: max)\n        case let .incrementing(initial: initial, increment: increment):\n            return IntervalIterator.incrementing(from: initial, by: increment)\n        case let .fibonacci(period: period, maximum: max):\n            return IntervalIterator.fibonacci(withPeriod: period, andMaximum: max)\n        case let .exponential(power: power, period: period, maximum: max):\n            return IntervalIterator.exponential(power: power, withPeriod: period, andMaximum: max)\n        }\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKit/Result.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n/// A BlockProcedure subclass which returns an output value from a block\n///\n///  ResultProcedure is useful to return a value as\n///     an `OutputProcedure`. This allow injection of a result into\n///     Procedure subclasses which conform to InputProcedure.\n///\n///  The result can be returned synchonously, for example using\n///     a literal:\n///\n///     let result = ResultProceure { return \"Hello World\" }\n///\n///  Or, if there is an error, it can be thrown.\n///\n///     let resultError = ResultProcedure<String> { throw MyError() }\n/// \nopen class ResultProcedure<Output>: BlockProcedure, OutputProcedure {\n\n    public typealias ThrowingOutputBlock = (ResultProcedure<Output>) throws -> Output\n\n    public var output: Pending<ProcedureResult<Output>> = .pending\n\n    public override init(block: @escaping (ResultProcedure<Output>) -> Void) {\n        super.init { block($0 as! ResultProcedure<Output>) }\n    }\n\n    /// Create a ResultProcedure using a throwing block\n    ///\n    /// - Parameter block: the block receives an instance of self,\n    ///    and should return the `Output` value, or throw an error.\n    ///    use the procedure argument to cancel use the logger etc.\n    public init(block: @escaping ThrowingOutputBlock) {\n        super.init { (procedure) -> Void in\n            let resultProcedure = procedure as! ResultProcedure<Output>\n            defer {\n                if false == resultProcedure.isFinished {\n                    resultProcedure.finish(with: resultProcedure.output.error)\n                }\n            }\n            do {\n                resultProcedure.output = .ready(.success(try block(resultProcedure)))\n            }\n            catch {\n                resultProcedure.output = .ready(.failure(error))\n            }\n        }\n    }\n\n    public init(block: @escaping () throws -> Output) {\n        super.init { (procedure) in\n            var outputProcedure = procedure as! ResultProcedure<Output>\n            defer { outputProcedure.finish(with: outputProcedure.output.error) }\n            do { outputProcedure.output = .ready(.success(try block())) }\n            catch { outputProcedure.output = .ready(.failure(error)) }\n        }\n    }\n}\n\nopen class AsyncResultProcedure<Output>: ResultProcedure<Output> {\n\n    public typealias FinishingBlock = (ProcedureResult<Output>) -> Void\n    public typealias Block = (@escaping FinishingBlock) -> Void\n\n\n    public init(block: @escaping Block) {\n        super.init { (procedure) in\n            block { result in\n                defer {\n                    if false == procedure.isFinished {\n                        procedure.finish(with: procedure.output.error)\n                    }\n                }\n                procedure.finish(withResult: result)\n            }\n        }\n    }\n}\n\n@available(*, deprecated, message: \"Use ResultProcedure directly and query the procedure argument inside your block.\")\nopen class CancellableResultProcedure<Output>: ResultProcedure<Output> {\n\n    /// A block that receives a closure (that returns the current value of `isCancelled`\n    /// for the CancellableResultProcedure), and returns a value (which is set as the\n    /// CancellableResultProcedure's `output`).\n    public typealias ThrowingCancellableOutputBlock = (() -> Bool) throws -> Output\n\n    public init(cancellableBlock: @escaping ThrowingCancellableOutputBlock) {\n        super.init { (resultProcedure) -> Output in\n            return try cancellableBlock { resultProcedure.isCancelled }\n        }\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKit/Retry.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport Foundation\nimport Dispatch\n\npublic struct RetryFailureInfo<T: Procedure> {\n\n    /// - returns: the failed operation\n    public let operation: T\n\n    /// - returns: the errors the operation finished with\n    public let error: Error\n\n    /// - returns: the number of attempts made so far\n    public let count: Int\n\n    /**\n     This is a block which can be used to add Operation(s)\n     to a queue. For example, perhaps it is necessary to\n     retrying the task, but only until another operation\n     has completed.\n\n     This can be done by creating the operation, setting\n     the dependency and adding it using the block.\n\n     - returns: a block which accepts var arg Operation instances\n    */\n    public let addOperations: (Operation...) -> Void\n\n    /// - returns: a logger (from the RetryProcedure)\n    public let log: ProcedureLog\n\n    /**\n     - returns: the block which is used to replace the\n     configure block, which in turns configures the\n     operation instances.\n    */\n    public let configure: (T) -> Void\n}\n\npublic extension RetryFailureInfo {\n\n    var errorCode: Int? {\n        return (error as NSError?)?.code\n    }\n}\n\ninternal class RetryIterator<T: Procedure>: IteratorProtocol {\n    typealias Payload = RepeatProcedure<T>.Payload\n    typealias Handler = RetryProcedure<T>.Handler\n    typealias FailureInfo = RetryProcedure<T>.FailureInfo\n\n    internal let handler: Handler\n    internal var info: FailureInfo?\n    private var iterator: AnyIterator<Payload>\n\n    init<PayloadIterator: IteratorProtocol>(handler: @escaping Handler, iterator base: PayloadIterator) where PayloadIterator.Element == Payload {\n        self.handler = handler\n        self.iterator = AnyIterator(base)\n    }\n\n    func next() -> Payload? {\n        guard let payload = iterator.next() else { return nil }\n        guard let info = info else { return payload }\n        return handler(info, payload)\n    }\n}\n\n/**\n RetryProcedure is a RepeatProcedure subclass which can be used\n to automatically retry another instance of procedure T if the\n first instance finishes with errors. It is generic over T, a\n `Procedure` subclass.\n\n To support effective error recovery, in addition to a (T, Delay?)\n iterator, RetryProcedure is initialized with a block. This block\n will receive failure info, in addition to the next result (if not\n nil) of the payload iterator.\n\n Therefore, consumers can inspect the failure info, and adjust\n the delay, or re-configure the operation before it is retried.\n\n To exit with the error, this block can return nil.\n */\nopen class RetryProcedure<T: Procedure>: RepeatProcedure<T> {\n    public typealias Handler = (FailureInfo, Payload) -> Payload?\n    public typealias FailureInfo = RetryFailureInfo<T>\n\n    let retry: RetryIterator<T>\n\n    public init<PayloadIterator>(dispatchQueue: DispatchQueue? = nil, max: Int? = nil, iterator base: PayloadIterator, retry block: @escaping Handler) where PayloadIterator: IteratorProtocol, PayloadIterator.Element == Payload {\n        retry = RetryIterator(handler: block, iterator: base)\n        super.init(dispatchQueue: dispatchQueue, max: max, iterator: retry)\n    }\n\n    public init<OperationIterator, DelayIterator>(dispatchQueue: DispatchQueue? = nil, max: Int? = nil, delay: DelayIterator, iterator base: OperationIterator, retry block: @escaping Handler) where OperationIterator: IteratorProtocol, DelayIterator: IteratorProtocol, OperationIterator.Element == T, DelayIterator.Element == Delay {\n        let payloadIterator = MapIterator(PairIterator(primary: base, secondary: delay)) { Payload(operation: $0.0, delay: $0.1) }\n        retry = RetryIterator(handler: block, iterator: payloadIterator)\n        super.init(dispatchQueue: dispatchQueue, max: max, iterator: retry)\n    }\n\n    public init<OperationIterator>(dispatchQueue: DispatchQueue? = nil, max: Int? = nil, wait: WaitStrategy, iterator base: OperationIterator, retry block: @escaping Handler) where OperationIterator: IteratorProtocol, OperationIterator.Element == T {\n        let payloadIterator = MapIterator(PairIterator(primary: base, secondary: Delay.iterator(wait.iterator))) { Payload(operation: $0.0, delay: $0.1) }\n        retry = RetryIterator(handler: block, iterator: payloadIterator)\n        super.init(dispatchQueue: dispatchQueue, max: max, iterator: retry)\n    }\n\n    public init(upto max: Int, wait: WaitStrategy = .constant(0.2), body: @escaping () -> T?) {\n        let payloadIterator = MapIterator(PairIterator(primary: AnyIterator(body), secondary: Delay.iterator(wait.iterator))) { Payload(operation: $0.0, delay: $0.1) }\n        retry = RetryIterator(handler: { $1 }, iterator: payloadIterator)\n        super.init(max: max, iterator: retry)\n    }\n\n    /// Handle child willFinish event\n    ///\n    /// This is used by RetryProcedure to trigger adding the next Procedure,\n    /// if the current Procedure fails with an error.\n    ///\n    /// If no further Procedure will be attempted (based on the Retry block / iterator),\n    /// it adds the current (last) Procedure's error to the Group's error.\n    ///\n    /// - IMPORTANT: If subclassing RetryProcedure and overriding this method, consider\n    /// carefully whether / when / how you should call `super.child(_:willFinishWithError:)`.\n    open override func child(_ child: Procedure, willFinishWithError childError: Error?) {\n        eventQueue.debugAssertIsOnQueue()\n        assert(!child.isFinished, \"child(_:willFinishWithErrors:) called with a child that has already finished\")\n\n        guard child === current else {\n            // There may be other Procedures that finish, such as DelayProcedures (between retried\n            // Procedures), and Procedures produced onto the Group's internal queue.\n            // \n            // These other Procedures do not affect whether the RetryProcedure tries a next\n            // Procedure, and their errors (if any) are excluded from the RetryProcedure's\n            // errors.\n            return\n        }\n\n        guard let childError = childError else {\n            // The RetryProcedure's current Procedure succeeded - stop retrying.\n            return\n        }\n\n        var willAttemptAnotherOperation = false\n        defer {\n            log.info.message(\"\\(willAttemptAnotherOperation ? \"will attempt\" : \"will not attempt\") recovery from error: \\(childError) in operation: \\(child)\")\n        }\n\n        retry.info = createFailureInfo(for: current, error: childError)\n        willAttemptAnotherOperation = _addNextOperation()\n        retry.info = .none\n        if !willAttemptAnotherOperation {\n            // If no further operation will be attempted, set the first error\n            setErrorOnce(childError)\n        }\n        // Do not call super.child(_:willFinishWithErrors:)\n        // To ensure that we do not retry/repeat successful procedures (via RepeatProcedure)\n    }\n\n    internal func createFailureInfo(for operation: T, error: Error) -> FailureInfo {\n        return FailureInfo(\n            operation: operation,\n            error: error,\n            count: count,\n            addOperations: { (ops: Operation...) in self.addChildren(ops, before: nil); return },\n            log: log,\n            configure: configure\n        )\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKit/SignpostObserver.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport Foundation\nimport os\n\n@available(iOS 12.0, tvOS 12.0, watchOS 5.0, OSX 10.14, *)\npublic final class SignpostObserver<Procedure: ProcedureProtocol> {\n\n    public let log: OSLog\n\n    public init(log: OSLog) {\n        self.log = log\n    }\n\n    internal convenience init() {\n        self.init(log: ProcedureKit.Signposts.procedure)\n    }\n\n    private func signpostID(for procedure: Procedure) -> OSSignpostID {\n        return OSSignpostID(log: log, object: procedure)\n    }\n}\n\n@available(iOS 12.0, tvOS 12.0, watchOS 5.0, OSX 10.14, *)\nextension SignpostObserver: ProcedureObserver {\n\n    public func will(execute procedure: Procedure, pendingExecute: PendingExecuteEvent) {\n        os_signpost(.begin, log: log, name: \"Executing\", signpostID: signpostID(for: procedure), \"Procedure name: %{public}s\", procedure.procedureName)\n    }\n\n    public func did(finish procedure: Procedure, withErrors errors: [Error]) {\n        os_signpost(.end, log: log, name: \"Execution\", signpostID: signpostID(for: procedure), \"Procedure name: %{public}s, status: %{public}s\", procedure.procedureName, procedure.status.rawValue)\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKit/SilentCondition.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n/**\n A simple condition which suppresses its contained condition to not\n enqueue any dependencies. This is useful for verifying access to\n a resource without prompting for permission, for example.\n */\npublic final class SilentCondition<C: Condition>: ComposedCondition<C> {\n\n    /// Public override of initializer.\n    public override init(_ condition: C) {\n        condition.producedDependencies.forEach(condition.removeDependency)\n        super.init(condition)\n        name = condition.name.map { \"Silent<\\($0)>\" }\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKit/Support.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport Foundation\nimport Dispatch\n\ninternal func _abstractMethod(file: StaticString = #file, line: UInt = #line) {\n    fatalError(\"Method must be overriden\", file: file, line: line)\n}\n\nextension Dictionary {\n\n    internal init<S: Sequence>(sequence: S, keyMapper: (Value) -> Key?) where S.Iterator.Element == Value {\n        self.init()\n        for item in sequence {\n            if let key = keyMapper(item) {\n                self[key] = item\n            }\n        }\n    }\n}\n\n// MARK: - Thread Safety\n\nprotocol ReadWriteLock {\n    mutating func read<T>(_ block: () throws -> T) rethrows -> T\n    mutating func write_async(_ block: @escaping () -> Void, completion: (() -> Void)?)\n    mutating func write_sync<T>(_ block: () throws -> T) rethrows -> T\n}\n\nextension ReadWriteLock {\n\n    mutating func write_async(_ block: @escaping () -> Void) {\n        write_async(block, completion: nil)\n    }\n}\n\nstruct Lock: ReadWriteLock {\n\n    let queue = DispatchQueue.concurrent(label: \"run.kit.procedure.ProcedureKit.Lock\", qos: .userInitiated)\n\n    mutating func read<T>(_ block: () throws -> T) rethrows -> T {\n        return try queue.sync(execute: block)\n    }\n\n    mutating func write_async(_ block: @escaping () -> Void, completion: (() -> Void)?) {\n        queue.async(group: nil, flags: [.barrier]) {\n            block()\n            if let completion = completion {\n                DispatchQueue.main.async(execute: completion)\n            }\n        }\n    }\n\n    mutating func write_sync<T>(_ block: () throws -> T) rethrows -> T {\n        let result = try queue.sync(flags: [.barrier]) {\n            try block()\n        }\n        return result\n    }\n}\n\n/// A wrapper class for a pthread_mutex\nfinal public class PThreadMutex {\n    private var mutex = pthread_mutex_t()\n\n    public init() {\n        let result = pthread_mutex_init(&mutex, nil)\n        precondition(result == 0, \"Failed to create pthread mutex\")\n    }\n\n    deinit {\n        let result = pthread_mutex_destroy(&mutex)\n        assert(result == 0, \"Failed to destroy mutex\")\n    }\n\n    fileprivate func lock() {\n        let result = pthread_mutex_lock(&mutex)\n        assert(result == 0, \"Failed to lock mutex\")\n    }\n\n    fileprivate func unlock() {\n        let result = pthread_mutex_unlock(&mutex)\n        assert(result == 0, \"Failed to unlock mutex\")\n    }\n\n    /// Convenience API to execute block after acquiring the lock\n    ///\n    /// - Parameter block: the block to run\n    /// - Returns: returns the return value of the block\n    public func withCriticalScope<T>(block: () -> T) -> T {\n        lock()\n        defer { unlock() }\n        let value = block()\n        return value\n    }\n}\n\npublic class Protector<T> {\n\n    private var lock = PThreadMutex()\n    private var ward: T\n\n    public init(_ ward: T) {\n        self.ward = ward\n    }\n\n    public var access: T {\n        var value: T?\n        lock.lock()\n        value = ward\n        lock.unlock()\n        return value!\n    }\n\n    public func read<U>(_ block: (T) -> U) -> U {\n        return lock.withCriticalScope { block(self.ward) }\n    }\n\n    /// Synchronously modify the protected value\n    ///\n    /// - Returns: The value returned by the `block`, if any. (discardable)\n    @discardableResult public func write<U>(_ block: (inout T) -> U) -> U {\n        return lock.withCriticalScope { block(&self.ward) }\n    }\n\n    /// Synchronously overwrite the protected value\n    public func overwrite(with newValue: T) {\n        write { (ward: inout T) in ward = newValue }\n    }\n}\n\npublic extension Protector where T: RangeReplaceableCollection {\n\n    func append(_ newElement: T.Iterator.Element) {\n        write { (ward: inout T) in\n            ward.append(newElement)\n        }\n    }\n\n    func append<S: Sequence>(contentsOf newElements: S) where S.Iterator.Element == T.Iterator.Element {\n        write { (ward: inout T) in\n            ward.append(contentsOf: newElements)\n        }\n    }\n\n    func append<C: Collection>(contentsOf newElements: C) where C.Iterator.Element == T.Iterator.Element {\n        write { (ward: inout T) in\n            ward.append(contentsOf: newElements)\n        }\n    }\n}\n\npublic extension Protector where T: Strideable {\n\n    func advance(by stride: T.Stride) {\n        write { (ward: inout T) in\n            ward = ward.advanced(by: stride)\n        }\n    }\n}\n\npublic extension NSLock {\n\n    /// Convenience API to execute block after acquiring the lock\n    ///\n    /// - Parameter block: the block to run\n    /// - Returns: returns the return value of the block\n    func withCriticalScope<T>(block: () -> T) -> T {\n        lock()\n        let value = block()\n        unlock()\n        return value\n    }\n}\n\npublic extension NSRecursiveLock {\n\n    /// Convenience API to execute block after acquiring the lock\n    ///\n    /// - Parameter block: the block to run\n    /// - Returns: returns the return value of the block\n    func withCriticalScope<T>(block: () -> T) -> T {\n        lock()\n        let value = block()\n        unlock()\n        return value\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKit/TimeoutObserver.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport Foundation\nimport Dispatch\n\n/**\n An observer which will automatically cancel (with an error) the `Procedure`\n to which it is attached if the `Procedure` doesn't finish executing before a\n time interval is expired.\n\n The timer starts right before the Procedure's `execute()` function is called\n (after the Procedure has been started).\n\n - IMPORTANT:\n This will cancel a `Procedure`. It is the responsibility of the `Procedure`\n subclass to handle cancellation as appropriate for it to rapidly finish after\n it is cancelled.\n\n - See: the documentation for `Procedure.cancel()`\n */\npublic struct TimeoutObserver: ProcedureObserver {\n\n    private let delay: Delay\n\n    /**\n     Initialize the `TimeoutObserver` with a time interval.\n\n     - parameter by: a `TimeInterval`.\n     */\n    public init(by interval: TimeInterval) {\n        delay = .by(interval)\n    }\n\n    /**\n     Initialize the `TimeoutObserver` with a date.\n\n     - parameter until: a `Date`.\n     */\n    public init(until date: Date) {\n        delay = .until(date)\n    }\n\n    public func will(execute procedure: Procedure, pendingExecute: PendingExecuteEvent) {\n        switch delay.interval {\n        case (let interval) where interval > 0.0:\n            ProcedureTimeoutRegistrar.shared.createFinishTimeout(forProcedure: procedure, withDelay: delay)\n            break\n        default: break\n        }\n    }\n\n    public func did(finish procedure: Procedure, with error: Error?) {\n        ProcedureTimeoutRegistrar.shared.registerFinished(procedure: procedure)\n    }\n}\n\n// A shared registrar of Procedure -> timeout timers.\n// Used to cancel all outstanding timers for a Procedure if:\n//      - that Procedure finishes\n//      - one of the Procedure's timers fires\ninternal class ProcedureTimeoutRegistrar {\n\n    static let shared = ProcedureTimeoutRegistrar()\n\n    private let queue = DispatchQueue(label: \"run.kit.procedure.ProcedureKit.ProcedureTimeouts\", attributes: [.concurrent])\n    private let protectedFinishTimers = Protector<[Procedure : [DispatchTimerWrapper]]>([:])\n\n    func createFinishTimeout(forProcedure procedure: Procedure, withDelay delay: Delay) {\n        let timer = DispatchTimerWrapper(queue: queue)\n        timer.setEventHandler { [delay, weak procedure, weak registrar = self] in\n            guard let strongProcedure = procedure else { return }\n            guard !strongProcedure.isFinished && !strongProcedure.isCancelled else { return }\n            strongProcedure.cancel(with: ProcedureKitError.timedOut(with: delay))\n            registrar?.registerTimeoutProcessed(forProcedure: strongProcedure)\n        }\n        protectedFinishTimers.write {\n            guard var procedureTimers = $0[procedure] else {\n                $0.updateValue([timer], forKey: procedure)\n                return\n            }\n            procedureTimers.append(timer)\n            $0[procedure] = procedureTimers\n        }\n        timer.scheduleOneshot(deadline: .now() + delay.interval)\n        timer.resume()\n    }\n\n    // Called when a Procedure will/did Finish.\n    // Only the first call is processed, and removes all pending timers/timeouts for that Procedure.\n    func registerFinished(procedure: Procedure) {\n        registerTimeoutProcessed(forProcedure: procedure)\n    }\n\n    // Removes all DispatchTimers associated with a Procedure's registered timeouts.\n    // Is called when a Procedure finishes and when a timeout fires.\n    private func registerTimeoutProcessed(forProcedure procedure: Procedure) {\n        guard let dispatchTimers = protectedFinishTimers.write({\n            return $0.removeValue(forKey: procedure)\n        })\n        else {\n            return\n        }\n        for timer in dispatchTimers {\n            timer.cancel()\n        }\n    }\n}\n\n// A wrapper for a DispatchSourceTimer that ensures that the timer is cancelled\n// and not suspended prior to deinitialization.\nfileprivate class DispatchTimerWrapper {\n    fileprivate typealias EventHandler = @convention(block) () -> Swift.Void\n    private let timer: DispatchSourceTimer\n    private let lock = NSLock()\n    private var didResume = false\n\n    init(queue: DispatchQueue) {\n        timer = DispatchSource.makeTimerSource(flags: [], queue: queue)\n    }\n    deinit {\n        // ensure that the timer is cancelled and resumed before deiniting\n        // (trying to deconstruct a suspended DispatchSource will fail)\n        timer.cancel()\n        lock.withCriticalScope {\n            guard !didResume else { return }\n            timer.resume()\n        }\n    }\n\n    // MARK: - DispatchSourceTimer methods\n\n    func setEventHandler(qos: DispatchQoS = .unspecified, flags: DispatchWorkItemFlags = [], handler: @escaping EventHandler) {\n        timer.setEventHandler(qos: qos, flags: flags, handler: handler)\n    }\n    func setEventHandler(handler: DispatchWorkItem) {\n        timer.setEventHandler(handler: handler)\n    }\n    func scheduleOneshot(deadline: DispatchTime, leeway: DispatchTimeInterval = .nanoseconds(0)) {\n        #if swift(>=4.0)\n            timer.schedule(deadline: deadline, leeway: leeway)\n        #else\n            timer.scheduleOneshot(deadline: deadline, leeway: leeway)\n        #endif\n    }\n    func resume() {\n        lock.withCriticalScope {\n            guard !didResume else { fatalError(\"Do not call resume() twice.\") }\n            timer.resume()\n            didResume = true\n        }\n    }\n    func cancel() {\n        timer.cancel()\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKit/Transform.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nopen class TransformProcedure<Input, Output>: Procedure, InputProcedure, OutputProcedure {\n\n    public typealias Transform = (Input) throws -> Output\n\n    private let transform: Transform\n\n    public var input: Pending<Input> = .pending\n    public var output: Pending<ProcedureResult<Output>> = .pending\n\n    public init(transform: @escaping Transform) {\n        self.transform = transform\n        super.init()\n    }\n\n    open override func execute() {\n        defer { finish(with: output.error) }\n        do {\n            guard let inputValue = input.value else { throw ProcedureKitError.requirementNotSatisfied() }\n            output = .ready(.success(try transform(inputValue)))\n        }\n        catch { output = .ready(.failure(error)) }\n    }\n}\n\nopen class AsyncTransformProcedure<Input, Output>: Procedure, InputProcedure, OutputProcedure {\n\n    public typealias FinishingBlock = (ProcedureResult<Output>) -> Void\n    public typealias Transform = (Input, @escaping FinishingBlock) -> Void\n\n    private let transform: Transform\n\n    public var input: Pending<Input> = .pending\n    public var output: Pending<ProcedureResult<Output>> = .pending\n\n    public init(transform: @escaping Transform) {\n        self.transform = transform\n        super.init()\n    }\n\n    open override func execute() {\n        guard let inputValue = input.value else {\n            finish(withResult: .failure(ProcedureKitError.requirementNotSatisfied()))\n            return\n        }\n        transform(inputValue) { self.finish(withResult: $0) }\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKitCloud/CKOperation.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n#if SWIFT_PACKAGE\n    import ProcedureKit\n    import Foundation\n#endif\n\nimport CloudKit\n\n/**\n A generic protocol which exposes the types and properties used by\n Apple's CloudKit Operation types.\n */\npublic protocol CKOperationProtocol: class {\n\n    /// The type of the CloudKit Container\n    associatedtype Container\n\n    /// The type of the CloudKit ServerChangeToken\n    associatedtype ServerChangeToken\n\n    /// The type of the CloudKit Notification\n    associatedtype Notification\n\n    /// The type of the CloudKit RecordZone\n    associatedtype RecordZone\n\n    /// The type of the CloudKit Record\n    associatedtype Record\n\n    /// The type of the CloudKit Subscription\n    associatedtype Subscription\n\n    /// The type of the CloudKit RecordSavePolicy\n    associatedtype RecordSavePolicy\n\n    /// The type of the CloudKit Query\n    associatedtype Query\n\n    /// The type of the CloudKit QueryCursor\n    associatedtype QueryCursor\n\n    /// The type of the CloudKit RecordZoneID\n    associatedtype RecordZoneID: Hashable\n\n    /// The type of the CloudKit NotificationID\n    associatedtype NotificationID: Hashable\n\n    /// The type of the CloudKit RecordID\n    associatedtype RecordID: Hashable\n\n    /// The type of the CloudKit UserIdentity\n    associatedtype UserIdentity\n\n    /// The type of the CloudKit UserIdentityLookupInfo\n    associatedtype UserIdentityLookupInfo\n\n    /// The type of the CloudKit Share\n    associatedtype Share\n\n    /// The type of the CloudKit ShareMetadata\n    associatedtype ShareMetadata\n\n    /// The type of the CloudKit ShareParticipant\n    associatedtype ShareParticipant\n\n    /// The type of the longLivedOperationWasPersistedBlock property\n    associatedtype LongLivedOperationWasPersistedBlockType\n\n    /// - returns the CloudKit Container\n    var container: Container? { get set }\n\n    /// - returns whether to use cellular data access, if WiFi is unavailable (CKOperation default is true)\n    var allowsCellularAccess: Bool { get set }\n\n    /// - returns a unique identifier for a long-lived CKOperation\n    @available(iOS 9.3, tvOS 9.3, OSX 10.12, watchOS 2.3, *)\n    var operationID: String { get }\n\n    #if swift(>=3.2)\n        /// - returns whether the operation is long-lived\n        @available(iOS 9.3, tvOS 9.3, OSX 10.12, watchOS 2.3, *)\n        var isLongLived: Bool { get set }\n    #else // Swift < 3.2 (Xcode 8.x)\n        /// - returns whether the operation is long-lived\n        @available(iOS 9.3, tvOS 9.3, OSX 10.12, watchOS 2.3, *)\n        var longLived: Bool { get set }\n    #endif\n\n    /// - returns the block to execute when the server starts storing callbacks for this long-lived CKOperation\n    @available(iOS 9.3, tvOS 9.3, OSX 10.12, watchOS 2.3, *)\n    var longLivedOperationWasPersistedBlock: LongLivedOperationWasPersistedBlockType { get set }\n\n    /// If non-zero, overrides the timeout interval for any network requests issued by this operation.\n    /// See NSURLSessionConfiguration.timeoutIntervalForRequest\n    @available(iOS 10.0, tvOS 10.0, OSX 10.12, watchOS 3.0, *)\n    var timeoutIntervalForRequest: TimeInterval { get set }\n\n    /// If non-zero, overrides the timeout interval for any network resources retrieved by this operation.\n    /// See NSURLSessionConfiguration.timeoutIntervalForResource\n    @available(iOS 10.0, tvOS 10.0, OSX 10.12, watchOS 3.0, *)\n    var timeoutIntervalForResource: TimeInterval { get set }\n}\n\n/// An extension to make CKOperation to conform to the CKOperationProtocol.\nextension CKOperation: CKOperationProtocol {\n\n    /// The Container is a CKContainer\n    public typealias Container = CKContainer\n\n    /// The ServerChangeToken is a CKServerChangeToken\n    public typealias ServerChangeToken = CKServerChangeToken\n\n    /// The RecordZone is a CKRecordZone\n    public typealias RecordZone = CKRecordZone\n\n    /// The RecordZoneID is a CKRecordZoneID\n    public typealias RecordZoneID = CKRecordZone.ID\n\n    /// The Notification is a CKNotification\n    public typealias Notification = CKNotification\n\n    /// The NotificationID is a CKNotificationID\n    public typealias NotificationID = CKNotification.ID\n\n    /// The Record is a CKRecord\n    public typealias Record = CKRecord\n\n    /// The RecordID is a CKRecordID\n    public typealias RecordID = CKRecord.ID\n\n    #if !os(watchOS)\n    /// The Subscription is a CKSubscription\n    public typealias Subscription = CKSubscription\n    #else\n    // CKSubscription is unsupported on watchOS\n    public typealias Subscription = Void\n    #endif\n\n    /// The RecordSavePolicy is a CKRecordSavePolicy\n    public typealias RecordSavePolicy = CKModifyRecordsOperation.RecordSavePolicy\n\n    /// The Query is a CKQuery\n    public typealias Query = CKQuery\n\n    /// The QueryCursor is a CKQueryCursor\n    public typealias QueryCursor = CKQueryOperation.Cursor\n\n    /// The UserIdentity is a CKUserIdentity\n    @available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *)\n    public typealias UserIdentity = CKUserIdentity\n\n    /// The UserIdentityLookupInfo is a CKUserIdentityLookupInfo\n    @available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *)\n    public typealias UserIdentityLookupInfo = CKUserIdentity.LookupInfo\n\n    /// The Share is a CKShare\n    @available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *)\n    public typealias Share = CKShare\n\n    /// The ShareMetadata is a CKShareMetadata\n    @available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *)\n    public typealias ShareMetadata = CKShare.Metadata\n\n    /// The ShareParticipant is a CKShareParticipant\n    @available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *)\n    public typealias ShareParticipant = CKShare.Participant\n\n    public typealias LongLivedOperationWasPersistedBlockType = (() -> Void)?\n}\n\nextension CKProcedure {\n\n    public var container: T.Container? {\n        get { return operation.container }\n        set { operation.container = newValue }\n    }\n\n    public var allowsCellularAccess: Bool {\n        get { return operation.allowsCellularAccess }\n        set { operation.allowsCellularAccess = newValue }\n    }\n\n    @available(iOS 9.3, tvOS 9.3, OSX 10.12, watchOS 2.3, *)\n    public var operationID: String {\n        get { return operation.operationID }\n    }\n\n    #if swift(>=3.2)\n        @available(iOS 9.3, tvOS 9.3, OSX 10.12, watchOS 2.3, *)\n        public var isLongLived: Bool {\n            get { return operation.isLongLived }\n            set { operation.isLongLived = newValue }\n        }\n\n        // Renamed in Swift 3.2+\n        @available(*, unavailable, renamed: \"isLongLived\")\n        public var longLived: Bool { fatalError(\"Use isLongLived\") }\n    #else // Swift < 3.2 (Xcode 8.x)\n        @available(iOS 9.3, tvOS 9.3, OSX 10.12, watchOS 2.3, *)\n        public var longLived: Bool {\n            get { return operation.longLived }\n            set { operation.longLived = newValue }\n        }\n    #endif\n\n    @available(iOS 9.3, tvOS 9.3, OSX 10.12, watchOS 2.3, *)\n    public var longLivedOperationWasPersistedBlock: T.LongLivedOperationWasPersistedBlockType {\n        get { return operation.longLivedOperationWasPersistedBlock }\n        set { operation.longLivedOperationWasPersistedBlock = newValue }\n    }\n\n    @available(iOS 10.0, tvOS 10.0, OSX 10.12, watchOS 3.0, *)\n    public var timeoutIntervalForRequest: TimeInterval {\n        get { return operation.timeoutIntervalForRequest }\n        set { operation.timeoutIntervalForRequest = newValue }\n    }\n\n    @available(iOS 10.0, tvOS 10.0, OSX 10.12, watchOS 3.0, *)\n    public var timeoutIntervalForResource: TimeInterval {\n        get { return operation.timeoutIntervalForResource }\n        set { operation.timeoutIntervalForResource = newValue }\n    }\n}\n\nextension CloudKitProcedure {\n\n    /// - returns: the CloudKit container\n    public var container: T.Container? {\n        get { return current.container }\n        set {\n            current.container = newValue\n            appendConfigureBlock { $0.container = newValue }\n        }\n    }\n\n    /// - returns whether to use cellular data access, if WiFi is unavailable (CKOperation default is true)\n    public var allowsCellularAccess: Bool {\n        get { return current.allowsCellularAccess }\n        set {\n            current.allowsCellularAccess = newValue\n            appendConfigureBlock { $0.allowsCellularAccess = newValue }\n        }\n    }\n\n    /// - returns a unique identifier for a long-lived CKOperation\n    @available(iOS 9.3, tvOS 9.3, OSX 10.12, watchOS 2.3, *)\n    public var operationID: String {\n        get { return current.operationID }\n    }\n\n    #if swift(>=3.2)\n        /// - returns whether the operation is long-lived\n        @available(iOS 9.3, tvOS 9.3, OSX 10.12, watchOS 2.3, *)\n        public var isLongLived: Bool {\n            get { return current.isLongLived }\n            set {\n                current.isLongLived = newValue\n                appendConfigureBlock { $0.isLongLived = newValue }\n            }\n        }\n\n        // Renamed in Swift 4\n        @available(*, unavailable, renamed: \"isLongLived\")\n        public var longLived: Bool { fatalError(\"Use isLongLived\") }\n    #else // Swift < 3.2 (Xcode 8.x)\n        /// - returns whether the operation is long-lived\n        @available(iOS 9.3, tvOS 9.3, OSX 10.12, watchOS 2.3, *)\n        public var longLived: Bool {\n            get { return current.longLived }\n            set {\n                current.longLived = newValue\n                appendConfigureBlock { $0.longLived = newValue }\n            }\n        }\n    #endif\n\n    /// - returns the block to execute when the server starts storing callbacks for this long-lived CKOperation\n    @available(iOS 9.3, tvOS 9.3, OSX 10.12, watchOS 2.3, *)\n    public var longLivedOperationWasPersistedBlock: T.LongLivedOperationWasPersistedBlockType {\n        get { return current.longLivedOperationWasPersistedBlock }\n        set {\n            current.longLivedOperationWasPersistedBlock = newValue\n            appendConfigureBlock { $0.longLivedOperationWasPersistedBlock = newValue }\n        }\n    }\n\n    /// If non-zero, overrides the timeout interval for any network requests issued by this operation.\n    /// See NSURLSessionConfiguration.timeoutIntervalForRequest\n    @available(iOS 10.0, tvOS 10.0, OSX 10.12, watchOS 3.0, *)\n    public var timeoutIntervalForRequest: TimeInterval {\n        get { return current.timeoutIntervalForRequest }\n        set {\n            current.timeoutIntervalForRequest = newValue\n            appendConfigureBlock { $0.timeoutIntervalForRequest = newValue }\n        }\n    }\n\n    /// If non-zero, overrides the timeout interval for any network resources retrieved by this operation.\n    /// See NSURLSessionConfiguration.timeoutIntervalForResource\n    @available(iOS 10.0, tvOS 10.0, OSX 10.12, watchOS 3.0, *)\n    public var timeoutIntervalForResource: TimeInterval {\n        get { return current.timeoutIntervalForResource }\n        set {\n            current.timeoutIntervalForResource = newValue\n            appendConfigureBlock { $0.timeoutIntervalForResource = newValue }\n        }\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKitCloud/CloudKit.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n#if SWIFT_PACKAGE\n    import ProcedureKit\n    import Foundation\n#endif\n\nimport Dispatch\nimport CloudKit\n\n/**\n CKProcedure is a simple wrapper to compose `CKOperation` instances inside a procedure.\n */\npublic final class CKProcedure<T: Operation>: ComposedProcedure<T> where T: CKOperationProtocol {\n\n    init(dispatchQueue: DispatchQueue? = nil, timeout: TimeInterval? = 30, operation: T) {\n        super.init(dispatchQueue: dispatchQueue, operation: operation)\n        self.log.enabled = false\n        if let observer = timeout.map({ TimeoutObserver(by: $0) }) {\n            addObserver(observer)\n        }\n    }\n}\n\n// MARK: - CloudKitRecovery\n\npublic final class CloudKitRecovery<T: Operation> where T: CKOperationProtocol, T: AssociatedErrorProtocol, T.AssociatedError: CloudKitError {\n\n    public typealias WrappedOperation = CKProcedure<T>\n    public typealias ConfigureBlock = (WrappedOperation) -> Void\n    public typealias Recovery = (Delay?, ConfigureBlock)\n    public typealias Payload = RepeatProcedurePayload<WrappedOperation>\n    public typealias Handler = (T, T.AssociatedError, LogChannels, Recovery) -> Recovery?\n\n    var defaultHandlers: [CKError.Code: Handler] = [:]\n    var customHandlers: [CKError.Code: Handler] = [:]\n    private var finallyConfigureRetryOperationBlock: ConfigureBlock?\n\n    internal init() {\n        addDefaultHandlers()\n    }\n\n    func cloudKitError(fromInfo info: RetryFailureInfo<WrappedOperation>) -> (CKError.Code, T.AssociatedError)? {\n        guard\n            let cloudKitError = info.error as? T.AssociatedError,\n            let code = cloudKitError.code\n        else { return nil }\n        return (code, cloudKitError)\n    }\n\n    func recover(withInfo info: RetryFailureInfo<WrappedOperation>, payload: Payload) -> Recovery? {\n        guard let (code, error) = cloudKitError(fromInfo: info) else { return nil }\n\n        let suggestion: Recovery = (payload.delay, info.configure)\n\n        guard\n            let handler = customHandlers[code] ?? defaultHandlers[code],\n            var response = handler(info.operation.operation, error, info.log, suggestion)\n        else { return nil }\n\n        if let finallyConfigureBlock = finallyConfigureRetryOperationBlock {\n            let previousConfigureBlock = response.1\n            response.1 = { operation in\n                previousConfigureBlock(operation)\n                finallyConfigureBlock(operation)\n            }\n        }\n\n        return response\n    }\n\n    func addDefaultHandlers() {\n\n        let exit: Handler = { _, error, log, _ in\n            log.fatal.message(\"Exiting due to CloudKit Error: \\(error)\")\n            return nil\n        }\n\n        set(defaultHandlerForCode: .internalError, handler: exit)\n        set(defaultHandlerForCode: .missingEntitlement, handler: exit)\n        set(defaultHandlerForCode: .invalidArguments, handler: exit)\n        set(defaultHandlerForCode: .serverRejectedRequest, handler: exit)\n        set(defaultHandlerForCode: .assetFileNotFound, handler: exit)\n        set(defaultHandlerForCode: .incompatibleVersion, handler: exit)\n        set(defaultHandlerForCode: .constraintViolation, handler: exit)\n        set(defaultHandlerForCode: .badDatabase, handler: exit)\n        set(defaultHandlerForCode: .quotaExceeded, handler: exit)\n        set(defaultHandlerForCode: .operationCancelled, handler: exit)\n\n        let retry: Handler = { _, error, log, suggestion in\n            log.info.message(\"Will retry after receiving error: \\(error)\")\n            return error.retryAfterDelay.map { ($0, suggestion.1) } ?? suggestion\n        }\n\n        set(defaultHandlerForCode: .networkUnavailable, handler: retry)\n        set(defaultHandlerForCode: .networkFailure, handler: retry)\n        set(defaultHandlerForCode: .serviceUnavailable, handler: retry)\n        set(defaultHandlerForCode: .requestRateLimited, handler: retry)\n        set(defaultHandlerForCode: .assetFileModified, handler: retry)\n        set(defaultHandlerForCode: .batchRequestFailed, handler: retry)\n        set(defaultHandlerForCode: .zoneBusy, handler: retry)\n    }\n\n    func set(defaultHandlerForCode code: CKError.Code, handler: @escaping Handler) {\n        defaultHandlers[code] = handler\n    }\n\n    func set(customHandlerForCode code: CKError.Code, handler: @escaping Handler) {\n        customHandlers[code] = handler\n    }\n\n    func set(finallyConfigureRetryOperationBlock block: ConfigureBlock?) {\n        finallyConfigureRetryOperationBlock = block\n    }\n}\n\n// MARK: - CloudKitProcedure\n\n/**\n # CloudKitProcedure\n\n CloudKitProcedure is a generic operation which can be used to configure and schedule\n the execution of Apple's CKOperation subclasses.\n\n ## Generics\n\n CloudKitProcedure is generic over the type of the CKOperation. See Apple's documentation\n on their CloudKit NSOperation classes.\n\n ## Initialization\n\n CloudKitProcedure is initialized with a block which should return an instance of the\n required operation. Note that some CKOperation subclasses have static methods to\n return standard instances. Given Swift's treatment of trailing closure arguments, this\n means that the following is a standard initialization pattern:\n\n ```swift\n let operation = CloudKitProcedure { CKFetchRecordZonesOperation.fetchAllRecordZonesOperation() }\n ```\n\n This works because, the initializer only takes a trailing closure. The closure receives no arguments\n and is only one line, so the return is not needed.\n\n ## Configuration\n\n Most CKOperation subclasses need various properties setting before they are added to a queue. Sometimes\n these can be done via their initializers. However, it is also possible to set the properties directly.\n This can be done directly onto the CloudKitProcedure. For example, given the above:\n\n ```swift\n let container = CKContainer.defaultContainer()\n operation.container = container\n operation.database = container.privateCloudDatabase\n ```\n\n This will set the container and the database through the CloudKitProcedure into the wrapped CKOperation\n instance.\n\n ## Completion\n\n All CKOperation subclasses have a completion block which should be set. This completion block receives\n the \"results\" of the operation, and an `NSError` argument. However, CloudKitProcedure features its own\n semi-automatic error handling system. Therefore, the only completion block needed is one which receives\n the \"results\". Essentially, all that is needed is to manage the happy path of the operation. For all\n CKOperation subclasses, this can be configured directly on the CloudKitProcedure instance, using a\n pattern of `setOperationKindCompletionBlock { }`. For example, given the above:\n\n ```swift\n operation.setFetchRecordZonesCompletionBlock { zonesByID in\n // Do something with the zonesByID\n }\n ```\n\n Note, that for the automatic error handling to kick in, the happy path must be set (as above).\n\n ### Error Handling\n\n When the completion block is set as above, any errors receives from the CKOperation subclass are\n intercepted, and instead of the provided block being executed, the operation finsihes with an error.\n\n However, CloudKitProcedure is a subclass of RetryOperation, which is actually a GroupOperation subclass,\n and when a child operation finishes with an error, RetryOperation will consult its error handler, and\n attempt to retry the operation.\n\n In the case of CloudKitProcedure, the error handler, which is configured internally has automatic\n support for many common error kinds. When the CKOperation receives an error, the CKErrorCode is extracted,\n and the handler consults a CloudKitRecovery instance to check for a particular way to handle that error\n code. In some cases, this will result in a tuple being returned. The tuple is an optional Delay, and\n a new instance of the CKOperation class.\n\n This is why the initializer takes a block which returns an instance of the CKOperation subclass, rather\n than just an instance directly. In addition, any configuration set on the operation is captured and\n applied again to new instances of the CKOperation subclass.\n\n The delay is used to automatically respect any wait periods returned in the CloudKit NSError object. If\n none are given, a random time delay between 0.1 and 1.0 seconds is used.\n\n If the error recovery does not have a handler, or the handler returns nil (no tuple), the CloudKitProcedure\n will finish (with the errors).\n\n ### Custom Error Handling\n\n To provide bespoke error handling, further configure the CloudKitProcedure by calling setErrorHandlerForCode.\n For example:\n\n ```swift\n operation.setErrorHandlerForCode(.PartialFailure) { error, log, suggested in\n return suggested\n }\n ```\n\n Note that the error handler receives the received error, a logger object, and the suggested tuple, which\n could be modified before being returned. Alternatively, return nil to not retry.\n\n */\npublic final class CloudKitProcedure<T: Operation>: RetryProcedure<CKProcedure<T>> where T: CKOperationProtocol, T: AssociatedErrorProtocol, T.AssociatedError: CloudKitError {\n\n    public typealias ErrorHandler = CloudKitRecovery<T>.Handler\n\n    let recovery: CloudKitRecovery<T>\n\n    public var errorHandlers: [CKError.Code: ErrorHandler] {\n        return recovery.customHandlers\n    }\n\n    public init<Iterator: IteratorProtocol>(dispatchQueue: DispatchQueue, timeout: TimeInterval?, strategy: WaitStrategy, iterator: Iterator) where T == Iterator.Element {\n\n        // Create a delay between retries\n        let delayIterator = Delay.iterator(strategy.iterator)\n\n        let operationIterator = MapIterator(iterator) { CKProcedure(dispatchQueue: dispatchQueue, timeout: timeout, operation: $0) }\n\n        let recovery = CloudKitRecovery<T>()\n\n        let handler: Handler = { [weak recovery] info, payload in\n            guard\n                let recovery = recovery,\n                let (delay, configure) = recovery.recover(withInfo: info, payload: payload)\n            else { return nil }\n            return RepeatProcedurePayload(operation: payload.operation, delay: delay, configure: configure)\n        }\n\n        self.recovery = recovery\n\n        super.init(dispatchQueue: dispatchQueue, delay: delayIterator, iterator: operationIterator, retry: handler)\n    }\n\n    public convenience init(dispatchQueue: DispatchQueue = DispatchQueue.default, timeout: TimeInterval? = 30, strategy: WaitStrategy = .random(minimum: 0.1, maximum: 1.0), body: @escaping () -> T?) {\n        self.init(dispatchQueue: dispatchQueue, timeout: timeout, strategy: strategy, iterator: AnyIterator(body))\n    }\n\n    public func set(errorHandlerForCode code: CKError.Code, handler: @escaping ErrorHandler) {\n        recovery.set(customHandlerForCode: code, handler: handler)\n    }\n\n    public func set(errorHandlers: [CKError.Code: ErrorHandler]) {\n        recovery.customHandlers = errorHandlers\n    }\n\n    // When an error occurs, CloudKitProcedure executes the appropriate error handler (as long as the completion block is set).\n    // (By default, certain errors are automatically handled with a retry attempt, such as common network errors.)\n    //\n    // If the error handler specifies that the operation should retry, it also specifies a configuration block for the operation.\n    // After the configuration block returned by the error handler configures the operation, the finallyConfigureRetryOperationBlock\n    // will be passed the new (\"retry\") operation so it can further modify its properties.\n    //\n    // For example:\n    //      - CKFetchDatabaseChangesOperation, for updating:\n    //          - `previousServerChangeToken`\n    //              - with the last changeToken received by the changeTokenUpdatedBlock prior to the error\n    //                (assuming you have persisted the information received prior to the last changeToken update)\n    //\n    //      - CKFetchRecordZoneChangesOperation, for updating:\n    //          - `recordZoneIDs`\n    //              - to remove zones that were completely fetched prior to the error\n    //                (assuming you have persisted the fetched data)\n    //          - `optionsByRecordZoneID`\n    //              - to update the previousServerChangeToken for zones that were partially fetched prior to the error\n    //                (assuming you have persisted the successfully-fetched data)\n    //\n    public func set(finallyConfigureRetryOperationBlock block: CloudKitRecovery<T>.ConfigureBlock?) {\n        recovery.set(finallyConfigureRetryOperationBlock: block)\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKitCloud/CloudKitCapability.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n#if SWIFT_PACKAGE\n    import ProcedureKit\n    import Foundation\n#endif\n\nimport CloudKit\n\n/**\n # Cloud Status\n\n Value represents the current CloudKit status for the user.\n\n CloudKit has a relatively convoluted status API.\n\n First, we must check the user's accout status, i.e. are\n they logged in to iCloud.\n\n Next, we check the status for the application permissions.\n\n Then, we might need to request the application permissions.\n */\npublic struct CloudKitStatus: AuthorizationStatus {\n\n    public typealias Requirement = CKContainer.Application.Permissions\n\n    /// - returns: the CKAccountStatus\n    public let account: CKAccountStatus\n\n    /// - returns: the CKApplicationPermissionStatus?\n    public let permissions: CKContainer.Application.PermissionStatus?\n\n    /// - returns: any NSError?\n    public let error: Error?\n\n    /**\n     Determine whether the application permissions have been met.\n     This method takes into account, any errors received from CloudKit,\n     the account status, application permission status, and the required\n     application permissions.\n     */\n    public func meets(requirement: CKContainer.Application.Permissions?) -> Bool {\n        guard error == nil else { return false }\n\n        guard let requirement = requirement else {\n            return account == .available\n        }\n\n        switch (requirement, account, permissions) {\n        case ([], .available, _):\n            return true\n        case (_, .available, .some(.granted)) where requirement != []:\n            return true\n        default:\n            return false\n        }\n    }\n}\n\nextension Capability {\n\n    public class CloudKit: CapabilityProtocol {\n\n        public private(set) var requirement: CKContainer.Application.Permissions?\n\n        internal let containerId: String?\n\n        internal var storedRegistrar: CloudKitContainerRegistrar?\n        internal var registrar: CloudKitContainerRegistrar {\n            get {\n                storedRegistrar = storedRegistrar ?? containerId.map { CKContainer(identifier: $0) } ?? CKContainer.default()\n                return storedRegistrar!\n            }\n        }\n\n        public init(_ requirement: CKContainer.Application.Permissions? = nil, containerId: String? = nil) {\n            self.requirement = requirement\n            self.containerId = containerId\n        }\n\n        public func isAvailable() -> Bool {\n            return true\n        }\n\n        public func getAuthorizationStatus(_ completion: @escaping (CloudKitStatus) -> Void) {\n            verifyAccountStatus(completion: completion)\n        }\n\n        public func requestAuthorization(withCompletion completion: @escaping () -> Void) {\n            verifyAccountStatus(andPermissions: true, completion: { _ in completion() })\n        }\n\n        func verifyAccountStatus(andPermissions shouldVerifyAndRequestPermissions: Bool = false, completion: @escaping (CloudKitStatus) -> Void) {\n            let hasRequirements = requirement.map { $0 != [] } ?? false\n            registrar.pk_accountStatus { [weak self] accountStatus, error in\n                switch (accountStatus, hasRequirements) {\n                case (.available, true):\n                    self?.verifyApplicationPermissions(andRequestPermission: shouldVerifyAndRequestPermissions, completion: completion)\n                default:\n                    completion(CloudKitStatus(account: accountStatus, permissions: nil, error: error))\n                }\n            }\n        }\n\n        func verifyApplicationPermissions(andRequestPermission shouldRequestPermission: Bool = false, completion: @escaping (CloudKitStatus) -> Void) {\n            registrar.pk_status(forApplicationPermission: requirement!) { [weak self] permissionStatus, error in\n                switch (permissionStatus, shouldRequestPermission) {\n                case (.initialState, true):\n                    self?.requestPermissions(withCompletion: completion)\n                default:\n                    completion(CloudKitStatus(account: .available, permissions: permissionStatus, error: error))\n                }\n            }\n        }\n\n        func requestPermissions(withCompletion completion: @escaping (CloudKitStatus) -> Void) {\n            DispatchQueue.main.async {\n                self.registrar.pk_requestApplicationPermission(self.requirement!) { permissionStatus, error in\n                    completion(CloudKitStatus(account: .available, permissions: permissionStatus, error: error))\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKitCloud/CloudKitError.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n#if SWIFT_PACKAGE\n    import ProcedureKit\n    import Foundation\n#endif\n\nimport CloudKit\n\n/// An error protocol for CloudKit errors.\npublic protocol CloudKitError: Error {\n\n    /// - returns: the original NSError received from CloudKit\n    var underlyingError: Error { get }\n\n    /// - returns: an operation Delay, used to indicate how long to wait until retry\n    var retryAfterDelay: Delay? { get }\n}\n\n/// Public extensions to extract useful error information\npublic extension CloudKitError {\n\n    internal var underlyingNSError: NSError {\n        return underlyingError as NSError\n    }\n\n    /// - returns: the CKErrorCode if possible\n    var code: CKError.Code? {\n        return CKError.Code(rawValue: underlyingNSError.code)\n    }\n\n    /// - returns: an optional Delay, if the underlying error's user info contains CKErrorRetryAfterKey\n    var retryAfterDelay: Delay? {\n        return (underlyingNSError.userInfo[CKErrorRetryAfterKey] as? NSNumber).flatMap { .by($0.doubleValue) }\n    }\n}\n\n// MARK: - Batch Errors\n\n/// An error protocol for batch modifying operations\npublic protocol CloudKitBatchModifyError: CloudKitError {\n    associatedtype Save\n    associatedtype Delete\n\n    var saved: [Save]? { get }\n    var deleted: [Delete]? { get }\n}\n\n/// An error protocol for batch processing operations\npublic protocol CloudKitBatchProcessError: CloudKitError {\n    associatedtype Process\n\n    var processed: [Process]? { get }\n}\n\n// MARK: - Concrete types\n\npublic struct PKCKError: CloudKitError {\n    public let underlyingError: Error\n}\n"
  },
  {
    "path": "Sources/ProcedureKitCloud/CloudKitSupport.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n#if SWIFT_PACKAGE\n    import ProcedureKit\n    import Foundation\n#endif\n\nimport CloudKit\n\nprotocol CloudKitContainerRegistrar {\n\n    func pk_accountStatus(withCompletionHandler completionHandler: @escaping (CKAccountStatus, Error?) -> Void)\n\n    func pk_status(forApplicationPermission: CKContainer.Application.Permissions, completionHandler: @escaping CKContainer.Application.PermissionBlock)\n\n    func pk_requestApplicationPermission(_ applicationPermission: CKContainer.Application.Permissions, completionHandler: @escaping CKContainer.Application.PermissionBlock)\n}\n\nextension CKContainer: CloudKitContainerRegistrar {\n\n    func pk_accountStatus(withCompletionHandler completionHandler: @escaping (CKAccountStatus, Error?) -> Void) {\n        accountStatus(completionHandler: completionHandler)\n    }\n\n    func pk_status(forApplicationPermission applicationPermission: CKContainer.Application.Permissions, completionHandler: @escaping CKContainer.Application.PermissionBlock) {\n        status(forApplicationPermission: applicationPermission, completionHandler: completionHandler)\n    }\n\n    func pk_requestApplicationPermission(_ applicationPermission: CKContainer.Application.Permissions, completionHandler: @escaping CKContainer.Application.PermissionBlock) {\n        requestApplicationPermission(applicationPermission, completionHandler: completionHandler)\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKitCloud/Database Operations/CKDatabaseOperation.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n#if SWIFT_PACKAGE\n    import ProcedureKit\n    import Foundation\n#endif\n\nimport CloudKit\n\n/**\n A generic protocol which exposes the types and properties used by\n Apple's CloudKit Database Operation types.\n */\npublic protocol CKDatabaseOperationProtocol: CKOperationProtocol {\n\n    /// The type of the CloudKit Database\n    associatedtype Database\n\n    /// - returns: the CloudKit Database\n    var database: Database? { get set }\n}\n\n/// An extension to make CKDatabaseOperation to conform to the CKDatabaseOperationProtocol.\nextension CKDatabaseOperation: CKDatabaseOperationProtocol {\n\n    /// The Database is a CKDatabase\n    public typealias Database = CKDatabase\n}\n\nextension CKProcedure where T: CKDatabaseOperationProtocol {\n\n    public var database: T.Database? {\n        get { return operation.database }\n        set { operation.database = newValue }\n    }\n}\n\nextension CloudKitProcedure where T: CKDatabaseOperationProtocol {\n\n    /// - returns: the CloudKit database\n    public var database: T.Database? {\n        get { return current.database }\n        set {\n            current.database = newValue\n            appendConfigureBlock { $0.database = newValue }\n        }\n    }\n}\n\n// MARK: - CKPreviousServerChangeToken\n\n/**\n A generic protocol which exposes the types and properties used by\n Apple's CloudKit Operation's which return the previous sever change\n token.\n */\npublic protocol CKPreviousServerChangeToken: CKOperationProtocol {\n\n    /// - returns: the previous sever change token\n    var previousServerChangeToken: ServerChangeToken? { get set }\n}\n\nextension CKProcedure where T: CKPreviousServerChangeToken {\n\n    public var previousServerChangeToken: T.ServerChangeToken? {\n        get { return operation.previousServerChangeToken }\n        set { operation.previousServerChangeToken = newValue }\n    }\n}\n\nextension CloudKitProcedure where T: CKPreviousServerChangeToken {\n\n    /// - returns: the previous server change token\n    public var previousServerChangeToken: T.ServerChangeToken? {\n        get { return current.previousServerChangeToken }\n        set {\n            current.previousServerChangeToken = newValue\n            appendConfigureBlock { $0.previousServerChangeToken = newValue }\n        }\n    }\n}\n\n// MARK: - CKResultsLimit\n\n/// A generic protocol which exposes the properties used by Apple's CloudKit Operation's which return a results limit.\npublic protocol CKResultsLimit: CKOperationProtocol {\n\n    /// - returns: the results limit\n    var resultsLimit: Int { get set }\n}\n\nextension CKProcedure where T: CKResultsLimit {\n\n    public var resultsLimit: Int {\n        get { return operation.resultsLimit }\n        set { operation.resultsLimit = newValue }\n    }\n}\n\nextension CloudKitProcedure where T: CKResultsLimit {\n\n    /// - returns: the results limit\n    public var resultsLimit: Int {\n        get { return current.resultsLimit }\n        set {\n            current.resultsLimit = newValue\n            appendConfigureBlock { $0.resultsLimit = newValue }\n        }\n    }\n}\n\n// MARK: - CKMoreComing\n\n/// A generic protocol which exposes the properties used by Apple's CloudKit Operation's which return a flag for more coming.\npublic protocol CKMoreComing: CKOperationProtocol {\n\n    /// - returns: whether there are more results on the server\n    var moreComing: Bool { get }\n}\n\nextension CKProcedure where T: CKMoreComing {\n\n    public var moreComing: Bool {\n        return operation.moreComing\n    }\n}\n\nextension CloudKitProcedure where T: CKMoreComing {\n\n    /// - returns: a flag to indicate whether there are more results on the server\n    public var moreComing: Bool {\n        return current.moreComing\n    }\n}\n\n// MARK: - CKDesiredKeys\n\n/// A generic protocol which exposes the properties used by Apple's CloudKit Operation's which have desired keys.\npublic protocol CKDesiredKeys: CKOperationProtocol {\n\n    /// - returns: the desired keys to fetch or fetched.\n    var desiredKeys: [String]? { get set }\n}\n\nextension CKProcedure where T: CKDesiredKeys {\n\n    public var desiredKeys: [String]? {\n        get { return operation.desiredKeys }\n        set { operation.desiredKeys = newValue }\n    }\n}\n\nextension CloudKitProcedure where T: CKDesiredKeys {\n\n    /// - returns: the desired keys\n    public var desiredKeys: [String]? {\n        get { return current.desiredKeys }\n        set {\n            current.desiredKeys = newValue\n            appendConfigureBlock { $0.desiredKeys = newValue }\n        }\n    }\n}\n\n/// A protocol typealias which exposes the properties used by Apple's CloudKit batched operation types.\npublic typealias CKBatchedOperation = CKResultsLimit & CKMoreComing\n\n/// A protocol typealias which exposes the properties used by Apple's CloudKit fetched operation types.\npublic typealias CKFetchOperation = CKPreviousServerChangeToken & CKBatchedOperation\n"
  },
  {
    "path": "Sources/ProcedureKitCloud/Database Operations/CKDiscoverAllUserIdentitiesOperation.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n#if !os(tvOS)\n\n#if SWIFT_PACKAGE\n    import ProcedureKit\n    import Foundation\n#endif\n\nimport CloudKit\n\n/// A generic protocol which exposes the properties used by Apple's CKDiscoverAllUserIdentitiesOperation.\npublic protocol CKDiscoverAllUserIdentitiesOperationProtocol: CKOperationProtocol {\n\n    /// - returns: a block for when a user identity is discovered\n    var userIdentityDiscoveredBlock: ((UserIdentity) -> Void)? { get set }\n\n    /// - returns: the completion block used for discovering all user identities\n    var discoverAllUserIdentitiesCompletionBlock: ((Error?) -> Void)? { get set }\n}\n\n@available(iOS 10.0, OSX 10.12, watchOS 3.0, *)\nextension CKDiscoverAllUserIdentitiesOperation: CKDiscoverAllUserIdentitiesOperationProtocol, AssociatedErrorProtocol {\n\n    // The associated error type\n    public typealias AssociatedError = PKCKError\n}\n\nextension CKProcedure where T: CKDiscoverAllUserIdentitiesOperationProtocol, T: AssociatedErrorProtocol, T.AssociatedError: CloudKitError {\n\n    public var userIdentityDiscoveredBlock: CloudKitProcedure<T>.DiscoverAllUserIdentitiesUserIdentityDiscoveredBlock? {\n        get { return operation.userIdentityDiscoveredBlock }\n        set { operation.userIdentityDiscoveredBlock = newValue }\n    }\n\n    func setDiscoverAllUserIdentitiesCompletionBlock(_ block: @escaping CloudKitProcedure<T>.DiscoverAllUserIdentitiesCompletionBlock) {\n        operation.discoverAllUserIdentitiesCompletionBlock = { [weak self] error in\n            if let strongSelf = self, let error = error {\n                strongSelf.setErrorOnce(PKCKError(underlyingError: error))\n            }\n            else {\n                block()\n            }\n        }\n    }\n}\n\nextension CloudKitProcedure where T: CKDiscoverAllUserIdentitiesOperationProtocol {\n\n    /// A typealias for the block type used by CloudKitOperation<CKDiscoverAllUserIdentitiesOperationType>\n    public typealias DiscoverAllUserIdentitiesUserIdentityDiscoveredBlock = (T.UserIdentity) -> Void\n\n    /// A typealias for the block type used by CloudKitOperation<CKDiscoverAllUserIdentitiesOperationType>\n    public typealias DiscoverAllUserIdentitiesCompletionBlock = () -> Void\n\n    /// - returns: a block for when a recordZone changeToken update is sent\n    public var userIdentityDiscoveredBlock: DiscoverAllUserIdentitiesUserIdentityDiscoveredBlock? {\n        get { return current.userIdentityDiscoveredBlock }\n        set {\n            current.userIdentityDiscoveredBlock = newValue\n            appendConfigureBlock { $0.userIdentityDiscoveredBlock = newValue }\n        }\n    }\n\n    /**\n     Before adding the CloudKitOperation instance to a queue, set a completion block\n     to collect the results in the successful case. Setting this completion block also\n     ensures that error handling gets triggered.\n\n     - parameter block: a DiscoverAllContactsCompletionBlock block\n     */\n    public func setDiscoverAllUserIdentitiesCompletionBlock(block: @escaping DiscoverAllUserIdentitiesCompletionBlock) {\n        appendConfigureBlock { $0.setDiscoverAllUserIdentitiesCompletionBlock(block) }\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Sources/ProcedureKitCloud/Database Operations/CKDiscoverUserIdentitiesOperation.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n#if SWIFT_PACKAGE\n    import ProcedureKit\n    import Foundation\n#endif\n\nimport CloudKit\n\n/// A generic protocol which exposes the properties used by Apple's CKDiscoverUserIdentitiesOperation.\npublic protocol CKDiscoverUserIdentitiesOperationProtocol: CKOperationProtocol {\n\n    /// - returns: the user identity lookup info used in discovery\n    var userIdentityLookupInfos: [UserIdentityLookupInfo] { get set }\n\n    /// - returns: the block used to return discovered user identities\n    var userIdentityDiscoveredBlock: ((UserIdentity, UserIdentityLookupInfo) -> Void)? { get set }\n\n    /// - returns: the completion block used for discovering user identities\n    var discoverUserIdentitiesCompletionBlock: ((Error?) -> Void)? { get set }\n}\n\n@available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *)\nextension CKDiscoverUserIdentitiesOperation: CKDiscoverUserIdentitiesOperationProtocol, AssociatedErrorProtocol {\n\n    // The associated error type\n    public typealias AssociatedError = PKCKError\n}\n\nextension CKProcedure where T: CKDiscoverUserIdentitiesOperationProtocol, T: AssociatedErrorProtocol, T.AssociatedError: CloudKitError {\n\n    public var userIdentityLookupInfos: [T.UserIdentityLookupInfo] {\n        get { return operation.userIdentityLookupInfos }\n        set { operation.userIdentityLookupInfos = newValue }\n    }\n\n    public var userIdentityDiscoveredBlock: CloudKitProcedure<T>.DiscoverUserIdentitiesUserIdentityDiscoveredBlock? {\n        get { return operation.userIdentityDiscoveredBlock }\n        set { operation.userIdentityDiscoveredBlock = newValue }\n    }\n\n    func setDiscoverUserIdentitiesCompletionBlock(_ block: @escaping CloudKitProcedure<T>.DiscoverUserIdentitiesCompletionBlock) {\n        operation.discoverUserIdentitiesCompletionBlock = { [weak self] error in\n            if let strongSelf = self, let error = error {\n                strongSelf.setErrorOnce(PKCKError(underlyingError: error))\n            }\n            else {\n                block()\n            }\n        }\n    }\n}\n\nextension CloudKitProcedure where T: CKDiscoverUserIdentitiesOperationProtocol {\n\n    /// A typealias for the block type used by CloudKitOperation<CKDiscoverUserIdentitiesOperationType>\n    public typealias DiscoverUserIdentitiesUserIdentityDiscoveredBlock = (T.UserIdentity, T.UserIdentityLookupInfo) -> Void\n\n    /// A typealias for the block type used by CloudKitOperation<CKDiscoverUserIdentitiesOperationType>\n    public typealias DiscoverUserIdentitiesCompletionBlock = () -> Void\n\n    /// - returns: the user identity lookup info used in discovery\n    public var userIdentityLookupInfos: [T.UserIdentityLookupInfo] {\n        get { return current.userIdentityLookupInfos }\n        set {\n            current.userIdentityLookupInfos = newValue\n            appendConfigureBlock { $0.userIdentityLookupInfos = newValue }\n        }\n    }\n\n    /// - returns: the block used to return discovered user identities\n    public var userIdentityDiscoveredBlock: DiscoverUserIdentitiesUserIdentityDiscoveredBlock? {\n        get { return current.userIdentityDiscoveredBlock }\n        set {\n            current.userIdentityDiscoveredBlock = newValue\n            appendConfigureBlock { $0.userIdentityDiscoveredBlock = newValue }\n        }\n    }\n\n    /**\n     Before adding the CloudKitOperation instance to a queue, set a completion block\n     to collect the results in the successful case. Setting this completion block also\n     ensures that error handling gets triggered.\n\n     - parameter block: a DiscoverUserIdentitiesCompletionBlock block\n     */\n    public func setDiscoverUserIdentitiesCompletionBlock(block: @escaping DiscoverUserIdentitiesCompletionBlock) {\n        appendConfigureBlock { $0.setDiscoverUserIdentitiesCompletionBlock(block) }\n    }\n}\n\n"
  },
  {
    "path": "Sources/ProcedureKitCloud/Database Operations/CKModifyBadgeOperation.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n#if SWIFT_PACKAGE\n    import ProcedureKit\n    import Foundation\n#endif\n\nimport CloudKit\n\n/// A generic protocol which exposes the properties used by Apple's CKModifyBadgeOperation.\npublic protocol CKModifyBadgeOperationProtocol: CKOperationProtocol {\n\n    /// - returns: the badge value\n    var badgeValue: Int { get set }\n\n    /// - returns: the completion block used\n    var modifyBadgeCompletionBlock: ((Error?) -> Void)? { get set }\n}\n\nextension CKModifyBadgeOperation: CKModifyBadgeOperationProtocol, AssociatedErrorProtocol {\n\n    // The associated error type\n    public typealias AssociatedError = PKCKError\n}\n\n@available(iOS, introduced: 8.0, deprecated: 11.0, message: \"No longer supported, will cease working at some point in the future\")\n@available(OSX, introduced: 10.10, deprecated: 10.13, message: \"No longer supported, will cease working at some point in the future\")\n@available(tvOS, introduced: 9.0, deprecated: 11.0, message: \"No longer supported, will cease working at some point in the future\")\n@available(watchOS, introduced: 3.0, deprecated: 4.0, message: \"No longer supported, will cease working at some point in the future\")\nextension CKProcedure where T: CKModifyBadgeOperationProtocol, T: AssociatedErrorProtocol, T.AssociatedError: CloudKitError {\n\n    public var badgeValue: Int {\n        get { return operation.badgeValue }\n        set { operation.badgeValue = newValue }\n    }\n\n    func setModifyBadgeCompletionBlock(_ block: @escaping CloudKitProcedure<T>.ModifyBadgeCompletionBlock) {\n        operation.modifyBadgeCompletionBlock = { [weak self] error in\n            if let strongSelf = self, let error = error {\n                strongSelf.setErrorOnce(PKCKError(underlyingError: error))\n            }\n            else {\n                block()\n            }\n        }\n    }\n}\n\n@available(iOS, introduced: 8.0, deprecated: 11.0, message: \"No longer supported, will cease working at some point in the future\")\n@available(OSX, introduced: 10.10, deprecated: 10.13, message: \"No longer supported, will cease working at some point in the future\")\n@available(tvOS, introduced: 9.0, deprecated: 11.0, message: \"No longer supported, will cease working at some point in the future\")\n@available(watchOS, introduced: 3.0, deprecated: 4.0, message: \"No longer supported, will cease working at some point in the future\")\nextension CloudKitProcedure where T: CKModifyBadgeOperationProtocol {\n\n    /// A typealias for the block types used by CloudKitOperation<CKModifyBadgeOperation>\n    public typealias ModifyBadgeCompletionBlock = () -> Void\n\n    public var badgeValue: Int {\n        get { return current.badgeValue }\n        set {\n            current.badgeValue = newValue\n            appendConfigureBlock { $0.badgeValue = newValue }\n        }\n    }\n\n    public func setModifyBadgeCompletionBlock(block: @escaping ModifyBadgeCompletionBlock) {\n        appendConfigureBlock { $0.setModifyBadgeCompletionBlock(block) }\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKitCloud/Notification Operations/CKFetchNotificationChangesOperation.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n#if SWIFT_PACKAGE\n    import ProcedureKit\n    import Foundation\n#endif\n\nimport CloudKit\n\n/// A generic protocol which exposes the properties used by Apple's CKFetchNotificationChangesOperation.\npublic protocol CKFetchNotificationChangesOperationProtocol: CKFetchOperation {\n\n    /// - returns: the block invoked when there are notification changes.\n    var notificationChangedBlock: ((Notification) -> Void)? { get set }\n\n    /// - returns: the completion block used for notification changes.\n    var fetchNotificationChangesCompletionBlock: ((ServerChangeToken?, Error?) -> Void)? { get set }\n}\n\npublic struct FetchNotificationChangesError<ServerChangeToken>: CloudKitError {\n    public let underlyingError: Error\n    public let token: ServerChangeToken?\n}\n\nextension CKFetchNotificationChangesOperation: CKFetchNotificationChangesOperationProtocol, AssociatedErrorProtocol {\n\n    // The associated error type\n    public typealias AssociatedError = FetchNotificationChangesError<ServerChangeToken>\n}\n\n@available(iOS, introduced: 8.0, deprecated: 11.0, message: \"Instead of iterating notifications to enumerate changed record zones, use CKDatabaseSubscription, CKFetchDatabaseChangesOperation, and CKFetchRecordZoneChangesOperation\")\n@available(OSX, introduced: 10.10, deprecated: 10.13, message: \"Instead of iterating notifications to enumerate changed record zones, use CKDatabaseSubscription, CKFetchDatabaseChangesOperation, and CKFetchRecordZoneChangesOperation\")\n@available(tvOS, introduced: 9.0, deprecated: 11.0, message: \"Instead of iterating notifications to enumerate changed record zones, use CKDatabaseSubscription, CKFetchDatabaseChangesOperation, and CKFetchRecordZoneChangesOperation\")\n@available(watchOS, introduced: 3.0, deprecated: 4.0, message: \"Instead of iterating notifications to enumerate changed record zones, use CKDatabaseSubscription, CKFetchDatabaseChangesOperation, and CKFetchRecordZoneChangesOperation\")\nextension CKProcedure where T: CKFetchNotificationChangesOperationProtocol, T: AssociatedErrorProtocol, T.AssociatedError: CloudKitError {\n\n    public var notificationChangedBlock: CloudKitProcedure<T>.FetchNotificationChangesChangedBlock? {\n        get { return operation.notificationChangedBlock }\n        set { operation.notificationChangedBlock = newValue }\n    }\n\n    func setFetchNotificationChangesCompletionBlock(_ block: @escaping CloudKitProcedure<T>.FetchNotificationChangesCompletionBlock) {\n\n        operation.fetchNotificationChangesCompletionBlock = { [weak self] token, error in\n            if let strongSelf = self, let error = error {\n                strongSelf.setErrorOnce(FetchNotificationChangesError(underlyingError: error, token: token))\n            }\n            else {\n                block(token)\n            }\n        }\n    }\n}\n\n@available(iOS, introduced: 8.0, deprecated: 11.0, message: \"Instead of iterating notifications to enumerate changed record zones, use CKDatabaseSubscription, CKFetchDatabaseChangesOperation, and CKFetchRecordZoneChangesOperation\")\n@available(OSX, introduced: 10.10, deprecated: 10.13, message: \"Instead of iterating notifications to enumerate changed record zones, use CKDatabaseSubscription, CKFetchDatabaseChangesOperation, and CKFetchRecordZoneChangesOperation\")\n@available(tvOS, introduced: 9.0, deprecated: 11.0, message: \"Instead of iterating notifications to enumerate changed record zones, use CKDatabaseSubscription, CKFetchDatabaseChangesOperation, and CKFetchRecordZoneChangesOperation\")\n@available(watchOS, introduced: 3.0, deprecated: 4.0, message: \"Instead of iterating notifications to enumerate changed record zones, use CKDatabaseSubscription, CKFetchDatabaseChangesOperation, and CKFetchRecordZoneChangesOperation\")\nextension CloudKitProcedure where T: CKFetchNotificationChangesOperationProtocol {\n\n    /// A typealias for the block types used by CloudKitOperation<CKFetchNotificationChangesOperation>\n    public typealias FetchNotificationChangesChangedBlock = (T.Notification) -> Void\n\n    /// A typealias for the block types used by CloudKitOperation<CKFetchNotificationChangesOperation>\n    public typealias FetchNotificationChangesCompletionBlock = (T.ServerChangeToken?) -> Void\n\n    /// - returns: the notification changed block\n    public var notificationChangedBlock: FetchNotificationChangesChangedBlock? {\n        get { return current.notificationChangedBlock }\n        set {\n            current.notificationChangedBlock = newValue\n            appendConfigureBlock { $0.notificationChangedBlock = newValue }\n        }\n    }\n\n    /**\n     Before adding the CloudKitOperation instance to a queue, set a completion block\n     to collect the results in the successful case. Setting this completion block also\n     ensures that error handling gets triggered.\n\n     - parameter block: a FetchNotificationChangesCompletionBlock block\n     */\n    public func setFetchNotificationChangesCompletionBlock(block: @escaping FetchNotificationChangesCompletionBlock) {\n        appendConfigureBlock { $0.setFetchNotificationChangesCompletionBlock(block) }\n    }\n}\n\n"
  },
  {
    "path": "Sources/ProcedureKitCloud/Notification Operations/CKMarkNotificationsReadOperation.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n#if SWIFT_PACKAGE\n    import ProcedureKit\n    import Foundation\n#endif\n\nimport CloudKit\n\n/// A generic protocol which exposes the properties used by Apple's CKMarkNotificationsReadOperation.\npublic protocol CKMarkNotificationsReadOperationProtocol: CKOperationProtocol {\n\n    /// The type of the notificationIDs property\n    associatedtype NotificationIDsPropertyType\n\n    /// - returns: the notification IDs\n    var notificationIDs: NotificationIDsPropertyType { get set }\n\n    /// - returns: the completion block used when marking notifications\n    var markNotificationsReadCompletionBlock: (([NotificationID]?, Error?) -> Void)? { get set }\n}\n\npublic struct MarkNotificationsReadError<NotificationID>: CloudKitError {\n\n    public let underlyingError: Error\n    public let marked: [NotificationID]?\n}\n\nextension CKMarkNotificationsReadOperation: CKMarkNotificationsReadOperationProtocol, AssociatedErrorProtocol {\n\n    // The associated error type\n    public typealias AssociatedError = MarkNotificationsReadError<NotificationID>\n}\n\n@available(iOS, introduced: 8.0, deprecated: 11.0, message: \"Instead of iterating notifications to enumerate changed record zones, use CKDatabaseSubscription, CKFetchDatabaseChangesOperation, and CKFetchRecordZoneChangesOperation\")\n@available(OSX, introduced: 10.10, deprecated: 10.13, message: \"Instead of iterating notifications to enumerate changed record zones, use CKDatabaseSubscription, CKFetchDatabaseChangesOperation, and CKFetchRecordZoneChangesOperation\")\n@available(tvOS, introduced: 9.0, deprecated: 11.0, message: \"Instead of iterating notifications to enumerate changed record zones, use CKDatabaseSubscription, CKFetchDatabaseChangesOperation, and CKFetchRecordZoneChangesOperation\")\n@available(watchOS, introduced: 3.0, deprecated: 4.0, message: \"Instead of iterating notifications to enumerate changed record zones, use CKDatabaseSubscription, CKFetchDatabaseChangesOperation, and CKFetchRecordZoneChangesOperation\")\nextension CKProcedure where T: CKMarkNotificationsReadOperationProtocol, T: AssociatedErrorProtocol, T.AssociatedError: CloudKitError {\n\n    public var notificationIDs: T.NotificationIDsPropertyType {\n        get { return operation.notificationIDs }\n        set { operation.notificationIDs = newValue }\n    }\n\n    func setMarkNotificationsReadCompletionBlock(_ block: @escaping CloudKitProcedure<T>.MarkNotificationsReadCompletionBlock) {\n        operation.markNotificationsReadCompletionBlock = { [weak self] notificationIDs, error in\n            if let strongSelf = self, let error = error {\n                strongSelf.setErrorOnce(MarkNotificationsReadError(underlyingError: error, marked: notificationIDs))\n            }\n            else {\n                block(notificationIDs)\n            }\n        }\n    }\n}\n\n@available(iOS, introduced: 8.0, deprecated: 11.0, message: \"Instead of iterating notifications to enumerate changed record zones, use CKDatabaseSubscription, CKFetchDatabaseChangesOperation, and CKFetchRecordZoneChangesOperation\")\n@available(OSX, introduced: 10.10, deprecated: 10.13, message: \"Instead of iterating notifications to enumerate changed record zones, use CKDatabaseSubscription, CKFetchDatabaseChangesOperation, and CKFetchRecordZoneChangesOperation\")\n@available(tvOS, introduced: 9.0, deprecated: 11.0, message: \"Instead of iterating notifications to enumerate changed record zones, use CKDatabaseSubscription, CKFetchDatabaseChangesOperation, and CKFetchRecordZoneChangesOperation\")\n@available(watchOS, introduced: 3.0, deprecated: 4.0, message: \"Instead of iterating notifications to enumerate changed record zones, use CKDatabaseSubscription, CKFetchDatabaseChangesOperation, and CKFetchRecordZoneChangesOperation\")\nextension CloudKitProcedure where T: CKMarkNotificationsReadOperationProtocol {\n\n    /// A typealias for the block types used by CloudKitOperation<CKMarkNotificationsReadOperation>\n    public typealias MarkNotificationsReadCompletionBlock = ([T.NotificationID]?) -> Void\n\n    /// - returns: the notification IDs\n    public var notificationIDs: T.NotificationIDsPropertyType {\n        get { return current.notificationIDs }\n        set {\n            current.notificationIDs = newValue\n            appendConfigureBlock { $0.notificationIDs = newValue }\n        }\n    }\n\n    /**\n     Before adding the CloudKitOperation instance to a queue, set a completion block\n     to collect the results in the successful case. Setting this completion block also\n     ensures that error handling gets triggered.\n\n     - parameter block: a MarkNotificationReadCompletionBlock block\n     */\n    public func setMarkNotificationsReadCompletionBlock(block: @escaping MarkNotificationsReadCompletionBlock) {\n        appendConfigureBlock { $0.setMarkNotificationsReadCompletionBlock(block) }\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKitCloud/Query Operations/CKQueryOperation.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n#if SWIFT_PACKAGE\n    import ProcedureKit\n    import Foundation\n#endif\n\nimport CloudKit\n\n/// A generic protocol which exposes the properties used by Apple's CKQueryOperation.\npublic protocol CKQueryOperationProtocol: CKDatabaseOperationProtocol, CKResultsLimit, CKDesiredKeys {\n\n    /// - returns: the query to execute\n    var query: Query? { get set }\n\n    /// - returns: the query cursor\n    var cursor: QueryCursor? { get set }\n\n    /// - returns: the zone ID\n    var zoneID: RecordZoneID? { get set }\n\n    /// - returns: a record fetched block\n    var recordFetchedBlock: ((Record) -> Void)? { get set }\n\n    /// - returns: the query completion block\n    var queryCompletionBlock: ((QueryCursor?, Error?) -> Void)? { get set }\n}\n\npublic struct QueryError<QueryCursor>: CloudKitError {\n\n    public let underlyingError: Error\n    public let cursor: QueryCursor?\n}\n\nextension CKQueryOperation: CKQueryOperationProtocol, AssociatedErrorProtocol {\n\n    // The associated error type\n    public typealias AssociatedError = QueryError<QueryCursor>\n}\n\nextension CKProcedure where T: CKQueryOperationProtocol, T: AssociatedErrorProtocol, T.AssociatedError: CloudKitError {\n\n    public var query: T.Query? {\n        get { return operation.query }\n        set { operation.query = newValue }\n    }\n\n    public var cursor: T.QueryCursor? {\n        get { return operation.cursor }\n        set { operation.cursor = newValue }\n    }\n\n    public var zoneID: T.RecordZoneID? {\n        get { return operation.zoneID }\n        set { operation.zoneID = newValue }\n    }\n\n    public var recordFetchedBlock: CloudKitProcedure<T>.QueryRecordFetchedBlock? {\n        get { return operation.recordFetchedBlock }\n        set { operation.recordFetchedBlock = newValue }\n    }\n\n    func setQueryCompletionBlock(_ block: @escaping CloudKitProcedure<T>.QueryCompletionBlock) {\n        operation.queryCompletionBlock = { [weak self] cursor, error in\n            if let strongSelf = self, let error = error {\n                strongSelf.setErrorOnce(QueryError(underlyingError: error, cursor: cursor))\n            }\n            else {\n                block(cursor)\n            }\n        }\n    }\n}\n\nextension CloudKitProcedure where T: CKQueryOperationProtocol {\n\n    /// A typealias for the block types used by CloudKitOperation<CKQueryOperation>\n    public typealias QueryRecordFetchedBlock = (T.Record) -> Void\n\n    /// A typealias for the block types used by CloudKitOperation<CKQueryOperation>\n    public typealias QueryCompletionBlock = (T.QueryCursor?) -> Void\n\n    /// - returns: the query\n    public var query: T.Query? {\n        get { return current.query }\n        set {\n            current.query = newValue\n            appendConfigureBlock { $0.query = newValue }\n        }\n    }\n\n    /// - returns: the query cursor\n    public var cursor: T.QueryCursor? {\n        get { return current.cursor }\n        set {\n            current.cursor = newValue\n            appendConfigureBlock { $0.cursor = newValue }\n        }\n    }\n\n    /// - returns: the zone ID\n    public var zoneID: T.RecordZoneID? {\n        get { return current.zoneID }\n        set {\n            current.zoneID = newValue\n            appendConfigureBlock { $0.zoneID = newValue }\n        }\n    }\n\n    /// - returns: a block for each record fetched\n    public var recordFetchedBlock: QueryRecordFetchedBlock? {\n        get { return current.recordFetchedBlock }\n        set {\n            current.recordFetchedBlock = newValue\n            appendConfigureBlock { $0.recordFetchedBlock = newValue }\n        }\n    }\n\n    /**\n     Before adding the CloudKitOperation instance to a queue, set a completion block\n     to collect the results in the successful case. Setting this completion block also\n     ensures that error handling gets triggered.\n\n     - parameter block: a QueryCompletionBlock block\n     */\n    public func setQueryCompletionBlock(block: @escaping QueryCompletionBlock) {\n        appendConfigureBlock { $0.setQueryCompletionBlock(block) }\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKitCloud/Record Operations/CKFetchDatabaseChangesOperation.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n#if SWIFT_PACKAGE\n    import ProcedureKit\n    import Foundation\n#endif\n\nimport CloudKit\n\n/// A generic protocol which exposes the properties used by Apple's CloudKit Operation's which have a flag to fetch all changes.\npublic protocol CKFetchAllChanges: CKOperationProtocol {\n\n    /// - returns: whether there are more results on the server\n    var fetchAllChanges: Bool { get set }\n}\n\nextension CKProcedure where T: CKFetchAllChanges {\n\n    var fetchAllChanges: Bool {\n        get { return operation.fetchAllChanges }\n        set { operation.fetchAllChanges = newValue }\n    }\n}\n\nextension CloudKitProcedure where T: CKFetchAllChanges {\n\n    /// - returns: the previous server change token\n    public var fetchAllChanges: Bool {\n        get { return current.fetchAllChanges }\n        set {\n            current.fetchAllChanges = newValue\n            appendConfigureBlock { $0.fetchAllChanges = newValue }\n        }\n    }\n}\n\n/// A generic protocol which exposes the properties used by Apple's CKFetchDatabaseChangesOperationType.\npublic protocol CKFetchDatabaseChangesOperationProtocol: CKDatabaseOperationProtocol, CKFetchAllChanges, CKPreviousServerChangeToken, CKResultsLimit {\n\n    /// - returns: a block for when a the changeToken is updated\n    var changeTokenUpdatedBlock: ((ServerChangeToken) -> Void)? { get set }\n\n    /// - returns: a block for when a recordZone was changed\n    var recordZoneWithIDChangedBlock: ((RecordZoneID) -> Void)? { get set }\n\n    /// - returns: a block for when a recordZone was deleted\n    var recordZoneWithIDWasDeletedBlock: ((RecordZoneID) -> Void)? { get set }\n\n    /// - returns: the completion for fetching database changes\n    var fetchDatabaseChangesCompletionBlock: ((ServerChangeToken?, Bool, Error?) -> Void)? { get set }\n}\n\npublic struct FetchDatabaseChangesError<ServerChangeToken>: CloudKitError {\n    public let underlyingError: Error\n    public let token: ServerChangeToken?\n    public let moreComing: Bool\n}\n\n@available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *)\nextension CKFetchDatabaseChangesOperation: CKFetchDatabaseChangesOperationProtocol, AssociatedErrorProtocol {\n\n    // The associated error type\n    public typealias AssociatedError = FetchDatabaseChangesError<ServerChangeToken>\n}\n\nextension CKProcedure where T: CKFetchDatabaseChangesOperationProtocol, T: AssociatedErrorProtocol, T.AssociatedError: CloudKitError {\n\n    public var recordZoneWithIDChangedBlock: CloudKitProcedure<T>.FetchDatabaseChangesRecordZoneWithIDChangedBlock? {\n        get { return operation.recordZoneWithIDChangedBlock }\n        set { operation.recordZoneWithIDChangedBlock = newValue }\n    }\n\n    public var recordZoneWithIDWasDeletedBlock: CloudKitProcedure<T>.FetchDatabaseChangesRecordZoneWithIDWasDeletedBlock? {\n        get { return operation.recordZoneWithIDWasDeletedBlock }\n        set { operation.recordZoneWithIDWasDeletedBlock = newValue }\n    }\n\n    public var changeTokenUpdatedBlock: CloudKitProcedure<T>.FetchDatabaseChangesChangeTokenUpdatedBlock? {\n        get { return operation.changeTokenUpdatedBlock }\n        set { operation.changeTokenUpdatedBlock = newValue }\n    }\n\n    func setFetchDatabaseChangesCompletionBlock(_ block: @escaping CloudKitProcedure<T>.FetchDatabaseChangesCompletionBlock) {\n        operation.fetchDatabaseChangesCompletionBlock = { [weak self] (serverChangeToken, moreComing, error) in\n            if let strongSelf = self, let error = error {\n                strongSelf.setErrorOnce(FetchDatabaseChangesError(underlyingError: error, token: serverChangeToken, moreComing: moreComing))\n            }\n            else {\n                block(serverChangeToken, moreComing)\n            }\n        }\n    }\n}\n\nextension CloudKitProcedure where T: CKFetchDatabaseChangesOperationProtocol {\n\n    /// A typealias for the block types used by CloudKitOperation<CKFetchDatabaseChangesOperationType>\n    public typealias FetchDatabaseChangesRecordZoneWithIDChangedBlock = (T.RecordZoneID) -> Void\n\n    /// A typealias for the block types used by CloudKitOperation<CKFetchDatabaseChangesOperationType>\n    public typealias FetchDatabaseChangesRecordZoneWithIDWasDeletedBlock = (T.RecordZoneID) -> Void\n\n    /// A typealias for the block types used by CloudKitOperation<CKFetchDatabaseChangesOperationType>\n    public typealias FetchDatabaseChangesChangeTokenUpdatedBlock = (T.ServerChangeToken) -> Void\n\n    /// A typealias for the block types used by CloudKitOperation<CKFetchDatabaseChangesOperationType>\n    public typealias FetchDatabaseChangesCompletionBlock = (T.ServerChangeToken?, Bool) -> Void\n\n    /// - returns: a block for when a record is changed\n    public var recordZoneWithIDChangedBlock: FetchDatabaseChangesRecordZoneWithIDChangedBlock? {\n        get { return current.recordZoneWithIDChangedBlock }\n        set {\n            current.recordZoneWithIDChangedBlock = newValue\n            appendConfigureBlock { $0.recordZoneWithIDChangedBlock = newValue }\n        }\n    }\n\n    /// - returns: a block for when a recordID is deleted (receives the recordID and the recordType)\n    public var recordZoneWithIDWasDeletedBlock: FetchDatabaseChangesRecordZoneWithIDWasDeletedBlock? {\n        get { return current.recordZoneWithIDWasDeletedBlock }\n        set {\n            current.recordZoneWithIDWasDeletedBlock = newValue\n            appendConfigureBlock { $0.recordZoneWithIDWasDeletedBlock = newValue }\n        }\n    }\n\n    /// - returns: a block for when a recordZone changeToken update is sent\n    public var changeTokenUpdatedBlock: FetchDatabaseChangesChangeTokenUpdatedBlock? {\n        get { return current.changeTokenUpdatedBlock }\n        set {\n            current.changeTokenUpdatedBlock = newValue\n            appendConfigureBlock { $0.changeTokenUpdatedBlock = newValue }\n        }\n    }\n\n    /**\n     Before adding the CloudKitOperation instance to a queue, set a completion block\n     to collect the results in the successful case. Setting this completion block also\n     ensures that error handling gets triggered.\n\n     - parameter block: a FetchDatabaseChangesCompletionBlock block\n     */\n    public func setFetchDatabaseChangesCompletionBlock(block: @escaping FetchDatabaseChangesCompletionBlock) {\n        appendConfigureBlock { $0.setFetchDatabaseChangesCompletionBlock(block) }\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKitCloud/Record Operations/CKFetchRecordZoneChangesOperation.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n#if SWIFT_PACKAGE\n    import ProcedureKit\n    import Foundation\n#endif\n\nimport CloudKit\n\n/// A generic protocol which exposes the properties used by Apple's CKFetchRecordZoneChangesOperation.\npublic protocol CKFetchRecordZoneChangesOperationProtocol: CKDatabaseOperationProtocol, CKFetchAllChanges {\n\n    /// The type of the CloudKit FetchRecordZoneChangesOptions\n    associatedtype FetchRecordZoneChangesOptions\n\n    /// The type of the CloudKit FetchRecordZoneCHangesConfiguration\n    associatedtype FetchRecordZoneChangesConfiguration\n\n    /// The type of the recordZoneIDs property\n    associatedtype RecordZoneIDsPropertyType\n\n    /// - returns: the record zone IDs which will fetch changes\n    var recordZoneIDs: RecordZoneIDsPropertyType { get set }\n\n    /// - returns: the per-record-zone options\n    @available(iOS, introduced: 10.0, deprecated: 12.0)\n    @available(OSX, introduced: 10.12, deprecated: 10.14)\n    @available(tvOS, introduced: 10.0, deprecated: 12.0)\n    @available(watchOS, introduced: 3.0, deprecated: 5.0)\n    var optionsByRecordZoneID: [RecordZoneID: FetchRecordZoneChangesOptions]? { get set }\n\n    /// - returns: the per-record-zone configuration\n    @available(iOS 12.0, OSX 10.14, tvOS 12.0, watchOS 5.0, *)\n    var configurationsByRecordZoneID: [RecordZoneID: FetchRecordZoneChangesConfiguration]? { get set }\n\n    /// - returns: a block for when a record is changed\n    var recordChangedBlock: ((Record) -> Void)? { get set }\n\n    /// - returns: a block for when a recordID is deleted (receives the recordID and the recordType)\n    var recordWithIDWasDeletedBlock: ((RecordID, String) -> Void)? { get set }\n\n    /// - returns: a block for when a recordZone changeToken update is sent\n    var recordZoneChangeTokensUpdatedBlock: ((RecordZoneID, ServerChangeToken?, Data?) -> Void)? { get set }\n\n    /// - returns: a block for when a recordZone fetch is complete\n    var recordZoneFetchCompletionBlock: ((RecordZoneID, ServerChangeToken?, Data?, Bool, Error?) -> Void)? { get set }\n\n    /// - returns: the completion for fetching records (i.e. for the entire operation)\n    var fetchRecordZoneChangesCompletionBlock: ((Error?) -> Void)? { get set }\n}\n\n@available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *)\nextension CKFetchRecordZoneChangesOperation: CKFetchRecordZoneChangesOperationProtocol, AssociatedErrorProtocol {\n\n    // The associated error type\n    public typealias AssociatedError = PKCKError\n\n    /// The type of the CloudKit FetchRecordZoneChangesOptions\n    @available(iOS, introduced: 10.0, deprecated: 12.0)\n    @available(OSX, introduced: 10.12, deprecated: 10.14)\n    @available(tvOS, introduced: 10.0, deprecated: 12.0)\n    @available(watchOS, introduced: 3.0, deprecated: 5.0)\n    public typealias FetchRecordZoneChangesOptions = CKFetchRecordZoneChangesOperation.ZoneOptions\n\n    @available(iOS 12.0, OSX 10.14, tvOS 12.0, watchOS 5.0, *)\n    public typealias FetchRecordZoneChangesConfiguration = CKFetchRecordZoneChangesOperation.ZoneConfiguration\n}\n\nextension CKProcedure where T: CKFetchRecordZoneChangesOperationProtocol, T: AssociatedErrorProtocol, T.AssociatedError: CloudKitError {\n\n    /// - returns: the record zone IDs which will fetch changes\n    public var recordZoneIDs: T.RecordZoneIDsPropertyType {\n        get { return operation.recordZoneIDs }\n        set { operation.recordZoneIDs = newValue }\n    }\n\n    /// - returns: the per-record-zone options\n    @available(iOS, introduced: 10.0, deprecated: 12.0)\n    @available(OSX, introduced: 10.12, deprecated: 10.14)\n    @available(tvOS, introduced: 10.0, deprecated: 12.0)\n    @available(watchOS, introduced: 3.0, deprecated: 5.0)\n    public var optionsByRecordZoneID: [T.RecordZoneID : T.FetchRecordZoneChangesOptions]? {\n        get { return operation.optionsByRecordZoneID }\n        set { operation.optionsByRecordZoneID = newValue }\n    }\n\n    /// - returns: the per-record-zone configuration\n    @available(iOS 12.0, OSX 10.14, tvOS 12.0, watchOS 5.0, *)\n    public var configurationsByRecordZoneID: [T.RecordZoneID: T.FetchRecordZoneChangesConfiguration]? {\n        get { return operation.configurationsByRecordZoneID }\n        set {operation.configurationsByRecordZoneID = newValue }\n    }\n\n    /// - returns: a block for when a record is changed\n    public var recordChangedBlock: CloudKitProcedure<T>.FetchRecordZoneChangesRecordChangedBlock? {\n        get { return operation.recordChangedBlock }\n        set { operation.recordChangedBlock = newValue }\n    }\n\n    /// - returns: a block for when a recordID is deleted (receives the recordID and the recordType)\n    public var recordWithIDWasDeletedBlock: CloudKitProcedure<T>.FetchRecordZoneChangesRecordWithIDWasDeletedBlock? {\n        get { return operation.recordWithIDWasDeletedBlock }\n        set { operation.recordWithIDWasDeletedBlock = newValue }\n    }\n\n    /// - returns: a block for when a recordZone changeToken update is sent\n    public var recordZoneChangeTokensUpdatedBlock: CloudKitProcedure<T>.FetchRecordZoneChangesRecordZoneChangeTokensUpdatedBlock? {\n        get { return operation.recordZoneChangeTokensUpdatedBlock }\n        set { operation.recordZoneChangeTokensUpdatedBlock = newValue }\n    }\n\n    /// - returns: a block to execute when the fetch for a zone has completed\n    public var recordZoneFetchCompletionBlock: CloudKitProcedure<T>.FetchRecordZoneChangesCompletionRecordZoneFetchCompletionBlock? {\n        get { return operation.recordZoneFetchCompletionBlock }\n        set { operation.recordZoneFetchCompletionBlock = newValue }\n    }\n\n    /// - returns: the completion for fetching records (i.e. for the entire operation)\n    func setFetchRecordZoneChangesCompletionBlock(_ block: @escaping CloudKitProcedure<T>.FetchRecordZoneChangesCompletionBlock) {\n        operation.fetchRecordZoneChangesCompletionBlock = { [weak self] error in\n            if let strongSelf = self, let error = error {\n                strongSelf.setErrorOnce(PKCKError(underlyingError: error))\n            }\n            else {\n                block()\n            }\n        }\n    }\n}\n\nextension CloudKitProcedure where T: CKFetchRecordZoneChangesOperationProtocol {\n\n    /// A typealias for the block types used by CloudKitOperation<CKFetchRecordZoneChangesOperationType>\n    public typealias FetchRecordZoneChangesRecordChangedBlock = (T.Record) -> Void\n\n    /// A typealias for the block types used by CloudKitOperation<CKFetchRecordZoneChangesOperationType>\n    public typealias FetchRecordZoneChangesRecordWithIDWasDeletedBlock = (T.RecordID, String) -> Void\n\n    /// A typealias for the block types used by CloudKitOperation<CKFetchRecordZoneChangesOperationType>\n    public typealias FetchRecordZoneChangesRecordZoneChangeTokensUpdatedBlock = (T.RecordZoneID, T.ServerChangeToken?, Data?) -> Void\n\n    /// A typealias for the block types used by CloudKitOperation<CKFetchRecordZoneChangesOperationType>\n    public typealias FetchRecordZoneChangesCompletionRecordZoneFetchCompletionBlock = (T.RecordZoneID, T.ServerChangeToken?, Data?, Bool, Error?) -> Void\n\n    /// A typealias for the block types used by CloudKitOperation<CKFetchRecordZoneChangesOperationType>\n    public typealias FetchRecordZoneChangesCompletionBlock = () -> Void\n\n    /// - returns: the record zone IDs which will fetch changes\n    public var recordZoneIDs: T.RecordZoneIDsPropertyType {\n        get { return current.recordZoneIDs }\n        set {\n            current.recordZoneIDs = newValue\n            appendConfigureBlock { $0.recordZoneIDs = newValue }\n        }\n    }\n\n    /// - returns: the per-record-zone options\n    @available(iOS, introduced: 10.0, deprecated: 12.0)\n    @available(OSX, introduced: 10.12, deprecated: 10.14)\n    @available(tvOS, introduced: 10.0, deprecated: 12.0)\n    @available(watchOS, introduced: 3.0, deprecated: 5.0)\n    public var optionsByRecordZoneID: [T.RecordZoneID : T.FetchRecordZoneChangesOptions]? {\n        get { return current.optionsByRecordZoneID }\n        set {\n            current.optionsByRecordZoneID = newValue\n            appendConfigureBlock { $0.optionsByRecordZoneID = newValue }\n        }\n    }\n\n    /// - returns: the per-record-zone configuration\n    @available(iOS 12.0, OSX 10.14, tvOS 12.0, watchOS 5.0, *)\n    public var configurationsByRecordZoneID: [T.RecordZoneID: T.FetchRecordZoneChangesConfiguration]? {\n        get { return current.configurationsByRecordZoneID }\n        set {\n            current.configurationsByRecordZoneID = newValue\n            appendConfigureBlock { $0.configurationsByRecordZoneID = newValue }\n        }\n    }\n\n    /// - returns: a block for when a record is changed\n    public var recordChangedBlock: FetchRecordZoneChangesRecordChangedBlock? {\n        get { return current.recordChangedBlock }\n        set {\n            current.recordChangedBlock = newValue\n            appendConfigureBlock { $0.recordChangedBlock = newValue }\n        }\n    }\n\n    /// - returns: a block for when a recordID is deleted (receives the recordID and the recordType)\n    public var recordWithIDWasDeletedBlock: FetchRecordZoneChangesRecordWithIDWasDeletedBlock? {\n        get { return current.recordWithIDWasDeletedBlock }\n        set {\n            current.recordWithIDWasDeletedBlock = newValue\n            appendConfigureBlock { $0.recordWithIDWasDeletedBlock = newValue }\n        }\n    }\n\n    /// - returns: a block for when a recordZone changeToken update is sent\n    public var recordZoneChangeTokensUpdatedBlock: FetchRecordZoneChangesRecordZoneChangeTokensUpdatedBlock? {\n        get { return current.recordZoneChangeTokensUpdatedBlock }\n        set {\n            current.recordZoneChangeTokensUpdatedBlock = newValue\n            appendConfigureBlock { $0.recordZoneChangeTokensUpdatedBlock = newValue }\n        }\n    }\n\n    /// - returns: a block to execute when the fetch for a zone has completed\n    public var recordZoneFetchCompletionBlock: FetchRecordZoneChangesCompletionRecordZoneFetchCompletionBlock? {\n        get { return current.recordZoneFetchCompletionBlock }\n        set {\n            current.recordZoneFetchCompletionBlock = newValue\n            appendConfigureBlock { $0.recordZoneFetchCompletionBlock = newValue }\n        }\n    }\n\n    /**\n     Before adding the CloudKitOperation instance to a queue, set a completion block\n     to collect the results in the successful case. Setting this completion block also\n     ensures that error handling gets triggered.\n\n     - parameter block: a FetchRecordZoneChangesCompletionBlock block\n     */\n    public func setFetchRecordZoneChangesCompletionBlock(block: @escaping FetchRecordZoneChangesCompletionBlock) {\n        appendConfigureBlock { $0.setFetchRecordZoneChangesCompletionBlock(block) }\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKitCloud/Record Operations/CKFetchRecordZonesOperation.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n#if SWIFT_PACKAGE\n    import ProcedureKit\n    import Foundation\n#endif\n\nimport CloudKit\n\n/// A generic protocol which exposes the properties used by Apple's CKFetchRecordZonesOperation.\npublic protocol CKFetchRecordZonesOperationProtocol: CKDatabaseOperationProtocol {\n\n    /// - returns: the record zone IDs which will be fetched\n    var recordZoneIDs: [RecordZoneID]? { get set }\n\n    /// - returns: the completion block for fetching record zones\n    var fetchRecordZonesCompletionBlock: (([RecordZoneID: RecordZone]?, Error?) -> Void)? { get set }\n}\n\npublic struct FetchRecordZonesError<RecordZone, RecordZoneID: Hashable>: CloudKitError {\n\n    public let underlyingError: Error\n    public let zonesByID: [RecordZoneID: RecordZone]?\n}\n\nextension CKFetchRecordZonesOperation: CKFetchRecordZonesOperationProtocol, AssociatedErrorProtocol {\n\n    // The associated error type\n    public typealias AssociatedError = FetchRecordZonesError<RecordZone, RecordZoneID>\n}\n\nextension CKProcedure where T: CKFetchRecordZonesOperationProtocol, T: AssociatedErrorProtocol, T.AssociatedError: CloudKitError {\n\n    public var recordZoneIDs: [T.RecordZoneID]? {\n        get { return operation.recordZoneIDs }\n        set { operation.recordZoneIDs = newValue }\n    }\n\n    func setFetchRecordZonesCompletionBlock(_ block: @escaping CloudKitProcedure<T>.FetchRecordZonesCompletionBlock) {\n        operation.fetchRecordZonesCompletionBlock = { [weak self] zonesByID, error in\n            if let strongSelf = self, let error = error {\n                strongSelf.setErrorOnce(FetchRecordZonesError(underlyingError: error, zonesByID: zonesByID))\n            }\n            else {\n                block(zonesByID)\n            }\n        }\n    }\n}\n\nextension CloudKitProcedure where T: CKFetchRecordZonesOperationProtocol {\n\n    /// A typealias for the block types used by CloudKitOperation<CKFetchRecordZonesOperation>\n    public typealias FetchRecordZonesCompletionBlock = ([T.RecordZoneID: T.RecordZone]?) -> Void\n\n    /// - returns: the record zone IDs\n    public var recordZoneIDs: [T.RecordZoneID]? {\n        get { return current.recordZoneIDs }\n        set {\n            current.recordZoneIDs = newValue\n            appendConfigureBlock { $0.recordZoneIDs = newValue }\n        }\n    }\n\n    /**\n     Before adding the CloudKitOperation instance to a queue, set a completion block\n     to collect the results in the successful case. Setting this completion block also\n     ensures that error handling gets triggered.\n\n     - parameter block: a FetchRecordZonesCompletionBlock block\n     */\n    public func setFetchRecordZonesCompletionBlock(block: @escaping FetchRecordZonesCompletionBlock) {\n        appendConfigureBlock { $0.setFetchRecordZonesCompletionBlock(block) }\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKitCloud/Record Operations/CKFetchRecordsOperation.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n#if SWIFT_PACKAGE\n    import ProcedureKit\n    import Foundation\n#endif\n\nimport CloudKit\n\n/// A generic protocol which exposes the properties used by Apple's CKFetchRecordsOperation.\npublic protocol CKFetchRecordsOperationProtocol: CKDatabaseOperationProtocol, CKDesiredKeys {\n\n    /// - returns: the record IDs\n    var recordIDs: [RecordID]? { get set }\n\n    /// - returns: a per record progress block\n    var perRecordProgressBlock: ((RecordID, Double) -> Void)? { get set }\n\n    /// - returns: a per record completion block\n    var perRecordCompletionBlock: ((Record?, RecordID?, Error?) -> Void)? { get set }\n\n    /// - returns: the fetch record completion block\n    var fetchRecordsCompletionBlock: (([RecordID: Record]?, Error?) -> Void)? { get set }\n}\n\npublic struct FetchRecordsError<Record, RecordID: Hashable>: CloudKitError {\n\n    public let underlyingError: Error\n    public let recordsByID: [RecordID: Record]?\n}\n\nextension CKFetchRecordsOperation: CKFetchRecordsOperationProtocol, AssociatedErrorProtocol {\n\n    // The associated error type\n    public typealias AssociatedError = FetchRecordsError<Record, RecordID>\n}\n\nextension CKProcedure where T: CKFetchRecordsOperationProtocol, T: AssociatedErrorProtocol, T.AssociatedError: CloudKitError {\n\n    public var recordIDs: [T.RecordID]? {\n        get { return operation.recordIDs }\n        set { operation.recordIDs = newValue }\n    }\n\n    public var perRecordProgressBlock: CloudKitProcedure<T>.FetchRecordsPerRecordProgressBlock? {\n        get { return operation.perRecordProgressBlock }\n        set { operation.perRecordProgressBlock = newValue }\n    }\n\n    public var perRecordCompletionBlock: CloudKitProcedure<T>.FetchRecordsPerRecordCompletionBlock? {\n        get { return operation.perRecordCompletionBlock }\n        set { operation.perRecordCompletionBlock = newValue }\n    }\n\n    func setFetchRecordsCompletionBlock(_ block: @escaping CloudKitProcedure<T>.FetchRecordsCompletionBlock) {\n        operation.fetchRecordsCompletionBlock = { [weak self] recordsByID, error in\n            if let strongSelf = self, let error = error {\n                strongSelf.setErrorOnce(FetchRecordsError(underlyingError: error, recordsByID: recordsByID))\n            }\n            else {\n                block(recordsByID)\n            }\n        }\n    }\n}\n\nextension CloudKitProcedure where T: CKFetchRecordsOperationProtocol {\n\n    /// A typealias for the block types used by CloudKitOperation<CKFetchRecordsOperation>\n    public typealias FetchRecordsPerRecordProgressBlock = (T.RecordID, Double) -> Void\n\n    /// A typealias for the block types used by CloudKitOperation<CKFetchRecordsOperation>\n    public typealias FetchRecordsPerRecordCompletionBlock = (T.Record?, T.RecordID?, Error?) -> Void\n\n    /// A typealias for the block types used by CloudKitOperation<CKFetchRecordsOperation>\n    public typealias FetchRecordsCompletionBlock = ([T.RecordID: T.Record]?) -> Void\n\n    /// - returns: the record IDs\n    public var recordIDs: [T.RecordID]? {\n        get { return current.recordIDs }\n        set {\n            current.recordIDs = newValue\n            appendConfigureBlock { $0.recordIDs = newValue }\n        }\n    }\n\n    /// - returns: a block for the record progress\n    public var perRecordProgressBlock: FetchRecordsPerRecordProgressBlock? {\n        get { return current.perRecordProgressBlock }\n        set {\n            current.perRecordProgressBlock = newValue\n            appendConfigureBlock { $0.perRecordProgressBlock = newValue }\n        }\n    }\n\n    /// - returns: a block for the record completion\n    public var perRecordCompletionBlock: FetchRecordsPerRecordCompletionBlock? {\n        get { return current.perRecordCompletionBlock }\n        set {\n            current.perRecordCompletionBlock = newValue\n            appendConfigureBlock { $0.perRecordCompletionBlock = newValue }\n        }\n    }\n\n    /**\n     Before adding the CloudKitOperation instance to a queue, set a completion block\n     to collect the results in the successful case. Setting this completion block also\n     ensures that error handling gets triggered.\n\n     - parameter block: a FetchRecordsCompletionBlock block\n     */\n    public func setFetchRecordsCompletionBlock(block: @escaping FetchRecordsCompletionBlock) {\n        appendConfigureBlock { $0.setFetchRecordsCompletionBlock(block) }\n    }\n}\n\n"
  },
  {
    "path": "Sources/ProcedureKitCloud/Record Operations/CKModifyRecordZonesOperation.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n#if SWIFT_PACKAGE\n    import ProcedureKit\n    import Foundation\n#endif\n\nimport CloudKit\n\n/// A generic protocol which exposes the properties used by Apple's CKModifyRecordZonesOperation.\npublic protocol CKModifyRecordZonesOperationProtocol: CKDatabaseOperationProtocol {\n\n    /// - returns: the record zones to save\n    var recordZonesToSave: [RecordZone]? { get set }\n\n    /// - returns: the record zone IDs to delete\n    var recordZoneIDsToDelete: [RecordZoneID]? { get set }\n\n    /// - returns: the modify record zones completion block\n    var modifyRecordZonesCompletionBlock: (([RecordZone]?, [RecordZoneID]?, Error?) -> Void)? { get set }\n}\n\npublic struct ModifyRecordZonesError<RecordZone, RecordZoneID>: CloudKitError, CloudKitBatchModifyError {\n\n    public let underlyingError: Error\n    public let saved: [RecordZone]?\n    public let deleted: [RecordZoneID]?\n}\n\nextension CKModifyRecordZonesOperation: CKModifyRecordZonesOperationProtocol, AssociatedErrorProtocol {\n\n    // The associated error type\n    public typealias AssociatedError = ModifyRecordZonesError<RecordZone, RecordZoneID>\n}\n\nextension CKProcedure where T: CKModifyRecordZonesOperationProtocol, T: AssociatedErrorProtocol, T.AssociatedError: CloudKitError {\n\n    public var recordZonesToSave: [T.RecordZone]? {\n        get { return operation.recordZonesToSave }\n        set { operation.recordZonesToSave = newValue }\n    }\n\n    public var recordZoneIDsToDelete: [T.RecordZoneID]? {\n        get { return operation.recordZoneIDsToDelete }\n        set { operation.recordZoneIDsToDelete = newValue }\n    }\n\n    func setModifyRecordZonesCompletionBlock(_ block: @escaping CloudKitProcedure<T>.ModifyRecordZonesCompletionBlock) {\n        operation.modifyRecordZonesCompletionBlock = { [weak self] saved, deleted, error in\n            if let strongSelf = self, let error = error {\n                strongSelf.setErrorOnce(ModifyRecordZonesError(underlyingError: error, saved: saved, deleted: deleted))\n            }\n            else {\n                block(saved, deleted)\n            }\n        }\n    }\n}\n\nextension CloudKitProcedure where T: CKModifyRecordZonesOperationProtocol {\n\n    internal typealias ModifyRecordZonesCompletion = ([T.RecordZone]?, [T.RecordZoneID]?)\n\n    /// A typealias for the block types used by CloudKitOperation<CKModifyRecordZonesOperation>\n    public typealias ModifyRecordZonesCompletionBlock = ([T.RecordZone]?, [T.RecordZoneID]?) -> Void\n\n    /// - returns: the record zones to save\n    public var recordZonesToSave: [T.RecordZone]? {\n        get { return current.recordZonesToSave }\n        set {\n            current.recordZonesToSave = newValue\n            appendConfigureBlock { $0.recordZonesToSave = newValue }\n        }\n    }\n\n    /// - returns: the record zone IDs to delete\n    public var recordZoneIDsToDelete: [T.RecordZoneID]? {\n        get { return current.recordZoneIDsToDelete }\n        set {\n            current.recordZoneIDsToDelete = newValue\n            appendConfigureBlock { $0.recordZoneIDsToDelete = newValue }\n        }\n    }\n\n    /**\n     Before adding the CloudKitOperation instance to a queue, set a completion block\n     to collect the results in the successful case. Setting this completion block also\n     ensures that error handling gets triggered.\n\n     - parameter block: a ModifyRecordZonesCompletionBlock block\n     */\n    public func setModifyRecordZonesCompletionBlock(block: @escaping ModifyRecordZonesCompletionBlock) {\n        appendConfigureBlock { $0.setModifyRecordZonesCompletionBlock(block) }\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKitCloud/Record Operations/CKModifyRecordsOperation.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n#if SWIFT_PACKAGE\n    import ProcedureKit\n    import Foundation\n#endif\n\nimport CloudKit\n\n/// A generic protocol which exposes the properties used by Apple's CKModifyRecordsOperation.\npublic protocol CKModifyRecordsOperationProtocol: CKDatabaseOperationProtocol {\n\n    /// The type of the perRecordCompletionBlock property\n    associatedtype PerRecordCompletionBlockType\n\n    /// - returns: the records to save\n    var recordsToSave: [Record]? { get set }\n\n    /// - returns: the record IDs to delete\n    var recordIDsToDelete: [RecordID]? { get set }\n\n    /// - returns: the save policy\n    var savePolicy: RecordSavePolicy { get set }\n\n    /// - returns: the client change token data\n    var clientChangeTokenData: Data? { get set }\n\n    /// - returns: a flag for atomic changes\n    var isAtomic: Bool { get set }\n\n    /// - returns: a per record progress block\n    var perRecordProgressBlock: ((Record, Double) -> Void)? { get set }\n\n    /// - returns: a per record completion block\n    var perRecordCompletionBlock: PerRecordCompletionBlockType { get set }\n\n    /// - returns: the modify records completion block\n    var modifyRecordsCompletionBlock: (([Record]?, [RecordID]?, Error?) -> Void)? { get set }\n}\n\npublic struct ModifyRecordsError<Record, RecordID>: CloudKitError, CloudKitBatchModifyError {\n\n    public let underlyingError: Error\n    public let saved: [Record]?\n    public let deleted: [RecordID]?\n}\n\nextension CKModifyRecordsOperation: CKModifyRecordsOperationProtocol, AssociatedErrorProtocol {\n\n    // The associated error type\n    public typealias AssociatedError = ModifyRecordsError<Record, RecordID>\n}\n\nextension CKProcedure where T: CKModifyRecordsOperationProtocol, T: AssociatedErrorProtocol, T.AssociatedError: CloudKitError {\n\n    public var recordsToSave: [T.Record]? {\n        get { return operation.recordsToSave }\n        set { operation.recordsToSave = newValue }\n    }\n\n    public var recordIDsToDelete: [T.RecordID]? {\n        get { return operation.recordIDsToDelete }\n        set { operation.recordIDsToDelete = newValue }\n    }\n\n    public var savePolicy: T.RecordSavePolicy {\n        get { return operation.savePolicy }\n        set { operation.savePolicy = newValue }\n    }\n\n    public var clientChangeTokenData: Data? {\n        get { return operation.clientChangeTokenData }\n        set { operation.clientChangeTokenData = newValue }\n    }\n\n    public var isAtomic: Bool {\n        get { return operation.isAtomic }\n        set { operation.isAtomic = newValue }\n    }\n\n    public var perRecordProgressBlock: CloudKitProcedure<T>.ModifyRecordsPerRecordProgressBlock? {\n        get { return operation.perRecordProgressBlock }\n        set { operation.perRecordProgressBlock = newValue }\n    }\n\n    public var perRecordCompletionBlock: CloudKitProcedure<T>.ModifyRecordsPerRecordCompletionBlock {\n        get { return operation.perRecordCompletionBlock }\n        set { operation.perRecordCompletionBlock = newValue }\n    }\n\n    func setModifyRecordsCompletionBlock(_ block: @escaping CloudKitProcedure<T>.ModifyRecordsCompletionBlock) {\n        operation.modifyRecordsCompletionBlock = { [weak self] saved, deleted, error in\n            if let strongSelf = self, let error = error {\n                strongSelf.setErrorOnce(ModifyRecordsError(underlyingError: error, saved: saved, deleted: deleted))\n            }\n            else {\n                block(saved, deleted)\n            }\n        }\n    }\n}\n\nextension CloudKitProcedure where T: CKModifyRecordsOperationProtocol {\n\n    internal typealias ModifyRecordsPerRecordProgress = (T.Record, Double)\n    internal typealias ModifyRecordsPerRecordCompletion = (T.Record?, Error?)\n    internal typealias ModifyRecordsCompletion = ([T.Record]?, [T.RecordID]?)\n\n    /// A typealias for the block types used by CloudKitOperation<CKModifyRecordsOperation>\n    public typealias ModifyRecordsPerRecordProgressBlock = (T.Record, Double) -> Void\n\n    /// A typealias for the block types used by CloudKitOperation<CKModifyRecordsOperation>\n    public typealias ModifyRecordsPerRecordCompletionBlock = T.PerRecordCompletionBlockType\n\n    /// A typealias for the block types used by CloudKitOperation<CKModifyRecordsOperation>\n    public typealias ModifyRecordsCompletionBlock = ([T.Record]?, [T.RecordID]?) -> Void\n\n    /// - returns: the records to save\n    public var recordsToSave: [T.Record]? {\n        get { return current.recordsToSave }\n        set {\n            current.recordsToSave = newValue\n            appendConfigureBlock { $0.recordsToSave = newValue }\n        }\n    }\n\n    /// - returns: the record IDs to delete\n    public var recordIDsToDelete: [T.RecordID]? {\n        get { return current.recordIDsToDelete }\n        set {\n            current.recordIDsToDelete = newValue\n            appendConfigureBlock { $0.recordIDsToDelete = newValue }\n        }\n    }\n\n    /// - returns: the save policy\n    public var savePolicy: T.RecordSavePolicy {\n        get { return current.savePolicy }\n        set {\n            current.savePolicy = newValue\n            appendConfigureBlock { $0.savePolicy = newValue }\n        }\n    }\n\n    /// - returns: the client change token data\n    public var clientChangeTokenData: Data? {\n        get { return current.clientChangeTokenData }\n        set {\n            current.clientChangeTokenData = newValue\n            appendConfigureBlock { $0.clientChangeTokenData = newValue }\n        }\n    }\n\n    /// - returns: a flag to indicate atomicity\n    public var isAtomic: Bool {\n        get { return current.isAtomic }\n        set {\n            current.isAtomic = newValue\n            appendConfigureBlock { $0.isAtomic = newValue }\n        }\n    }\n\n    /// - returns: a block for per record progress\n    public var perRecordProgressBlock: ModifyRecordsPerRecordProgressBlock? {\n        get { return current.perRecordProgressBlock }\n        set {\n            current.perRecordProgressBlock = newValue\n            appendConfigureBlock { $0.perRecordProgressBlock = newValue }\n        }\n    }\n\n    /// - returns: a block for per record completion\n    public var perRecordCompletionBlock: ModifyRecordsPerRecordCompletionBlock {\n        get { return current.perRecordCompletionBlock }\n        set {\n            current.perRecordCompletionBlock = newValue\n            appendConfigureBlock { $0.perRecordCompletionBlock = newValue }\n        }\n    }\n\n    /**\n     Before adding the CloudKitOperation instance to a queue, set a completion block\n     to collect the results in the successful case. Setting this completion block also\n     ensures that error handling gets triggered.\n\n     - parameter block: a ModifyRecordsCompletionBlock block\n     */\n    public func setModifyRecordsCompletionBlock(block: @escaping ModifyRecordsCompletionBlock) {\n        appendConfigureBlock { $0.setModifyRecordsCompletionBlock(block) }\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKitCloud/Share Operations/CKAcceptSharesOperation.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n#if SWIFT_PACKAGE\n    import ProcedureKit\n    import Foundation\n#endif\n\nimport CloudKit\n\n/// A generic protocol which exposes the properties used by Apple's CKAcceptSharesOperation.\npublic protocol CKAcceptSharesOperationProtocol: CKOperationProtocol {\n\n    /// The type of the shareMetadatas property\n    associatedtype ShareMetadatasPropertyType\n\n    /// - returns: the share metadatas\n    var shareMetadatas: ShareMetadatasPropertyType { get set }\n\n    /// - returns: the block used to return accepted shares\n    var perShareCompletionBlock: ((ShareMetadata, Share?, Swift.Error?) -> Void)? { get set }\n\n    /// - returns: the completion block used for accepting shares\n    var acceptSharesCompletionBlock: ((Swift.Error?) -> Void)? { get set }\n}\n\n@available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *)\nextension CKAcceptSharesOperation: CKAcceptSharesOperationProtocol, AssociatedErrorProtocol {\n\n    // The associated error type\n    public typealias AssociatedError = PKCKError\n}\n\nextension CKProcedure where T: CKAcceptSharesOperationProtocol, T: AssociatedErrorProtocol, T.AssociatedError: CloudKitError {\n\n    public var shareMetadatas: T.ShareMetadatasPropertyType {\n        get { return operation.shareMetadatas }\n        set { operation.shareMetadatas = newValue }\n    }\n\n    public var perShareCompletionBlock: CloudKitProcedure<T>.AcceptSharesPerShareCompletionBlock? {\n        get { return operation.perShareCompletionBlock }\n        set { operation.perShareCompletionBlock = newValue }\n    }\n\n    func setAcceptSharesCompletionBlock(_ block: @escaping CloudKitProcedure<T>.AcceptSharesCompletionBlock) {\n        operation.acceptSharesCompletionBlock = { [weak self] error in\n            if let strongSelf = self, let error = error {\n                strongSelf.setErrorOnce(PKCKError(underlyingError: error))\n            }\n            else {\n                block()\n            }\n        }\n    }\n}\n\nextension CloudKitProcedure where T: CKAcceptSharesOperationProtocol {\n\n    /// A typealias for the block type used by CloudKitOperation<CKAcceptSharesOperationType>\n    public typealias AcceptSharesPerShareCompletionBlock = (T.ShareMetadata, T.Share?, Error?) -> Void\n\n    /// A typealias for the block type used by CloudKitOperation<CKAcceptSharesOperationType>\n    public typealias AcceptSharesCompletionBlock = () -> Void\n\n    /// - returns: the share metadatas\n    public var shareMetadatas: T.ShareMetadatasPropertyType {\n        get { return current.shareMetadatas }\n        set {\n            current.shareMetadatas = newValue\n            appendConfigureBlock { $0.shareMetadatas = newValue }\n        }\n    }\n\n    /// - returns: the block used to return accepted shares\n    public var perShareCompletionBlock: AcceptSharesPerShareCompletionBlock? {\n        get { return current.perShareCompletionBlock }\n        set {\n            current.perShareCompletionBlock = newValue\n            appendConfigureBlock { $0.perShareCompletionBlock = newValue }\n        }\n    }\n\n    /**\n     Before adding the CloudKitOperation instance to a queue, set a completion block\n     to collect the results in the successful case. Setting this completion block also\n     ensures that error handling gets triggered.\n\n     - parameter block: an AcceptSharesCompletionBlock block\n     */\n    public func setAcceptSharesCompletionBlock(block: @escaping AcceptSharesCompletionBlock) {\n        appendConfigureBlock { $0.setAcceptSharesCompletionBlock(block) }\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKitCloud/Share Operations/CKFetchShareMetadataOperation.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n#if SWIFT_PACKAGE\n    import ProcedureKit\n    import Foundation\n#endif\n\nimport CloudKit\n\n/// A generic protocol which exposes the properties used by Apple's CKFetchShareMetadataOperation.\npublic protocol CKFetchShareMetadataOperationProtocol: CKOperationProtocol {\n\n    /// The type of the shareURLs property\n    associatedtype ShareURLsPropertyType\n\n    /// The type of the field keys\n    associatedtype FieldKey\n\n    /// - returns: the share URLs\n    var shareURLs: ShareURLsPropertyType { get set }\n\n    /// - returns: whether to fetch the share root record\n    var shouldFetchRootRecord: Bool { get set }\n\n    /// - returns: the share root record desired keys\n    var rootRecordDesiredKeys: [FieldKey]? { get set }\n\n    /// - returns: the per share metadata block\n    var perShareMetadataBlock: ((URL, ShareMetadata?, Error?) -> Void)? { get set }\n\n    /// - returns: the fetch share metadata completion block\n    var fetchShareMetadataCompletionBlock: ((Error?) -> Void)? { get set }\n}\n\n@available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *)\nextension CKFetchShareMetadataOperation: CKFetchShareMetadataOperationProtocol, AssociatedErrorProtocol {\n\n    // The associated error type\n    public typealias AssociatedError = PKCKError\n\n    #if swift(>=4.2)\n    public typealias FieldKey = CKRecord.FieldKey\n    #else\n    public typealias FieldKey = String\n    #endif\n}\n\nextension CKProcedure where T: CKFetchShareMetadataOperationProtocol, T: AssociatedErrorProtocol, T.AssociatedError: CloudKitError {\n\n    public var shareURLs: T.ShareURLsPropertyType {\n        get { return operation.shareURLs }\n        set { operation.shareURLs = newValue }\n    }\n\n    public var shouldFetchRootRecord: Bool {\n        get { return operation.shouldFetchRootRecord }\n        set { operation.shouldFetchRootRecord = newValue }\n    }\n\n    public var rootRecordDesiredKeys: [T.FieldKey]? {\n        get { return operation.rootRecordDesiredKeys }\n        set { operation.rootRecordDesiredKeys = newValue }\n    }\n\n    public var perShareMetadataBlock: CloudKitProcedure<T>.FetchShareMetadataPerShareMetadataBlock? {\n        get { return operation.perShareMetadataBlock }\n        set { operation.perShareMetadataBlock = newValue }\n    }\n\n    func setFetchShareMetadataCompletionBlock(_ block: @escaping CloudKitProcedure<T>.FetchShareMetadataCompletionBlock) {\n        operation.fetchShareMetadataCompletionBlock = { [weak self] error in\n            if let strongSelf = self, let error = error {\n                strongSelf.setErrorOnce(PKCKError(underlyingError: error))\n            }\n            else {\n                block()\n            }\n        }\n    }\n}\n\nextension CloudKitProcedure where T: CKFetchShareMetadataOperationProtocol {\n\n    /// A typealias for the block types used by CloudKitOperation<CKFetchShareMetadataOperationType>\n    public typealias FetchShareMetadataPerShareMetadataBlock = (URL, T.ShareMetadata?, Error?) -> Void\n\n    /// A typealias for the block types used by CloudKitOperation<CKFetchShareMetadataOperationType>\n    public typealias FetchShareMetadataCompletionBlock = () -> Void\n\n    /// - returns: the share URLs\n    public var shareURLs: T.ShareURLsPropertyType {\n        get { return current.shareURLs }\n        set {\n            current.shareURLs = newValue\n            appendConfigureBlock { $0.shareURLs = newValue }\n        }\n    }\n\n    /// - returns: whether to fetch the share root record\n    public var shouldFetchRootRecord: Bool {\n        get { return current.shouldFetchRootRecord }\n        set {\n            current.shouldFetchRootRecord = newValue\n            appendConfigureBlock { $0.shouldFetchRootRecord = newValue }\n        }\n    }\n\n    /// - returns: the share root record desired keys\n    public var rootRecordDesiredKeys: [T.FieldKey]? {\n        get { return current.rootRecordDesiredKeys }\n        set {\n            current.rootRecordDesiredKeys = newValue\n            appendConfigureBlock { $0.rootRecordDesiredKeys = newValue }\n        }\n    }\n\n    /// - returns: the per share metadata block\n    public var perShareMetadataBlock: FetchShareMetadataPerShareMetadataBlock? {\n        get { return current.perShareMetadataBlock }\n        set {\n            current.perShareMetadataBlock = newValue\n            appendConfigureBlock { $0.perShareMetadataBlock = newValue }\n        }\n    }\n\n    /**\n     Before adding the CloudKitOperation instance to a queue, set a completion block\n     to collect the results in the successful case. Setting this completion block also\n     ensures that error handling gets triggered.\n\n     - parameter block: a FetchShareMetadataCompletionBlock block\n     */\n    public func setFetchShareMetadataCompletionBlock(block: @escaping FetchShareMetadataCompletionBlock) {\n        appendConfigureBlock { $0.setFetchShareMetadataCompletionBlock(block) }\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKitCloud/Share Operations/CKFetchShareParticipantsOperation.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n#if SWIFT_PACKAGE\n    import ProcedureKit\n    import Foundation\n#endif\n\nimport CloudKit\n\n/// A generic protocol which exposes the properties used by Apple's CKFetchShareParticipantsOperation.\npublic protocol CKFetchShareParticipantsOperationProtocol: CKOperationProtocol {\n\n    /// The type of the userIdentityLookupInfos property\n    associatedtype UserIdentityLookupInfosPropertyType\n\n    /// - returns: the user identity lookup infos\n    var userIdentityLookupInfos: UserIdentityLookupInfosPropertyType { get set }\n\n    /// - returns: the share participant fetched block\n    var shareParticipantFetchedBlock: ((ShareParticipant) -> Void)? { get set }\n\n    /// - returns: the fetch share participants completion block\n    var fetchShareParticipantsCompletionBlock: ((Error?) -> Void)? { get set }\n}\n\n@available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *)\nextension CKFetchShareParticipantsOperation: CKFetchShareParticipantsOperationProtocol, AssociatedErrorProtocol {\n\n    // The associated error type\n    public typealias AssociatedError = PKCKError\n}\n\nextension CKProcedure where T: CKFetchShareParticipantsOperationProtocol, T: AssociatedErrorProtocol, T.AssociatedError: CloudKitError {\n\n    public var userIdentityLookupInfos: T.UserIdentityLookupInfosPropertyType {\n        get { return operation.userIdentityLookupInfos }\n        set { operation.userIdentityLookupInfos = newValue }\n    }\n\n    public var shareParticipantFetchedBlock: CloudKitProcedure<T>.FetchShareParticipantsParticipantFetchedBlock? {\n        get { return operation.shareParticipantFetchedBlock }\n        set { operation.shareParticipantFetchedBlock = newValue }\n    }\n\n    func setFetchShareParticipantsCompletionBlock(_ block: @escaping CloudKitProcedure<T>.FetchShareParticipantsCompletionBlock) {\n        operation.fetchShareParticipantsCompletionBlock = { [weak self] error in\n            if let strongSelf = self, let error = error {\n                strongSelf.setErrorOnce(PKCKError(underlyingError: error))\n            }\n            else {\n                block()\n            }\n        }\n    }\n}\n\nextension CloudKitProcedure where T: CKFetchShareParticipantsOperationProtocol {\n\n    /// A typealias for the block types used by CloudKitOperation<CKFetchShareMetadataOperationType>\n    public typealias FetchShareParticipantsParticipantFetchedBlock = (T.ShareParticipant) -> Void\n\n    /// A typealias for the block types used by CloudKitOperation<CKFetchShareMetadataOperationType>\n    public typealias FetchShareParticipantsCompletionBlock = () -> Void\n\n    /// - returns: the user identity lookup infos\n    public var userIdentityLookupInfos: T.UserIdentityLookupInfosPropertyType {\n        get { return current.userIdentityLookupInfos }\n        set {\n            current.userIdentityLookupInfos = newValue\n            appendConfigureBlock { $0.userIdentityLookupInfos = newValue }\n        }\n    }\n\n    /// - returns: the share participant fetched block\n    public var shareParticipantFetchedBlock: FetchShareParticipantsParticipantFetchedBlock? {\n        get { return current.shareParticipantFetchedBlock }\n        set {\n            current.shareParticipantFetchedBlock = newValue\n            appendConfigureBlock { $0.shareParticipantFetchedBlock = newValue }\n        }\n    }\n\n    /**\n     Before adding the CloudKitOperation instance to a queue, set a completion block\n     to collect the results in the successful case. Setting this completion block also\n     ensures that error handling gets triggered.\n\n     - parameter block: a FetchShareParticipantsCompletionBlock block\n     */\n    public func setFetchShareParticipantsCompletionBlock(block: @escaping FetchShareParticipantsCompletionBlock) {\n        appendConfigureBlock { $0.setFetchShareParticipantsCompletionBlock(block) }\n    }\n}\n\n"
  },
  {
    "path": "Sources/ProcedureKitCloud/Subscription Operations/CKFetchSubscriptionsOperation.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n#if !os(watchOS)\n\n#if SWIFT_PACKAGE\n    import ProcedureKit\n    import Foundation\n#endif\n\nimport CloudKit\n\n/// A generic protocol which exposes the properties used by Apple's CKFetchSubscriptionsOperation.\npublic protocol CKFetchSubscriptionsOperationProtocol: CKDatabaseOperationProtocol {\n\n    /// - returns: the subscription IDs\n    var subscriptionIDs: [String]? { get set }\n\n    /// - returns: the fetch subscription completion block\n    var fetchSubscriptionCompletionBlock: (([String: Subscription]?, Error?) -> Void)? { get set }\n}\n\npublic struct FetchSubscriptionsError<Subscription>: CloudKitError {\n\n    public let underlyingError: Error\n    public let subscriptionsByID: [String: Subscription]?\n}\n\nextension CKFetchSubscriptionsOperation: CKFetchSubscriptionsOperationProtocol, AssociatedErrorProtocol {\n\n    // The associated error type\n    public typealias AssociatedError = FetchSubscriptionsError<Subscription>\n}\n\nextension CKProcedure where T: CKFetchSubscriptionsOperationProtocol, T: AssociatedErrorProtocol, T.AssociatedError: CloudKitError {\n\n    public var subscriptionIDs: [String]? {\n        get { return operation.subscriptionIDs }\n        set { operation.subscriptionIDs = newValue }\n    }\n\n    func setFetchSubscriptionCompletionBlock(_ block: @escaping CloudKitProcedure<T>.FetchSubscriptionCompletionBlock) {\n        operation.fetchSubscriptionCompletionBlock = { [weak self] subscriptionsByID, error in\n            if let strongSelf = self, let error = error {\n                strongSelf.setErrorOnce(FetchSubscriptionsError(underlyingError: error, subscriptionsByID: subscriptionsByID))\n            }\n            else {\n                block(subscriptionsByID)\n            }\n        }\n    }\n}\n\nextension CloudKitProcedure where T: CKFetchSubscriptionsOperationProtocol {\n\n    /// A typealias for the block types used by CloudKitOperation<CKFetchSubscriptionsOperation>\n    public typealias FetchSubscriptionCompletionBlock = ([String: T.Subscription]?) -> Void\n\n    /// - returns: the subscription IDs\n    public var subscriptionIDs: [String]? {\n        get { return current.subscriptionIDs }\n        set {\n            current.subscriptionIDs = newValue\n            appendConfigureBlock { $0.subscriptionIDs = newValue }\n        }\n    }\n\n    /**\n     Before adding the CloudKitOperation instance to a queue, set a completion block\n     to collect the results in the successful case. Setting this completion block also\n     ensures that error handling gets triggered.\n\n     - parameter block: a FetchSubscriptionCompletionBlock block\n     */\n    public func setFetchSubscriptionCompletionBlock(block: @escaping FetchSubscriptionCompletionBlock) {\n        appendConfigureBlock { $0.setFetchSubscriptionCompletionBlock(block) }\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Sources/ProcedureKitCloud/Subscription Operations/CKModifySubscriptionsOperation.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n#if !os(watchOS)\n\n#if SWIFT_PACKAGE\n    import ProcedureKit\n    import Foundation\n#endif\n\nimport CloudKit\n\n/// A generic protocol which exposes the properties used by Apple's CKModifySubscriptionsOperation.\npublic protocol CKModifySubscriptionsOperationProtocol: CKDatabaseOperationProtocol {\n\n    /// - returns: the subscriptions to save\n    var subscriptionsToSave: [Subscription]? { get set }\n\n    /// - returns: the subscriptions IDs to delete\n    var subscriptionIDsToDelete: [String]? { get set }\n\n    /// - returns: the modify subscription completion block\n    var modifySubscriptionsCompletionBlock: (([Subscription]?, [String]?, Error?) -> Void)? { get set }\n}\n\npublic struct ModifySubscriptionsError<Subscription, SubscriptionID>: CloudKitError, CloudKitBatchModifyError {\n\n    public let underlyingError: Error\n    public let saved: [Subscription]?\n    public let deleted: [SubscriptionID]?\n}\n\nextension CKModifySubscriptionsOperation: CKModifySubscriptionsOperationProtocol, AssociatedErrorProtocol {\n\n    // The associated error type\n    public typealias AssociatedError = ModifySubscriptionsError<Subscription, String>\n}\n\nextension CKProcedure where T: CKModifySubscriptionsOperationProtocol, T: AssociatedErrorProtocol, T.AssociatedError: CloudKitError {\n\n    public var subscriptionsToSave: [T.Subscription]? {\n        get { return operation.subscriptionsToSave }\n        set { operation.subscriptionsToSave = newValue }\n    }\n\n    public var subscriptionIDsToDelete: [String]? {\n        get { return operation.subscriptionIDsToDelete }\n        set { operation.subscriptionIDsToDelete = newValue }\n    }\n\n    func setModifySubscriptionsCompletionBlock(_ block: @escaping CloudKitProcedure<T>.ModifySubscriptionsCompletionBlock) {\n        operation.modifySubscriptionsCompletionBlock = { [weak self] saved, deleted, error in\n            if let strongSelf = self, let error = error {\n                strongSelf.setErrorOnce(ModifySubscriptionsError(underlyingError: error, saved: saved, deleted: deleted))\n            }\n            else {\n                block(saved, deleted)\n            }\n        }\n    }\n}\n\nextension CloudKitProcedure where T: CKModifySubscriptionsOperationProtocol {\n\n    /// A typealias for the block types used by CloudKitOperation<CKModifySubscriptionsOperation>\n    public typealias ModifySubscriptionsCompletionBlock = ([T.Subscription]?, [String]?) -> Void\n\n    /// - returns: the subscriptions to save\n    public var subscriptionsToSave: [T.Subscription]? {\n        get { return current.subscriptionsToSave }\n        set {\n            current.subscriptionsToSave = newValue\n            appendConfigureBlock { $0.subscriptionsToSave = newValue }\n        }\n    }\n\n    /// - returns: the subscription IDs to delete\n    public var subscriptionIDsToDelete: [String]? {\n        get { return current.subscriptionIDsToDelete }\n        set {\n            current.subscriptionIDsToDelete = newValue\n            appendConfigureBlock { $0.subscriptionIDsToDelete = newValue }\n        }\n    }\n\n    /**\n     Before adding the CloudKitOperation instance to a queue, set a completion block\n     to collect the results in the successful case. Setting this completion block also\n     ensures that error handling gets triggered.\n\n     - parameter block: a ModifySubscriptionsCompletionBlock block\n     */\n    public func setModifySubscriptionsCompletionBlock(block: @escaping ModifySubscriptionsCompletionBlock) {\n        appendConfigureBlock { $0.setModifySubscriptionsCompletionBlock(block) }\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Sources/ProcedureKitCoreData/CoreDataHelpers.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n#if SWIFT_PACKAGE\nimport ProcedureKit\nimport Foundation\n#endif\n\nimport CoreData\n\n// MARK: - Internal Core Data Helpers\n\ninternal extension NSManagedObject {\n\n    static var entityName: String {\n        if #available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *) {\n            return entity().name ?? description()\n        }\n        else {\n            return description()\n        }\n    }\n}\n\n\ninternal extension NSManagedObjectContext {\n\n    typealias VoidBlock = () -> Void\n    typealias VoidBlockBlock = (VoidBlock) -> Void\n\n    /// - see: https://oleb.net/blog/2018/02/performandwait/\n    func performAndWait<T>(block: () throws -> T) rethrows -> T {\n\n        func _helper(fn: VoidBlockBlock, execute work: () throws -> T, rescue: ((Error) throws -> (T))) rethrows -> T {\n            var r: T?\n            var e: Error?\n\n            withoutActuallyEscaping(work) { _work in\n                fn {\n                    do { r = try _work() }\n                    catch { e = error }\n                }\n            }\n\n            if let error = e {\n                return try rescue(error)\n            }\n            guard let result = r else {\n                fatalError(\"Failed to generate a result or throw error.\")\n            }\n            return result\n        }\n\n        return try _helper(fn: performAndWait(_:), execute: block, rescue: { throw $0 })\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKitCoreData/InsertManagedObjects.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n#if SWIFT_PACKAGE\nimport ProcedureKit\nimport Foundation\n#endif\n\nimport CoreData\n\n/**\n A Procedure subclass which abstracts the details of inserting managed objects. This\n subclass is designed for the very common scenario where an array of items (such as\n might get returned as a network response) needs parsing/mapping to Entities in\n Core Data.\n\n Considering this, lets assume that there is another Procedure which will return\n the array of items (perhaps parsed from a JSON network response into an array of\n structs). There is deliberately no constrains on this type - so it could be Void.\n\n The procedure is initialized with a managed object context, and a block. The\n block receives both the Item value, and the NSManagedObject instance. This can be\n used to set the properties on the managed object.\n\n Lastly the managed object context is saved.\n */\n@available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *)\nopen class InsertManagedObjectsProcedure<Item, ManagedObject>: GroupProcedure, InputProcedure, OutputProcedure where ManagedObject: NSManagedObject {\n\n    public typealias ProcessingBlock = (Int, Item, ManagedObject) -> ()\n\n    private class Insert: Procedure, InputProcedure, OutputProcedure, ManagedObjectContextProcessing {\n\n        var input: Pending<[Item]> = .pending\n\n        var output: Pending<ProcedureResult<[NSManagedObjectID]>> = .pending\n\n        var managedObjectContext: Pending<NSManagedObjectContext> = .pending\n\n        let block: ProcessingBlock\n\n        init(_ block: @escaping ProcessingBlock) {\n            self.block = block\n            super.init()\n        }\n\n        override func execute() {\n\n            guard\n                let managedObjectContext = managedObjectContext.value,\n                let items = input.value\n            else {\n                finish(with: ProcedureKitError.requirementNotSatisfied())\n                return\n            }\n\n            guard items.count > 0 else {\n                finish(withResult: .success([]))\n                return\n            }\n\n            let result: Output = managedObjectContext.performAndWait {\n                return items.enumerated().map { (enumeratedItem) in\n                    let managed = ManagedObject(context: managedObjectContext)\n                    block(enumeratedItem.0, enumeratedItem.1, managed)\n                    return managed.objectID\n                }\n            }\n\n            finish(withResult: .success(result))\n        }\n    }\n\n    public var input: Pending<[Item]> = .pending\n\n    public var output: Pending<ProcedureResult<[NSManagedObjectID]>> = .pending\n\n    /**\n     Initialize the Procedure with the NSManagedObjectContext to insert into, and\n     a block. For example:\n\n     ```swift\n     let insert = InsertManagedObjectsProcedure<MyItem, MyManagedObject>(into: managedObjectContext) { (index, item, managedObject) in\n        managedObject.identifier = item.identifier\n        managedObject.name = item.name\n     }.injectResult(from: downloadItems)\n     ```\n     In the above example, we assume that `downloadItems` has an output\n       of `[MyItem]`, and `MyItem` is a PONSO or \"dumb\" struct type. Certainly\n       it must be a type which is safe to be used across threads (so not another\n       NSManagedObject instance).\n\n     - parameter dispatchQueue: an optional DispatchQueue to specify.\n     - parameter into: a MakesBackgroundManagedObjectContext type,\n         which in turn will create a new background context to insert into.\n     - parameter andSave: a Bool, default true, which if set to\n         false will not save the context.\n     - parameter block: a `(Int, Item, ManagedObject) -> ()` block,\n         the arguments are the index in the array of items, the\n         item this index, and the inserted managed object which\n         represents the item.\n    */\n    public init(dispatchQueue: DispatchQueue? = nil, into makesManagedObjectContext: MakesBackgroundManagedObjectContext, andSave shouldSave: Bool = true, block: @escaping ProcessingBlock) {\n\n        let queue: DispatchQueue = dispatchQueue ?? .initiated\n\n        let insert = Insert(block)\n\n        let processing = ProcessManagedObjectContext(dispatchQueue: queue, do: insert, in: makesManagedObjectContext, save: shouldSave)\n        processing.name = \"Processing Inserts of \\(ManagedObject.entityName)\"\n\n        super.init(dispatchQueue: queue, operations: [processing])\n        name = \"Insert \\(ManagedObject.entityName)\"\n\n        bind(to: insert)\n        bind(from: insert)\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKitCoreData/LoadCoreData.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n#if SWIFT_PACKAGE\nimport ProcedureKit\nimport Foundation\n#endif\n\nimport CoreData\n\n/**\n`LoadCoreDataProcedure` is a procedure which does the bare minimum to\n instantiate a `NSPersistentContainer` and load the stores.\n\n ## Usage\n In a production application, we would expect this class to\n be subclassed. Something like this, note the name of the model\n has been set.\n\n ```swift\nfinal class MakeCoreDataStack: LoadCoreDataProcedure {\n    init() {\n\n        // Call the super, with the name of the model file\n        super.init(filename: \"Earthquakes\")\n\n        // Add a will finish observer, to configure the view context\n        addWillFinishBlockObserver { (procedure, errors, _) in\n            guard errors.isEmpty, let container = procedure.output.success else { return }\n\n            // Sets the merge policy\n            container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy\n\n            // In this case, we don't want an undo manager on the view context\n            container.viewContext.undoManager = nil\n\n            // Keeps the context with loaded objects\n            container.viewContext.shouldDeleteInaccessibleFaults = true\n            container.viewContext.automaticallyMergesChangesFromParent = true\n        }\n    }\n}\n ```\n\n In the example above, we add a WillFinishObserver which can be used to configure the\n the container, in this case, the viewContext property, before the MOCs can be used\n throughout the application.\n\n This container would then be injected as the input into subsequent procedures.\n */\n@available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *)\nopen class LoadCoreDataProcedure: Procedure, OutputProcedure {\n\n    /// - returns: the output Pending<ProcedureResult<<NSPersistentContainer>>\n    public var output: Pending<ProcedureResult<NSPersistentContainer>> = .pending\n\n    /// - returns: String the initialized filename, representing the model file\n    public let filename: String\n\n    /// - returns: an optional managed object model which will be used if provided.\n    public let managedObjectModel: NSManagedObjectModel?\n\n    /// - returns: [NSPersistentStoreDescription] the initialized store descriptions\n    public let persistentStoreDescriptions: [NSPersistentStoreDescription]\n\n    public init(name: String, managedObjectModel: NSManagedObjectModel? = nil, persistentStoreDescriptions: [NSPersistentStoreDescription] = []) {\n        self.filename = name\n        self.managedObjectModel = managedObjectModel\n        self.persistentStoreDescriptions = persistentStoreDescriptions\n        super.init()\n        self.name = \"Load Core Data\"\n        addCondition(MutuallyExclusive<LoadCoreDataProcedure>())\n    }\n\n    open override func execute() {\n\n        // Create a persistent container\n        let container: NSPersistentContainer\n\n        if let model = managedObjectModel {\n            container = NSPersistentContainer(name: filename, managedObjectModel: model)\n        }\n        else {\n            container = NSPersistentContainer(name: filename)\n        }\n\n        // Override the persistent store descriptions\n        if persistentStoreDescriptions.count > 0 {\n            container.persistentStoreDescriptions = persistentStoreDescriptions\n        }\n\n        // Load the stores\n        container.loadPersistentStores { (persistentStoreDescription, error) in\n            if let error = error {\n                self.finish(withResult: .failure(error))\n            }\n            self.finish(withResult: .success(container))\n        }\n    }\n}\n\n"
  },
  {
    "path": "Sources/ProcedureKitCoreData/MakeFetchedResultController.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n#if SWIFT_PACKAGE\nimport ProcedureKit\nimport Foundation\n#endif\n\nimport CoreData\n\n/**\n Makes a FetchResultsController, using the viewContext from a NSPersistenContainer\n which is injected before execution, but after initialization. For example:\n\n ```swift\n let coreDataStack = LoadCoreDataProcedure(name: \"CoreDataEntities\")\n let makeFRC = MakeFetchedResultControllerProcedure(for: \"MyEntity\")\n     .injectResult(from: coreDataStack)\n ```\n */\n@available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *)\nopen class MakeFetchedResultControllerProcedure<Result: NSFetchRequestResult>: TransformProcedure<NSPersistentContainer, NSFetchedResultsController<Result>> {\n\n    static func transform(fetchRequest: NSFetchRequest<Result>, sectionNameKeyPath: String? = nil, cacheName: String? = nil) -> (NSPersistentContainer) throws -> NSFetchedResultsController<Result> {\n        return { (container) in\n\n            let frc = NSFetchedResultsController(\n                fetchRequest: fetchRequest,\n                managedObjectContext: container.viewContext,\n                sectionNameKeyPath: sectionNameKeyPath,\n                cacheName: cacheName)\n\n            try container.viewContext.performAndWait(block: frc.performFetch)\n\n            return frc\n        }\n    }\n\n    /// Initializes the FetchedResultsController with a NSFetchRequest\n    public init(fetchRequest: NSFetchRequest<Result>, sectionNameKeyPath: String? = nil, cacheName: String? = nil) {\n        super.init(transform: MakeFetchedResultControllerProcedure<Result>.transform(fetchRequest: fetchRequest, sectionNameKeyPath: sectionNameKeyPath, cacheName: cacheName))\n        name = \"Make FRC \\(fetchRequest.entityName ?? \"\")\".trimmingCharacters(in: .whitespaces)\n    }\n\n    /// Convenience initalizer using just the entity name, fetch limit (default is 50) and sort descriptors (default is empty).\n    public init(for entityName: String, fetchLimit: Int = 50, sortDescriptors: [NSSortDescriptor] = [], sectionNameKeyPath: String? = nil, cacheName: String? = nil) {\n\n        let fetchRequest: NSFetchRequest<Result> = NSFetchRequest(entityName: entityName)\n        fetchRequest.fetchLimit = fetchLimit\n        fetchRequest.sortDescriptors = sortDescriptors\n\n        super.init(transform: MakeFetchedResultControllerProcedure<Result>.transform(fetchRequest: fetchRequest, sectionNameKeyPath: sectionNameKeyPath, cacheName: cacheName))\n        name = \"Make FRC \\(fetchRequest.entityName ?? \"\")\".trimmingCharacters(in: .whitespaces)\n    }\n}\n\n@available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *)\npublic extension MakeFetchedResultControllerProcedure where Result: NSManagedObject {\n\n    convenience init(fetchLimit: Int = 50, sortDescriptors: [NSSortDescriptor] = [], sectionNameKeyPath: String? = nil, cacheName: String? = nil) {\n        self.init(for: Result.entityName, fetchLimit: fetchLimit, sortDescriptors: sortDescriptors, sectionNameKeyPath: sectionNameKeyPath, cacheName: cacheName)\n    }\n}\n\n\n\n"
  },
  {
    "path": "Sources/ProcedureKitCoreData/MakesBackgroundManagedObjectContext.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n#if SWIFT_PACKAGE\nimport ProcedureKit\nimport Foundation\n#endif\n\nimport CoreData\n\n/**\n Abstracts the producer of a background context into a protocol\n to allow framework consumers to provide any source of a context\n */\npublic protocol MakesBackgroundManagedObjectContext {\n\n    func newBackgroundContext() -> NSManagedObjectContext\n}\n\n@available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *)\nextension NSPersistentContainer: MakesBackgroundManagedObjectContext { }\n\nextension NSManagedObjectContext: MakesBackgroundManagedObjectContext {\n\n    public func newBackgroundContext() -> NSManagedObjectContext {\n\n        let moc = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)\n        moc.parent = self\n        moc.undoManager = nil\n        return moc\n    }\n}\n\nextension NSPersistentStoreCoordinator: MakesBackgroundManagedObjectContext {\n\n    public func newBackgroundContext() -> NSManagedObjectContext {\n\n        let moc = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)\n        moc.persistentStoreCoordinator = self\n        return moc\n    }\n}\n\n\n"
  },
  {
    "path": "Sources/ProcedureKitCoreData/ProcessManagedObjectContext.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n#if SWIFT_PACKAGE\nimport ProcedureKit\nimport Foundation\n#endif\n\nimport CoreData\n\nprotocol ManagedObjectContextProcessing: class {\n\n    var managedObjectContext: Pending<NSManagedObjectContext> { get set }\n}\n\ninternal final class ProcessManagedObjectContext: GroupProcedure {\n\n    init<Processing: Procedure>(dispatchQueue underlyingQueue: DispatchQueue?, do processing: Processing, in makesManagedObjectContext: MakesBackgroundManagedObjectContext, save shouldSaveManagedObjectContext: Bool) where Processing: ManagedObjectContextProcessing {\n\n        var operations: [Operation] = []\n\n        // 1. Create MOC\n        let create = ResultProcedure { makesManagedObjectContext.newBackgroundContext() }\n        create.addWillFinishBlockObserver { (procedure, error, _) in\n            if let moc = procedure.output.success {\n                processing.managedObjectContext = .ready(moc)\n            }\n        }\n        processing.addDependency(create)\n        operations.append(create)\n\n        // 2. Perform processing\n        operations.append(processing)\n\n        // 3. Save MOC\n        if shouldSaveManagedObjectContext {\n            let save = SaveManagedObjectContext().injectResult(from: create)\n            save.addDependency(processing)\n            operations.append(save)\n        }\n\n        super.init(dispatchQueue: underlyingQueue, operations: operations)\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKitCoreData/SaveManagedObjectContext.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n#if SWIFT_PACKAGE\nimport ProcedureKit\nimport Foundation\n#endif\n\nimport CoreData\n\n/**\n This procedure will save a NSManagedObjectContext. It can be used directly, if the\n context is available at initializaton, via:\n\n ```swift\n queue.add(operation: SaveManagedObjectContext(managedObjectContext))\n ```\n\n Alternatively, if the managedObjectContext is not available like this, it can be\n injected with it before execution.\n\n ```swift\n let coreDataStack = LoadCoreDataProcedure(name: \"MyModels\")\n\n let processManagedObjects = ProcessManagedObjects()\n     .injectResult(from: coreDataStack)\n\n let save = SaveManagedObjectContext()\n     .injectResult(from: processManagedObjects)\n\n queue.add(operations:\n    coreDataStack,\n    processManagedObjects,\n    save)\n ```\n */\nopen class SaveManagedObjectContext: AsyncTransformProcedure<NSManagedObjectContext, Void> {\n\n    public init(_ managedObjectContext: NSManagedObjectContext? = nil) {\n\n        super.init { (managedObjectContext, finishWithResult) in\n\n            guard managedObjectContext.hasChanges else {\n                finishWithResult(success)\n                return\n            }\n\n            managedObjectContext.perform {\n                do {\n                    try managedObjectContext.save()\n                    finishWithResult(success)\n                }\n                catch {\n                    finishWithResult(.failure(error))\n                }\n            }\n        }\n\n        if let moc = managedObjectContext {\n            input = .ready(moc)\n        }\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKitInstruments/ProcedureKitInstruments.instrpkg",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<package>\n\t<id>run.kit.procedure.ProcedureKitInstruments</id>\n    <version>3</version>\n\t<title>ProcedureKit Instruments</title>\n\t<owner>\n\t\t<name>The ProcedureKit Contributors</name>\n\t</owner>\n\n    <os-signpost-interval-schema>\n        <id>procedurekit-signpost-schema</id>\n        <title>ProcedureKit</title>\n        <subsystem>\"run.kit.procedure\"</subsystem>\n        <category>\"ProcedureKit\"</category>\n\n        <name>?signpostName</name>\n\n        <start-pattern>\n            <message>\"Procedure name: \" ?procedureName</message>\n        </start-pattern>\n\n        <end-pattern>\n            <message>\"Procedure name: \" ?procedureName \", status: \" ?status</message>\n        </end-pattern>\n\n        <duration-column>\n            <mnemonic>duration</mnemonic>\n            <title>Duration</title>\n            <type>duration</type>\n        </duration-column>\n\n        <column>\n            <mnemonic>signpost-name</mnemonic>\n            <title>Signpost</title>\n            <type>string</type>\n            <expression>?signpostName</expression>\n        </column>\n\n        <column>\n            <mnemonic>procedure-name</mnemonic>\n            <title>Procedure</title>\n            <type>string</type>\n            <expression>?procedureName</expression>\n        </column>\n\n        <column>\n            <mnemonic>status</mnemonic>\n            <title>Status</title>\n            <type>string</type>\n            <expression>?status</expression>\n        </column>\n\n    </os-signpost-interval-schema>\n\n    <instrument>\n        <id>procedurekit-signpost-instrument</id>\n        <title>ProcedureKit Signposts</title>\n        <category>Behavior</category>\n        <purpose>Shows when Procedure are running.</purpose>\n        <icon>Scheduling</icon>\n\n        <create-table>\n            <id>procedurekit-instrument-table</id>\n            <schema-ref>procedurekit-signpost-schema</schema-ref>\n        </create-table>\n\n        <!-- Define graph to draw for your Instrument (optional) -->\n        <graph>\n            <title>Procedure Life Cycle</title>\n            <lane>\n                <title>Procedure Life Cycle</title>\n                <table-ref>procedurekit-instrument-table</table-ref>\n\n                <!-- plot, plot-template or histogram elements -->\n                <plot>\n                    <value-from>procedure-name</value-from>\n                </plot>\n            </lane>\n        </graph>\n\n        <!-- Define at least one detail view for your Instrument -->\n        <list>\n            <title>Procedure Life Cycle</title>\n            <table-ref>procedurekit-instrument-table</table-ref>\n            <column>signpost-name</column>\n            <column>duration</column>\n            <column>procedure-name</column>\n            <column>status</column>\n        </list>\n\n    </instrument>\n\n</package>\n"
  },
  {
    "path": "Sources/ProcedureKitLocation/LocationCapability.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n#if SWIFT_PACKAGE\n    import ProcedureKit\n    import Foundation\n#endif\n\nimport CoreLocation\nimport MapKit\n\npublic enum LocationUsage {\n    case whenInUse\n    case always\n}\n\nextension CLAuthorizationStatus: AuthorizationStatus {\n\n    public func meets(requirement: LocationUsage?) -> Bool {\n        if #available(OSX 10.12, iOS 8.0, tvOS 8.0, watchOS 2.0, *) {\n            switch (requirement, self) {\n            case (.some(.whenInUse), .authorizedWhenInUse), (_, .authorizedAlways): return true\n            default: return false\n            }\n        }\n        else {\n            #if os(OSX)\n                switch (requirement, self) {\n                case (_, .authorized): return true\n                default: return false\n                }\n            #else\n                return false\n            #endif\n        }\n    }\n}\n\npublic extension Capability {\n\n    class Location: CapabilityProtocol {\n\n        public private(set) var requirement: LocationUsage?\n\n        internal lazy var registrar: LocationServicesRegistrarProtocol = CLLocationManager.make()\n\n        // Note, that this property is the authorization delegate, however, it is not\n        // owned by anything else, so should not be weak referenced.\n        private var authorizationDelegate: LocationManagerAuthorizationDelegate? // swiftlint:disable:this weak_delegate\n\n        public init(_ requirement: LocationUsage = .whenInUse) {\n            self.requirement = requirement\n        }\n\n        deinit {\n            registrar.pk_set(delegate: nil)\n        }\n\n        public func isAvailable() -> Bool {\n            return registrar.pk_locationServicesEnabled()\n        }\n\n        public func getAuthorizationStatus(_ completion: @escaping (CLAuthorizationStatus) -> Void) {\n            completion(registrar.pk_authorizationStatus())\n        }\n\n        public func requestAuthorization(withCompletion completion: @escaping () -> Void) {\n            guard isAvailable() else {\n                completion()\n                return\n            }\n\n            let status = registrar.pk_authorizationStatus()\n            switch (status, requirement) {\n            case (.notDetermined, _), (.authorizedWhenInUse, .some(.always)):\n                authorizationDelegate = LocationManagerAuthorizationDelegate { _, status in\n                    guard status != .notDetermined else { return }\n                    completion()\n                }\n                registrar.pk_set(delegate: authorizationDelegate)\n                registrar.pk_requestAuthorization(withRequirement: requirement)\n            default:\n                completion()\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKitLocation/LocationSupport.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n#if SWIFT_PACKAGE\n    import ProcedureKit\n    import Foundation\n#endif\n\nimport Dispatch\nimport CoreLocation\nimport MapKit\n\nstruct ProcedureKitLocationComponent: ProcedureKitComponent {\n    let name = \"ProcedureKitLocation\"\n}\n\ninternal extension CLLocationManager {\n\n    static func make() -> CLLocationManager {\n        return DispatchQueue.onMain { CLLocationManager() }\n    }\n}\n\ninternal extension CLGeocoder {\n\n    static func make() -> CLGeocoder {\n        return DispatchQueue.onMain { CLGeocoder() }\n    }\n}\n\nprotocol LocationServicesRegistrarProtocol {\n\n    func pk_locationServicesEnabled() -> Bool\n\n    func pk_authorizationStatus() -> CLAuthorizationStatus\n\n    func pk_set(delegate aDelegate: CLLocationManagerDelegate?)\n\n    @available(iOS 8.0, *)\n    func pk_requestAuthorization(withRequirement: LocationUsage?)\n}\n\nextension CLLocationManager: LocationServicesRegistrarProtocol {\n\n    func pk_locationServicesEnabled() -> Bool {\n        return CLLocationManager.locationServicesEnabled()\n    }\n\n    func pk_authorizationStatus() -> CLAuthorizationStatus {\n        return CLLocationManager.authorizationStatus()\n    }\n\n    func pk_set(delegate aDelegate: CLLocationManagerDelegate?) {\n        self.delegate = aDelegate\n    }\n\n    @available(iOS 8.0, *)\n    func pk_requestAuthorization(withRequirement requirement: LocationUsage?) {\n        #if os(iOS) || os(watchOS)\n            switch requirement {\n            case .some(.always):\n                requestAlwaysAuthorization()\n            case _:\n                requestWhenInUseAuthorization()\n            }\n        #endif\n\n        #if os(tvOS)\n            requestWhenInUseAuthorization()\n        #endif\n    }\n}\n\nprotocol LocationServicesProtocol {\n\n    func pk_set(desiredAccuracy: CLLocationAccuracy)\n\n    func pk_startUpdatingLocation()\n\n    func pk_stopUpdatingLocation()\n}\n\nextension CLLocationManager: LocationServicesProtocol {\n\n    func pk_set(desiredAccuracy accuracy: CLLocationAccuracy) {\n        desiredAccuracy = accuracy\n    }\n\n    func pk_startUpdatingLocation() {\n        #if os(iOS) || os(watchOS)\n            startUpdatingLocation()\n        #endif\n\n        #if os(tvOS)\n            requestLocation()\n        #endif\n    }\n\n    func pk_stopUpdatingLocation() {\n        stopUpdatingLocation()\n    }\n}\n\ninternal class LocationManagerAuthorizationDelegate: NSObject, CLLocationManagerDelegate {\n\n    let didChangeAuthorizationStatusBlock: (CLLocationManager, CLAuthorizationStatus) -> Void\n\n    init(didChangeAuthorizationStatusBlock block: @escaping (CLLocationManager, CLAuthorizationStatus) -> Void) {\n        didChangeAuthorizationStatusBlock = block\n    }\n\n    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {\n        didChangeAuthorizationStatusBlock(manager, status)\n    }\n}\n\nprotocol GeocodeProtocol {\n\n    func pk_cancel()\n}\n\nextension CLGeocoder: GeocodeProtocol {\n\n    func pk_cancel() {\n        cancelGeocode()\n    }\n}\n\nprotocol ReverseGeocodeProtocol {\n\n    func pk_reverseGeocodeLocation(location: CLLocation, completionHandler completion: @escaping CLGeocodeCompletionHandler)\n}\n\nextension CLGeocoder: ReverseGeocodeProtocol {\n\n    func pk_reverseGeocodeLocation(location: CLLocation, completionHandler completion: @escaping CLGeocodeCompletionHandler) {\n        reverseGeocodeLocation(location, completionHandler: completion)\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKitLocation/ReverseGeocode.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n#if SWIFT_PACKAGE\n    import ProcedureKit\n    import Foundation\n#endif\n\nimport Foundation\nimport Dispatch\nimport CoreLocation\nimport MapKit\n\nopen class ReverseGeocodeProcedure: Procedure, InputProcedure, OutputProcedure {\n    public typealias CompletionBlock = (CLPlacemark) -> Void\n\n    public var input: Pending<CLLocation> = .pending\n    public var output: Pending<ProcedureResult<CLPlacemark>> = .pending\n\n    public let completion: CompletionBlock?\n\n    public var placemark: CLPlacemark? {\n        return output.success\n    }\n\n    public var location: CLLocation? {\n        return input.value\n    }\n\n    internal var geocoder: ReverseGeocodeProtocol & GeocodeProtocol = CLGeocoder.make()\n\n    public init(timeout: TimeInterval = 3.0, location: CLLocation? = nil, completion: CompletionBlock? = nil) {\n        self.input = location.flatMap { .ready($0) } ?? .pending\n        self.completion = completion\n        super.init()\n        addCondition(MutuallyExclusive<ReverseGeocodeProcedure>())\n        addObserver(TimeoutObserver(by: timeout))\n        addDidCancelBlockObserver { [weak self] _, _ in\n            DispatchQueue.main.async {\n                self?.cancelGeocoder()\n                self?.finish()\n            }\n        }\n    }\n\n    deinit {\n        cancelGeocoder()\n    }\n\n    open override func execute() {\n\n        guard let location = input.value else {\n            finish(withResult: .failure(ProcedureKitError.requirementNotSatisfied()))\n            return\n        }\n\n        geocoder.pk_reverseGeocodeLocation(location: location) { [weak self] results, error in\n\n            // Check that the procedure is still running\n            guard let strongSelf = self, !strongSelf.isFinished else { return }\n\n            // Check for placemarks results\n            guard let placemarks = results else {\n                let error: Error = error ?? ProcedureKitError.component(ProcedureKitLocationComponent(), error: error)\n                strongSelf.finish(withResult: .failure(error))\n                return\n            }\n\n            // Continue if there is a suitable placemark\n            if let placemark = strongSelf.shouldFinish(afterReceivingPlacemarks: placemarks) {\n                if let block = strongSelf.completion {\n                    DispatchQueue.main.async { block(placemark) }\n                }\n                strongSelf.finish(withResult: .success(placemark))\n            }\n        }\n    }\n\n    public func cancelGeocoder() {\n        geocoder.pk_cancel()\n    }\n\n    open func shouldFinish(afterReceivingPlacemarks placemarks: [CLPlacemark]) -> CLPlacemark? {\n        return placemarks.first\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKitLocation/ReverseGeocodeUserLocation.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n#if SWIFT_PACKAGE\n    import ProcedureKit\n    import Foundation\n#endif\n\nimport Foundation\nimport Dispatch\nimport CoreLocation\nimport MapKit\n\npublic struct UserLocationPlacemark: Equatable {\n    public let location: CLLocation\n    public let placemark: CLPlacemark\n}\n\nopen class ReverseGeocodeUserLocationProcedure: GroupProcedure, OutputProcedure {\n\n    public typealias CompletionBlock = (UserLocationPlacemark) -> Void\n\n    class Finishing: Procedure, OutputProcedure {\n\n        let completion: CompletionBlock?\n\n        var location: Pending<CLLocation> = .pending\n        var placemark: Pending<CLPlacemark> = .pending\n\n        var output: Pending<ProcedureResult<UserLocationPlacemark>> = .pending\n\n        init(completion: CompletionBlock? = nil) {\n            self.completion = completion\n            super.init()\n        }\n\n        override func execute() {\n\n            guard\n                !isCancelled,\n                let location = location.value,\n                let placemark = placemark.value\n            else {\n                finish(withResult: .failure(ProcedureKitError.requirementNotSatisfied()))\n                return\n            }\n\n            let userLocationPlacemark = UserLocationPlacemark(location: location, placemark: placemark)\n\n            if let block = completion {\n                DispatchQueue.main.async {\n                    block(userLocationPlacemark)\n                }\n            }\n\n            finish(withResult: .success(userLocationPlacemark))\n        }\n    }\n\n    private let finishing: Finishing\n    private let userLocation: UserLocationProcedure\n    private let reverseGeocodeLocation: ReverseGeocodeProcedure\n\n    public var output: Pending<ProcedureResult<UserLocationPlacemark>> {\n        get { return finishing.output }\n        set { assertionFailure(\"\\(#function) should not be publically settable.\") }\n    }\n\n    public init(dispatchQueue: DispatchQueue? = nil, timeout: TimeInterval = 3.0, accuracy: CLLocationAccuracy = kCLLocationAccuracyThreeKilometers, completion: CompletionBlock? = nil) {\n\n        finishing = Finishing(completion: completion)\n\n        userLocation = UserLocationProcedure(timeout: timeout, accuracy: accuracy)\n\n        reverseGeocodeLocation = ReverseGeocodeProcedure(timeout: timeout).injectResult(from: userLocation)\n\n        finishing.inject(dependency: userLocation) { finishing, userLocation, error in\n            guard let location = userLocation.location, error == nil else {\n                finishing.cancel(with: ProcedureKitError.dependency(finishedWithError: error)); return\n            }\n            finishing.location = .ready(location)\n        }\n\n        finishing.inject(dependency: reverseGeocodeLocation) { finishing, reverseGeocodeLocation, error in\n            guard let placemark = reverseGeocodeLocation.placemark, error == nil else {\n                finishing.cancel(with: ProcedureKitError.dependency(finishedWithError: error)); return\n            }\n            finishing.placemark = .ready(placemark)\n        }\n\n        super.init(dispatchQueue: dispatchQueue, operations: [userLocation, reverseGeocodeLocation, finishing])\n        addObserver(TimeoutObserver(by: timeout))\n    }\n\n    internal func set(manager: LocationServicesRegistrarProtocol & LocationServicesProtocol) -> ReverseGeocodeUserLocationProcedure {\n        precondition(!isExecuting)\n        userLocation.manager = manager\n        return self\n    }\n\n    internal func set(geocoder: ReverseGeocodeProtocol & GeocodeProtocol) -> ReverseGeocodeUserLocationProcedure {\n        precondition(!isExecuting)\n        reverseGeocodeLocation.geocoder = geocoder\n        return self\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKitLocation/UserLocation.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n#if SWIFT_PACKAGE\n    import ProcedureKit\n    import Foundation\n#endif\n\nimport Foundation\nimport Dispatch\nimport CoreLocation\nimport MapKit\n\nopen class UserLocationProcedure: Procedure, OutputProcedure, CLLocationManagerDelegate {\n    public typealias CompletionBlock = (CLLocation) -> Void\n\n    public let accuracy: CLLocationAccuracy\n    public let completion: CompletionBlock?\n\n    public var output: Pending<ProcedureResult<CLLocation>> = .pending\n\n    public var location: CLLocation? {\n        return output.success\n    }\n\n    internal var capability = Capability.Location()\n\n    internal lazy var locationManager: LocationServicesRegistrarProtocol & LocationServicesProtocol = CLLocationManager.make()\n    internal var manager: LocationServicesRegistrarProtocol & LocationServicesProtocol {\n        get { return locationManager }\n        set {\n            locationManager = newValue\n            capability.registrar = newValue\n        }\n    }\n\n    public init(timeout: TimeInterval = 3.0, accuracy: CLLocationAccuracy = kCLLocationAccuracyThreeKilometers, completion: CompletionBlock? = nil) {\n        self.accuracy = accuracy\n        self.completion = completion\n        super.init()\n        addCondition(AuthorizedFor(capability))\n        addCondition(MutuallyExclusive<UserLocationProcedure>())\n        addObserver(TimeoutObserver(by: timeout))\n        addDidCancelBlockObserver { [weak self] _, _ in\n            DispatchQueue.main.async {\n                self?.stopLocationUpdates()\n                self?.finish()\n            }\n        }\n    }\n\n    deinit {\n        stopLocationUpdates()\n    }\n\n    open override func execute() {\n        manager.pk_set(desiredAccuracy: accuracy)\n        manager.pk_set(delegate: self)\n        manager.pk_startUpdatingLocation()\n    }\n\n    public func stopLocationUpdates() {\n        manager.pk_stopUpdatingLocation()\n        manager.pk_set(delegate: nil)\n    }\n\n    open func shouldFinish(afterReceivingLocation location: CLLocation) -> Bool {\n        switch accuracy {\n        case _ where accuracy < 0:\n            return true\n        case _ where location.horizontalAccuracy <= accuracy:\n            return true\n        default:\n            return false\n        }\n    }\n\n    public func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {\n        guard !isFinished, let location = locations.last else { return }\n        guard shouldFinish(afterReceivingLocation: location) else {\n            output = .ready(.success(location))\n            return\n        }\n        log.info.message(\"Updated last location: \\(location)\")\n        DispatchQueue.main.async { [weak self] in\n            guard let strongSelf = self, !strongSelf.isFinished else { return }\n            strongSelf.stopLocationUpdates()\n            strongSelf.output = .ready(.success(location))\n            strongSelf.completion?(location)\n            strongSelf.finish()\n        }\n    }\n\n    public func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {\n        DispatchQueue.main.async { [weak self] in\n            guard let strongSelf = self else { return }\n            strongSelf.stopLocationUpdates()\n            strongSelf.finish(withResult: .failure(error))\n        }\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKitMac/Process.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n#if SWIFT_PACKAGE\n    import ProcedureKit\n    import Foundation\n#endif\n\nimport Dispatch\n\nopen class ProcessProcedure: Procedure, InputProcedure, OutputProcedure {\n\n    public struct LaunchRequest {\n        /// (Read-only) The path to the executable to be launched.\n        public let executableURL: URL\n\n        /// (Read-only) The command arguments that should be used to launch the executable.\n        public let arguments: [String]?\n\n        /// (Read-only) The current directory to be used when launching the executable.\n        public let currentDirectoryURL: URL?\n\n        /// (Read-only) The environment to be used when launching the executable.\n        public let environment: [String : String]?\n\n        /// (Read-only) The standard error (FileHandle or Pipe object).\n        public let standardError: Any?\n\n        /// (Read-only) The standard input (FileHandle or Pipe object).\n        public let standardInput: Any?\n\n        /// (Read-only) The standard output (FileHandle or Pipe object).\n        public let standardOutput: Any?\n\n        /// Initialize a request to launch a Process.\n        ///\n        /// The minimum required parameter is a path to the executable to launch (`executableURL`).\n        ///\n        /// Other parameters are optional, and are described in full in the documentation\n        /// for NSTask/Process: https://developer.apple.com/reference/foundation/process\n        ///\n        /// By default, `Process` inherits the environment and some other parameters from the current process.\n        ///\n        /// - Parameters:\n        ///   - executableURL: the path to the executable to be launched.\n        ///   - arguments: (optional) the command arguments that should be used to launch the executable.\n        ///   - currentDirectoryURL: (optional) the current directory to be used when launching the executable.\n        ///   - environment: (optional) the environment to be used when launching the executable.\n        ///   - standardError: (optional) the standard error (FileHandle or Pipe object)\n        ///   - standardInput: (optional) the standard input (FileHandle or Pipe object)\n        ///   - standardOutput: (optional) the standard output (FileHandle or Pipe object)\n        public init(executableURL: URL, arguments: [String]? = nil, currentDirectoryURL: URL? = nil, environment: [String : String]? = nil, standardError: Any? = nil, standardInput: Any? = nil, standardOutput: Any? = nil) {\n            self.executableURL = executableURL\n            self.arguments = arguments\n            self.currentDirectoryURL = currentDirectoryURL\n            self.environment = environment\n            self.standardError = standardError\n            self.standardInput = standardInput\n            self.standardOutput = standardOutput\n        }\n    }\n\n    public struct TerminationResult {\n        let status: Int32\n        let reason: Process.TerminationReason\n    }\n\n    /// Error type for ProcessProcedure\n    public enum Error: Swift.Error, Equatable {\n        case emptyLaunchPath\n        case invalidLaunchPath\n        case didNotExitCleanly(Int32, Process.TerminationReason)\n\n        public static func == (lhs: ProcessProcedure.Error, rhs: ProcessProcedure.Error) -> Bool {\n            switch (lhs, rhs) {\n            case (.emptyLaunchPath, .emptyLaunchPath): return true\n            case (.invalidLaunchPath, .invalidLaunchPath): return true\n            case let (.didNotExitCleanly(lhsStatus, lhsReason), .didNotExitCleanly(rhsStatus, rhsReason)):\n                return (lhsReason == rhsReason) && (lhsStatus == rhsStatus)\n            default: return false\n            }\n        }\n    }\n\n    /// Closure type for processDidLaunch event\n    public typealias ProcessDidLaunch = (ProcessProcedure) -> Void\n\n    /// Closure type for determining whether the process exited cleanly\n    /// - Parameters:\n    ///   - Process.terminationStatus (In32)\n    ///   - Process.terminationReason (Process.TerminationReason)\n    /// - returns Bool: `true` if the Process exited cleanly, `false` otherwise\n    public typealias ProcessDidExitCleanly = (Int32, Process.TerminationReason) -> Bool\n\n    /// The default closure for checking the exit status\n    public static let defaultProcessDidExitCleanly: ProcessDidExitCleanly = { status, reason in\n        switch reason {\n        case .uncaughtSignal: return false\n        case .exit:\n            switch status {\n            case 0: return true\n            default: return false\n            }\n        }\n    }\n\n    /// The LaunchRequest used to launch a Process.\n    public var input: Pending<LaunchRequest> {\n        get { return stateLock.withCriticalScope { _input } }\n        set {\n            assert(!isExecuting, \"Changing the input on a ProcessProcedure after it has started to execute will not have any effect.\")\n            assert(!isFinished, \"Changing the input on a ProcessProcedure after it has finished will not have any effect.\")\n            stateLock.withCriticalScope {\n                _input = newValue\n            }\n        }\n    }\n\n    /// The ProcessProcedure result.\n    ///\n    /// On success (determined by the `processDidExitCleanly` handler), it will\n    /// be set to `.success(TerminationResult)`.\n    ///\n    /// If the `processDidExitCleanly` handler returns `false`, `output` will\n    /// bet set to `.failure(ProcessProcedure.Error.didNotExitCleanly)`.\n    ///\n    /// Both `TerminationResult` and `ProcessProcedure.Error.didNotExitCleanly`\n    /// provide the Process `terminationStatus` and `terminationReason`.\n    public var output: Pending<ProcedureResult<TerminationResult>> {\n        get { return stateLock.withCriticalScope { _output } }\n        set {\n            stateLock.withCriticalScope {\n                _output = newValue\n            }\n        }\n    }\n\n    // - returns process: the Process   // internal for testing\n    internal fileprivate(set) var process: Process? {\n        get { return stateLock.withCriticalScope { _process } }\n        set {\n            stateLock.withCriticalScope {\n                _process = newValue\n            }\n        }\n    }\n\n    fileprivate var _process: Process?\n    fileprivate var _processIdentifier: Int32 = 0\n    fileprivate var _input: Pending<LaunchRequest> = .pending\n    fileprivate var _output: Pending<ProcedureResult<TerminationResult>> = .pending\n    fileprivate let stateLock = PThreadMutex()\n\n    /// - the closure that is called once the Process has been launched\n    private let processDidLaunch: ProcessDidLaunch\n\n    /// - returns processDidExitCleanly: the closure for exiting cleanly.\n    private let processDidExitCleanly: ProcessDidExitCleanly\n\n    // MARK: Initializer (with launchPath + currentDirectoryPath)\n\n    /// Initialize a ProcessProcedure.\n    ///\n    /// The minimum required parameter is a path to the executable to launch (`launchPath`).\n    ///\n    /// Other parameters are optional, and are described in full in the documentation\n    /// for NSTask/Process: https://developer.apple.com/reference/foundation/process\n    ///\n    /// By default, `Process` inherits the environment and some other parameters from the current process.\n    ///\n    /// - Parameters:\n    ///   - launchPath: the path to the executable to be launched.\n    ///   - arguments: (optional) the command arguments that should be used to launch the executable.\n    ///   - currentDirectoryPath: (optional) the current directory to be used when launching the executable.\n    ///   - environment: (optional) the environment to be used when launching the executable.\n    ///   - standardError: (optional) the standard error (FileHandle or Pipe object)\n    ///   - standardInput: (optional) the standard input (FileHandle or Pipe object)\n    ///   - standardOutput: (optional) the standard output (FileHandle or Pipe object)\n    ///   - processDidLaunch: a ProcessDidLaunch block that is called once the Process has been launched.\n    ///   - processDidExitCleanly: a ProcessDidExitCleanly block that is called once the Process has terminated, and is used to determine whether the ProcessProcedure finishes with an error.\n    public convenience init(launchPath: String, arguments: [String]? = nil, currentDirectoryPath: String? = nil, environment: [String : String]? = nil, standardError: Any? = nil, standardInput: Any? = nil, standardOutput: Any? = nil, processDidLaunch: @escaping ProcessDidLaunch = { _ in }, processDidExitCleanly: @escaping ProcessDidExitCleanly = ProcessProcedure.defaultProcessDidExitCleanly) {\n\n        let executableURL = URL(fileURLWithPath: launchPath)\n        let currentDirectoryURL = (currentDirectoryPath != nil) ? URL(fileURLWithPath: currentDirectoryPath!) : nil\n\n        let launchRequest = LaunchRequest(executableURL: executableURL, arguments: arguments, currentDirectoryURL: currentDirectoryURL, environment: environment, standardError: standardError, standardInput: standardInput, standardOutput: standardOutput)\n\n        self.init(launchRequest: launchRequest, processDidLaunch: processDidLaunch, processDidExitCleanly: processDidExitCleanly)\n    }\n\n    // MARK: Initializer (with executableURL + currentDirectoryURL)\n\n    /// Initialize a ProcessProcedure.\n    ///\n    /// The minimum required parameter is a path to the executable to launch (`executableURL`).\n    ///\n    /// Other parameters are optional, and are described in full in the documentation\n    /// for NSTask/Process: https://developer.apple.com/reference/foundation/process\n    ///\n    /// By default, `Process` inherits the environment and some other parameters from the current process.\n    ///\n    /// - Parameters:\n    ///   - executableURL: the path to the executable to be launched.\n    ///   - arguments: (optional) the command arguments that should be used to launch the executable.\n    ///   - currentDirectoryURL: (optional) the current directory to be used when launching the executable.\n    ///   - environment: (optional) the environment to be used when launching the executable.\n    ///   - standardError: (optional) the standard error (FileHandle or Pipe object)\n    ///   - standardInput: (optional) the standard input (FileHandle or Pipe object)\n    ///   - standardOutput: (optional) the standard output (FileHandle or Pipe object)\n    ///   - processDidLaunch: a ProcessDidLaunch block that is called once the Process has been launched.\n    ///   - processDidExitCleanly: a ProcessDidExitCleanly block that is called once the Process has terminated, and is used to determine whether the ProcessProcedure finishes with an error.\n    public convenience init(executableURL: URL, arguments: [String]? = nil, currentDirectoryURL: URL? = nil, environment: [String : String]? = nil, standardError: Any? = nil, standardInput: Any? = nil, standardOutput: Any? = nil, processDidLaunch: @escaping ProcessDidLaunch = { _ in }, processDidExitCleanly: @escaping ProcessDidExitCleanly = ProcessProcedure.defaultProcessDidExitCleanly) {\n\n        let launchRequest = LaunchRequest(executableURL: executableURL, arguments: arguments, currentDirectoryURL: currentDirectoryURL, environment: environment, standardError: standardError, standardInput: standardInput, standardOutput: standardOutput)\n\n        self.init(launchRequest: launchRequest, processDidLaunch: processDidLaunch, processDidExitCleanly: processDidExitCleanly)\n    }\n\n    /// Initialize a ProcessProcedure.\n    ///\n    /// A LaunchRequest must be provided before the ProcessProcedure executes.\n    /// It can be provided up-front, via this initializer, or later via result injection.\n    ///\n    /// Optionally, a `processDidLaunch` and/or `processDidExitCleanly` handler may be\n    /// provided.\n    ///\n    /// The `processDidLaunch` and `processDidExitCleanly` handlers are executed\n    /// on the ProcessProcedure's internal EventQueue.\n    ///\n    /// - Parameters:\n    ///   - launchRequest: a `LaunchRequest` containing the parameters used to launch a Process\n    ///   - processDidLaunch: a ProcessDidLaunch block that is called once the Process has been launched.\n    ///   - processDidExitCleanly: a ProcessDidExitCleanly block that is called once the Process has terminated, and is used to determine whether the ProcessProcedure finishes with an error.\n    public init(launchRequest: LaunchRequest? = nil, processDidLaunch: @escaping ProcessDidLaunch = { _ in }, processDidExitCleanly: @escaping ProcessDidExitCleanly = ProcessProcedure.defaultProcessDidExitCleanly) {\n\n        self.processDidLaunch = processDidLaunch\n        self.processDidExitCleanly = processDidExitCleanly\n        super.init()\n        self.input = launchRequest.flatMap { .ready($0) } ?? .pending\n\n        addDidCancelBlockObserver { procedure, _ in\n            DispatchQueue.main.async {\n                guard let process = procedure.process else { return }\n                guard procedure.isExecuting && process.isRunning else { return }\n                process.terminate()\n                // `finish()` is handled by the process termination handler\n            }\n        }\n    }\n\n    open override func execute() {\n\n        guard let request = input.value else {\n            finish(withResult: .failure(ProcedureKitError.requirementNotSatisfied()))\n            return\n        }\n\n        guard request.executableURL.isFileURL else {\n            finish(withResult: .failure(Error.invalidLaunchPath))\n            return\n        }\n\n        let launchPath = request.executableURL.path\n        guard !launchPath.isEmpty else {\n            finish(withResult: .failure(Error.emptyLaunchPath))\n            return\n        }\n\n        // Check whether the launchPath provided in the request is executable\n        //\n        // NOTE: This check is a \"snapshot\" check, is **not** exhaustive, and\n        // exists largely to assist in catching simple programmer error.\n        //\n        // If the `launchPath` disappears or becomes non-executable between the time\n        // of this check, and the ProcessProcedure's later call to `Process.launch()`,\n        // or if various other error situations occur with the provided LaunchRequest\n        // parameters passed to the Process, Process may throw an Objective-C exception\n        // on macOS < 10.13.\n        // See the documentation for Process / NSTask for more details.\n        //\n        guard FileManager.default.isExecutableFile(atPath: launchPath) else {\n            finish(withResult: .failure(Error.invalidLaunchPath))\n            return\n        }\n\n        // NOTE: NSTask / Process is *not* thread-safe.\n        // See: https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Multithreading/ThreadSafetySummary/ThreadSafetySummary.html#//apple_ref/doc/uid/10000057i-CH12-125664\n        //\n        // It's not a good idea to call `launch()` on a thread that may disappear before the\n        // NSTask / Process goes away. Thus, we use the main queue/thread.\n\n        DispatchQueue.main.async { [weak self] in\n            guard let procedure = self else { return }\n\n            // create Process\n            let process = procedure.createProcess(withRequest: request)\n\n            process.terminationHandler = { [weak procedure] process in\n                guard let procedure = procedure else { return }\n\n                guard !procedure.isCancelled else {\n                    // special case: hide the Process's cancellation error\n                    // if the ProcessProcedure was cancelled\n                    procedure.finish()\n                    return\n                }\n\n                let terminationStatus = process.terminationStatus\n                let terminationReason = process.terminationReason\n\n                // Dispatch the `processDidExitCleanly` closure on the EventQueue\n                procedure.eventQueue.dispatch {\n\n                    if procedure.processDidExitCleanly(terminationStatus, terminationReason) {\n                        procedure.finish(withResult: .success(TerminationResult(status: terminationStatus, reason: terminationReason)))\n                    }\n                    else {\n                        procedure.finish(withResult: .failure(Error.didNotExitCleanly(terminationStatus, terminationReason)))\n                    }\n                }\n            }\n\n            // The ProcessProcedure can be cancelled concurrently with this block on the main queue.\n            // Check whether the Procedure has been cancelled.\n            guard !procedure.isCancelled else {\n                procedure.finish()\n                return\n            }\n\n            // Store the process\n            procedure.process = process\n\n            // Launch the Process\n            do { try procedure.run(process: process) }\n            catch {\n                // Failed to run the Process\n                // Note: This will generally only occur on macOS 10.13+, where new methods\n                //       on Process are available that throw errors (instead of raising\n                //       Objective-C exceptions).\n                procedure.finish(withResult: .failure(error))\n                return\n            }\n\n            // Store the processIdentifier\n            procedure.processIdentifier = process.processIdentifier\n\n            // Dispatch the ProcessDidLaunch callback\n            procedure.eventQueue.dispatch {\n                procedure.processDidLaunch(procedure)\n            }\n        }\n    }\n}\n\n// MARK: - Properties of the Process\n\npublic extension ProcessProcedure {\n\n    /// The processIdentifier for the started Process.\n    ///\n    /// This value is 0 until the ProcessProcedure executes and starts the Process.\n    ///\n    /// To retrieve the processIdentifier as soon as it is available,\n    /// access it inside the ProcessDidLaunch callback (added to the ProcessProcedure).\n    ///\n    /// The processIdentifier remains non-zero after the ProcessProcedure starts the\n    /// Process - even after the Process terminates. Do not assume based on a non-zero\n    /// processIdentifier that the expected associated Process is still running.\n    fileprivate(set) var processIdentifier: Int32 {\n        get { return stateLock.withCriticalScope { _processIdentifier } }\n        set {\n            stateLock.withCriticalScope {\n                _processIdentifier = newValue\n            }\n        }\n    }\n}\n\n// MARK: - Configuration Properties (Read-only)\n\npublic extension ProcessProcedure {\n\n    /// (Read-only) The command arguments that should be used to launch the executable.\n    var arguments: [String]? {\n        get { return input.value?.arguments }\n    }\n\n    /// (Read-only) The current directory to be used when launching the executable.\n    var currentDirectoryURL: URL? {\n        get { return input.value?.currentDirectoryURL }\n    }\n\n    /// (Read-only) The environment to be used when launching the executable.\n    var environment: [String : String]? {\n        get { return input.value?.environment }\n    }\n\n    /// (Read-only) The path (URL) for the executable to be launched.\n    var executableURL: URL? {\n        get { return input.value?.executableURL }\n    }\n\n    /// (Read-only) The standard error (FileHandle or Pipe object).\n    var standardError: Any? {\n        get { return input.value?.standardError }\n    }\n\n    /// (Read-only) The standard input (FileHandle or Pipe object).\n    var standardInput: Any? {\n        get { return input.value?.standardInput }\n    }\n\n    /// (Read-only) The standard output (FileHandle or Pipe object).\n    var standardOutput: Any? {\n        get { return input.value?.standardOutput }\n    }\n}\n\n// MARK: - Process Suspend / Resume\n\npublic extension ProcessProcedure {\n\n    /// Resumes execution of the ProcessProcedure's Process that had previously been suspended with\n    /// a call to suspend().\n    ///\n    /// See the documentation for Process.resume():\n    /// https://developer.apple.com/reference/foundation/process/1407819-resume\n    ///\n    /// If multiple `suspend()` messages were sent to the receiver, an equal number of `resume()`\n    /// messages must be sent before the task resumes execution.\n    ///\n    /// Calling `resume()` when the ProcessProcedure is not executing (i.e. before it executes or\n    /// after it finishes) has no effect and returns false.\n    ///\n    /// - parameter completion: A completion block that is called with the result of the resume() call\n    func resume(completion: @escaping (Bool) -> Void) {\n        DispatchQueue.main.async { [weak self] in\n            guard let procedure = self else { return }\n            guard procedure.isExecuting else {\n                completion(false)\n                return\n            }\n            let result = procedure.process?.resume() ?? false\n            completion(result)\n        }\n    }\n\n    /// Suspends execution of the ProcessProcedure's Process.\n    ///\n    /// See the documentation for Process.suspend():\n    /// https://developer.apple.com/reference/foundation/process/1411590-suspend\n    ///\n    /// Multiple `suspend()` messages can be sent, but they must be balanced with an equal number of\n    /// `resume()` messages before the Process resumes execution.\n    ///\n    /// Calling `suspend()` when the ProcessProcedure is not executing (i.e. before it executes or\n    /// after it finishes) has no effect and returns false.\n    ///\n    /// - parameter completion: A completion block that is called with the result of the suspend() call\n    func suspend(completion: @escaping (Bool) -> Void) {\n        DispatchQueue.main.async { [weak self] in\n            guard let procedure = self else { return }\n            guard procedure.isExecuting else {\n                completion(false)\n                return\n            }\n            let result = procedure.process?.suspend() ?? false\n            completion(result)\n        }\n    }\n}\n\nfileprivate extension ProcessProcedure {\n\n    func createProcess(withRequest request: LaunchRequest) -> Process {\n        let process = Process()\n\n        #if swift(>=3.2)\n            if #available(OSX 10.13, *) {\n                process.executableURL = request.executableURL\n                if let currentDirectoryURL = request.currentDirectoryURL {\n                    process.currentDirectoryURL = currentDirectoryURL\n                }\n            }\n            else {\n                // Versions of macOS < 10.13 only support string-based paths\n                process.launchPath = request.executableURL.path\n                if let currentDirectoryPath = request.currentDirectoryURL?.path {\n                    process.currentDirectoryPath = currentDirectoryPath\n                }\n            }\n        #else\n            process.launchPath = request.executableURL.path\n            if let currentDirectoryPath = request.currentDirectoryURL?.path {\n                process.currentDirectoryPath = currentDirectoryPath\n            }\n        #endif\n        if let arguments = request.arguments {\n            process.arguments = arguments\n        }\n        if let environment = request.environment {\n            process.environment = environment\n        }\n        if let standardError = request.standardError {\n            process.standardError = standardError\n        }\n        if let standardInput = request.standardInput {\n            process.standardInput = standardInput\n        }\n        if let standardOutput = request.standardOutput {\n            process.standardOutput = standardOutput\n        }\n        return process\n    }\n\n    #if swift(>=3.2)\n    // On macOS 10.13+, new methods on Process are available that throw errors\n    // (instead of raising Objective-C exceptions). This method uses them if\n    // possible.\n    func run(process: Process) throws {\n        if #available(OSX 10.13, *) {\n            try process.run()\n        }\n        else {\n            // macOS < 10.13 only support the launch() method, which may throw an ObjC exception\n            process.launch()\n        }\n    }\n    #else\n    fileprivate func run(process: Process) throws {\n        // Earlier SDKs only support Process.launch()\n        process.launch()\n    }\n    #endif\n}\n\n// MARK: - Unavailable\n\npublic extension ProcessProcedure {\n\n    @available(*, unavailable, renamed: \"executableURL\")\n    var launchPath: String? { fatalError(\"Use executableURL\") }\n\n    @available(*, unavailable, renamed: \"currentDirectoryURL\")\n    var currentDirectoryPath: String? { fatalError(\"Use currentDirectoryURL\") }\n}\n"
  },
  {
    "path": "Sources/ProcedureKitMobile/Alert.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport Foundation\nimport UIKit\n\n/**\n `AlertProcedure` is a Procedure subclass which will present a `UIAlertController`.\n\n The alert controller is entirely managed by the procedure. The title, message,\n text fields and actions are set via properties and methods on `AlertProcedure`.\n\n A key understanding here is that `AlertProcedure` can finish when it is\n dismissed, which is the default behaviour, or after it has presented the alert\n controller.\n\n In order to finish when the alert is dismissed, it is critical that the alert\n action handler includes logic to call finish. Therefore, the procedure itself\n exposes API to add actions, so that finish is called correctly. Therefore,\n by restricting exposure to the underlying `UIAlertController` this behaviour\n can be guaranteed.\n */\nopen class AlertProcedure: Procedure {\n\n    internal let controller: UIAlertController\n\n    internal let waitForDismissal: Bool\n\n    // - returns: The presenting view controller\n    public weak var viewController: PresentingViewController?\n\n\n    /**\n     The style of the alert controller. (read-only)\n\n     The value of this property is set to the value you specified in the [alertControllerWithTitle:message:preferredStyle:](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIAlertController_class/#//apple_ref/occ/clm/UIAlertController/alertControllerWithTitle:message:preferredStyle:) method. This value determines how the alert is displayed onscreen.\n\n     - returns: the preferred style of the alert\n     */\n    public var preferredStyle: UIAlertController.Style {\n        return controller.preferredStyle\n    }\n\n    /**\n     The title of the alert.\n\n     The title string is displayed prominently in the alert or action sheet. You should use this string to get the user’s attention and communicate the reason for displaying the alert.\n\n     - returns: the optional title String?\n     */\n    public var title: String? {\n        get { return controller.title }\n        set {\n            guard false == isExecuting && false == isFinished else { return }\n            controller.title = newValue\n        }\n    }\n\n    /**\n     Descriptive text that provides more details about the reason for the alert.\n\n     The message string is displayed below the title string and is less prominent. Use this string to provide additional context about the reason for the alert or about the actions that the user might take.\n\n     - returns: the optional message String?\n     */\n    public var message: String? {\n        get { return controller.message }\n        set {\n            guard false == isExecuting && false == isFinished else { return }\n            controller.message = newValue\n        }\n    }\n\n    /**\n     The array of text fields displayed by the alert. (read-only)\n\n     Use this property to access the text fields displayed by the alert. The text fields are in the order in which you added them to the alert controller. This order also corresponds to the order in which they are displayed in the alert.\n\n     - returns: the optional array of UITextField instances\n     */\n    public var textFields: [UITextField]? {\n        return controller.textFields\n    }\n\n    /**\n     The actions that the user can take in response to the alert or action sheet. (read-only)\n\n     The actions are in the order in which you added them to the alert controller. This order also corresponds to the order in which they are displayed in the alert or action sheet. The second action in the array is displayed below the first, the third is displayed below the second, and so on.\n\n     - returns: the array of UIAlertAction actions.\n     */\n    public var actions: [UIAlertAction] {\n        return controller.actions\n    }\n\n    /**\n     The preferred action for the user to take from an alert.\n\n     The preferred action is relevant for the [UIAlertControllerStyleAlert](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIAlertController_class/#//apple_ref/c/tdef/UIAlertControllerStyle) style only; it is not used by action sheets. When you specify a preferred action, the alert controller highlights the text of that action to give it emphasis. (If the alert also contains a cancel button, the preferred action receives the highlighting instead of the cancel button.) If the iOS device is connected to a physical keyboard, pressing the Return key triggers the preferred action.\n\n     The action object you assign to this property must have already been added to the alert controller’s list of actions. Assigning an object to this property before adding it with the [addAction:](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIAlertController_class/#//apple_ref/occ/instm/UIAlertController/addAction:) method is a programmer error.\n\n     The default value of this property is `nil`.\n\n     - returns: the optional preferredAction, UIAlertAction\n     */\n    @available (iOS 9.0, *)\n    public var preferredAction: UIAlertAction? {\n        get { return controller.preferredAction }\n        set { fatalError(\"Set the preferred action using the add(actionWithTitle:style:isPreferred:handler:) method.\") }\n    }\n\n    /**\n     Creates an `AlertProcedure`. It must be constructed with the view\n     controller which the alert will be presented from. This is stored as a\n     weak reference.\n\n     - parameter title: an optional alert title, defaults to nil\n     - parameter message: an optional alert message, defaults to nil\n     - parameter from: a `UIViewController` instance.\n     - parameter waitForDismissal: a Bool, defaults to true, which indicates whether the\n          procedure should wait until the alert controller is dismissed until finishing.\n\n     - notes: The presenting view controller is weakly held.\n     - notes: The AlertController uses an \"alert\" style, and it is not possible to use AlertProcedure\n       to show \"action sheet\" style alerts.\n     */\n    public init(title: String? = nil, message: String? = nil, from viewController: PresentingViewController, waitForDismissal: Bool = true) {\n        self.controller = UIAlertController(title: title, message: message, preferredStyle: .alert)\n        self.waitForDismissal = waitForDismissal\n        self.viewController = viewController\n        super.init()\n        addCondition(MutuallyExclusive<UIAlertController>())\n    }\n\n    @available(*, deprecated, message: \"Use init(title:message:style:from:waitForDismissal:) instead.\")\n    public convenience init(presentAlertFrom presenting: PresentingViewController, withPreferredStyle preferredAlertStyle: UIAlertController.Style = .alert, waitForDismissal: Bool = true) {\n        self.init(title: nil, message: nil, from: presenting, waitForDismissal: waitForDismissal)\n    }\n\n    open override func execute() {\n        guard false == isCancelled else { return }\n\n        if controller.actions.isEmpty {\n            add(actionWithTitle: NSLocalizedString(\"Okay\", comment: \"Okay\"))\n        }\n\n        let present = UIBlockProcedure { [weak self] in\n            guard let this = self, let viewController = this.viewController else { return }\n            viewController.present(this.controller, animated: true) {\n                guard let alsothis = self else { return }\n                if false == alsothis.waitForDismissal {\n                    alsothis.finish()\n                }\n            }\n        }\n        present.log.enabled = false\n\n        do { try produce(operation: present) }\n        catch { log.fatal.message(\"Unable to present alert, error: \\(error)\") }\n    }\n\n    /**\n     Adds an action button with a title, style and handler.\n\n     Do not add actions directly to the `UIAlertController`, as\n     this will prevent the `AlertProcedure` from correctly finishing.\n\n     - parameter actionWithTitle: an optional String?.\n     - parameter style: a `UIAlertActionStyle` which defaults to `.default`.\n     - parameter handler: a block which receives the operation, and returns Void.\n     */\n    @discardableResult public func add(actionWithTitle title: String?, style: UIAlertAction.Style = .default, isPreferred: Bool = false, handler: @escaping (AlertProcedure, UIAlertAction) -> Void = { _, _ in }) -> UIAlertAction {\n        let action = UIAlertAction(title: title, style: style) { [weak self] action in\n            guard let this = self else { return }\n            handler(this, action)\n            guard this.isExecuting else { return }\n            if this.waitForDismissal {\n                this.finish()\n            }\n        }\n        controller.addAction(action)\n        if #available(iOS 9.0, *), isPreferred {\n            controller.preferredAction = action\n        }\n        return action\n    }\n\n    /**\n     Adds a text field to an alert.\n\n     Calling this method adds an editable text field to the alert. You can call this method more than once to add additional text fields. The text fields are stacked in the resulting alert.\n\n     You can add a text field only if the [preferredStyle](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIAlertController_class/#//apple_ref/occ/instp/UIAlertController/preferredStyle) property is set to [UIAlertControllerStyleAlert](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIAlertController_class/#//apple_ref/c/tdef/UIAlertControllerStyle).\n\n     - parameter configurationHandler: A block for configuring the text field prior to displaying the alert. This block has no return value and takes a single parameter corresponding to the text field object. Use that parameter to change the text field properties.\n     */\n    public func addTextField(configurationHandler: ((UITextField) -> Void)?) {\n        controller.addTextField(configurationHandler: configurationHandler)\n    }\n}\n\n\n"
  },
  {
    "path": "Sources/ProcedureKitMobile/BackgroundObserver.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport Foundation\nimport UIKit\n\ninternal protocol BackgroundTaskApplicationProtocol {\n\n    var applicationState: UIApplication.State { get }\n\n    func beginBackgroundTask(withName taskName: String?, expirationHandler handler: (() -> Swift.Void)?) -> UIBackgroundTaskIdentifier\n\n    func endBackgroundTask(_ identifier: UIBackgroundTaskIdentifier)\n}\n\nextension UIApplication: BackgroundTaskApplicationProtocol { }\n\npublic extension ProcedureKitError {\n\n    /// When the app enters (or is already in) the background state,\n    /// Procedures with an attached `BackgroundObserver` with\n    /// cancellationOption == `.cancelProcedureWhenAppIsBackgrounded`\n    /// will be cancelled with this error.\n    struct AppWasBackgrounded: Error {\n        internal init() { }\n    }\n}\n\n/**\n An observer that automatically establishes a background task for the attached `Procedure`, and\n provides (optional) cancellation behavior for background-related events.\n\n Every `Procedure` with an attached BackgroundObserver begins a [background task](https://developer.apple.com/library/content/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html#//apple_ref/doc/uid/TP40007072-CH4-SW3)\n that is ended when either:\n\n - The `Procedure` finishes.\n - The background execution time expires (and background task expiration handlers are notified).\n\n (Whichever comes first.)\n\n ### Handling Background Events\n\n By default, `BackgroundObserver` will never cancel its attached `Procedure`.\n\n However, you can optionally specify a `CancellationBehavior` when initializing a `BackgroundObserver`.\n\n Specifying `.whenAppIsBackgrounded` causes the `BackgroundObserver` to cancel the attached `Procedure`\n with error `ProcedureKitError.AppWasBackgrounded` when the application is backgrounded (or if it is\n already in the background).\n\n In any case, the `Procedure` still has an associated background task until it finishes, which provides a\n [system-determined finite amount of time](https://developer.apple.com/documentation/uikit/uiapplication/1623029-backgroundtimeremaining) to handle cancellation, clean-up, and finish.\n\n - NOTE:\n For a short, finite-length `Procedure` that should be completed even if the app goes into the background,\n attach a `BackgroundObserver` with `CancellationBehavior` `.never` (the default).\n\n - NOTE:\n For a `Procedure` that shouldn't start or continue running if the app goes into the background (or if the\n app is already in the background), attach a `BackgroundObserver` with `CancellationBehavior`\n `.whenAppIsBackgrounded`.\n */\npublic class BackgroundObserver: ProcedureObserver {\n\n    /// A behavior used to specify when the `BackgroundObserver` will cancel the attached `Procedure`.\n    ///\n    /// - whenAppIsBackgrounded: when the application is backgrounded (or if it is already backgrounded)\n    /// - whenBackgroundExecutionTimeExpires: when the application's background execution time expires\n    /// - never: do not cancel the attached Procedure\n    public enum CancellationBehavior {\n        case whenAppIsBackgrounded\n        case never\n    }\n\n    private let manager: BackgroundManager\n    private let cancelProcedure: CancellationBehavior\n\n    /// Initialize a BackgroundObserver (which internally uses UIApplication.shared).\n    ///\n    /// - Parameter cancelProcedure: (optional) when to cancel the attached `Procedure` (by default, never)\n    public convenience init(cancelProcedure: CancellationBehavior = .never) {\n        self.init(manager: BackgroundManager.shared, cancelProcedure: cancelProcedure)\n    }\n\n    /// Internal: For testing purposes, initialize with a custom `BackgroundManager`.\n    internal init(manager: BackgroundManager, cancelProcedure: CancellationBehavior = .never) {\n        self.manager = manager\n        self.cancelProcedure = cancelProcedure\n    }\n\n    internal static var logMessage_FailedToInitiateBackgroundTask = \"Failed to initiate background task / handling for Procedure. (Running in the background may not be possible.)\"\n\n    /// Public override of `didAttach(to:)` `ProcedureObserver` method that handles starting\n    /// a background task for the attached `Procedure` (and setting up background event handlers).\n    ///\n    /// - Parameter procedure: the `Procedure`\n    public func didAttach(to procedure: Procedure) {\n        var result: BackgroundManager.BackgroundHandlingResult = []\n        switch cancelProcedure {\n        case .never:\n            result = manager.startBackgroundHandling(for: procedure, withExpirationHandler: { _ in })\n        case .whenAppIsBackgrounded:\n            result = manager.startBackgroundHandling(for: procedure, withAppIsInBackgroundHandler: { procedure in\n                procedure.cancel(withErrors: [ProcedureKitError.AppWasBackgrounded()])\n            }, withExpirationHandler: { _ in })\n        }\n\n        guard result.contains(.success) else {\n            procedure.log.warning.message(BackgroundObserver.logMessage_FailedToInitiateBackgroundTask)\n            return\n        }\n\n        if result.contains(.additionalHandlersForThisProcedure) {\n            procedure.log.warning.message(\"More than one BackgroundObserver has been attached to this Procedure\")\n        }\n    }\n\n    /// Public override of `did(finish:)` `ProcedureObserver` method that handles ending the\n    /// background task for the attached `Procedure`, as well as cleaning up any background\n    /// event handlers.\n    ///\n    /// - Parameter procedure: the `Procedure`\n    public func did(finish procedure: Procedure, with error: Error?) {\n        manager.didFinish(procedure: procedure)\n    }\n}\n\n/// Used to manage background tasks (and related background-state event handlers) for all Procedures.\ninternal class BackgroundManager {\n\n    typealias BackgroundTaskExpirationHandler = (Procedure) -> Void\n    typealias AppIsInBackgroundHandler = (Procedure) -> Void\n\n    static let shared = BackgroundManager(app: UIApplication.shared)\n\n    private class ProcedureBackgroundRegistry {\n\n        class AppDidEnterBackgroundHandlerRecord {\n            let handler: AppDidEnterBackgroundHandler\n            init(_ handler: @escaping AppDidEnterBackgroundHandler) {\n                self.handler = handler\n            }\n        }\n\n        enum ProcedureInfo {\n            case firstBackgroundTaskIdentifierForProcedure\n            case additionalBackgroundTaskIdentifierForProcedure\n        }\n\n        typealias AppDidEnterBackgroundHandler = AppIsInBackgroundHandler\n\n        private var _backgroundTasksPerProcedure = [Procedure: [Protector<UIBackgroundTaskIdentifier>]]()\n        private var _backgroundEventHandlersPerProcedure = [Procedure: [AppDidEnterBackgroundHandlerRecord]]()\n        private let lock = PThreadMutex()\n\n        /// Adds a background task identifier to the registry for a specific `Procedure`.\n        ///\n        /// While this always succeeds, it will return information about the\n        /// state of the registry for that `Procedure`.\n        ///\n        /// - Parameters:\n        ///   - identifier: the `UIBackgroundTaskIdentifier`\n        ///   - procedure: the `Procedure`\n        /// - Returns: `ProcedureInfo`\n        func add(backgroundTaskIdentifier identifier: Protector<UIBackgroundTaskIdentifier>, for procedure: Procedure) -> ProcedureInfo {\n            return lock.withCriticalScope {\n                guard var backgroundTaskIdentifiers = _backgroundTasksPerProcedure[procedure] else {\n                    _backgroundTasksPerProcedure.updateValue([identifier], forKey: procedure)\n                    return .firstBackgroundTaskIdentifierForProcedure\n                }\n                backgroundTaskIdentifiers.append(identifier)\n                _backgroundTasksPerProcedure[procedure] = backgroundTaskIdentifiers\n                return .additionalBackgroundTaskIdentifierForProcedure\n            }\n        }\n\n        func add(appDidEnterBackgroundHandler handler: @escaping AppDidEnterBackgroundHandler, for procedure: Procedure) -> AppDidEnterBackgroundHandlerRecord {\n            return lock.withCriticalScope {\n                let newRecord = AppDidEnterBackgroundHandlerRecord(handler)\n                guard var backgroundHandlers = _backgroundEventHandlersPerProcedure[procedure] else {\n                    _backgroundEventHandlersPerProcedure.updateValue([newRecord], forKey: procedure)\n                    return newRecord\n                }\n                backgroundHandlers.append(newRecord)\n                _backgroundEventHandlersPerProcedure[procedure] = backgroundHandlers\n                return newRecord\n            }\n        }\n\n        /// Claim an AppDidEnterBackgroundHandlerRecord for execution.\n        ///\n        /// - Returns: `true` if this is the first claim on execution, `false` if the handler has been previously claimed for execution\n        func claim(appIsInBackgroundHandler record: AppDidEnterBackgroundHandlerRecord, for procedure: Procedure) -> Bool {\n            return lock.withCriticalScope { () -> Bool in\n                // verify that the AppIsInBackgroundHandlerRecord is still in the _backgroundEventHandlersPerProcedure\n                guard var backgroundHandlersForProcedure = _backgroundEventHandlersPerProcedure[procedure] else { return false }\n                guard let handlerRecordIndex = backgroundHandlersForProcedure.firstIndex(where: { $0 === record }) else {\n                    // otherwise, something else (ex. background state change) already claimed it\n                    return false\n                }\n                backgroundHandlersForProcedure.remove(at: handlerRecordIndex)\n                _backgroundEventHandlersPerProcedure[procedure] = backgroundHandlersForProcedure\n                return true\n            }\n        }\n\n        /// Claims all existing AppDidEnterBackgroundHandlerRecords for execution.\n        ///\n        /// - Returns: all claimed AppDidEnterBackgroundHandlerRecords (by Procedure)\n        func claimAllBackgroundHandlersForExecution() -> [Procedure: [AppDidEnterBackgroundHandlerRecord]] {\n            return lock.withCriticalScope {\n                let claimedHandlers = _backgroundEventHandlersPerProcedure\n                _backgroundEventHandlersPerProcedure = [Procedure: [AppDidEnterBackgroundHandlerRecord]]()\n                return claimedHandlers\n            }\n        }\n\n        /// Remove all registered BackgroundTaskIdentifiers and AppDidEnterBackground handlers\n        /// for a specified Procedure from the registry.\n        ///\n        /// - Parameter procedure: the Procedure\n        /// - Returns: an array of the removed UIBackgroundTaskIdentifiers\n        func remove(for procedure: Procedure) -> [UIBackgroundTaskIdentifier]? {\n            let backgroundTasks = lock.withCriticalScope { () -> [Protector<UIBackgroundTaskIdentifier>]? in\n                let backgroundTasks = _backgroundTasksPerProcedure.removeValue(forKey: procedure)\n                _backgroundEventHandlersPerProcedure.removeValue(forKey: procedure)\n                return backgroundTasks\n            }\n            let backgroundTaskIdentifiers: [UIBackgroundTaskIdentifier]? = backgroundTasks?.compactMap {\n                let identifier = $0.returnCurrentAndOverwrite(with: UIBackgroundTaskIdentifier.invalid)\n                guard identifier != UIBackgroundTaskIdentifier.invalid else { return nil }\n                return identifier\n            }\n            return backgroundTaskIdentifiers\n        }\n    }\n\n    struct BackgroundHandlingResult: OptionSet {\n        public let rawValue: UInt8\n        public init(rawValue: UInt8) { self.rawValue = rawValue }\n\n        public static let success                               = BackgroundHandlingResult(rawValue: 1 << 0)\n        public static let additionalHandlersForThisProcedure    = BackgroundHandlingResult(rawValue: 1 << 1)\n    }\n\n    private let registry = ProcedureBackgroundRegistry()\n    private let application: BackgroundTaskApplicationProtocol\n    private var appIsInBackground: Bool {\n        get { return backgroundStateLock.withCriticalScope { _appIsInBackground } }\n        set {\n            backgroundStateLock.withCriticalScope {\n                _appIsInBackground = newValue\n            }\n        }\n    }\n    private var _appIsInBackground: Bool = false\n    private let backgroundStateLock = PThreadMutex()\n\n    init(app: BackgroundTaskApplicationProtocol) {\n        self.application = app\n\n        // Register to receive Background Enter / Leave notifications\n        let nc = NotificationCenter.default\n        nc.addObserver(self, selector: #selector(BackgroundManager.didEnterBackground(withNotification:)), name: UIApplication.didEnterBackgroundNotification, object: application)\n        nc.addObserver(self, selector: #selector(BackgroundManager.didBecomeActive(withNotification:)), name: UIApplication.didBecomeActiveNotification, object: application)\n\n        // To obtain the current application state, dispatch to main\n        DispatchQueue.main.async {\n\n            let currentlyIsInBackground = (self.application.applicationState == .background)\n            self.appIsInBackground = currentlyIsInBackground\n\n            // Upon first retrieval of the current app background state,\n            // if the app is backgrounded, dispatch any existing\n            // AppIsInBackgroundHandlers for Procedures.\n            if currentlyIsInBackground {\n                self.executeAppIsInBackgroundHandlers()\n            }\n        }\n    }\n\n    deinit {\n        removeNotificationCenterObservers()\n    }\n\n    private func executeAppIsInBackgroundHandlers() {\n        assert(DispatchQueue.isMainDispatchQueue || Thread.current.isMainThread)\n        let handlersByProcedure = registry.claimAllBackgroundHandlersForExecution()\n        for (procedure, handlers) in handlersByProcedure {\n            // call all the handlers for the Procedure\n            handlers.forEach { $0.handler(procedure) }\n        }\n    }\n\n    @objc func didEnterBackground(withNotification notification: NSNotification) {\n        assert(DispatchQueue.isMainDispatchQueue || Thread.current.isMainThread)\n        // app entered background\n        appIsInBackground = true\n        // retrieve and execute the AppIsInBackground handlers for any Procedures\n        executeAppIsInBackgroundHandlers()\n    }\n\n    @objc func didBecomeActive(withNotification notification: NSNotification) {\n        assert(DispatchQueue.isMainDispatchQueue || Thread.current.isMainThread)\n        // app became active\n        appIsInBackground = false\n    }\n\n    /// Begins a background task for the `Procedure`, with an expiration handler.\n    ///\n    /// The BackgroundManager internally provides an expiration handler for the background task that:\n    ///     1.) Calls the provided expirationHandler\n    ///     2.) Ends the background task\n    ///\n    /// - Parameters:\n    ///   - procedure: the Procedure\n    ///   - expirationHandler: an expiration handler that is called when the background task created for the Procedure is signaled of impending expiration of background time\n    func startBackgroundHandling(for procedure: Procedure, withExpirationHandler expirationHandler: @escaping BackgroundTaskExpirationHandler) -> BackgroundHandlingResult {\n        // register a background task for the Procedure\n        return registerBackgroundTask(for: procedure, withExpirationHandler: expirationHandler)\n    }\n\n    /// Begins a background task for the `Procedure`, with a appIsInBackground handler and an expiration handler.\n    ///\n    /// The BackgroundManager internally provides an expiration handler for the background task that:\n    ///     1.) Calls the provided expirationHandler\n    ///     2.) Ends the background task\n    ///\n    /// The appIsInBackground handler is called *once*, when the app first enters the background state\n    /// or if the app is *already* in the background state (when background handling is started for the\n    /// `Procedure`).\n    ///\n    /// - Parameters:\n    ///   - procedure: the Procedure\n    ///   - appIsInBackgroundHandler: a handler that is called (once) when the app first enters the background state or if it is already in the background state.\n    ///   - expirationHandler: an expiration handler that is called when the background task created for the Procedure is signaled of impending expiration of background time\n    func startBackgroundHandling(for procedure: Procedure, withAppIsInBackgroundHandler appIsInBackgroundHandler: @escaping AppIsInBackgroundHandler, withExpirationHandler expirationHandler: @escaping BackgroundTaskExpirationHandler) -> BackgroundHandlingResult {\n        // Register a background task for the Procedure\n        let result = registerBackgroundTask(for: procedure, withExpirationHandler: expirationHandler)\n\n        // Register handler for app background state change\n        let backgroundHandler = registry.add(appDidEnterBackgroundHandler: appIsInBackgroundHandler, for: procedure)\n\n        // Check if the app is already backgrounded\n        if appIsInBackground {\n            // If so, this may have happened prior to the call to registry.add(appDidEnterBackgroundHandler:) above\n            // in which case there will be no state change to trigger a call of the appIsInBackgroundHandler.\n\n            // So, dispatch async to main immediately\n            DispatchQueue.main.async {\n                // And then on the main queue, attempt to claim the handler for execution\n                guard self.registry.claim(appIsInBackgroundHandler: backgroundHandler, for: procedure) else {\n                    // Something else - such as a processed DidEnterBackground event - claimed this\n                    // handler for execution. Return immediately to avoid calling the handler twice.\n                    return\n                }\n                backgroundHandler.handler(procedure)\n            }\n        }\n\n        return result\n    }\n\n    /// Must be paired with every successful call to `startBackgroundHandling(for: ...)`\n    /// Call it when the procedure didFinish.\n    ///\n    /// Removes outstanding background tasks and registered background handlers associated with the Procedure\n    ///\n    /// - Parameter procedure: the Procedure\n    func didFinish(procedure: Procedure) {\n        // Remove procedure from registry\n        guard let procedureBackgroundTasks = registry.remove(for: procedure) else {\n            // didFinish(procedure:) called for Procedure that does not currently exist in registry\n            return\n        }\n        // End all background tasks associated with procedure\n        for taskIdentifier in procedureBackgroundTasks {\n            application.endBackgroundTask(taskIdentifier)\n        }\n    }\n\n    /// Registers a background task for a Procedure.\n    private func registerBackgroundTask(for procedure: Procedure, withExpirationHandler expirationHandler: @escaping BackgroundTaskExpirationHandler) -> BackgroundHandlingResult {\n        // register a background task for the Procedure\n\n        let identifier = Protector<UIBackgroundTaskIdentifier>(UIBackgroundTaskIdentifier.invalid)\n        let finalExpirationHandler = { [weak procedure, application, identifier] in\n            // call provided expiration handler\n            if let procedure = procedure {\n                expirationHandler(procedure)\n            }\n\n            // claim the identifier (for ending *once*) here\n            let claimedIdentifier = identifier.returnCurrentAndOverwrite(with: UIBackgroundTaskIdentifier.invalid)\n\n            // end background task (if it hasn't already ended)\n            guard claimedIdentifier != UIBackgroundTaskIdentifier.invalid else { return }\n            application.endBackgroundTask(claimedIdentifier)\n        }\n\n        let createdIdentifier = identifier.write { ward -> UIBackgroundTaskIdentifier in\n            ward = application.beginBackgroundTask(withName: BackgroundManager.backgroundTaskName(for: procedure), expirationHandler: finalExpirationHandler)\n            return ward\n        }\n\n        guard createdIdentifier != UIBackgroundTaskIdentifier.invalid else {\n            // beginBackgroundTask(withName:expirationHandler:) returned `UIBackgroundTaskInvalid`\n            // This can happen if running in the background is not possible.\n            // Return the empty set of BackgroundHandlingResult\n            return []\n        }\n\n        // store the identifier in the registrar\n        let result = registry.add(backgroundTaskIdentifier: identifier, for: procedure)\n        switch result {\n        case .firstBackgroundTaskIdentifierForProcedure:\n            return [.success]\n        case .additionalBackgroundTaskIdentifierForProcedure:\n            return [.success, .additionalHandlersForThisProcedure]\n        }\n    }\n\n    internal static func backgroundTaskName(for procedure: Procedure) -> String {\n        return \"Background Task for \\(String(describing: type(of: procedure))): \\\"\\(procedure.operationName)\\\"\"\n    }\n\n    private func removeNotificationCenterObservers() {\n        // To support iOS < 9.0 and macOS < 10.11, NotificationCenter observers must be removed.\n        // (Or a crash may result.)\n        // Reference: https://developer.apple.com/reference/foundation/notificationcenter/1415360-addobserver\n        let nc = NotificationCenter.default\n        nc.removeObserver(self, name: UIApplication.didEnterBackgroundNotification, object: nil)\n        nc.removeObserver(self, name: UIApplication.didBecomeActiveNotification, object: nil)\n    }\n}\n\nfileprivate extension Protector {\n    func returnCurrentAndOverwrite(with newValue: T) -> T {\n        return write { (ward: inout T) -> T in\n            let previous = ward\n            ward = newValue\n            return previous\n        }\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKitMobile/NetworkObserver+Mobile.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport Foundation\nimport UIKit\n\nextension UIApplication: NetworkActivityIndicatorProtocol { }\n\npublic extension NetworkActivityController {\n\n    /// (iOS-only) A shared NetworkActivityController that uses `UIApplication.shared`\n    /// to display/hide the network activity indicator in the status bar.\n    ///\n    /// Since each NetworkActivityController manages its own count of started/stopped\n    /// procedures with attached NetworkObservers, you are encouraged to use this\n    /// shared NetworkActivityController to manage the network activity indicator\n    /// in the status bar (or the convenience initializers that do so).\n    static let shared = NetworkActivityController()\n\n    /// (iOS-only) Initialize a NetworkActivityController that displays/hides the\n    /// network activity indicator in the status bar. (via UIApplication)\n    ///\n    /// - Parameter timerInterval: How long to wait after observed network activity stops\n    ///                            before the network activity indicator is set to false.\n    ///                            (This helps reduce flickering if you rapidly create\n    ///                            procedures with attached NetworkObservers.)\n    convenience init(timerInterval: TimeInterval = 1.0) {\n        self.init(timerInterval: timerInterval, indicator: UIApplication.shared)\n    }\n}\n\npublic extension NetworkObserver {\n\n    /// (iOS-only) Initialize a NetworkObserver that displays/hides\n    /// the network activity indicator in the status bar. (via UIApplication)\n    convenience init() {\n        self.init(controller: NetworkActivityController.shared)\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKitMobile/UI.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport Foundation\nimport UIKit\n\npublic protocol PresentingViewController: class {\n\n    func present(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Void)?)\n\n    func show(_ viewControllerToShow: UIViewController, sender: Any?)\n\n    func showDetailViewController(_ viewControllerToShow: UIViewController, sender: Any?)\n}\n\nextension UIViewController: PresentingViewController { }\n\npublic protocol DismissingViewController: class {\n    var didDismissViewControllerBlock: () -> Void { get set }\n}\n\npublic enum PresentationStyle {\n    case show, showDetail, present\n}\n\n@available(*, deprecated, message: \"UIProcedure is now deprecated and will be removed\")\nopen class UIProcedure: Procedure {\n\n    public let presented: UIViewController\n    public let presenting: PresentingViewController\n    public let style: PresentationStyle\n    public let wrapInNavigationController: Bool\n    public let sender: Any?\n    public let finishAfterPresentating: Bool\n\n    internal var shouldWaitUntilDismissal: Bool {\n        return !finishAfterPresentating\n    }\n\n    public init<T: UIViewController>(present: T, from: PresentingViewController, withStyle style: PresentationStyle, inNavigationController: Bool = true, sender: Any? = nil, finishAfterPresenting: Bool = true) {\n        self.presented = present\n        self.presenting = from\n        self.style = style\n        self.wrapInNavigationController = inNavigationController\n        self.sender = sender\n        self.finishAfterPresentating = finishAfterPresenting\n        super.init()\n    }\n\n    public convenience init<T: UIViewController>(present: T, from: PresentingViewController, withStyle style: PresentationStyle, inNavigationController: Bool = true, sender: Any? = nil, waitForDismissal: Bool) where T: DismissingViewController {\n        self.init(present: present, from: from, withStyle: style, inNavigationController: inNavigationController, sender: sender, finishAfterPresenting: !waitForDismissal)\n        if waitForDismissal {\n            present.didDismissViewControllerBlock = { [weak self] in\n                guard let strongSelf = self else { return }\n                if !strongSelf.finishAfterPresentating && strongSelf.isExecuting {\n                    strongSelf.finish()\n                }\n            }\n        }\n    }\n\n    open override func execute() {\n        DispatchQueue.main.async { [weak self] in\n            guard let strongSelf = self else { return }\n\n            switch strongSelf.style {\n            case .present:\n                let viewControllerToPresent: UIViewController\n                if strongSelf.presented is UIAlertController || !strongSelf.wrapInNavigationController {\n                    viewControllerToPresent = strongSelf.presented\n                }\n                else {\n                    viewControllerToPresent = UINavigationController(rootViewController: strongSelf.presented)\n                }\n                strongSelf.presenting.present(viewControllerToPresent, animated: true, completion: nil)\n\n            case .show:\n                strongSelf.presenting.show(strongSelf.presented, sender: strongSelf.sender)\n\n            case .showDetail:\n                strongSelf.presenting.showDetailViewController(strongSelf.presented, sender: strongSelf.sender)\n            }\n\n            if strongSelf.finishAfterPresentating {\n                strongSelf.finish()\n                return\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKitMobile/UserConfirmation.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport Foundation\nimport UIKit\n\n\n/**\n The condition succeeds if the user's response to the shown alert\n is a confirmation action. Else, the condition will fail.\n\n Therefore, this condition can be attached to procedures which\n require the user to consent. For example, consider deleting\n data or user-generated records. You might present an alert to\n get the user to confirm deletion.\n */\npublic class UserConfirmationCondition: Condition {\n\n    /// The Response type\n    public enum Response {\n        case unknown, confirmed, cancelled\n    }\n\n    fileprivate var alert: AlertProcedure\n\n    private var response: Response = .unknown\n\n\n    /// Initialize a new UserConfirmationCondition\n    ///\n    /// - Parameters:\n    ///   - title: a String? the alert title, defaults to \"User Confirmation\"\n    ///   - message: a String?, the alert message, default to nil\n    ///   - confirmationActionTitle: a String, the action title which\n    ///        indicates the user's confirmation. Defaults to \"Okay\".\n    ///   - isDestructive: a Bool, which indicates if the procedure is\n    //         destructive. Defaults to true.\n    ///   - cancelActionTitle: a String, the action title for the user\n    ///        not confirming. Default to \"Cancel\"\n    ///   - viewController: a UIViewController, the view controller which will\n    ///        present the alert controller.\n    public init(\n        title: String? = NSLocalizedString(\"User Confirmation\", comment: \"User Confirmation\"),\n        message: String? = nil,\n        confirmationActionTitle: String = NSLocalizedString(\"Okay\", comment: \"Okay\"),\n        isDestructive: Bool = true,\n        cancelActionTitle: String = NSLocalizedString(\"Cancel\", comment: \"Cancel\"),\n        from viewController: UIViewController) {\n\n        alert = AlertProcedure(title: title, message: message, from: viewController, waitForDismissal: true)\n\n        super.init()\n        name = \"UserConfirmationCondition\"\n        alert.add(actionWithTitle: confirmationActionTitle, style: isDestructive ? .destructive : .default) { [weak self] _, _ in\n            self?.response = .confirmed\n        }\n        alert.add(actionWithTitle: cancelActionTitle, style: .cancel) { [weak self] _, _ in\n            self?.response = .cancelled\n        }\n        produceDependency(alert)\n    }\n\n    public override func evaluate(procedure: Procedure, completion: @escaping (ConditionResult) -> Void) {\n        let result: ConditionResult = {\n            switch response {\n            case .unknown: return .failure(ProcedureKitError.unknown)\n            case .cancelled: return .failure(ProcedureKitError.ConditionEvaluationCancelled())\n            case .confirmed: return .success(true)\n            }\n        }()\n        completion(result)\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKitMobile/ViewControllerContainment.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n#if SWIFT_PACKAGE\nimport ProcedureKit\nimport Foundation\nimport UIKit\n#endif\n\n/// A struct of the views which require autolayout constraints\npublic struct AutolayoutViews {\n    public let child: UIView\n    public let parent: UIView\n}\n\n/// A block type which receives the child's view to perform any autolayout.\npublic typealias SetAutolayoutConstraintsBlockType = (AutolayoutViews) -> ()\n\n@available(iOS 9.0, *)\npublic enum SetAutolayoutConstraints {\n\n    // Uses NSLayoutConstraint pinning the child to the parent's anchors.\n    case pinnedToParent\n\n    // Provide a custom block\n    case custom(SetAutolayoutConstraintsBlockType)\n\n    public var block: SetAutolayoutConstraintsBlockType {\n        switch self {\n        case .pinnedToParent:\n            return { views in\n                NSLayoutConstraint.activate([\n                    views.child.leadingAnchor.constraint(equalTo: views.parent.leadingAnchor),\n                    views.child.trailingAnchor.constraint(equalTo: views.parent.trailingAnchor),\n                    views.child.topAnchor.constraint(equalTo: views.parent.topAnchor),\n                    views.child.bottomAnchor.constraint(equalTo: views.parent.bottomAnchor)\n                ])\n            }\n        case let .custom(block):\n            return block\n        }\n    }\n}\n\n\ninternal extension UIViewController {\n\n    func pk_add(child: UIViewController, with frame: CGRect? = nil, in subview: UIView, setAutolayoutConstraints block: @escaping SetAutolayoutConstraintsBlockType) {\n        addChild(child)\n        child.view.frame = frame ?? CGRect(x: 0, y: 0, width: view.bounds.width, height: view.bounds.height)\n        subview.addSubview(child.view)\n        block(AutolayoutViews(child: child.view, parent: subview))\n        child.didMove(toParent: self)\n    }\n\n    func pk_removeFromParent() {\n        self.willMove(toParent: nil)\n        self.view.removeFromSuperview()\n        self.removeFromParent()\n    }\n}\n\n\n/**\n Procedure to safely add a child view controller to a parent using\n UIViewController containment.\n */\nopen class AddChildViewControllerProcedure: UIBlockProcedure {\n\n    public init(_ child: UIViewController, to parent: UIViewController, with frame: CGRect? = nil, in subview: UIView? = nil, setAutolayoutConstraints block: @escaping SetAutolayoutConstraintsBlockType) {\n        let view: UIView = subview ?? parent.view\n        assert(view.isDescendant(of: parent.view))\n        super.init {\n            parent.pk_add(child: child, with: frame, in: view, setAutolayoutConstraints: block)\n        }\n        name = \"Add Child ViewController\"\n    }\n\n    @available(iOS 9.0, *)\n    public convenience init(_ child: UIViewController, to parent: UIViewController, with frame: CGRect? = nil, in subview: UIView? = nil, setAutolayoutConstraints strategy: SetAutolayoutConstraints = .pinnedToParent) {\n        self.init(child, to: parent, with: frame, in: subview, setAutolayoutConstraints: strategy.block)\n    }\n}\n\n/**\n Procedure to safely remove a child view controller from its parent using\n UIViewController containment.\n */\nopen class RemoveChildViewControllerProcedure: UIBlockProcedure {\n\n    public init(_ child: UIViewController) {\n        super.init {\n            child.pk_removeFromParent()\n        }\n        name = \"Remove Child ViewController\"\n    }\n}\n\nopen class SetChildViewControllerProcedure: UIBlockProcedure {\n\n    public init(_ child: UIViewController, in parent: UIViewController, with frame: CGRect? = nil, in subview: UIView? = nil, setAutolayoutConstraints block: @escaping SetAutolayoutConstraintsBlockType) {\n        let view: UIView = subview ?? parent.view\n        assert(view.isDescendant(of: parent.view))\n        super.init {\n            parent.children.forEach { $0.pk_removeFromParent() }\n            parent.pk_add(child: child, with: frame, in: view, setAutolayoutConstraints: block)\n        }\n        name = \"Set Child ViewController\"\n    }\n\n    @available(iOS 9.0, *)\n    public convenience init(_ child: UIViewController, in parent: UIViewController, with frame: CGRect? = nil, in subview: UIView? = nil, setAutolayoutConstraints strategy: SetAutolayoutConstraints = .pinnedToParent) {\n        self.init(child, in: parent, with: frame, in: subview, setAutolayoutConstraints: strategy.block)\n    }\n}\n\n\n"
  },
  {
    "path": "Sources/ProcedureKitNetwork/Network.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n#if !os(watchOS)\n\n#if SWIFT_PACKAGE\n    import ProcedureKit\n    import Foundation\n#endif\n\nimport SystemConfiguration\n\npublic protocol NetworkResilience {\n\n    /**\n     The number of attempts to make for the\n     network request. It represents the total number\n     of attempts which should be made.\n\n     - returns: a Int\n     */\n    var maximumNumberOfAttempts: Int { get }\n\n    /**\n     The timeout backoff wait strategy defines the time between\n     retry attempts in the event of a network timout.\n     Use `.Immediate` to indicate no time between retry attempts.\n\n     - returns: a WaitStrategy\n     */\n    var backoffStrategy: WaitStrategy { get }\n\n    /**\n     A request timeout, which if specified indicates the maximum\n     amount of time to wait for a response.\n\n     - returns: a TimeInterval\n     */\n    var requestTimeout: TimeInterval? { get }\n\n    /**\n     Some HTTP status codes should be treated as errors, and\n     retried\n\n     - parameter statusCode: an Int\n     - returns: a Bool, to indicate that the\n     */\n    func shouldRetry(forResponseWithHTTPStatusCode statusCode: HTTPStatusCode) -> Bool\n}\n\npublic struct DefaultNetworkResilience: NetworkResilience {\n\n    public let maximumNumberOfAttempts: Int\n\n    public let backoffStrategy: WaitStrategy\n\n    public let requestTimeout: TimeInterval?\n\n    public init(maximumNumberOfAttempts: Int = 3, backoffStrategy: WaitStrategy = .incrementing(initial: 2, increment: 2), requestTimeout: TimeInterval? = 8.0) {\n        self.maximumNumberOfAttempts = maximumNumberOfAttempts\n        self.backoffStrategy = backoffStrategy\n        self.requestTimeout = requestTimeout\n    }\n\n    public func shouldRetry(forResponseWithHTTPStatusCode statusCode: HTTPStatusCode) -> Bool {\n        switch statusCode {\n        case let code where code.isServerError:\n            return true\n        case .requestTimeout, .tooManyRequests:\n            return true\n        default:\n            return false\n        }\n    }\n}\n\npublic enum ProcedureKitNetworkResiliencyError: Error {\n    case receivedErrorStatusCode(HTTPStatusCode)\n}\n\nclass NetworkReachabilityWaitProcedure: Procedure {\n\n    let reachability: SystemReachability\n    let connectivity: Reachability.Connectivity\n\n    init(reachability: SystemReachability, via connectivity: Reachability.Connectivity = .any) {\n        self.reachability = reachability\n        self.connectivity = connectivity\n        super.init()\n    }\n\n    override func execute() {\n        reachability.whenReachable(via: connectivity) { [weak self] in self?.finish() }\n    }\n}\n\nopen class NetworkRecovery<T: Procedure> where T: NetworkOperation {\n\n    let resilience: NetworkResilience\n    let connectivity: Reachability.Connectivity\n    fileprivate var reachability: SystemReachability = Reachability.Manager.shared\n\n    var max: Int { return resilience.maximumNumberOfAttempts }\n\n    var wait: WaitStrategy { return resilience.backoffStrategy }\n\n    public init(resilience: NetworkResilience, connectivity: Reachability.Connectivity) {\n        self.resilience = resilience\n        self.connectivity = connectivity\n    }\n\n    open func recover(withInfo info: RetryFailureInfo<T>, payload: RepeatProcedurePayload<T>) -> RepeatProcedurePayload<T>? {\n\n        let networkResponse = info.operation.makeNetworkResponse()\n\n        // Check to see if we should wait for a network reachability change before retrying\n        if shouldWaitForReachabilityChange(givenNetworkResponse: networkResponse) {\n            let waiter = NetworkReachabilityWaitProcedure(reachability: reachability, via: connectivity)\n            payload.operation.addDependency(waiter)\n            info.addOperations(waiter)\n            return RepeatProcedurePayload(operation: payload.operation, delay: nil, configure: payload.configure)\n        }\n\n        // Check if the resiliency behavior indicates a retry\n        guard shouldRetry(givenNetworkResponse: networkResponse) else { return nil }\n\n        return payload\n    }\n\n    func shouldWaitForReachabilityChange(givenNetworkResponse networkResponse: ProcedureKitNetworkResponse) -> Bool {\n        guard let networkError = networkResponse.error else { return false }\n        return networkError.waitForReachabilityChangeBeforeRetrying\n    }\n\n    open func shouldRetry(givenNetworkResponse networkResponse: ProcedureKitNetworkResponse) -> Bool {\n\n        // Check that we've actually got a network error & suggested delay\n        if let networkError = networkResponse.error {\n\n            // Check to see if we have a transient or timeout network error - retry with suggested delay\n            if networkError.isTransientError || networkError.isTimeoutError {\n                return true\n            }\n        }\n\n        // Check to see if we have an http error code\n        guard let statusCode = networkResponse.httpStatusCode, statusCode.isClientError || statusCode.isServerError else {\n            return false\n        }\n\n        // Query the network resilience type to determine the behavior.\n        return resilience.shouldRetry(forResponseWithHTTPStatusCode: statusCode)\n    }\n}\n\nopen class NetworkProcedure<T: Procedure>: RetryProcedure<T> where T: NetworkOperation {\n\n    let recovery: NetworkRecovery<T>\n\n    internal var reachability: SystemReachability {\n        get { return recovery.reachability }\n        set { recovery.reachability = newValue }\n    }\n\n    public init<OperationIterator>(dispatchQueue: DispatchQueue? = nil, recovery: NetworkRecovery<T>, iterator base: OperationIterator) where OperationIterator: IteratorProtocol, OperationIterator.Element == T {\n        self.recovery = recovery\n        super.init(dispatchQueue: dispatchQueue, max: recovery.max, wait: recovery.wait, iterator: base, retry: recovery.recover(withInfo:payload:))\n        if let timeout = recovery.resilience.requestTimeout {\n            appendConfigureBlock { $0.addObserver(TimeoutObserver(by: timeout)) }\n        }\n    }\n\n    public convenience init<OperationIterator>(dispatchQueue: DispatchQueue? = nil, resilience: NetworkResilience = DefaultNetworkResilience(), connectivity: Reachability.Connectivity = .any, iterator base: OperationIterator) where OperationIterator: IteratorProtocol, OperationIterator.Element == T {\n        self.init(dispatchQueue: dispatchQueue, recovery: NetworkRecovery<T>(resilience: resilience, connectivity: connectivity), iterator: base)\n    }\n\n    public convenience init(dispatchQueue: DispatchQueue = DispatchQueue.default, resilience: NetworkResilience = DefaultNetworkResilience(), connectivity: Reachability.Connectivity = .any, body: @escaping () -> T?) {\n        self.init(dispatchQueue: dispatchQueue, resilience: resilience, connectivity: connectivity, iterator: AnyIterator(body))\n    }\n\n    open override func child(_ child: Procedure, willFinishWithError error: Error?) {\n        var networkError = error\n\n        // Ultimately, always call super to correctly manage the operation lifecycle.\n        defer { super.child(child, willFinishWithError: networkError) }\n\n        // Check that the operation is the current one.\n        guard child == current else { return }\n\n        // If we have an error let RetryProcedure (super) deal with it by returning here\n        guard error == nil else { return }\n\n        // Create a network response from the network operation\n        let networkResponse = current.makeNetworkResponse()\n\n        // Check to see if this network response should be retried\n        guard recovery.shouldRetry(givenNetworkResponse: networkResponse), let statusCode = networkResponse.httpStatusCode else { return }\n\n        // Create resiliency error\n        let resiliencyError: ProcedureKitNetworkResiliencyError = .receivedErrorStatusCode(statusCode)\n\n        // Set the network errors\n        networkError = resiliencyError\n    }\n}\n\n#endif\n\npublic extension InputProcedure where Input: Equatable {\n\n    @discardableResult func injectPayload<Dependency: OutputProcedure>(fromNetwork dependency: Dependency) -> Self where Dependency.Output: HTTPPayloadResponseProtocol, Dependency.Output.Payload == Input {\n        return injectResult(from: dependency) { http in\n            guard let payload = http.payload else { throw ProcedureKitError.requirementNotSatisfied() }\n            return payload\n        }\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKitNetwork/NetworkData.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n#if SWIFT_PACKAGE\n    import ProcedureKit\n    import Foundation\n#endif\n\n/**\n NetworkDataProcedure is a simple procedure which will perform a data task using\n URLSession based APIs. It only supports the completion block style API, therefore\n do not use this procedure if you wish to use delegate based APIs on URLSession.\n*/\nopen class NetworkDataProcedure: Procedure, InputProcedure, OutputProcedure, NetworkOperation {\n\n    public typealias NetworkResult = ProcedureResult<HTTPPayloadResponse<Data>>\n    public typealias CompletionBlock = (NetworkResult) -> Void\n\n    public var input: Pending<URLRequest> {\n        get { return stateLock.withCriticalScope { _input } }\n        set {\n            stateLock.withCriticalScope {\n                _input = newValue\n            }\n        }\n    }\n\n    public var output: Pending<NetworkResult> {\n        get { return stateLock.withCriticalScope { _output } }\n        set {\n            stateLock.withCriticalScope {\n                _output = newValue\n            }\n        }\n    }\n\n    public let session: NetworkSession\n    public let completion: CompletionBlock\n\n    private let stateLock = NSLock()\n    internal private(set) var task: NetworkDataTask? // internal for testing\n    private var _input: Pending<URLRequest> = .pending\n    private var _output: Pending<NetworkResult> = .pending\n\n    public init(session: NetworkSession, request: URLRequest? = nil, completionHandler: @escaping CompletionBlock = { _ in }) {\n\n        self.session = session\n        self.completion = completionHandler\n        super.init()\n        self.input = request.flatMap { .ready($0) } ?? .pending\n\n        addDidCancelBlockObserver { procedure, _ in\n            procedure.task?.cancel()\n            // a call to `finish()` is not necessary here, because the URLSessionTask's\n            // completion handler is always called (even if cancelled) and it\n            // ensures that `finish()` is called\n        }\n    }\n\n    open override func execute() {\n        guard let request = input.value else {\n            finish(withResult: .failure(ProcedureKitError.requirementNotSatisfied()))\n            return\n        }\n\n        guard !isCancelled else {\n            finish()\n            return\n        }\n        task = session.dataTask(with: request) { [weak self] data, response, error in\n            guard let strongSelf = self else { return }\n\n            if let error = error {\n                if strongSelf.isCancelled, let error = error as? URLError, error.code == .cancelled {\n                    // special case: hide the task's cancellation error\n                    // if the NetworkProcedure was cancelled\n                    strongSelf.finish()\n                    return\n                }\n                strongSelf.finish(withResult: .failure(error))\n                return\n            }\n\n            guard let data = data, let response = response as? HTTPURLResponse else {\n                strongSelf.finish(withResult: .failure(ProcedureKitError.unknown))\n                return\n            }\n\n            let http = HTTPPayloadResponse(payload: data, response: response)\n\n            strongSelf.completion(.success(http))\n            strongSelf.finish(withResult: .success(http))\n        }\n\n        log.info.message(\"Will make request: \\(request)\")\n        task?.resume()\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKitNetwork/NetworkDownload.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n#if SWIFT_PACKAGE\n    import ProcedureKit\n    import Foundation\n#endif\n\n/**\n NetworkDownloadProcedure is a simple procedure which will perform a download task using\n URLSession based APIs. It only supports the completion block style API, therefore\n do not use this procedure if you wish to use delegate based APIs on URLSession.\n */\nopen class NetworkDownloadProcedure: Procedure, InputProcedure, OutputProcedure, NetworkOperation {\n    public typealias NetworkResult = ProcedureResult<HTTPPayloadResponse<URL>>\n    public typealias CompletionBlock = (NetworkResult) -> Void\n\n    public var input: Pending<URLRequest> {\n        get { return stateLock.withCriticalScope { _input } }\n        set {\n            stateLock.withCriticalScope {\n                _input = newValue\n            }\n        }\n    }\n\n    public var output: Pending<NetworkResult> {\n        get { return stateLock.withCriticalScope { _output } }\n        set {\n            stateLock.withCriticalScope {\n                _output = newValue\n            }\n        }\n    }\n\n    public let session: NetworkSession\n    public let completion: CompletionBlock\n\n    private let stateLock = NSLock()\n    internal private(set) var task: NetworkDownloadTask?\n    private var _input: Pending<URLRequest> = .pending\n    private var _output: Pending<NetworkResult> = .pending\n\n    public init(session: NetworkSession, request: URLRequest? = nil, completionHandler: @escaping CompletionBlock = { _ in }) {\n\n        self.session = session\n        self.completion = completionHandler\n        super.init()\n        self.input = request.flatMap { .ready($0) } ?? .pending\n\n        addDidCancelBlockObserver { procedure, _ in\n            procedure.task?.cancel()\n            // a call to `finish()` is not necessary here, because the URLSessionTask's\n            // completion handler is always called (even if cancelled) and it\n            // ensures that `finish()` is called\n        }\n    }\n\n    open override func execute() {\n        guard let request = input.value else {\n            finish(withResult: .failure(ProcedureKitError.requirementNotSatisfied()))\n            return\n        }\n\n        guard !isCancelled else {\n            finish()\n            return\n        }\n        task = session.downloadTask(with: request) { [weak self] location, response, error in\n            guard let strongSelf = self else { return }\n\n            if let error = error {\n                if strongSelf.isCancelled, let error = error as? URLError, error.code == .cancelled {\n                    // special case: hide the task's cancellation error\n                    // if the NetworkProcedure was cancelled\n                    strongSelf.finish()\n                    return\n                }\n                strongSelf.finish(withResult: .failure(error))\n                return\n            }\n\n            guard let location = location, let response = response as? HTTPURLResponse else {\n                strongSelf.finish(withResult: .failure(ProcedureKitError.unknown))\n                return\n            }\n\n            let http = HTTPPayloadResponse(payload: location, response: response)\n\n            strongSelf.completion(.success(http))\n            strongSelf.finish(withResult: .success(http))\n        }\n\n        task?.resume()\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKitNetwork/NetworkReachability.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n#if !os(watchOS)\n\n#if SWIFT_PACKAGE\n    import ProcedureKit\n    import Foundation\n#endif\n\nimport SystemConfiguration\n\n// MARK: - Internal concrete types\n\nextension Reachability {\n\n    final class Manager {\n        typealias Status = NetworkStatus\n\n        static let shared = Reachability.Manager(Device())\n\n        let queue = DispatchQueue(label: \"run.kit.ProcedureKit.Network.Reachability\")\n        var network: NetworkReachability\n        fileprivate var protectedObservers = Protector(Array<Observer>())\n\n        var observers: [Observer] {\n            return protectedObservers.access\n        }\n\n        init(_ network: NetworkReachability) {\n            self.network = network\n            self.network.delegate = self\n        }\n    }\n}\n\nextension Reachability.Manager: NetworkReachabilityDelegate {\n\n    func didChangeReachability(flags: SCNetworkReachabilityFlags) {\n        guard observers.count > 0 else { return }\n\n        let status = Status(flags: flags)\n        let observersToCheck = observers\n\n        protectedObservers.write { (observers: inout Array<Reachability.Observer>) in\n\n            var observersToBeRemoved = Array<Reachability.Observer>()\n\n            let newObservers = observersToCheck.filter { observer in\n                let shouldRemove = status.isConnected(via: observer.connectivity)\n                if shouldRemove {\n                    observersToBeRemoved.append(observer)\n                }\n                return !shouldRemove\n            }\n\n            if newObservers.count == 0 {\n                self.network.stopNotifier()\n            }\n\n            if observersToBeRemoved.count > 0 {\n                observersToBeRemoved.forEach {\n                    DispatchQueue.main.async(execute: $0.didConnectBlock)\n                }\n            }\n\n            observers = newObservers\n        }\n    }\n}\n\nextension Reachability.Manager: SystemReachability {\n\n    func whenReachable(via connectivity: Reachability.Connectivity, block: @escaping () -> Void) {\n        protectedObservers.write { (observers: inout Array<Reachability.Observer>) in\n            let observer = Reachability.Observer(connectivity: connectivity, didConnectBlock: block)\n            observers.append(observer)\n        }\n        do {\n            try network.startNotifier(onQueue: queue)\n        }\n        catch {\n            print(\"Caught error: \\(error) starting reachability notifier.\")\n        }\n    }\n\n    func reachability(of: URL, block: @escaping (Reachability.NetworkStatus) -> Void) {\n\n    }\n}\n\n// MARK: - Device Reachability\n\nextension Reachability {\n\n    final class Device {\n\n        static func makeDefaultRouteReachability() throws -> SCNetworkReachability {\n            var zeroAddress = sockaddr()\n            zeroAddress.sa_len = UInt8(MemoryLayout<sockaddr>.size)\n            zeroAddress.sa_family = sa_family_t(AF_INET)\n\n            guard let reachability: SCNetworkReachability = withUnsafePointer(to: &zeroAddress, {\n                SCNetworkReachabilityCreateWithAddress(nil, UnsafePointer($0))\n            }) else { throw ReachabilityError.failedToCreateDefaultRouteReachability }\n\n            return reachability\n        }\n\n        internal let defaultRouteReachability: SCNetworkReachability\n        fileprivate private(set) var threadSafeProtector = Protector(false)\n        weak var delegate: NetworkReachabilityDelegate?\n\n        var notifierIsRunning: Bool {\n            get { return threadSafeProtector.access }\n            set {\n                threadSafeProtector.write { (isRunning: inout Bool) in\n                    isRunning = newValue\n                }\n            }\n        }\n\n        init() {\n            defaultRouteReachability = try! Device.makeDefaultRouteReachability() // swiftlint:disable:this force_try\n        }\n\n        deinit {\n            stopNotifier()\n        }\n    }\n}\n\nextension Reachability.Device: NetworkReachability {\n\n    func getFlags(forReachability reachability: SCNetworkReachability) -> SCNetworkReachabilityFlags {\n        var flags = SCNetworkReachabilityFlags()\n        guard withUnsafeMutablePointer(to: &flags, {\n            SCNetworkReachabilityGetFlags(reachability, UnsafeMutablePointer($0))\n        }) else { return SCNetworkReachabilityFlags() }\n\n        return flags\n    }\n\n    func didChangeReachability(flags: SCNetworkReachabilityFlags) {\n        delegate?.didChangeReachability(flags: flags)\n    }\n\n    func check(reachability: SCNetworkReachability, on queue: DispatchQueue) {\n        queue.async { [weak self] in\n            guard let strongSelf = self else { return }\n            let flags = strongSelf.getFlags(forReachability: reachability)\n            strongSelf.didChangeReachability(flags: flags)\n        }\n    }\n\n    func startNotifier(onQueue queue: DispatchQueue) throws {\n        precondition(delegate != nil, \"Reachability delegate not set.\")\n        guard !notifierIsRunning else { return }\n\n        notifierIsRunning = true\n\n        var context = SCNetworkReachabilityContext(version: 0, info: nil, retain: nil, release: nil, copyDescription: nil)\n        context.info = UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque())\n\n        guard SCNetworkReachabilitySetCallback(defaultRouteReachability, __device_reachability_callback, &context) else {\n            stopNotifier()\n            throw ReachabilityError.failedToSetNotifierCallback\n        }\n\n        guard SCNetworkReachabilitySetDispatchQueue(defaultRouteReachability, queue) else {\n            stopNotifier()\n            throw ReachabilityError.failedToSetNotifierDispatchQueue\n        }\n\n        check(reachability: defaultRouteReachability, on: queue)\n    }\n\n    func stopNotifier() {\n        SCNetworkReachabilitySetCallback(defaultRouteReachability, nil, nil)\n        SCNetworkReachabilitySetDispatchQueue(defaultRouteReachability, nil)\n        notifierIsRunning = false\n    }\n}\n\nprivate func __device_reachability_callback(reachability: SCNetworkReachability, flags: SCNetworkReachabilityFlags, info: UnsafeMutableRawPointer?) {\n    guard let info = info else { return }\n    let deviceReachability = Unmanaged<Reachability.Device>.fromOpaque(info).takeUnretainedValue()\n    DispatchQueue.main.async {\n        deviceReachability.didChangeReachability(flags: flags)\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Sources/ProcedureKitNetwork/NetworkSupport.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n#if SWIFT_PACKAGE\n    import ProcedureKit\n    import Foundation\n#endif\n\n// MARK: - URLSession\n\npublic protocol URLSessionTaskProtocol {\n    func resume()\n    func cancel()\n}\n\npublic protocol NetworkDataTask: URLSessionTaskProtocol { }\npublic protocol NetworkDownloadTask: URLSessionTaskProtocol { }\npublic protocol NetworkUploadTask: URLSessionTaskProtocol { }\n\npublic protocol NetworkSession {\n\n    func dataTask(with request: URLRequest, completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void) -> NetworkDataTask\n\n    func downloadTask(with request: URLRequest, completionHandler: @escaping (URL?, URLResponse?, Error?) -> Void) -> NetworkDownloadTask\n\n    func uploadTask(with request: URLRequest, from bodyData: Data?, completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void) -> NetworkUploadTask\n}\n\nextension URLSessionTask: URLSessionTaskProtocol { }\nextension URLSessionDataTask: NetworkDataTask {}\nextension URLSessionDownloadTask: NetworkDownloadTask { }\nextension URLSessionUploadTask: NetworkUploadTask { }\nextension URLSession: NetworkSession {\n    public func dataTask(with request: URLRequest, completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void) -> NetworkDataTask {\n        let task: URLSessionDataTask = dataTask(with: request, completionHandler: completionHandler)\n        return task\n    }\n    \n    public func downloadTask(with request: URLRequest, completionHandler: @escaping (URL?, URLResponse?, Error?) -> Void) -> NetworkDownloadTask {\n        let task: URLSessionDownloadTask = downloadTask(with: request, completionHandler: completionHandler)\n        return task\n    }\n    \n    public func uploadTask(with request: URLRequest, from bodyData: Data?, completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void) -> NetworkUploadTask {\n        let task: URLSessionUploadTask = uploadTask(with: request, from: bodyData, completionHandler: completionHandler)\n        return task\n    }\n}\n\nextension URL: ExpressibleByStringLiteral {\n\n    public init(unicodeScalarLiteral value: String) {\n        self.init(string: value)!\n    }\n\n    public init(extendedGraphemeClusterLiteral value: String) {\n        self.init(string: value)!\n    }\n\n    public init(stringLiteral value: String) {\n        self.init(string: value)!\n    }\n}\n\n// MARK: - Input & Output wrapper types\n\npublic protocol HTTPPayloadResponseProtocol: Equatable {\n    associatedtype Payload: Equatable\n\n    var payload: Payload? { get }\n    var response: HTTPURLResponse { get }\n}\n\npublic struct HTTPPayloadResponse<Payload: Equatable>: HTTPPayloadResponseProtocol {\n\n    public var payload: Payload?\n    public var response: HTTPURLResponse\n\n    public init(payload: Payload, response: HTTPURLResponse) {\n        self.payload = payload\n        self.response = response\n    }\n}\n\npublic struct HTTPPayloadRequest<Payload: Equatable>: Equatable {\n\n    public var request: URLRequest\n    public var payload: Payload?\n\n    public init(payload: Payload? = nil, request: URLRequest) {\n        self.payload = payload\n        self.request = request\n    }\n}\n\n// MARK: - Error Handling\n\npublic struct ProcedureKitNetworkError: Error {\n\n    public let underlyingError: Error\n\n    public var errorCode: Int {\n        return (underlyingError as NSError).code\n    }\n\n    public var isTransientError: Bool {\n        switch errorCode {\n        case NSURLErrorNetworkConnectionLost:\n            return true\n        default:\n            return false\n        }\n    }\n\n    public var isTimeoutError: Bool {\n        guard let procedureKitError = underlyingError as? ProcedureKitError else { return false }\n        guard case .timedOut(with: _) = procedureKitError.context else { return false }\n        return true\n    }\n\n    var waitForReachabilityChangeBeforeRetrying: Bool {\n        switch errorCode {\n        case NSURLErrorNotConnectedToInternet, NSURLErrorInternationalRoamingOff, NSURLErrorCallIsActive, NSURLErrorDataNotAllowed:\n            return true\n        default:\n            return false\n        }\n    }\n\n    init(error: Error) {\n        self.underlyingError = error\n    }\n}\n\npublic struct ProcedureKitNetworkResponse {\n\n    public let response: HTTPURLResponse?\n    public let error: ProcedureKitNetworkError?\n\n    public var httpStatusCode: HTTPStatusCode? {\n        return response?.code\n    }\n\n    public init(response: HTTPURLResponse? = nil, error: Error? = nil) {\n        self.response = response\n        self.error = error.map { ProcedureKitNetworkError(error: $0) }\n    }\n}\n\npublic protocol NetworkOperation {\n\n    var error: Error? { get }\n\n    var urlResponse: HTTPURLResponse? { get }\n}\n\npublic enum HTTPStatusCode: Int, CustomStringConvertible {\n\n    case `continue` = 100\n    case switchingProtocols = 101\n    case processing = 102\n    case checkpoint = 103\n\n    case ok = 200\n    case created = 201\n    case accepted = 202\n    case nonAuthoritativeInformation = 203\n    case noContent = 204\n    case resetContent = 205\n    case partialContent = 206\n    case multiStatus = 207\n    case alreadyReported = 208\n    case imUsed = 226\n\n    case multipleChoices = 300\n    case movedPermenantly = 301\n    case found = 302\n    case seeOther = 303\n    case notModified = 304\n    case useProxy = 305\n    case temporaryRedirect = 307\n    case permanentRedirect = 308\n\n    case badRequest = 400\n    case unauthorized = 401\n    case paymentRequired = 402\n    case forbidden = 403\n    case notFound = 404\n    case methodNotAllowed = 405\n    case notAcceptable = 406\n    case proxyAuthenticationRequired = 407\n    case requestTimeout = 408\n    case conflict = 409\n    case gone = 410\n    case lengthRequired = 411\n    case preconditionFailed = 412\n    case payloadTooLarge = 413\n    case uriTooLong = 414\n    case unsupportedMediaType = 415\n    case rangeNotSatisfiable = 416\n    case expectationFailed = 417\n    case imATeapot = 418\n    case misdirectedRequest = 421\n    case unprocesssableEntity = 422\n    case locked = 423\n    case failedDependency = 424\n    case urpgradeRequired = 426\n    case preconditionRequired = 428\n    case tooManyRequests = 429\n    case requestHeadersFieldTooLarge = 431\n    case iisLoginTimeout = 440\n    case nginxNoResponse = 444\n    case iisRetryWith = 449\n    case blockedByWindowsParentalControls = 450\n    case unavailableForLegalReasons = 451\n    case nginxSSLCertificateError = 495\n    case nginxHTTPToHTTPS = 497\n    case tokenExpired = 498\n    case nginxClientClosedRequest = 499\n\n    case internalServerError = 500\n    case notImplemented = 501\n    case badGateway = 502\n    case serviceUnavailable = 503\n    case gatewayTimeout = 504\n    case httpVersionNotSupported = 505\n    case variantAlsoNegotiates = 506\n    case insufficientStorage = 507\n    case loopDetected = 508\n    case bandwidthLimitExceeded = 509\n    case notExtended = 510\n    case networkAuthenticationRequired = 511\n    case siteIsFrozen = 530\n\n    public var isInformational: Bool {\n        switch rawValue {\n        case 100..<200: return true\n        default: return false\n        }\n    }\n\n    public var isSuccess: Bool {\n        switch rawValue {\n        case 200..<300: return true\n        default: return false\n        }\n    }\n\n    public var isRedirection: Bool {\n        switch rawValue {\n        case 300..<400: return true\n        default: return false\n        }\n    }\n\n    public var isClientError: Bool {\n        switch rawValue {\n        case 400..<500: return true\n        default: return false\n        }\n    }\n\n    public var isServerError: Bool {\n        switch rawValue {\n        case 500..<600: return true\n        default: return false\n        }\n    }\n\n    public var localizedReason: String {\n        return HTTPURLResponse.localizedString(forStatusCode: rawValue)\n    }\n\n    public var description: String {\n        return \"\\(rawValue) \\(localizedReason)\"\n    }\n}\n\n// MARK: - Extensions\n\npublic extension HTTPURLResponse {\n\n    var code: HTTPStatusCode? {\n        return HTTPStatusCode(rawValue: statusCode)\n    }\n}\n\npublic extension NetworkOperation {\n\n    func makeNetworkResponse() -> ProcedureKitNetworkResponse {\n        return ProcedureKitNetworkResponse(response: urlResponse, error: error)\n    }\n}\n\nextension NetworkOperation where Self: OutputProcedure, Self.Output: HTTPPayloadResponseProtocol {\n\n    public var urlResponse: HTTPURLResponse? {\n        return output.success?.response\n    }\n}\n"
  },
  {
    "path": "Sources/ProcedureKitNetwork/NetworkUpload.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n#if SWIFT_PACKAGE\n    import ProcedureKit\n    import Foundation\n#endif\n\n/**\n NetworkUploadProcedure is a simple procedure which will perform a upload task using\n URLSession based APIs. It only supports the completion block style API, therefore\n do not use this procedure if you wish to use delegate based APIs on URLSession.\n */\nopen class NetworkUploadProcedure: Procedure, InputProcedure, OutputProcedure, NetworkOperation {\n    public typealias NetworkResult = ProcedureResult<HTTPPayloadResponse<Data>>\n    public typealias CompletionBlock = (NetworkResult) -> Void\n\n    public var input: Pending<HTTPPayloadRequest<Data>> {\n        get { return stateLock.withCriticalScope { _input } }\n        set {\n            stateLock.withCriticalScope {\n                _input = newValue\n            }\n        }\n    }\n\n    public var output: Pending<NetworkResult> {\n        get { return stateLock.withCriticalScope { _output } }\n        set {\n            stateLock.withCriticalScope {\n                _output = newValue\n            }\n        }\n    }\n\n    public let session: NetworkSession\n    public let completion: CompletionBlock\n\n    private let stateLock = NSLock()\n    internal private(set) var task: NetworkUploadTask?\n    private var _input: Pending<HTTPPayloadRequest<Data>> = .pending\n    private var _output: Pending<NetworkResult> = .pending\n\n    public init(session: NetworkSession, request: URLRequest? = nil, data: Data? = nil, completionHandler: @escaping CompletionBlock = { _ in }) {\n\n        self.session = session\n        self.completion = completionHandler\n        super.init()\n        self.input = request.flatMap { .ready(HTTPPayloadRequest(payload: data, request: $0)) } ?? .pending\n\n        addDidCancelBlockObserver { procedure, _ in\n            procedure.task?.cancel()\n            // a call to `finish()` is not necessary here, because the URLSessionTask's\n            // completion handler is always called (even if cancelled) and it\n            // ensures that `finish()` is called\n        }\n    }\n\n    open override func execute() {\n        guard let requirement = input.value else {\n            finish(withResult: .failure(ProcedureKitError.requirementNotSatisfied()))\n            return\n        }\n\n        guard !isCancelled else {\n            finish()\n            return\n        }\n        task = session.uploadTask(with: requirement.request, from: requirement.payload) { [weak self] data, response, error in\n            guard let strongSelf = self else { return }\n\n            if let error = error {\n                if strongSelf.isCancelled, let error = error as? URLError, error.code == .cancelled {\n                    // special case: hide the task's cancellation error\n                    // if the NetworkProcedure was cancelled\n                    strongSelf.finish()\n                    return\n                }\n                strongSelf.finish(withResult: .failure(error))\n                return\n            }\n\n            guard let data = data, let response = response as? HTTPURLResponse else {\n                strongSelf.finish(withResult: .failure(ProcedureKitError.unknown))\n                return\n            }\n\n            let http = HTTPPayloadResponse(payload: data, response: response)\n\n            strongSelf.completion(.success(http))\n            strongSelf.finish(withResult: .success(http))\n        }\n\n        task?.resume()\n    }\n}\n"
  },
  {
    "path": "Sources/TestingProcedureKit/CapabilityTestCase.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport Foundation\nimport XCTest\nimport ProcedureKit\n\npublic class TestableCapability: CapabilityProtocol {\n\n    public enum Status: AuthorizationStatus {\n        public enum Requirement { // swiftlint:disable:this nesting\n            case minimum, maximum\n        }\n\n        case unknown, restricted, denied, minimumAuthorized, maximumAuthorized\n\n        public func meets(requirement: Requirement?) -> Bool {\n            switch (requirement, self) {\n            case (.some(.minimum), .minimumAuthorized), (_, .maximumAuthorized):\n                return true\n            default: return false\n            }\n        }\n    }\n\n    public var requirement: Status.Requirement? = .minimum\n    public var isAsynchronous = false\n    public var serviceIsAvailable = true\n    public var didCheckIsAvailable = false\n    public var serviceAuthorizationStatus: Status = .unknown\n    public var didCheckAuthorizationStatus = false\n    public var responseAuthorizationStatus: Status = .maximumAuthorized\n    public var didRequestAuthorization = false\n\n    public func isAvailable() -> Bool {\n        didCheckIsAvailable = true\n        return serviceIsAvailable\n    }\n\n    public func getAuthorizationStatus(_ completion: @escaping (Status) -> Void) {\n        didCheckAuthorizationStatus = true\n        if isAsynchronous {\n            DispatchQueue.initiated.async {\n                completion(self.serviceAuthorizationStatus)\n            }\n        }\n        else {\n            completion(serviceAuthorizationStatus)\n        }\n    }\n\n    public func requestAuthorization(withCompletion completion: @escaping () -> Void) {\n        didRequestAuthorization = true\n        serviceAuthorizationStatus = responseAuthorizationStatus\n        if isAsynchronous {\n            DispatchQueue.initiated.async(execute: completion)\n        }\n        else {\n            completion()\n        }\n    }\n}\n\nopen class TestableCapabilityTestCase: ProcedureKitTestCase {\n\n    public var capability: TestableCapability!\n    public var getAuthorizationStatus: GetAuthorizationStatusProcedure<TestableCapability.Status>!\n    public var authorize: AuthorizeCapabilityProcedure<TestableCapability.Status>!\n    public var authorizedFor: AuthorizedFor<TestableCapability.Status>!\n\n    open override func setUp() {\n        super.setUp()\n        capability = TestableCapability()\n        getAuthorizationStatus = GetAuthorizationStatusProcedure(capability)\n        authorize = AuthorizeCapabilityProcedure(capability)\n        authorizedFor = AuthorizedFor(capability)\n        procedure.addCondition(authorizedFor)\n    }\n\n    open override func tearDown() {\n        capability = nil\n        getAuthorizationStatus.cancel()\n        getAuthorizationStatus = nil\n        authorize.cancel()\n        authorize = nil\n        authorizedFor = nil\n        super.tearDown()\n    }\n\n    public func XCTAssertGetAuthorizationStatus<Status: AuthorizationStatus>(_ exp1: @autoclosure () throws -> (Bool, Status)?, expected exp2: @autoclosure () throws -> (Bool, Status), _ message: @autoclosure () -> String = \"\", file: StaticString = #file, line: UInt = #line) where Status: Equatable {\n        __XCTEvaluateAssertion(testCase: self, message(), file: file, line: line) {\n            let result = try exp1()\n            let expected = try exp2()\n\n            guard let (isAvailable, status) = result else {\n                return .expectedFailure(\"GetAuthorizationStatus result was not set.\")\n            }\n            guard isAvailable == expected.0 else {\n                return .expectedFailure(\"Capability's availability was not \\(expected.0).\")\n            }\n            guard status == expected.1 else {\n                return .expectedFailure(\"\\(status) was not \\(expected.1).\")\n            }\n            return .success\n        }\n    }\n\n    public func XCTAssertTestCapabilityStatusChecked(_ message: @autoclosure () -> String = \"\", file: StaticString = #file, line: UInt = #line) {\n        __XCTEvaluateAssertion(testCase: self, message(), file: file, line: line) {\n            guard capability.didCheckIsAvailable else {\n                return .expectedFailure(\"Capability did not check availability.\")\n            }\n            guard capability.didCheckAuthorizationStatus else {\n                return .expectedFailure(\"Capability did not check authorization status.\")\n            }\n            guard !capability.didRequestAuthorization else {\n                return .expectedFailure(\"Capability did request authorization unexpectedly.\")\n            }\n            return .success\n        }\n    }\n}\n"
  },
  {
    "path": "Sources/TestingProcedureKit/ConcurrencyTestCase.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport Foundation\nimport XCTest\nimport ProcedureKit\n\npublic protocol ConcurrencyTestResultProtocol {\n    var procedures: [TestConcurrencyTrackingProcedure] { get }\n    var duration: Double { get }\n    var registrar: ConcurrencyRegistrar { get }\n}\n\n// MARK: - ConcurrencyTestCase\n\nopen class ConcurrencyTestCase: ProcedureKitTestCase {\n\n    public typealias Registrar = ConcurrencyRegistrar\n    public typealias TrackingProcedure = TestConcurrencyTrackingProcedure\n\n    public var registrar: Registrar!\n\n    public class TestResult: ConcurrencyTestResultProtocol {\n        public let procedures: [TrackingProcedure]\n        public let duration: TimeInterval\n        public let registrar: Registrar\n\n        public init(procedures: [TrackingProcedure], duration: TimeInterval, registrar: Registrar) {\n            self.procedures = procedures\n            self.duration = duration\n            self.registrar = registrar\n        }\n    }\n\n    public struct Expectations {\n        public let checkMinimumDetected: Int?\n        public let checkMaximumDetected: Int?\n        public let checkAllProceduresFinished: Bool?\n        public let checkMinimumDuration: TimeInterval?\n        public let checkExactDetected: Int?\n\n        public init(checkMinimumDetected: Int? = .none, checkMaximumDetected: Int? = .none, checkAllProceduresFinished: Bool? = .none, checkMinimumDuration: TimeInterval? = .none) {\n            if let checkMinimumDetected = checkMinimumDetected,\n                let checkMaximumDetected = checkMaximumDetected,\n                checkMinimumDetected == checkMaximumDetected {\n                self.checkExactDetected = checkMinimumDetected\n            }\n            else {\n                self.checkExactDetected = .none\n            }\n            self.checkMinimumDetected = checkMinimumDetected\n            self.checkMaximumDetected = checkMaximumDetected\n            self.checkAllProceduresFinished = checkAllProceduresFinished\n            self.checkMinimumDuration = checkMinimumDuration\n        }\n    }\n\n    public func create(procedures count: Int = 3, delayMicroseconds: useconds_t = 500000 /* 0.5 seconds */, withRegistrar registrar: Registrar) -> [TrackingProcedure] {\n        return (0..<count).map { i in\n            let name = \"TestConcurrencyTrackingProcedure: \\(i)\"\n            return TestConcurrencyTrackingProcedure(name: name, microsecondsToSleep: delayMicroseconds, registrar: registrar)\n        }\n    }\n\n    public func concurrencyTest(operations: Int = 3, withDelayMicroseconds delayMicroseconds: useconds_t = 500000 /* 0.5 seconds */, withName name: String = #function, withTimeout timeout: TimeInterval = 3, withConfigureBlock configure: (TrackingProcedure) -> TrackingProcedure = { return $0 }, withExpectations expectations: Expectations) {\n\n        concurrencyTest(operations: operations, withDelayMicroseconds: delayMicroseconds, withTimeout: timeout, withConfigureBlock: configure,\n            completionBlock: { (results) in\n                XCTAssertResults(results, matchExpectations: expectations)\n            }\n        )\n    }\n\n    public func concurrencyTest(operations: Int = 3, withDelayMicroseconds delayMicroseconds: useconds_t = 500000 /* 0.5 seconds */, withName name: String = #function, withTimeout timeout: TimeInterval = 3, withConfigureBlock configure: (TrackingProcedure) -> TrackingProcedure = { return $0 }, completionBlock completion: (TestResult) -> Void) {\n\n        let registrar = Registrar()\n        let procedures = create(procedures: operations, delayMicroseconds: delayMicroseconds, withRegistrar: registrar).map {\n            return configure($0)\n        }\n\n        let startTime = CFAbsoluteTimeGetCurrent()\n        wait(forAll: procedures, withTimeout: timeout)\n        let endTime = CFAbsoluteTimeGetCurrent()\n        let duration = Double(endTime) - Double(startTime)\n\n        completion(TestResult(procedures: procedures, duration: duration, registrar: registrar))\n    }\n\n    public func XCTAssertResults(_ results: TestResult, matchExpectations expectations: Expectations) {\n\n        // checkAllProceduresFinished\n        if let checkAllProceduresFinished = expectations.checkAllProceduresFinished, checkAllProceduresFinished {\n            for i in results.procedures.enumerated() {\n                XCTAssertTrue(i.element.isFinished, \"Test procedure [\\(i.offset)] did not finish\")\n            }\n        }\n        // exact test for registrar.maximumDetected\n        if let checkExactDetected = expectations.checkExactDetected {\n            XCTAssertEqual(results.registrar.maximumDetected, checkExactDetected, \"maximumDetected concurrent operations (\\(results.registrar.maximumDetected)) does not equal expected: \\(checkExactDetected)\")\n        }\n        else {\n            // checkMinimumDetected\n            if let checkMinimumDetected = expectations.checkMinimumDetected {\n                XCTAssertGreaterThanOrEqual(results.registrar.maximumDetected, checkMinimumDetected, \"maximumDetected concurrent operations (\\(results.registrar.maximumDetected)) is less than expected minimum: \\(checkMinimumDetected)\")\n            }\n            // checkMaximumDetected\n            if let checkMaximumDetected = expectations.checkMaximumDetected {\n                XCTAssertLessThanOrEqual(results.registrar.maximumDetected, checkMaximumDetected, \"maximumDetected concurrent operations (\\(results.registrar.maximumDetected)) is greater than expected maximum: \\(checkMaximumDetected)\")\n            }\n        }\n        // checkMinimumDuration\n        if let checkMinimumDuration = expectations.checkMinimumDuration {\n            XCTAssertGreaterThanOrEqual(results.duration, checkMinimumDuration, \"Test duration exceeded minimum expected duration.\")\n        }\n    }\n\n    open override func setUp() {\n        super.setUp()\n        registrar = Registrar()\n    }\n\n    open override func tearDown() {\n        registrar = nil\n        super.tearDown()\n    }\n}\n\n// MARK: - ConcurrencyRegistrar\n\nopen class ConcurrencyRegistrar {\n    private struct State {\n        var operations: [Operation] = []\n        var maximumDetected: Int = 0\n    }\n    private let state = Protector(State())\n\n    public var maximumDetected: Int {\n        get {\n            return state.read { $0.maximumDetected }\n        }\n    }\n    public func registerRunning(_ operation: Operation) {\n        state.write { ward in\n            ward.operations.append(operation)\n            ward.maximumDetected = max(ward.operations.count, ward.maximumDetected)\n        }\n    }\n    public func deregisterRunning(_ operation: Operation) {\n        state.write { ward in\n            if let opIndex = ward.operations.firstIndex(of: operation) {\n                ward.operations.remove(at: opIndex)\n            }\n        }\n    }\n}\n\n// MARK: - TestConcurrencyTrackingProcedure\n\nopen class TestConcurrencyTrackingProcedure: Procedure {\n    private(set) weak var concurrencyRegistrar: ConcurrencyRegistrar?\n    let microsecondsToSleep: useconds_t\n\n    init(name: String = \"TestConcurrencyTrackingProcedure\", microsecondsToSleep: useconds_t, registrar: ConcurrencyRegistrar) {\n        self.concurrencyRegistrar = registrar\n        self.microsecondsToSleep = microsecondsToSleep\n        super.init()\n        self.name = name\n    }\n    override open func execute() {\n        concurrencyRegistrar?.registerRunning(self)\n        usleep(microsecondsToSleep)\n        concurrencyRegistrar?.deregisterRunning(self)\n        finish()\n    }\n}\n\n// MARK: - EventConcurrencyTrackingRegistrar\n\n// Tracks Procedure Events and the Threads on which they occur.\n// Detects concurrency issues if two events occur conccurently on two different threads.\n// Use a unique EventConcurrencyTrackingRegistrar per Procedure instance.\npublic class EventConcurrencyTrackingRegistrar {\n    public enum ProcedureEvent: Equatable, CustomStringConvertible {\n\n        case do_Execute\n\n        case observer_didAttach\n        case observer_willExecute\n        case observer_didExecute\n        case observer_willCancel\n        case observer_didCancel\n        case observer_procedureWillAdd(String)\n        case observer_procedureDidAdd(String)\n        case observer_willFinish\n        case observer_didFinish\n\n        case override_procedureWillCancel\n        case override_procedureDidCancel\n        case override_procedureWillFinish\n        case override_procedureDidFinish\n\n        // GroupProcedure open functions\n        case override_groupWillAdd_child(String)\n        case override_child_willFinishWithErrors(String)\n\n        // GroupProcedure handlers\n        case group_transformChildErrorsBlock(String)\n\n        public var description: String {\n            switch self {\n            case .do_Execute: return \"execute()\"\n            case .observer_didAttach: return \"observer_didAttach\"\n            case .observer_willExecute: return \"observer_willExecute\"\n            case .observer_didExecute: return \"observer_didExecute\"\n            case .observer_willCancel: return \"observer_willCancel\"\n            case .observer_didCancel: return \"observer_didCancel\"\n            case .observer_procedureWillAdd(let name): return \"observer_procedureWillAdd [\\(name)]\"\n            case .observer_procedureDidAdd(let name): return \"observer_procedureDidAdd [\\(name)]\"\n            case .observer_willFinish: return \"observer_willFinish\"\n            case .observer_didFinish: return \"observer_didFinish\"\n            case .override_procedureWillCancel: return \"procedureWillCancel()\"\n            case .override_procedureDidCancel: return \"procedureDidCancel()\"\n            case .override_procedureWillFinish: return \"procedureWillFinish()\"\n            case .override_procedureDidFinish: return \"procedureDidFinish()\"\n            // GroupProcedure open functions\n            case .override_groupWillAdd_child(let child): return \"groupWillAdd(child:) [\\(child)]\"\n            case .override_child_willFinishWithErrors(let child): return \"child(_:willFinishWithErrors:) [\\(child)]\"\n            case .group_transformChildErrorsBlock(let child): return \"group.transformChildErrorsBlock [\\(child)]\"\n            }\n        }\n    }\n\n    public struct DetectedConcurrentEventSet: CustomStringConvertible {\n        private var array: [DetectedConcurrentEvent] = []\n\n        public var description: String {\n            var description: String = \"\"\n            for concurrentEvent in array {\n                guard !description.isEmpty else {\n                    description.append(\"\\(concurrentEvent)\")\n                    continue\n                }\n                description.append(\"\\n\\(concurrentEvent)\")\n            }\n            return description\n        }\n\n        public var isEmpty: Bool {\n            return array.isEmpty\n        }\n\n        public mutating func append(_ newElement: DetectedConcurrentEvent) {\n            array.append(newElement)\n        }\n    }\n\n    public struct DetectedConcurrentEvent: CustomStringConvertible {\n        var newEvent: (event: ProcedureEvent, threadUUID: String)\n        var currentEvents: [UUID: (event: ProcedureEvent, threadUUID: String)]\n\n        private func truncateThreadID(_ uuidString: String) -> String {\n            //let uuidString = threadUUID.uuidString\n            #if swift(>=3.2)\n            return String(uuidString[..<uuidString.index(uuidString.startIndex, offsetBy: 4)])\n            #else\n            return uuidString.substring(to: uuidString.index(uuidString.startIndex, offsetBy: 4))\n            #endif\n        }\n\n        public var description: String {\n            var description = \"+ \\(newEvent.event) (t: \\(truncateThreadID(newEvent.threadUUID))) while: \" /*+\n             \"while: \\n\"*/\n            for (_, event) in currentEvents {\n                description.append(\"\\n\\t- \\(event.event) (t: \\(truncateThreadID(event.threadUUID)))\")\n            }\n            return description\n        }\n    }\n\n    private struct State {\n        // the current eventCallbacks\n        var eventCallbacks: [UUID: (event: ProcedureEvent, threadUUID: String)] = [:]\n\n        // maximum simultaneous eventCallbacks detected\n        var maximumDetected: Int = 0\n\n        // a list of detected concurrent events\n        var detectedConcurrentEvents = DetectedConcurrentEventSet()\n\n        // a history of all detected events (optional)\n        var eventHistory: [ProcedureEvent] = []\n    }\n\n    private let state = Protector(State())\n\n    public var maximumDetected: Int { return state.read { $0.maximumDetected } }\n    public var detectedConcurrentEvents: DetectedConcurrentEventSet { return state.read { $0.detectedConcurrentEvents } }\n    public var eventHistory: [ProcedureEvent]? { return (recordHistory) ? state.read { $0.eventHistory } : nil }\n\n    private let recordHistory: Bool\n\n    public init(recordHistory: Bool = false) {\n        self.recordHistory = recordHistory\n    }\n\n    private let kThreadUUID: NSString = \"run.kit.procedure.ProcedureKit.Testing.ThreadUUID\"\n    private func registerRunning(_ event: ProcedureEvent) -> UUID {\n        // get current thread data\n        let currentThread = Thread.current\n        func getThreadUUID(_ thread: Thread) -> String {\n            guard !thread.isMainThread else {\n                return \"main\"\n            }\n            if let currentThreadUUID = currentThread.threadDictionary.object(forKey: kThreadUUID) as? UUID {\n                return currentThreadUUID.uuidString\n            }\n            else {\n                let newUUID = UUID()\n                currentThread.threadDictionary.setObject(newUUID, forKey: kThreadUUID)\n                return newUUID.uuidString\n            }\n        }\n\n        let currentThreadUUID = getThreadUUID(currentThread)\n        return state.write { ward -> UUID in\n            var newUUID = UUID()\n            while ward.eventCallbacks.keys.contains(newUUID) {\n                newUUID = UUID()\n            }\n            if ward.eventCallbacks.count >= 1 {\n                // determine if all existing event callbacks are on the same thread\n                // as the new event callback\n                if !ward.eventCallbacks.filter({ $0.1.threadUUID != currentThreadUUID }).isEmpty {\n                    ward.detectedConcurrentEvents.append(DetectedConcurrentEvent(newEvent: (event: event, threadUUID: currentThreadUUID), currentEvents: ward.eventCallbacks))\n                }\n            }\n            ward.eventCallbacks.updateValue((event, currentThreadUUID), forKey: newUUID)\n            ward.maximumDetected = max(ward.eventCallbacks.count, ward.maximumDetected)\n            if recordHistory {\n                ward.eventHistory.append(event)\n            }\n            return newUUID\n        }\n    }\n\n    private func deregisterRunning(_ uuid: UUID) {\n        state.write { ward -> Bool in\n            return ward.eventCallbacks.removeValue(forKey: uuid) != nil\n        }\n    }\n\n    public func doRun(_ callback: ProcedureEvent, withDelay delay: TimeInterval = 0.0001, block: (ProcedureEvent) -> Void = { _ in }) {\n        let id = registerRunning(callback)\n        if delay > 0 {\n            usleep(UInt32(delay * TimeInterval(1000000)))\n        }\n        block(callback)\n        deregisterRunning(id)\n    }\n}\n\n// MARK: - ConcurrencyTrackingObserver\n\nopen class ConcurrencyTrackingObserver: ProcedureObserver {\n\n    private var registrar: EventConcurrencyTrackingRegistrar!\n    public let eventQueue: DispatchQueueProtocol?\n    let callbackBlock: (Procedure, EventConcurrencyTrackingRegistrar.ProcedureEvent) -> Void\n\n    public init(registrar: EventConcurrencyTrackingRegistrar? = nil, eventQueue: DispatchQueueProtocol? = nil, callbackBlock: @escaping (Procedure, EventConcurrencyTrackingRegistrar.ProcedureEvent) -> Void = { _, _ in }) {\n        if let registrar = registrar {\n            self.registrar = registrar\n        }\n        self.eventQueue = eventQueue\n        self.callbackBlock = callbackBlock\n    }\n\n    public func didAttach(to procedure: Procedure) {\n        if let eventTrackingProcedure = procedure as? EventConcurrencyTrackingProcedureProtocol {\n            if registrar == nil {\n                registrar = eventTrackingProcedure.concurrencyRegistrar\n            }\n            doRun(.observer_didAttach, block: { callback in callbackBlock(procedure, callback) })\n        }\n    }\n\n    public func will(execute procedure: Procedure, pendingExecute: PendingExecuteEvent) {\n        doRun(.observer_willExecute, block: { callback in callbackBlock(procedure, callback) })\n    }\n\n    public func did(execute procedure: Procedure) {\n        doRun(.observer_didExecute, block: { callback in callbackBlock(procedure, callback) })\n    }\n\n    public func will(cancel procedure: Procedure, with: Error?) {\n        doRun(.observer_willCancel, block: { callback in callbackBlock(procedure, callback) })\n    }\n\n    public func did(cancel procedure: Procedure, with: Error?) {\n        doRun(.observer_didCancel, block: { callback in callbackBlock(procedure, callback) })\n    }\n\n    public func procedure(_ procedure: Procedure, willAdd newOperation: Operation) {\n        doRun(.observer_procedureWillAdd(newOperation.operationName), block: { callback in callbackBlock(procedure, callback) })\n    }\n\n    public func procedure(_ procedure: Procedure, didAdd newOperation: Operation) {\n        doRun(.observer_procedureDidAdd(newOperation.operationName), block: { callback in callbackBlock(procedure, callback) })\n    }\n\n    public func will(finish procedure: Procedure, with error: Error?, pendingFinish: PendingFinishEvent) {\n        doRun(.observer_willFinish, block: { callback in callbackBlock(procedure, callback) })\n    }\n\n    public func did(finish procedure: Procedure, with error: Error?) {\n        doRun(.observer_didFinish, block: { callback in callbackBlock(procedure, callback) })\n    }\n\n    public func doRun(_ callback: EventConcurrencyTrackingRegistrar.ProcedureEvent, withDelay delay: TimeInterval = 0.0001, block: (EventConcurrencyTrackingRegistrar.ProcedureEvent) -> Void = { _ in }) {\n        registrar.doRun(callback, withDelay: delay, block: block)\n    }\n}\n\n// MARK: - EventConcurrencyTrackingProcedure\n\npublic protocol EventConcurrencyTrackingProcedureProtocol {\n    var concurrencyRegistrar: EventConcurrencyTrackingRegistrar { get }\n}\n\n// Tracks the concurrent execution of various user code\n// (observers, `execute()` and other function overrides, etc.)\n// automatically handles events triggered from within other events\n// (as long as everything happens on the same thread)\nopen class EventConcurrencyTrackingProcedure: Procedure, EventConcurrencyTrackingProcedureProtocol {\n    public private(set) var concurrencyRegistrar: EventConcurrencyTrackingRegistrar\n    private let delay: TimeInterval\n    private let executeBlock: (EventConcurrencyTrackingProcedure) -> Void\n    public init(name: String = \"EventConcurrencyTrackingProcedure\", withDelay delay: TimeInterval = 0, registrar: EventConcurrencyTrackingRegistrar = EventConcurrencyTrackingRegistrar(), baseObserver: ConcurrencyTrackingObserver? = ConcurrencyTrackingObserver(), execute: @escaping (EventConcurrencyTrackingProcedure) -> Void) {\n        self.concurrencyRegistrar = registrar\n        self.delay = delay\n        self.executeBlock = execute\n        super.init()\n        self.name = name\n        if let baseObserver = baseObserver {\n            addObserver(baseObserver)\n        }\n    }\n    open override func execute() {\n        concurrencyRegistrar.doRun(.do_Execute, withDelay: delay, block: { _ in\n            executeBlock(self)\n        })\n    }\n    // Cancellation Handler Overrides\n    open override func procedureDidCancel(with error: Error?) {\n        concurrencyRegistrar.doRun(.override_procedureDidCancel)\n        super.procedureDidCancel(with: error)\n    }\n    // Finish Handler Overrides\n    open override func procedureWillFinish(with error: Error?) {\n        concurrencyRegistrar.doRun(.override_procedureWillFinish)\n        super.procedureWillFinish(with: error)\n    }\n    open override func procedureDidFinish(with error: Error?) {\n        concurrencyRegistrar.doRun(.override_procedureDidFinish)\n        super.procedureDidFinish(with: error)\n    }\n}\n\nopen class EventConcurrencyTrackingGroupProcedure: GroupProcedure, EventConcurrencyTrackingProcedureProtocol {\n    public private(set) var concurrencyRegistrar: EventConcurrencyTrackingRegistrar\n    private let delay: TimeInterval\n    public init(dispatchQueue underlyingQueue: DispatchQueue? = nil, operations: [Operation], name: String = \"EventConcurrencyTrackingGroupProcedure\", withDelay delay: TimeInterval = 0, registrar: EventConcurrencyTrackingRegistrar = EventConcurrencyTrackingRegistrar(), baseObserver: ConcurrencyTrackingObserver? = ConcurrencyTrackingObserver()) {\n        self.concurrencyRegistrar = registrar\n        self.delay = delay\n        super.init(dispatchQueue: underlyingQueue, operations: operations)\n        self.name = name\n        if let baseObserver = baseObserver {\n            addObserver(baseObserver)\n        }\n        // GroupProcedure transformChildErrorsBlock\n        transformChildErrorBlock = { [concurrencyRegistrar] (child, _) in\n            concurrencyRegistrar.doRun(.group_transformChildErrorsBlock(child.operationName))\n        }\n    }\n    open override func execute() {\n        concurrencyRegistrar.doRun(.do_Execute, withDelay: delay, block: { _ in\n            super.execute()\n        })\n    }\n    // Cancellation Handler Overrides\n    open override func procedureDidCancel(with error: Error?) {\n        concurrencyRegistrar.doRun(.override_procedureDidCancel)\n        super.procedureDidCancel(with: error)\n    }\n    // Finish Handler Overrides\n    open override func procedureWillFinish(with error: Error?) {\n        concurrencyRegistrar.doRun(.override_procedureWillFinish)\n        super.procedureWillFinish(with: error)\n    }\n    open override func procedureDidFinish(with error: Error?) {\n        concurrencyRegistrar.doRun(.override_procedureDidFinish)\n        super.procedureDidFinish(with: error)\n    }\n\n    // GroupProcedure Overrides\n    open override func groupWillAdd(child: Operation) {\n        concurrencyRegistrar.doRun(.override_groupWillAdd_child(child.operationName))\n        super.groupWillAdd(child: child)\n    }\n    open override func child(_ child: Procedure, willFinishWithError error: Error?) {\n        concurrencyRegistrar.doRun(.override_child_willFinishWithErrors(child.operationName))\n        return super.child(child, willFinishWithError: error)\n    }\n}\n"
  },
  {
    "path": "Sources/TestingProcedureKit/GroupTestCase.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport Foundation\nimport XCTest\nimport ProcedureKit\n\nopen class TestGroupProcedure: GroupProcedure {\n    public var didExecute: Bool { return _didExecute.access }\n\n    private var _didExecute = Protector(false)\n\n    open override func execute() {\n        _didExecute.overwrite(with: true)\n        super.execute()\n    } \n}\n\nopen class GroupTestCase: ProcedureKitTestCase {\n\n    public var children: [TestProcedure]!\n    public var group: TestGroupProcedure!\n\n    public func createTestProcedures(count: Int = 5, shouldError: Bool = false, duration: TimeInterval = 0.000_001) -> [TestProcedure] {\n        return (0..<count).map { i in\n            let name = \"Child: \\(i)\"\n            return shouldError ? TestProcedure(name: name, delay: duration, error: TestError()) : TestProcedure(name: name, delay: duration)\n        }\n    }\n\n    open override func setUp() {\n        super.setUp()\n        children = createTestProcedures()\n        group = TestGroupProcedure(operations: children)\n    }\n\n    open override func tearDown() {\n        group.cancel()\n        children = nil\n        super.tearDown()\n    }\n}\n\npublic extension ProcedureKitTestCase {\n\n    func PKAssertGroupErrors<T: GroupProcedure>(_ exp: @autoclosure () throws -> T, count exp2:  @autoclosure () throws -> Int, _ message: @autoclosure () -> String = \"\", file: StaticString = #file, line: UInt = #line) {\n        __XCTEvaluateAssertion(testCase: self, message(), file: file, line: line) {\n\n            let procedure = try exp()\n            let count = try exp2()\n\n            guard count > 0 else {\n                guard procedure.error == nil else {\n                    return .expectedFailure(\"\\(procedure.procedureName) had an error.\")\n                }\n                return .success\n            }\n\n            let groupErrors = procedure.children.compactMap { ($0 as? Procedure)?.error }\n\n            guard groupErrors.count == count else {\n                return .expectedFailure(\"\\(procedure.procedureName) expected \\(count) errors, received \\(groupErrors.count).\")\n            }\n\n            return .success\n        }\n    }\n\n    func PKAssertGroupErrors<T: GroupProcedure, E: Error>(_ exp: @autoclosure () throws -> T, doesNot: Bool = false, contain exp2:  @autoclosure () throws -> E, _ message: @autoclosure () -> String = \"\", file: StaticString = #file, line: UInt = #line) where E: Equatable {\n        __XCTEvaluateAssertion(testCase: self, message(), file: file, line: line) {\n\n            let procedure = try exp()\n            let otherError = try exp2()\n\n            guard procedure.error != nil else {\n                return .expectedFailure(\"\\(procedure.procedureName) did not have an error.\")\n            }\n\n            let errors: [E] = procedure.children.compactMap { ($0 as? Procedure)?.error as? E }\n\n            guard errors.count > 0 else {\n                return .expectedFailure(\"\\(procedure.procedureName) did not have any errors of type \\(E.self).\")\n            }\n\n            switch (doesNot, errors.contains(otherError)) {\n            case (false, false):\n                return .expectedFailure(\"\\(procedure.procedureName) errors did not contain \\(otherError).\")\n            case (true, true):\n                return .expectedFailure(\"\\(procedure.procedureName) errors did contain \\(otherError).\")\n            default:\n                break\n            }\n\n            return .success\n        }\n    }\n}\n\n// MARK: - GroupConcurrencyTestCase\n\nopen class GroupConcurrencyTestCase: ConcurrencyTestCase {\n\n    public class GroupTestResult: TestResult {\n        public let group: TestGroupProcedure\n\n        public init(group: TestGroupProcedure, procedures: [TrackingProcedure], duration: TimeInterval, registrar: Registrar) {\n            self.group = group\n            super.init(procedures: procedures, duration: duration, registrar: registrar)\n        }\n    }\n\n    @discardableResult public func concurrencyTestGroup(children: Int = 3, withDelayMicroseconds delayMicroseconds: useconds_t = 500000 /* 0.5 seconds */, withName name: String = #function, withTimeout timeout: TimeInterval = 3, withConfigureBlock configure: (TestGroupProcedure) -> Void, withExpectations expectations: Expectations) -> GroupTestResult {\n\n        return concurrencyTestGroup(children: children, withDelayMicroseconds: delayMicroseconds, withName: name, withTimeout: timeout,\n            withConfigureBlock: configure,\n            completionBlock: { (results) in\n                XCTAssertResults(results, matchExpectations: expectations)\n        })\n    }\n\n    @discardableResult public func concurrencyTestGroup(children: Int = 3, withDelayMicroseconds delayMicroseconds: useconds_t = 500000 /* 0.5 seconds */, withName name: String = #function, withTimeout timeout: TimeInterval = 3, withConfigureBlock configure: (TestGroupProcedure) -> Void, completionBlock completion: (GroupTestResult) -> Void) -> GroupTestResult {\n\n        let registrar = Registrar()\n        let testProcedures = create(procedures: children, delayMicroseconds: delayMicroseconds, withRegistrar: registrar)\n        let group = TestGroupProcedure(operations: testProcedures)\n\n        configure(group)\n\n        let startTime = CFAbsoluteTimeGetCurrent()\n        wait(for: group, withTimeout: timeout)\n        let endTime = CFAbsoluteTimeGetCurrent()\n        let duration = Double(endTime) - Double(startTime)\n\n        let result = GroupTestResult(group: group, procedures: testProcedures, duration: duration, registrar: registrar)\n        completion(result)\n        return result\n    }\n}\n"
  },
  {
    "path": "Sources/TestingProcedureKit/ProcedureKitTestCase.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport Foundation\nimport XCTest\nimport ProcedureKit\n\nopen class ProcedureKitTestCase: XCTestCase {\n\n    public var queue: ProcedureQueue!\n    public var delegate: QueueTestDelegate! // swiftlint:disable:this weak_delegate\n    open var procedure: TestProcedure!\n\n    open override func setUp() {\n        super.setUp()\n        queue = ProcedureQueue()\n        delegate = QueueTestDelegate()\n        queue.delegate = delegate\n        procedure = TestProcedure()\n    }\n\n    open override func tearDown() {\n        if let procedure = procedure {\n            procedure.cancel()\n        }\n        if let queue = queue {\n            queue.cancelAllOperations()\n            queue.waitUntilAllOperationsAreFinished()\n        }\n        delegate = nil\n        queue = nil\n        procedure = nil\n        Log.enabled = false\n        Log.severity = .warning\n        ExclusivityManager.__tearDownForUnitTesting()\n        super.tearDown()\n    }\n\n    public func set(queueDelegate delegate: QueueTestDelegate) {\n        self.delegate = delegate\n        queue.delegate = delegate\n    }\n\n    public func run(operation: Operation) {\n        run(operations: [operation])\n    }\n\n    public func run(operations: Operation...) {\n        run(operations: operations)\n    }\n\n    public func run(operations: [Operation]) {\n        queue.addOperations(operations, waitUntilFinished: false)\n    }\n\n    public func wait(for procedures: Procedure..., withTimeout timeout: TimeInterval = 3, withExpectationDescription expectationDescription: String = #function, handler: XCWaitCompletionHandler? = nil) {\n        wait(forAll: procedures, withTimeout: timeout, withExpectationDescription: expectationDescription, handler: handler)\n    }\n\n    public func wait(forAll procedures: [Procedure], withTimeout timeout: TimeInterval = 3, withExpectationDescription expectationDescription: String = #function, handler: XCWaitCompletionHandler? = nil) {\n        addCompletionBlockTo(procedures: procedures)\n        run(operations: procedures)\n        waitForExpectations(timeout: timeout, handler: handler)\n    }\n\n    /// Runs a Procedure on the queue, waiting until it is complete to return,\n    /// but calls a specified block before the wait.\n    ///\n    /// IMPORTANT: This function calls the specified block immediately after adding\n    ///            the Procedure to the queue. This does *not* ensure any specific\n    ///            ordering/timing in regards to the block and the Procedure executing.\n    ///\n    /// - Parameters:\n    ///   - procedure: a Procedure\n    ///   - timeout: (optional) a timeout for the wait\n    ///   - expectationDescription: (optional) an expectation description\n    ///   - checkBeforeWait: a block to be executed before the wait (see above)\n    public func check<T: Procedure>(procedure: T, withAdditionalProcedures additionalProcedures: Procedure..., withTimeout timeout: TimeInterval = 3, withExpectationDescription expectationDescription: String = #function, checkBeforeWait: (T) -> Void) {\n        var allProcedures = additionalProcedures\n        allProcedures.append(procedure)\n        addCompletionBlockTo(procedures: allProcedures)\n        run(operations: allProcedures)\n        checkBeforeWait(procedure)\n        waitForExpectations(timeout: timeout, handler: nil)\n    }\n\n    public func checkAfterDidExecute<T>(procedure: T, withTimeout timeout: TimeInterval = 3, withExpectationDescription expectationDescription: String = #function, checkAfterDidExecuteBlock: @escaping (T) -> Void) where T: Procedure {\n        addCompletionBlockTo(procedure: procedure, withExpectationDescription: expectationDescription)\n        procedure.addDidExecuteBlockObserver { (procedure) in\n            checkAfterDidExecuteBlock(procedure)\n        }\n        run(operations: procedure)\n        waitForExpectations(timeout: timeout, handler: nil)\n    }\n\n    public func addCompletionBlockTo(procedure: Procedure, withExpectationDescription expectationDescription: String = #function) {\n        // Make a finishing procedure, which depends on this target Procedure.\n        let finishingProcedure = makeFinishingProcedure(for: procedure, withExpectationDescription: expectationDescription)\n        // Add the did finish expectation block to the finishing procedure\n        addExpectationCompletionBlockTo(procedure: finishingProcedure, withExpectationDescription: expectationDescription)\n        run(operation: finishingProcedure)\n    }\n\n    public func addCompletionBlockTo<S: Sequence>(procedures: S, withExpectationDescription expectationDescription: String = #function) where S.Iterator.Element == Procedure {\n        for (i, procedure) in procedures.enumerated() {\n            addCompletionBlockTo(procedure: procedure, withExpectationDescription: \"\\(i), \\(expectationDescription)\")\n        }\n    }\n\n    @discardableResult public func addExpectationCompletionBlockTo(procedure: Procedure, withExpectationDescription expectationDescription: String = #function) -> XCTestExpectation {\n        let expect = expectation(description: \"Test: \\(expectationDescription), \\(UUID())\")\n        add(expectation: expect, to: procedure)\n        return expect\n    }\n\n    public func add(expectation: XCTestExpectation, to procedure: Procedure) {\n        weak var weakExpectation = expectation\n        procedure.addDidFinishBlockObserver { _, _ in\n            DispatchQueue.main.async {\n                weakExpectation?.fulfill()\n            }\n        }\n    }\n\n    func makeFinishingProcedure(for procedure: Procedure, withExpectationDescription expectationDescription: String = #function) -> Procedure {\n        let finishing = BlockProcedure { }\n        finishing.log.enabled = false\n        finishing.addDependency(procedure)\n        // Adds a will add operation observer, which adds the produced operation as a dependency\n        // of the finishing procedure. This way, we don't actually finish, until the\n        // procedure, and any produced operations also finish.\n        procedure.addWillAddOperationBlockObserver { [weak weakFinishing = finishing] _, operation in\n            guard let finishing = weakFinishing else { fatalError(\"Finishing procedure is finished + gone, but a WillAddOperation observer on a dependency was called. This should never happen.\") }\n            finishing.addDependency(operation)\n        }\n        finishing.name = \"FinishingBlockProcedure(for: \\(procedure.operationName))\"\n        return finishing\n    }\n}\n\npublic extension ProcedureKitTestCase {\n\n    func createCancellingProcedure() -> TestProcedure {\n        let procedure = TestProcedure(name: \"Cancelling Test Procedure\")\n        procedure.addWillExecuteBlockObserver { procedure, _ in\n            procedure.cancel()\n        }\n        return procedure\n    }\n}\n"
  },
  {
    "path": "Sources/TestingProcedureKit/QueueTestDelegate.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport Foundation\nimport ProcedureKit\n\npublic class QueueTestDelegate: ProcedureQueueDelegate {\n\n    public typealias OperationCheckType = (ProcedureQueue, Operation, Any?)\n    public typealias OperationFinishType = (ProcedureQueue, Operation)\n    public typealias ProcedureCheckType = (ProcedureQueue, Procedure, Any?)\n    public typealias ProcedureFinishType = (ProcedureQueue, Procedure, Error?)\n\n    public var procedureQueueWillAddOperation: [OperationCheckType] {\n        get { return _procedureQueueWillAddOperation.read { $0 } }\n    }\n    public var procedureQueueDidAddOperation: [OperationCheckType] {\n        get { return _procedureQueueDidAddOperation.read { $0 } }\n    }\n    public var procedureQueueDidFinishOperation: [OperationFinishType] {\n        get { return _procedureQueueDidFinishOperation.read { $0 } }\n    }\n\n    public var procedureQueueWillAddProcedure: [ProcedureCheckType] {\n        get { return _procedureQueueWillAddProcedure.read { $0 } }\n    }\n    public var procedureQueueDidAddProcedure: [ProcedureCheckType] {\n        get { return _procedureQueueDidAddProcedure.read { $0 } }\n    }\n\n    public var procedureQueueWillFinishProcedure: [ProcedureFinishType] {\n        get { return _procedureQueueWillFinishProcedure.read { $0 } }\n    }\n    public var procedureQueueDidFinishProcedure: [ProcedureFinishType] {\n        get { return _procedureQueueDidFinishProcedure.read { $0 } }\n    }\n\n    private var _procedureQueueWillAddOperation = Protector([OperationCheckType]())\n    private var _procedureQueueDidAddOperation = Protector([OperationCheckType]())\n    private var _procedureQueueDidFinishOperation = Protector([OperationFinishType]())\n\n    private var _procedureQueueWillAddProcedure = Protector([ProcedureCheckType]())\n    private var _procedureQueueDidAddProcedure = Protector([ProcedureCheckType]())\n    private var _procedureQueueWillFinishProcedure = Protector([ProcedureFinishType]())\n    private var _procedureQueueDidFinishProcedure = Protector([ProcedureFinishType]())\n\n    private let callbackBlock: CallbackBlock\n\n    public enum CallbackKind {\n        case willAddOperation(ProcedureQueue, Operation, Any?)\n        case didAddOperation(ProcedureQueue, Operation, Any?)\n        case didFinishOperation(ProcedureQueue, Operation)\n        case willAddProcedure(ProcedureQueue, Procedure, Any?)\n        case didAddProcedure(ProcedureQueue, Procedure, Any?)\n        case willFinishProcedure(ProcedureQueue, Procedure, Error?)\n        case didFinishProcedure(ProcedureQueue, Procedure, Error?)\n    }\n    public typealias CallbackBlock = (CallbackKind) -> Void\n\n    // MARK: - Init\n\n    public init(callbackBlock: @escaping CallbackBlock = { _ in }) {\n        self.callbackBlock = callbackBlock\n    }\n\n    // MARK: - ProcedureQueueDelegate Methods\n\n    // Operations\n\n    public func procedureQueue(_ queue: ProcedureQueue, willAddOperation operation: Operation, context: Any?) -> ProcedureFuture? {\n        _procedureQueueWillAddOperation.append((queue, operation, context))\n        callbackBlock(.willAddOperation(queue, operation, context))\n        return nil\n    }\n\n    public func procedureQueue(_ queue: ProcedureQueue, didAddOperation operation: Operation, context: Any?) {\n        _procedureQueueDidAddOperation.append((queue, operation, context))\n        callbackBlock(.didAddOperation(queue, operation, context))\n    }\n\n    public func procedureQueue(_ queue: ProcedureQueue, didFinishOperation operation: Operation) {\n        _procedureQueueDidFinishOperation.append((queue, operation))\n        callbackBlock(.didFinishOperation(queue, operation))\n    }\n\n    // Procedures\n\n    public func procedureQueue(_ queue: ProcedureQueue, willAddProcedure procedure: Procedure, context: Any?) -> ProcedureFuture? {\n        _procedureQueueWillAddProcedure.append((queue, procedure, context))\n        callbackBlock(.willAddProcedure(queue, procedure, context))\n        return nil\n    }\n\n    public func procedureQueue(_ queue: ProcedureQueue, didAddProcedure procedure: Procedure, context: Any?) {\n        _procedureQueueDidAddProcedure.append((queue, procedure, context))\n        callbackBlock(.didAddProcedure(queue, procedure, context))\n    }\n\n    public func procedureQueue(_ queue: ProcedureQueue, willFinishProcedure procedure: Procedure, with error: Error?) -> ProcedureFuture? {\n        _procedureQueueWillFinishProcedure.append((queue, procedure, error))\n        callbackBlock(.willFinishProcedure(queue, procedure, error))\n        return nil\n    }\n\n    public func procedureQueue(_ queue: ProcedureQueue, didFinishProcedure procedure: Procedure, with error: Error?) {\n        _procedureQueueDidFinishProcedure.append((queue, procedure, error))\n        callbackBlock(.didFinishProcedure(queue, procedure, error))\n    }\n}\n"
  },
  {
    "path": "Sources/TestingProcedureKit/RepeatTestCase.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport Foundation\nimport XCTest\nimport ProcedureKit\n\nopen class RepeatTestCase: ProcedureKitTestCase {\n\n    public var repeatProcedure: RepeatProcedure<TestProcedure>!\n\n    public var expectedError: TestError!\n\n    open override func setUp() {\n        super.setUp()\n        expectedError = TestError()\n    }\n\n    open override func tearDown() {\n        expectedError = nil\n        super.tearDown()\n    }\n\n    public func createIterator(withDelay delay: Delay = .by(0.001)) -> AnyIterator<RepeatProcedurePayload<TestProcedure>> {\n        return AnyIterator { RepeatProcedurePayload(operation: TestProcedure(), delay: .by(0.01)) }\n    }\n\n    public func createIterator(succeedsAfterCount target: Int) -> AnyIterator<TestProcedure> {\n        var count = 0\n        let _error = expectedError\n        return AnyIterator {\n            guard count < target else { return nil }\n            defer { count += 1 }\n            if count < target - 1 {\n                return TestProcedure(error: _error)\n            }\n            else {\n                return TestProcedure()\n            }\n        }\n    }\n}\n\nopen class RetryTestCase: ProcedureKitTestCase {\n\n    public typealias Test = TestProcedure\n    public typealias Retry = RetryProcedure<TestProcedure>\n    public typealias Handler = Retry.Handler\n\n    public class RetryTestCaseInfo {\n        public var numberOfExecuctions: Int = 0\n        public var numberOfFailures: Int = 0\n    }\n\n    public var retry: Retry!\n\n    public var error: TestError!\n\n    public func createOperationIterator(succeedsAfterFailureCount failureThreshold: Int) -> AnyIterator<Test> {\n        let info = RetryTestCaseInfo()\n        return AnyIterator {\n            let procedure = TestProcedure()\n            procedure.addCondition(BlockCondition {\n                guard info.numberOfFailures == failureThreshold else { throw ProcedureKitError.conditionFailed() }\n                return true\n            })\n            procedure.addWillFinishBlockObserver { _, _, _ in\n                info.numberOfExecuctions += 1\n                info.numberOfFailures += 1\n            }\n            return procedure\n        }\n    }\n\n    public func createPayloadIterator(succeedsAfterFailureCount failureThreshold: Int) -> AnyIterator<RepeatProcedurePayload<Test>> {\n        let info = RetryTestCaseInfo()\n        return AnyIterator {\n            let procedure = TestProcedure()\n            procedure.addCondition(BlockCondition {\n                guard info.numberOfFailures == failureThreshold else { throw ProcedureKitError.conditionFailed() }\n                return true\n            })\n            procedure.addWillFinishBlockObserver { _, _, _ in\n                info.numberOfExecuctions += 1\n                info.numberOfFailures += 1\n            }\n            return RepeatProcedurePayload(operation: procedure, delay: .by(0.0001))\n        }\n    }\n}\n"
  },
  {
    "path": "Sources/TestingProcedureKit/StressTestCase.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport Foundation\nimport XCTest\nimport ProcedureKit\n\npublic protocol BatchProtocol {\n    var startTime: CFAbsoluteTime { get }\n    var dispatchGroup: DispatchGroup { get }\n    var queue: ProcedureQueue { get }\n    var number: Int { get }\n    var size: Int { get }\n\n    func counter(named: String) -> Int\n\n    @discardableResult func incrementCounter(named: String) -> Int\n}\n\npublic extension BatchProtocol {\n\n    func didIncrementCounter(named name: String) -> Bool {\n        let currentValue = counter(named: name)\n        let newValue = Int(incrementCounter(named: name))\n        return newValue > currentValue\n    }\n}\n\nopen class Batch: BatchProtocol {\n    public let startTime = CFAbsoluteTimeGetCurrent()\n    public let dispatchGroup = DispatchGroup()\n    public let queue: ProcedureQueue\n    public let number: Int\n    public let size: Int\n\n    private var _countersLock = NSLock()\n    private var _counters = Dictionary<String, Int>()\n\n    public init(queue: ProcedureQueue = ProcedureQueue(), number: Int, size: Int) {\n        self.queue = queue\n        self.number = number\n        self.size = size\n    }\n\n    public func counter(named: String = \"Standard\") -> Int {\n        return _countersLock.withCriticalScope { _counters[named] ?? 0 }\n    }\n\n    @discardableResult public func incrementCounter(named: String = \"Standard\") -> Int {\n        return _countersLock.withCriticalScope {\n            guard let currentCount = _counters[named] else {\n                _counters[named] = 1\n                return 1\n            }\n            _counters[named] = currentCount + 1\n            return currentCount + 1\n        }\n    }\n}\n\nopen class StressTestCase: GroupTestCase {\n\n    public enum StressLevel {\n        case minimal, low, medium, high\n        case custom(Int, Int)\n\n        public var batches: Int {\n            switch self {\n            case .minimal: return 1\n            case .low: return 2\n            case .medium: return 3\n            case .high: return 5\n            case let .custom(batches, _): return batches\n            }\n        }\n\n        public var batchSize: Int {\n            switch self {\n            case .minimal: return 5_000\n            case .low: return 10_000\n            case .medium: return 15_000\n            case .high: return 30_000\n            case let .custom(_, batchSize): return batchSize\n            }\n        }\n\n        public var batchTimeout: TimeInterval {\n            switch self {\n            case .low: return 30\n            case .medium: return 200\n            case .high: return 1_000\n            default: return 20\n            }\n        }\n\n        public func forEach(body: (Int, Int) throws -> Void) rethrows {\n            try (0..<batches).forEach { batch in\n                try autoreleasepool {\n                    try (0..<batchSize).forEach { iteration in\n                        try body(batch, iteration)\n                    }\n                } // End of autorelease\n            } // End of batches\n        }\n    }\n\n    // MARK: Stress Tests\n\n    open func setUpStressTest() {\n        queue.delegate = nil\n        queue.qualityOfService = .userInteractive\n    }\n\n    open func tearDownStressTest() { }\n\n    open func started(batch number: Int, size: Int) -> BatchProtocol {\n        return Batch(number: number, size: size)\n    }\n\n    open func ended(batch: BatchProtocol) {\n        let now = CFAbsoluteTimeGetCurrent()\n        let duration = now - batch.startTime\n        print(\"    finished batch: \\(batch.number), in \\(duration) seconds\")\n    }\n\n    public func stress(level: StressLevel = .low, withName name: String = #function, withTimeout timeoutOverride: TimeInterval? = nil, block: (BatchProtocol, Int) -> Void) {\n        stress(level: level, withName: name, withTimeout: timeoutOverride, iteration: nil, block: block)\n    }\n\n    public func measure(withName name: String = #function, withTimeout timeoutOverride: TimeInterval? = nil, block: @escaping (BatchProtocol, Int) -> Void) {\n        var count: Int = 0\n        measure {\n            self.stress(level: .minimal, withName: name, withTimeout: timeoutOverride, iteration: count, block: block)\n            count = count.advanced(by: 1)\n        }\n    }\n\n    func stress(level: StressLevel, withName name: String = #function, withTimeout timeoutOverride: TimeInterval? = nil, iteration: Int? = nil, block: (BatchProtocol, Int) -> Void) {\n        let measurementDescription = iteration.map { \"Measurement: \\($0), \" } ?? \"\"\n        let stressTestName = \"\\(measurementDescription)Stress Test: \\(name)\"\n        let timeout: TimeInterval = timeoutOverride ?? level.batchTimeout\n        var shouldContinueBatches = true\n\n        print(\"\\(stressTestName)\\n  Parameters: \\(level.batches) batches, size \\(level.batchSize), timeout: \\(timeout)\")\n\n        setUpStressTest()\n\n        defer {\n            tearDownStressTest()\n        }\n\n        (0..<level.batches).forEach { batchCount in\n            guard shouldContinueBatches else { return }\n            autoreleasepool {\n\n                let batch = started(batch: batchCount, size: level.batchSize)\n                weak var batchExpectation = expectation(description: stressTestName)\n\n                (0..<level.batchSize).forEach { iteration in\n                    block(batch, iteration)\n                }\n\n                batch.dispatchGroup.notify(queue: .main) {\n                    guard let expect = batchExpectation else { print(\"\\(stressTestName): Completed after timeout\"); return }\n                    expect.fulfill()\n                }\n\n                waitForExpectations(timeout: timeout) { error in\n                    if error != nil {\n                        shouldContinueBatches = false\n                    }\n                }\n\n                ended(batch: batch)\n\n            } // End of autorelease\n        } // End of batches\n    }\n}\n"
  },
  {
    "path": "Sources/TestingProcedureKit/TestCondition.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport Foundation\nimport ProcedureKit\n\nopen class TestCondition: Condition {\n\n    let evaluate: () throws -> ConditionResult\n\n    public init(name: String = \"TestCondition\", producedDependencies: [Operation] = [], evaluate: @escaping () throws -> ConditionResult) {\n        self.evaluate = evaluate\n        super.init()\n        self.name = name\n        producedDependencies.forEach(produceDependency)\n    }\n\n    open override func evaluate(procedure: Procedure, completion: @escaping (ConditionResult) -> Void) {\n        let result: ConditionResult\n        do {\n            result = try evaluate()\n        }\n        catch {\n            result = .failure(error)\n        }\n        completion(result)\n    }\n}\n\nopen class AsyncTestCondition: Condition {\n\n    public typealias EvaluateBlock = (@escaping (ConditionResult) -> Void) -> Void\n    let evaluate: EvaluateBlock\n\n    public init(name: String = \"TestCondition\", producedDependencies: [Operation] = [], evaluate: @escaping EvaluateBlock) {\n        self.evaluate = evaluate\n        super.init()\n        self.name = name\n        producedDependencies.forEach(produceDependency)\n    }\n\n    open override func evaluate(procedure: Procedure, completion: @escaping (ConditionResult) -> Void) {\n        evaluate(completion)\n    }\n}\n"
  },
  {
    "path": "Sources/TestingProcedureKit/TestProcedure.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport Foundation\nimport ProcedureKit\n\npublic struct TestError: Error, Equatable, CustomDebugStringConvertible {\n\n    public static func verify(errors: [Error], count: Int = 1, contains error: TestError) -> Bool {\n        return (errors.count == count) && errors.contains { ($0 as? TestError) ?? TestError() == error }\n    }\n\n    let uuid = UUID()\n\n    public init() { }\n\n    public var debugDescription: String {\n        return \"TestError (\\(uuid.uuidString))\"\n    }\n}\n\nopen class TestProcedure: Procedure, InputProcedure, OutputProcedure {\n\n    public let delay: TimeInterval\n    public let expectedError: Error?\n    public let producedOperation: Operation?\n    public var input: Pending<String> = .pending\n    public var output: Pending<ProcedureResult<String>> = .ready(.success(\"Hello World\"))\n    public private(set) var executedAt: CFAbsoluteTime {\n        get { return protected.read { $0.executedAt } }\n        set { protected.write { $0.executedAt = newValue } }\n    }\n    public private(set) var didExecute: Bool {\n        get { return protected.read { $0.didExecute } }\n        set { protected.write { $0.didExecute = newValue } }\n    }\n    public private(set) var procedureWillFinishCalled: Bool {\n        get { return protected.read { $0.procedureWillFinishCalled } }\n        set { protected.write { $0.procedureWillFinishCalled = newValue } }\n    }\n    public private(set) var procedureDidFinishCalled: Bool {\n        get { return protected.read { $0.procedureDidFinishCalled } }\n        set { protected.write { $0.procedureDidFinishCalled = newValue } }\n    }\n    public private(set) var procedureDidCancelCalled: Bool {\n        get { return protected.read { $0.procedureDidCancelCalled } }\n        set { protected.write { $0.procedureDidCancelCalled = newValue } }\n    }\n    private class ProtectedProperties {\n        var executedAt: CFAbsoluteTime = 0\n        var didExecute = false\n        var procedureWillFinishCalled = false\n        var procedureDidFinishCalled = false\n        var procedureDidCancelCalled = false\n    }\n    private var protected = Protector(ProtectedProperties())\n\n    public init(name: String = \"TestProcedure\", delay: TimeInterval = 0.000_001, error: Error? = .none, produced: Operation? = .none) {\n        self.delay = delay\n        self.expectedError = error\n        self.producedOperation = produced\n        super.init()\n        self.name = name\n    }\n\n    open override func execute() {\n\n        executedAt = CFAbsoluteTimeGetCurrent()\n\n        if let input = input.value {\n            output = .ready(.success(\"Hello \\(input)\"))\n        }\n\n        if let operation = producedOperation {\n            let producedOperationGroup = DispatchGroup()\n            producedOperationGroup.enter()\n            DispatchQueue.global().asyncAfter(deadline: .now() + (delay / 2.0)) {\n                let future = try! self.produce(operation: operation) // swiftlint:disable:this force_try\n                future.then(on: DispatchQueue.global()) {\n                    producedOperationGroup.leave()\n                }\n            }\n            DispatchQueue.global().asyncAfter(deadline: .now() + delay) {\n                // If producing an operation, ensure that the TestProcedure finishes\n                // *after* the operation is successfully produced\n                producedOperationGroup.notify(queue: DispatchQueue.global()) {\n                    self.didExecute = true\n                    self.finish(with: self.expectedError)\n                }\n            }\n        }\n        else {\n            DispatchQueue.global().asyncAfter(deadline: .now() + delay) {\n                self.didExecute = true\n                self.finish(with: self.expectedError)\n            }\n        }\n    }\n\n    open override func procedureDidCancel(with: Error?) {\n        procedureDidCancelCalled = true\n    }\n\n    open override func procedureWillFinish(with: Error?) {\n        procedureWillFinishCalled = true\n    }\n\n    open override func procedureDidFinish(with: Error?) {\n        procedureDidFinishCalled = true\n    }\n}\n"
  },
  {
    "path": "Sources/TestingProcedureKit/TestableLogging.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport Foundation\nimport XCTest\nimport ProcedureKit\n\npublic class TestableLogWriter: LogWriter {\n\n    private let stateLock = PThreadMutex()\n    private var _entries: [Log.Entry] = []\n\n    public init() { }\n\n    @discardableResult\n    private func synchronise<T>(block: () -> T) -> T {\n        return stateLock.withCriticalScope(block: block)\n    }\n\n    public var entries: [Log.Entry] {\n        return synchronise { _entries }\n    }\n\n    public func write(entry: Log.Entry) {\n        synchronise {\n            _entries.append(entry)            \n        }\n    }\n}\n\npublic class TestableLogFormatter: LogFormatter {\n\n    private let stateLock = PThreadMutex()\n    private var _entries: [Log.Entry] = []\n\n    public init() { }\n\n    @discardableResult\n    private func synchronise<T>(block: () -> T) -> T {\n        return stateLock.withCriticalScope(block: block)\n    }\n\n    public var entries: [Log.Entry] {\n        return synchronise { _entries }\n    }\n\n    public func format(entry: Log.Entry) -> Log.Entry {\n        return synchronise {\n            _entries.append(entry)\n            return entry\n        }\n    }\n}\n\npublic class TestableLogSettings: LogSettings {\n\n    private static var shared: LogChannel = Log.Channel<TestableLogSettings>(enabled: true, severity: .verbose, writer: TestableLogWriter(), formatter: TestableLogFormatter())\n\n    public static var channel: LogChannel {\n        get { return shared }\n        set { shared = newValue }\n    }\n\n    public static var enabled: Bool {\n        get { return channel.enabled }\n        set { channel.enabled = newValue }\n    }\n\n    public static var severity: Log.Severity {\n        get { return channel.severity }\n        set { channel.severity = newValue }\n    }\n\n    public static var writer: LogWriter {\n        get { return channel.writer }\n        set { channel.writer = newValue }\n    }\n\n    public static var formatter: LogFormatter {\n        get { return channel.formatter }\n        set { channel.formatter = newValue }\n    }\n}\n\nopen class LoggingTestCase: ProcedureKitTestCase {\n\n    open var entry: Log.Entry!\n\n    override open func setUp() {\n        super.setUp()\n        Log.enabled = true\n        Log.severity = .verbose\n        TestableLogSettings.writer = TestableLogWriter()\n        TestableLogSettings.formatter = TestableLogFormatter()\n        entry = Log.Entry(payload: .message(\"Hello World\"), severity: .debug, file: \"the file\", function: \"the function\", line: 100, threadID: 1000)\n    }\n\n    override open func tearDown() {\n        Log.enabled = true\n        Log.severity = .warning\n        entry = nil\n        super.tearDown()\n    }\n}\n\npublic extension ProcedureKitTestCase {\n\n    func PKAssertProcedureLogContainsMessage<T: Procedure>(_ exp: @autoclosure () throws -> T, _ exp2: @autoclosure () throws -> String, _ message: @autoclosure () -> String = \"\", file: StaticString = #file, line: UInt = #line) {\n        __XCTEvaluateAssertion(testCase: self, message(), file: file, line: line) {\n\n            let procedure = try exp()\n\n            guard let writer = procedure.log.writer as? TestableLogWriter else {\n                return .expectedFailure(\"\\(procedure.procedureName) did not have a testable log writer.\")\n            }\n\n            let loggedMessages: [String] = writer.entries.compactMap { $0.message }\n\n            guard loggedMessages.count > 0 else {\n                return .expectedFailure(\"\\(procedure.procedureName) did not log any messages\")\n            }\n\n            let text = try exp2()\n\n            guard loggedMessages.contains(text) else {\n                return .expectedFailure(\"\\(procedure.procedureName) did not log the message: \\(text)\")\n            }\n\n            return .success\n        }\n    }\n}\n\n"
  },
  {
    "path": "Sources/TestingProcedureKit/TestableNetwork.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport Foundation\nimport XCTest\nimport ProcedureKit\n\npublic class TestableURLSessionTask: Equatable {\n\n    public static func == (lhs: TestableURLSessionTask, rhs: TestableURLSessionTask) -> Bool {\n        return lhs.uuid == rhs.uuid\n    }\n\n    public typealias CompletionBlock = (TestableURLSessionTask) -> Void\n\n    public let delay: TimeInterval\n    public let uuid = UUID()\n\n    public var didResume: Bool {\n        get { return stateLock.withCriticalScope { _didResume } }\n    }\n    public var didCancel: Bool {\n        get { return stateLock.withCriticalScope { _didCancel } }\n    }\n\n    private let completion: CompletionBlock\n    private var completionWorkItem: DispatchWorkItem!\n    private var stateLock = NSLock()\n    private var _didResume = false\n    private var _didCancel = false\n    private var _didFinish = false\n\n    public init(delay: TimeInterval = 0.000_001, completion: @escaping CompletionBlock) {\n        self.delay = delay\n        self.completion = completion\n        self.completionWorkItem = DispatchWorkItem(block: { [weak self] in\n            guard let strongSelf = self else { return }\n            guard !strongSelf.completionWorkItem.isCancelled else { return }\n            guard strongSelf.shouldFinish() else { return }\n            completion(strongSelf)\n        })\n    }\n\n    public func resume() {\n        stateLock.withCriticalScope {\n            _didResume = true\n        }\n        DispatchQueue.global(qos: .default).asyncAfter(deadline: .now() + delay, execute: completionWorkItem)\n    }\n\n    public func cancel() {\n        // Behavior: cancel the delayed completion, and call the completion handler immediately\n        // (Unless already finished)\n        guard shouldFinish() else { return }\n        stateLock.withCriticalScope {\n            _didCancel = true\n            completionWorkItem.cancel()\n        }\n        completion(self)\n    }\n\n    private func shouldFinish() -> Bool {\n        return stateLock.withCriticalScope { () -> Bool in\n            guard !_didFinish else { return false }\n            _didFinish = true\n            return true\n        }\n    }\n}\n\npublic class TestableURLSessionTaskFactory {\n\n    public var delay: TimeInterval {\n        get { return stateLock.withCriticalScope { _delay } }\n        set {\n            stateLock.withCriticalScope {\n                _delay = newValue\n            }\n        }\n    }\n    public var returnedResponse: HTTPURLResponse? {\n        get { return stateLock.withCriticalScope { _returnedResponse } }\n        set {\n            stateLock.withCriticalScope {\n                _returnedResponse = newValue\n            }\n        }\n    }\n    public var returnedError: Error? {\n        get { return stateLock.withCriticalScope { _returnedError } }\n        set {\n            stateLock.withCriticalScope {\n                _returnedError = newValue\n            }\n        }\n    }\n\n    // Data\n    public var didReceiveDataRequest: URLRequest? {\n        get { return stateLock.withCriticalScope { _didReceiveDataRequest } }\n        set {\n            stateLock.withCriticalScope {\n                _didReceiveDataRequest = newValue\n            }\n        }\n    }\n    public var didReturnDataTask: TestableURLSessionTask? {\n        get { return stateLock.withCriticalScope { _didReturnDataTask } }\n        set {\n            stateLock.withCriticalScope {\n                _didReturnDataTask = newValue\n            }\n        }\n    }\n    public var returnedData: Data? {\n        get { return stateLock.withCriticalScope { _returnedData } }\n        set {\n            stateLock.withCriticalScope {\n                _returnedData = newValue\n            }\n        }\n    }\n\n    // Download\n    public var didReceiveDownloadRequest: URLRequest? {\n        get { return stateLock.withCriticalScope { _didReceiveDownloadRequest } }\n        set {\n            stateLock.withCriticalScope {\n                _didReceiveDownloadRequest = newValue\n            }\n        }\n    }\n    public var didReturnDownloadTask: TestableURLSessionTask? {\n        get { return stateLock.withCriticalScope { _didReturnDownloadTask } }\n        set {\n            stateLock.withCriticalScope {\n                _didReturnDownloadTask = newValue\n            }\n        }\n    }\n    public var returnedURL: URL? {\n        get { return stateLock.withCriticalScope { _returnedURL } }\n        set {\n            stateLock.withCriticalScope {\n                _returnedURL = newValue\n            }\n        }\n    }\n\n    // Upload\n    public var didReceiveUploadRequest: URLRequest? {\n        get { return stateLock.withCriticalScope { _didReceiveUploadRequest } }\n        set {\n            stateLock.withCriticalScope {\n                _didReceiveUploadRequest = newValue\n            }\n        }\n    }\n    public var didReturnUploadTask: TestableURLSessionTask? {\n        get { return stateLock.withCriticalScope { _didReturnUploadTask } }\n        set {\n            stateLock.withCriticalScope {\n                _didReturnUploadTask = newValue\n            }\n        }\n    }\n\n    private var stateLock = NSLock()\n\n    // Private (protected) Properties\n    private var _delay: TimeInterval = 0\n    private var _returnedResponse: HTTPURLResponse? = HTTPURLResponse()\n    private var _returnedError: Error?\n\n    private var _didReceiveDataRequest: URLRequest?\n    private var _didReturnDataTask: TestableURLSessionTask?\n    private var _returnedData: Data? = \"hello world\".data(using: String.Encoding.utf8)\n\n    private var _didReceiveDownloadRequest: URLRequest?\n    private var _didReturnDownloadTask: TestableURLSessionTask?\n    private var _returnedURL: URL? = URL(fileURLWithPath: \"/var/tmp/hello/this/is/a/test/url\")\n\n    private var _didReceiveUploadRequest: URLRequest?\n    private var _didReturnUploadTask: TestableURLSessionTask?\n\n    // Initializers\n    public init() { }\n\n    public func dataTask(with request: URLRequest, completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void) -> TestableURLSessionTask {\n        didReceiveDataRequest = request\n        let task = TestableURLSessionTask(delay: delay) { (task) in\n            DispatchQueue.main.async {\n                guard !task.didCancel else {\n                    completionHandler(nil, nil, TestableURLSessionTaskFactory.cancelledError(forRequest: request))\n                    return\n                }\n                completionHandler(self.returnedData, self.returnedResponse, self.returnedError)\n            }\n        }\n        didReturnDataTask = task\n        return task\n    }\n\n    public func downloadTask(with request: URLRequest, completionHandler: @escaping (URL?, URLResponse?, Error?) -> Void) -> TestableURLSessionTask {\n        didReceiveDownloadRequest = request\n        let task = TestableURLSessionTask(delay: delay) { (task) in\n            DispatchQueue.main.async {\n                guard !task.didCancel else {\n                    completionHandler(nil, nil, TestableURLSessionTaskFactory.cancelledError(forRequest: request))\n                    return\n                }\n                completionHandler(self.returnedURL, self.returnedResponse, self.returnedError)\n            }\n        }\n        didReturnDownloadTask = task\n        return task\n    }\n\n    public func uploadTask(with request: URLRequest, from bodyData: Data?, completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void) -> TestableURLSessionTask {\n\n        didReceiveUploadRequest = request\n        let task = TestableURLSessionTask(delay: delay) { (task) in\n            DispatchQueue.main.async {\n                guard !task.didCancel else {\n                    completionHandler(nil, nil, TestableURLSessionTaskFactory.cancelledError(forRequest: request))\n                    return\n                }\n                completionHandler(self.returnedData, self.returnedResponse, self.returnedError)\n            }\n        }\n        didReturnUploadTask = task\n        return task\n    }\n\n    private static func cancelledError(forRequest request: URLRequest) -> Error {\n        var userInfo: [String: Any] = [NSLocalizedDescriptionKey: \"cancelled\"]\n        if let requestURL = request.url {\n            userInfo[NSURLErrorFailingURLErrorKey] = requestURL\n        }\n        if let requestURLString = request.url?.absoluteString {\n            userInfo[NSURLErrorFailingURLStringErrorKey] = requestURLString\n        }\n        return NSError(domain: NSURLErrorDomain, code: NSURLErrorCancelled, userInfo: userInfo)\n    }\n}\n"
  },
  {
    "path": "Sources/TestingProcedureKit/TestableNetworkReachability.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport Foundation\nimport SystemConfiguration\nimport XCTest\nimport ProcedureKit\n\npublic class TestableNetworkReachability {\n    typealias Reachability = String\n\n    public var flags: SCNetworkReachabilityFlags {\n        get { return stateLock.withCriticalScope { _flags } }\n        set {\n            stateLock.withCriticalScope {\n                _flags = newValue\n            }\n        }\n    }\n    public var didStartNotifier: Bool {\n        get { return stateLock.withCriticalScope { _didStartNotifier } }\n        set {\n            stateLock.withCriticalScope {\n                _didStartNotifier = newValue\n            }\n        }\n    }\n    public var didStopNotifier: Bool {\n        get { return stateLock.withCriticalScope { _didStopNotifier } }\n        set {\n            stateLock.withCriticalScope {\n                _didStopNotifier = newValue\n            }\n        }\n    }\n\n    public var log: LogChannel {\n        get { return stateLock.withCriticalScope { _log } }\n        set {\n            stateLock.withCriticalScope {\n                _log = newValue\n            }\n        }\n    }\n    public weak var delegate: NetworkReachabilityDelegate? {\n        get { return stateLock.withCriticalScope { _delegate } }\n        set {\n            stateLock.withCriticalScope {\n                _delegate = newValue\n            }\n        }\n    }\n\n    private var stateLock = NSRecursiveLock()\n    private var _flags: SCNetworkReachabilityFlags = .reachable {\n        didSet {\n            delegate?.didChangeReachability(flags: flags)\n        }\n    }\n    private var _didStartNotifier = false\n    private var _didStopNotifier = false\n    private var _log: LogChannel = Log.Channel<Log>()\n    private weak var _delegate: NetworkReachabilityDelegate?\n\n    public init() { }\n}\n\nextension TestableNetworkReachability: NetworkReachability {\n\n    public func startNotifier(onQueue queue: DispatchQueue) throws {\n        log.message(\"Started Reachability Notifier\")\n        didStartNotifier = true\n        delegate?.didChangeReachability(flags: flags)\n    }\n\n    public func stopNotifier() {\n        log.message(\"Stopped Reachability Notifier\")\n        didStopNotifier = true\n    }\n}\n"
  },
  {
    "path": "Sources/TestingProcedureKit/XCTAsserts.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport Foundation\nimport XCTest\nimport ProcedureKit\n\ninternal enum __XCTAssertionResult {\n    case success\n    case expectedFailure(String?)\n    case unexpectedFailure(Swift.Error)\n\n    var isExpected: Bool {\n        switch self {\n        case .unexpectedFailure: return false\n        default: return true\n        }\n    }\n\n    func failureDescription() -> String {\n        let explanation: String\n        switch self {\n        case .success: explanation = \"passed\"\n        case .expectedFailure(let details?): explanation = \"failed: \\(details)\"\n        case .expectedFailure: explanation = \"failed\"\n        case .unexpectedFailure(let error): explanation = \"threw error \\\"\\(error)\\\"\"\n        }\n        return explanation\n    }\n}\n\ninternal func __XCTEvaluateAssertion(testCase: XCTestCase, _ message: @autoclosure () -> String = \"\", file: StaticString = #file, line: UInt = #line, expression: () throws -> __XCTAssertionResult) {\n    let result: __XCTAssertionResult\n    do {\n        result = try expression()\n    }\n    catch {\n        result = .unexpectedFailure(error)\n    }\n\n    switch result {\n    case .success: return\n    default:\n        testCase.recordFailure(\n            withDescription: \"\\(result.failureDescription()) - \\(message())\",\n            inFile: String(describing: file), atLine: Int(line),\n            expected: result.isExpected\n        )\n    }\n\n}\n\n// MARK: Procedure Assertions\n\npublic extension ProcedureKitTestCase {\n\n    func PKAssertProcedureFinished<T: Procedure>(_ exp: @autoclosure () throws -> T, withErrors: Bool = false, cancelling: Bool = false, _ message: @autoclosure () -> String = \"\", file: StaticString = #file, line: UInt = #line) {\n        __XCTEvaluateAssertion(testCase: self, message(), file: file, line: line) {\n\n            let procedure = try exp()\n\n            // Errors are expected\n            if withErrors {\n                guard let _ = procedure.error else {\n                    return .expectedFailure(\"\\(procedure.procedureName) did not have an error.\")\n                }\n            }\n            // Errors are not expected\n            else {\n                guard procedure.error == nil else {\n                    return .expectedFailure(\"\\(procedure.procedureName) has an error.\")\n                }\n            }\n\n            if cancelling {\n                guard procedure.isCancelled else {\n                    return .expectedFailure(\"\\(procedure.procedureName) was not cancelled.\")\n                }\n            }\n            else {\n                guard !procedure.isCancelled else {\n                    return .expectedFailure(\"\\(procedure.procedureName) was cancelled.\")\n                }\n            }\n\n            guard procedure.isFinished else {\n                return .expectedFailure(\"\\(procedure.procedureName) did not finish.\")\n            }\n\n            return .success\n        }\n    }\n\n    func PKAssertProcedureError<T: Procedure, E: Error>(_ exp: @autoclosure () throws -> T, _ exp2: @autoclosure () throws -> E, _ message: @autoclosure () -> String = \"\", file: StaticString = #file, line: UInt = #line) where E: Equatable {\n        __XCTEvaluateAssertion(testCase: self, message(), file: file, line: line) {\n            let procedure = try exp()\n            let expectedError = try exp2()\n            guard let error = procedure.error else {\n                return .expectedFailure(\"\\(procedure.procedureName) did not error.\")\n            }\n            guard let e = error as? E else {\n                return .expectedFailure(\"\\(procedure.procedureName) error: \\(error), was not the expected type.\")\n            }\n            guard expectedError == e else {\n                return .expectedFailure(\"\\(procedure.procedureName) error: \\(e), did not equal expected error: \\(expectedError).\")\n            }\n            return .success\n        }\n    }\n\n\n    func PKAssertProcedureCancelled<T: Procedure>(_ exp: @autoclosure () throws -> T, withErrors: Bool = false, _ message: @autoclosure () -> String = \"\", file: StaticString = #file, line: UInt = #line) {\n        PKAssertProcedureFinished(try exp(), withErrors: withErrors, cancelling: true, message(), file: file, line: line)\n    }\n\n    func PKAssertProcedureFinishedWithError<T: Procedure, E: Error>(_ exp: @autoclosure () throws -> T, _ exp2: @autoclosure () throws -> E, _ message: @autoclosure () -> String = \"\", file: StaticString = #file, line: UInt = #line) where E: Equatable {\n        PKAssertProcedureFinished(try exp(), withErrors: true, message(), file: file, line: line)\n        PKAssertProcedureError(try exp(), try exp2(), message(), file: file, line: line)\n    }\n\n    func PKAssertProcedureCancelledWithError<T: Procedure, E: Error>(_ exp: @autoclosure () throws -> T, _ exp2: @autoclosure () throws -> E, _ message: @autoclosure () -> String = \"\", file: StaticString = #file, line: UInt = #line) where E: Equatable {\n        PKAssertProcedureCancelled(try exp(), withErrors: true, message(), file: file, line: line)\n        PKAssertProcedureError(try exp(), try exp2(), message(), file: file, line: line)\n    }\n\n    func PKAssertConditionSatisfied(_ exp1: @autoclosure () throws -> ConditionResult, _ message: @autoclosure () -> String = \"\", file: StaticString = #file, line: UInt = #line) {\n        __XCTEvaluateAssertion(testCase: self, message(), file: file, line: line) {\n            let result = try exp1()\n            switch result {\n            case .success(true): break\n            default:\n                return .expectedFailure(\"Condition was not satisfied: \\(result).\")\n            }\n            return .success\n        }\n    }\n\n    func PKAssertConditionFailed<E: Error>(_ exp1: @autoclosure () throws -> ConditionResult, failedWithError error: @autoclosure () throws -> E, _ message: @autoclosure () -> String = \"\", file: StaticString = #file, line: UInt = #line) where E: Equatable {\n        __XCTEvaluateAssertion(testCase: self, message(), file: file, line: line) {\n\n            let result = try exp1()\n            let expectedError = try error()\n\n            switch result {\n            case let .failure(receivedError):\n                guard let error = receivedError as? E else {\n                    return .expectedFailure(\"Condition failed with unexpected error, \\(receivedError).\")\n                }\n                guard error == expectedError else {\n                    return .expectedFailure(\"Condition failed with error: \\(error), instead of: \\(expectedError).\")\n                }\n            default:\n                return .expectedFailure(\"Condition did not fail, \\(result).\")\n            }\n            return .success\n        }\n    }\n\n    func PKAssertProcedureOutput<T: Procedure>(_ exp: @autoclosure () throws -> T, _ exp2: @autoclosure () -> T.Output, _ message: @autoclosure () -> String = \"\", file: StaticString = #file, line: UInt = #line) where T: OutputProcedure, T.Output: Equatable {\n        PKAssertProcedureFinished(try exp(), message(), file: file, line: line)\n        __XCTEvaluateAssertion(testCase: self, message(), file: file, line: line) {\n            let procedure = try exp()\n            guard let output = procedure.output.success else {\n                return .expectedFailure(\"\\(procedure.procedureName) did not have a successful output value.\")\n            }\n            let expectedOutput = exp2()\n            guard expectedOutput == output else {\n                return .expectedFailure(\"\\(procedure.procedureName)'s successful output did not == \\(expectedOutput).\")\n            }\n            return .success\n        }\n    }\n}\n\n\n// MARK: - Deprecations\n\npublic extension ProcedureKitTestCase {\n\n    @available(*, deprecated, renamed: \"PKAssertProcedureFinished\", message: \"Use PKAssertProcedure* functions instead.\")\n    func XCTAssertProcedureFinishedWithoutErrors<T: ProcedureProtocol>(_ exp: @autoclosure () throws -> T, _ message: @autoclosure () -> String = \"\", file: StaticString = #file, line: UInt = #line) {\n        __XCTEvaluateAssertion(testCase: self, message(), file: file, line: line) {\n            let procedure = try exp()\n            guard !procedure.failed else {\n                return .expectedFailure(\"\\(procedure.procedureName) has failed.\")\n            }\n            guard !procedure.isCancelled else {\n                return .expectedFailure(\"\\(procedure.procedureName) was cancelled.\")\n            }\n            guard procedure.isFinished else {\n                return .expectedFailure(\"\\(procedure.procedureName) did not finish.\")\n            }\n            return .success\n        }\n    }\n\n    @available(*, deprecated, message: \"Use PKAssertProcedure* functions instead.\")\n    func XCTAssertProcedureFinishedWithErrors<T: ProcedureProtocol>(_ exp: @autoclosure () throws -> T, _ message: @autoclosure () -> String = \"\", file: StaticString = #file, line: UInt = #line) {\n        __XCTEvaluateAssertion(testCase: self, message(), file: file, line: line) {\n            let procedure = try exp()\n            guard procedure.failed else {\n                return .expectedFailure(\"\\(procedure.procedureName) did not have any errors.\")\n            }\n            guard !procedure.isCancelled else {\n                return .expectedFailure(\"\\(procedure.procedureName) was cancelled.\")\n            }\n            guard procedure.isFinished else {\n                return .expectedFailure(\"\\(procedure.procedureName) did not finish.\")\n            }\n            return .success\n        }\n    }\n\n    @available(*, deprecated, renamed: \"PKAssertProcedureFinishedWithError\", message: \"Use XCTAssertProcedureFinishedWithErrors instead, providing an appropriate error.\")\n    func XCTAssertProcedureFinishedWithErrors<T: ProcedureProtocol>(_ exp1: @autoclosure () throws -> T, count exp2: @autoclosure () throws -> Int, _ message: @autoclosure () -> String = \"\", file: StaticString = #file, line: UInt = #line) { }\n\n    @available(*, deprecated, renamed: \"PKAssertProcedureCancelled\", message: \"Use PKAssertProcedureCancelled instead.\")\n    func XCTAssertProcedureCancelledWithoutErrors<T: ProcedureProtocol>(_ exp: @autoclosure () throws -> T, _ message: @autoclosure () -> String = \"\", file: StaticString = #file, line: UInt = #line) {\n        __XCTEvaluateAssertion(testCase: self, message(), file: file, line: line) {\n            let procedure = try exp()\n            guard !procedure.failed else {\n                return .expectedFailure(\"\\(procedure.procedureName) has failed.\")\n            }\n            guard procedure.isCancelled else {\n                return .expectedFailure(\"\\(procedure.procedureName) was not cancelled.\")\n            }\n            guard procedure.isFinished else {\n                return .expectedFailure(\"\\(procedure.procedureName) did not finish.\")\n            }\n            return .success\n        }\n    }\n\n    @available(*, deprecated, renamed: \"PKAssertProcedureCancelledWithError\", message: \"Use PKAssertProcedureCancelledWithError instead, providing an appropriate error.\")\n    func XCTAssertProcedureCancelledWithErrors<T: ProcedureProtocol>(_ exp: @autoclosure () throws -> T, _ message: @autoclosure () -> String = \"\", file: StaticString = #file, line: UInt = #line) {\n        __XCTEvaluateAssertion(testCase: self, message(), file: file, line: line) {\n            let procedure = try exp()\n            guard procedure.failed else {\n                return .expectedFailure(\"\\(procedure.procedureName) did not have any errors.\")\n            }\n            guard procedure.isCancelled else {\n                return .expectedFailure(\"\\(procedure.procedureName) was not cancelled.\")\n            }\n            guard procedure.isFinished else {\n                return .expectedFailure(\"\\(procedure.procedureName) did not finish.\")\n            }\n            return .success\n        }\n    }\n\n    @available(*, deprecated, renamed: \"PKAssertProcedureCancelledWithError\", message: \"Use PKAssertProcedureCancelledWithError instead, providing an appropriate error.\")\n    func XCTAssertProcedureCancelledWithErrors<T: ProcedureProtocol>(_ exp: @autoclosure () throws -> T, count exp2: @autoclosure () throws -> Int, _ message: @autoclosure () -> String = \"\", file: StaticString = #file, line: UInt = #line) { }\n\n    @available(*, deprecated, message: \"Use PKAssertProcedure* functions instead.\")\n    func XCTAssertConditionResult<E: Error>(_ exp1: @autoclosure () throws -> ConditionResult, failedWithError error: @autoclosure () throws -> E, _ message: @autoclosure () -> String = \"\", file: StaticString = #file, line: UInt = #line) where E: Equatable {\n        PKAssertConditionFailed(try exp1(), failedWithError: try error(), message(), file: file, line: line)\n    }\n\n    @available(*, deprecated, message: \"Use PKAssertProcedure* functions instead.\")\n    func XCTAssertConditionResultSatisfied(_ exp1: @autoclosure () throws -> ConditionResult, _ message: @autoclosure () -> String = \"\", file: StaticString = #file, line: UInt = #line) {\n        PKAssertConditionSatisfied(try exp1(), message(), file: file, line: line)\n    }\n\n    @available(*, deprecated, message: \"Use PKAssertProcedure* functions instead.\")\n    func XCTAssertProcedure<T: ProcedureProtocol, E: Error>(_ exp: @autoclosure () throws -> T, firstErrorEquals firstError: E, _ message: @autoclosure () -> String = \"\", file: StaticString = #file, line: UInt = #line) where E: Equatable { }\n\n    @available(*, deprecated, message: \"Use PKAssertProcedure* functions instead.\")\n    func XCTAssertProcedureOutputSuccess<T: OutputProcedure>(_ exp: @autoclosure () throws -> T, _ exp2: @autoclosure () -> T.Output, _ message: @autoclosure () -> String = \"\", file: StaticString = #file, line: UInt = #line) where T.Output: Equatable {\n        __XCTEvaluateAssertion(testCase: self, message(), file: file, line: line) {\n            let procedure = try exp()\n            guard !procedure.failed else {\n                return .expectedFailure(\"\\(procedure.procedureName) has failed.\")\n            }\n            guard !procedure.isCancelled else {\n                return .expectedFailure(\"\\(procedure.procedureName) was cancelled.\")\n            }\n            guard procedure.isFinished else {\n                return .expectedFailure(\"\\(procedure.procedureName) did not finish.\")\n            }\n            guard let output = procedure.output.success else {\n                return .expectedFailure(\"\\(procedure.procedureName) did not have a successful output value.\")\n            }\n            let expectedOutput = exp2()\n            guard expectedOutput == output else {\n                return .expectedFailure(\"\\(procedure.procedureName)'s successful output did not == .\")\n            }\n            return .success\n        }\n    }\n}\n\n// MARK: Constrained to TestProcedure\n\npublic extension ProcedureKitTestCase {\n\n    @available(*, unavailable, message: \"Use PKAssertProcedure* functions instead.\")\n    func XCTAssertProcedureFinishedWithoutErrors<T>(_ exp: @autoclosure () throws -> T, _ message: @autoclosure () -> String = \"\", file: StaticString = #file, line: UInt = #line) where T: TestProcedure { }\n\n    @available(*, unavailable, message: \"Use PKAssertProcedure* functions instead.\")\n    func XCTAssertProcedureCancelledWithoutErrors<T>(_ exp: @autoclosure () throws -> T, _ message: @autoclosure () -> String = \"\", file: StaticString = #file, line: UInt = #line) where T: TestProcedure { }\n\n}\n\npublic extension ProcedureKitTestCase {\n\n    @available(*, unavailable, message: \"Use PKAssertProcedure* functions instead.\")\n    func XCTAssertProcedureFinishedWithoutErrors(_ message: @autoclosure () -> String = \"\", file: StaticString = #file, line: UInt = #line) { }\n\n    @available(*, unavailable, message: \"Use PKAssertProcedure* functions instead.\")\n    func XCTAssertProcedureFinishedWithErrors(_ message: @autoclosure () -> String = \"\", file: StaticString = #file, line: UInt = #line) { }\n\n    @available(*, unavailable, message: \"Use PKAssertProcedure* functions instead.\")\n    func XCTAssertProcedureFinishedWithErrors(count: @autoclosure () throws -> Int, _ message: @autoclosure () -> String = \"\", file: StaticString = #file, line: UInt = #line) { }\n\n    @available(*, unavailable, message: \"Use PKAssertProcedure* functions instead.\")\n    func XCTAssertProcedureCancelledWithoutErrors(_ message: @autoclosure () -> String = \"\", file: StaticString = #file, line: UInt = #line) { }\n\n    @available(*, unavailable, message: \"Use PKAssertProcedure* functions instead.\")\n    func XCTAssertProcedureCancelledWithErrors(_ message: @autoclosure () -> String = \"\", file: StaticString = #file, line: UInt = #line) { }\n\n    @available(*, unavailable, message: \"Use PKAssertProcedure* functions instead.\")\n    func XCTAssertProcedureCancelledWithErrors(count: @autoclosure () throws -> Int, _ message: @autoclosure () -> String = \"\", file: StaticString = #file, line: UInt = #line) { }\n}\n\n// MARK: Constrained to EventConcurrencyTrackingProcedureProtocol\n\npublic extension ProcedureKitTestCase {\n\n    func PKAssertProcedureNoConcurrentEvents<T: EventConcurrencyTrackingProcedureProtocol>(_ exp: @autoclosure () throws -> T, minimumConcurrentDetected: Int = 1, _ message: @autoclosure () -> String = \"\", file: StaticString = #file, line: UInt = #line) where T: Procedure {\n        __XCTEvaluateAssertion(testCase: self, message(), file: file, line: line) {\n            let procedure = try exp()\n            let detectedConcurrentEvents = procedure.concurrencyRegistrar.detectedConcurrentEvents\n            guard procedure.concurrencyRegistrar.maximumDetected >= minimumConcurrentDetected && detectedConcurrentEvents.isEmpty else {\n                return .expectedFailure(\"\\(procedure.procedureName) detected concurrent events: \\n\\(detectedConcurrentEvents)\")\n            }\n            return .success\n        }\n    }\n\n    @available(*, unavailable, renamed: \"PKAssertProcedureNoConcurrentEvents\", message: \"Use PKAssertProcedure* functions instead.\")\n    func XCTAssertProcedureNoConcurrentEvents<T: EventConcurrencyTrackingProcedureProtocol>(_ exp: @autoclosure () throws -> T, minimumConcurrentDetected: Int = 1, _ message: @autoclosure () -> String = \"\", file: StaticString = #file, line: UInt = #line) where T: Procedure {\n        PKAssertProcedureNoConcurrentEvents(try exp(), minimumConcurrentDetected: minimumConcurrentDetected, message(), file: file, line: line)\n    }\n}\n"
  },
  {
    "path": "Supporting Files/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>FMWK</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>$(PROCEDUREKIT_VERSION)</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>$(CURRENT_PROJECT_VERSION)</string>\n\t<key>NSPrincipalClass</key>\n\t<string></string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Supporting Files/ProcedureKit.h",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n@import Foundation;\n\n//! Project version number for ProcedureKit.\nFOUNDATION_EXPORT double ProcedureKitVersionNumber;\n\n//! Project version string for ProcedureKit.\nFOUNDATION_EXPORT const unsigned char ProcedureKitVersionString[];\n\n// In this header, you should import all the public headers of your framework using statements like #import <ProcedureKit/PublicHeader.h>\n\n\n"
  },
  {
    "path": "Supporting Files/ProcedureKit.xcconfig",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n#include \"Version.xcconfig\"\n\n// Metadata\nINFOPLIST_FILE_framework = $(SRCROOT)/Supporting Files/Info.plist\nINFOPLIST_FILE_xctest = $(SRCROOT)/Tests/Info.plist\nINFOPLIST_FILE = $(INFOPLIST_FILE_$(WRAPPER_EXTENSION))\n\nPRODUCT_BUNDLE_IDENTIFIER_framework = run.kit.procedure.ProcedureKit\nPRODUCT_BUNDLE_IDENTIFIER_xctest = run.kit.procedure.ProcedureKitTests\nPRODUCT_BUNDLE_IDENTIFIER = $(PRODUCT_BUNDLE_IDENTIFIER_$(WRAPPER_EXTENSION))\n\nPRODUCT_NAME_framework = ProcedureKit\nPRODUCT_NAME_xctest = ProcedureKitTests\nPRODUCT_NAME = $(PRODUCT_NAME_$(WRAPPER_EXTENSION))\n\nAPPLICATION_EXTENSION_API_ONLY_framework = YES\nAPPLICATION_EXTENSION_API_ONLY_xctest = NO\nAPPLICATION_EXTENSION_API_ONLY = $(APPLICATION_EXTENSION_API_ONLY_$(WRAPPER_EXTENSION))\n\nSWIFT_VERSION = 4.2\nSWIFT_SWIFT3_OBJC_INFERENCE = Off\n\n// Build Settings\nSUPPORTED_PLATFORMS = macosx iphoneos appletvos watchos appletvsimulator iphonesimulator watchsimulator\n\n// Code Signing\nCODE_SIGN_IDENTITY = -\n\n// Deployment\nDEFINES_MODULE = YES\n\nMACOSX_DEPLOYMENT_TARGET = 10.11\nIPHONEOS_DEPLOYMENT_TARGET = 8.0\nTVOS_DEPLOYMENT_TARGET = 9.2\nWATCHOS_DEPLOYMENT_TARGET = 3.0\n\nLD_RUNPATH_SEARCH_PATHS_framework = @executable_path/../Frameworks @loader_path/Frameworks\nLD_RUNPATH_SEARCH_PATHS_xctest = @loader_path/Frameworks @executable_path/Frameworks @loader_path/../Frameworks @executable_path/../Frameworks\nLD_RUNPATH_SEARCH_PATHS = $(LD_RUNPATH_SEARCH_PATHS_$(WRAPPER_EXTENSION))\n\n#include \"Warnings.xcconfig\"\n\n"
  },
  {
    "path": "Supporting Files/ProcedureKitCloud.h",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n@import Foundation;\n@import ProcedureKit;\n\n//! Project version number for ProcedureKitCloud.\nFOUNDATION_EXPORT double ProcedureKitCloudVersionNumber;\n\n//! Project version string for ProcedureKitCloud.\nFOUNDATION_EXPORT const unsigned char ProcedureKitCloudVersionString[];\n\n// In this header, you should import all the public headers of your framework using statements like #import <ProcedureKitCloud/PublicHeader.h>\n\n\n"
  },
  {
    "path": "Supporting Files/ProcedureKitCloud.xcconfig",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nPRODUCT_BUNDLE_IDENTIFIER_framework = run.kit.procedure.ProcedureKitCloud\nPRODUCT_BUNDLE_IDENTIFIER_xctest = run.kit.procedure.ProcedureKitCloudTests\nPRODUCT_BUNDLE_IDENTIFIER = $(PRODUCT_BUNDLE_IDENTIFIER_$(WRAPPER_EXTENSION))\n\nPRODUCT_NAME_framework = ProcedureKitCloud\nPRODUCT_NAME_xctest = ProcedureKitCloudTests\nPRODUCT_NAME = $(PRODUCT_NAME_$(WRAPPER_EXTENSION))\n"
  },
  {
    "path": "Supporting Files/ProcedureKitCoreData.h",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n\n@import Foundation;\n@import CoreData;\n@import ProcedureKit;\n\n//! Project version number for ProcedureKitCoreData.\nFOUNDATION_EXPORT double ProcedureKitCoreDataVersionNumber;\n\n//! Project version string for ProcedureKitCoreData.\nFOUNDATION_EXPORT const unsigned char ProcedureKitCoreDataVersionString[];\n\n// In this header, you should import all the public headers of your framework using statements like #import <ProcedureKitCoreData/PublicHeader.h>\n\n\n"
  },
  {
    "path": "Supporting Files/ProcedureKitCoreData.xcconfig",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nPRODUCT_BUNDLE_IDENTIFIER_framework = run.kit.procedure.ProcedureKitCoreData\nPRODUCT_BUNDLE_IDENTIFIER_xctest = run.kit.procedure.ProcedureKitCoreDataTests\nPRODUCT_BUNDLE_IDENTIFIER = $(PRODUCT_BUNDLE_IDENTIFIER_$(WRAPPER_EXTENSION))\n\nPRODUCT_NAME_framework = ProcedureKitCoreData\nPRODUCT_NAME_xctest = ProcedureKitCoreDataTests\nPRODUCT_NAME = $(PRODUCT_NAME_$(WRAPPER_EXTENSION))\n\nMACOSX_DEPLOYMENT_TARGET = 10.12\nIPHONEOS_DEPLOYMENT_TARGET = 10.0\nTVOS_DEPLOYMENT_TARGET = 10.0\nWATCHOS_DEPLOYMENT_TARGET = 3.0\n"
  },
  {
    "path": "Supporting Files/ProcedureKitInstrument.xcconfig",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nPRODUCT_BUNDLE_IDENTIFIER = run.kit.procedure.ProcedureKitInstrument\nPRODUCT_NAME = ProcedureKitInstrument\n\nINSTALL_PATH = $(LOCAL_LIBRARY_DIR)/Instruments/Packages\n"
  },
  {
    "path": "Supporting Files/ProcedureKitInstruments.xcconfig",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nPRODUCT_BUNDLE_IDENTIFIER = run.kit.procedure.ProcedureKitInstruments\n\nPRODUCT_NAME = ProcedureKitInstruments\n\n"
  },
  {
    "path": "Supporting Files/ProcedureKitLocation.h",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n@import Foundation;\n@import ProcedureKit;\n\n//! Project version number for ProcedureKitLocation.\nFOUNDATION_EXPORT double ProcedureKitLocationVersionNumber;\n\n//! Project version string for ProcedureKitLocation.\nFOUNDATION_EXPORT const unsigned char ProcedureKitLocationVersionString[];\n\n// In this header, you should import all the public headers of your framework using statements like #import <ProcedureKitLocation/PublicHeader.h>\n\n\n"
  },
  {
    "path": "Supporting Files/ProcedureKitLocation.xcconfig",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nPRODUCT_BUNDLE_IDENTIFIER_framework = run.kit.procedure.ProcedureKitLocation\nPRODUCT_BUNDLE_IDENTIFIER_xctest = run.kit.procedure.ProcedureKitLocationTests\nPRODUCT_BUNDLE_IDENTIFIER = $(PRODUCT_BUNDLE_IDENTIFIER_$(WRAPPER_EXTENSION))\n\nPRODUCT_NAME_framework = ProcedureKitLocation\nPRODUCT_NAME_xctest = ProcedureKitLocationTests\nPRODUCT_NAME = $(PRODUCT_NAME_$(WRAPPER_EXTENSION))\n\n"
  },
  {
    "path": "Supporting Files/ProcedureKitMac.h",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n@import Cocoa;\n@import ProcedureKit;\n\n//! Project version number for ProcedureKitMac.\nFOUNDATION_EXPORT double ProcedureKitMacVersionNumber;\n\n//! Project version string for ProcedureKitMac.\nFOUNDATION_EXPORT const unsigned char ProcedureKitMacVersionString[];\n\n// In this header, you should import all the public headers of your framework using statements like #import <ProcedureKitMac/PublicHeader.h>\n\n\n"
  },
  {
    "path": "Supporting Files/ProcedureKitMac.xcconfig",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nPRODUCT_BUNDLE_IDENTIFIER_framework = run.kit.procedure.ProcedureKitMac\nPRODUCT_BUNDLE_IDENTIFIER_xctest = run.kit.procedure.ProcedureKitMacTests\nPRODUCT_BUNDLE_IDENTIFIER = $(PRODUCT_BUNDLE_IDENTIFIER_$(WRAPPER_EXTENSION))\n\nPRODUCT_NAME_framework = ProcedureKitMac\nPRODUCT_NAME_xctest = ProcedureKitMacTests\nPRODUCT_NAME = $(PRODUCT_NAME_$(WRAPPER_EXTENSION))\n\nSUPPORTED_PLATFORMS = macosx\n"
  },
  {
    "path": "Supporting Files/ProcedureKitMobile.h",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n@import UIKit;\n@import ProcedureKit;\n\n//! Project version number for ProcedureKitMobile.\nFOUNDATION_EXPORT double ProcedureKitMobileVersionNumber;\n\n//! Project version string for ProcedureKitMobile.\nFOUNDATION_EXPORT const unsigned char ProcedureKitMobileVersionString[];\n\n// In this header, you should import all the public headers of your framework using statements like #import <ProcedureKitMobile/PublicHeader.h>\n\n\n"
  },
  {
    "path": "Supporting Files/ProcedureKitMobile.xcconfig",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nPRODUCT_BUNDLE_IDENTIFIER_framework = run.kit.procedure.ProcedureKitMobile\nPRODUCT_BUNDLE_IDENTIFIER_xctest = run.kit.procedure.ProcedureKitMobileTests\nPRODUCT_BUNDLE_IDENTIFIER = $(PRODUCT_BUNDLE_IDENTIFIER_$(WRAPPER_EXTENSION))\n\nPRODUCT_NAME_framework = ProcedureKitMobile\nPRODUCT_NAME_xctest = ProcedureKitMobileTests\nPRODUCT_NAME = $(PRODUCT_NAME_$(WRAPPER_EXTENSION))\n\nAPPLICATION_EXTENSION_API_ONLY = NO\n\nSUPPORTED_PLATFORMS = iphoneos iphonesimulator\n\nSDKROOT = iphoneos\n"
  },
  {
    "path": "Supporting Files/ProcedureKitNetwork.h",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n@import Foundation;\n@import ProcedureKit;\n\n//! Project version number for ProcedureKitNetwork.\nFOUNDATION_EXPORT double ProcedureKitNetworkVersionNumber;\n\n//! Project version string for ProcedureKitNetwork.\nFOUNDATION_EXPORT const unsigned char ProcedureKitNetworkVersionString[];\n\n// In this header, you should import all the public headers of your framework using statements like #import <ProcedureKitNetwork/PublicHeader.h>\n\n\n"
  },
  {
    "path": "Supporting Files/ProcedureKitNetwork.xcconfig",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nPRODUCT_BUNDLE_IDENTIFIER_framework = run.kit.procedure.ProcedureKitNetwork\nPRODUCT_BUNDLE_IDENTIFIER_xctest = run.kit.procedure.ProcedureKitNetworkTests\nPRODUCT_BUNDLE_IDENTIFIER = $(PRODUCT_BUNDLE_IDENTIFIER_$(WRAPPER_EXTENSION))\n\nPRODUCT_NAME_framework = ProcedureKitNetwork\nPRODUCT_NAME_xctest = ProcedureKitNetworkTests\nPRODUCT_NAME = $(PRODUCT_NAME_$(WRAPPER_EXTENSION))\n\n"
  },
  {
    "path": "Supporting Files/ProcedureKitTV.h",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n@import UIKit;\n@import ProcedureKit;\n\n//! Project version number for ProcedureKitTV.\nFOUNDATION_EXPORT double ProcedureKitTVVersionNumber;\n\n//! Project version string for ProcedureKitTV.\nFOUNDATION_EXPORT const unsigned char ProcedureKitTVVersionString[];\n\n// In this header, you should import all the public headers of your framework using statements like #import <ProcedureKitTV/PublicHeader.h>\n\n\n"
  },
  {
    "path": "Supporting Files/ProcedureKitTV.xcconfig",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nPRODUCT_BUNDLE_IDENTIFIER_framework = run.kit.procedure.ProcedureKitTV\nPRODUCT_BUNDLE_IDENTIFIER_xctest = run.kit.procedure.ProcedureKitTVTests\nPRODUCT_BUNDLE_IDENTIFIER = $(PRODUCT_BUNDLE_IDENTIFIER_$(WRAPPER_EXTENSION))\n\nPRODUCT_NAME_framework = ProcedureKitTV\nPRODUCT_NAME_xctest = ProcedureKitTVTests\nPRODUCT_NAME = $(PRODUCT_NAME_$(WRAPPER_EXTENSION))\n\nSUPPORTED_PLATFORMS = appletvos appletvsimulator\n"
  },
  {
    "path": "Supporting Files/TestingProcedureKit.h",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n@import Foundation;\n@import ProcedureKit;\n\n//! Project version number for TestingProcedureKit.\nFOUNDATION_EXPORT double TestingProcedureKitVersionNumber;\n\n//! Project version string for TestingProcedureKit.\nFOUNDATION_EXPORT const unsigned char TestingProcedureKitVersionString[];\n\n// In this header, you should import all the public headers of your framework using statements like #import <TestingProcedureKit/PublicHeader.h>\n\n\n"
  },
  {
    "path": "Supporting Files/TestingProcedureKit.xcconfig",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nPRODUCT_BUNDLE_IDENTIFIER = run.kit.procedure.TestingProcedureKit\nPRODUCT_NAME = TestingProcedureKit\n\nAPPLICATION_EXTENSION_API_ONLY = NO\n\nENABLE_BITCODE = NO\n\nINSTALL_PATH = @rpath\n\nSUPPORTED_PLATFORMS = macosx iphoneos appletvos appletvsimulator iphonesimulator\n\nFRAMEWORK_SEARCH_PATHS = $(inherited) $(PLATFORM_DIR)/Developer/Library/Frameworks\n"
  },
  {
    "path": "Supporting Files/Version.xcconfig",
    "content": "PROCEDUREKIT_VERSION = 5.2.0\n"
  },
  {
    "path": "Supporting Files/Warnings.xcconfig",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nCLANG_WARN_DOCUMENTATION_COMMENTS = YES\nCLANG_WARN_BOOL_CONVERSION = YES\nCLANG_WARN_CONSTANT_CONVERSION = YES\nCLANG_WARN_EMPTY_BODY = YES\nCLANG_WARN_ENUM_CONVERSION = YES\nCLANG_WARN_INFINITE_RECURSION = YES\nCLANG_WARN_INT_CONVERSION = YES\nCLANG_WARN_SUSPICIOUS_MOVE = YES\nCLANG_WARN_UNREACHABLE_CODE = YES\nCLANG_WARN__DUPLICATE_METHOD_MATCH = YES\nENABLE_STRICT_OBJC_MSGSEND = YES\nENABLE_TESTABILITY = YES\nGCC_NO_COMMON_BLOCKS = YES\nGCC_WARN_64_TO_32_BIT_CONVERSION = YES\nGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR\nGCC_WARN_UNDECLARED_SELECTOR = YES\nGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE\nGCC_WARN_UNUSED_FUNCTION = YES\nGCC_WARN_UNUSED_VARIABLE = YES\nCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR\nCLANG_ANALYZER_NONNULL = YES\nCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES\nCLANG_WARN_COMMA = YES\nCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES\nCLANG_WARN_OBJC_LITERAL_CONVERSION = YES\nCLANG_WARN_RANGE_LOOP_ANALYSIS = YES\nCLANG_WARN_STRICT_PROTOTYPES = YES\n"
  },
  {
    "path": "TestingProcedureKit.podspec",
    "content": "Pod::Spec.new do |s|\n  s.name              = \"TestingProcedureKit\"\n  s.version           = \"5.2.0\"\n  s.summary           = \"XCTest support for ProcedureKit.\"\n  s.homepage          = \"https://github.com/ProcedureKit/ProcedureKit\"\n  s.license           = 'MIT'\n  s.authors           = { \"ProcedureKit Core Contributors\" => \"hello@procedure.kit.run\" }\n  s.source            = { :git => \"https://github.com/ProcedureKit/ProcedureKit.git\", :tag => s.version.to_s }\n  s.module_name       = 'TestingProcedureKit'\n\n  s.ios.deployment_target = '9.0'\n  s.tvos.deployment_target = '9.2'\n  s.osx.deployment_target = '10.11'\n  \n  s.frameworks = 'XCTest'\n  \n  # Ensure the correct version of Swift is used\n  s.swift_version = '5.0'\n\n  # Defaul spec is 'Testing'\n  s.default_subspec   = 'Testing'\n\n  # TestingProcedureKit\n  s.subspec 'Testing' do |ss|\n  \tss.dependency 'ProcedureKit'\n  \tss.frameworks = 'XCTest'  \t\n  \tss.source_files = ['Sources/TestingProcedureKit']\n  end\nend\n"
  },
  {
    "path": "Tests/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>BNDL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Tests/ProcedureKitCloudTests/CKAcceptSharesOperationTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n#if !os(tvOS)\n\nimport XCTest\nimport CloudKit\nimport ProcedureKit\nimport TestingProcedureKit\n@testable import ProcedureKitCloud\n\nclass TestCKAcceptSharesOperation: TestCKOperation, CKAcceptSharesOperationProtocol, AssociatedErrorProtocol {\n    typealias AssociatedError = PKCKError\n\n    var error: Error? = nil\n    var shareMetadatas: [ShareMetadata] = []\n    var perShareCompletionBlock: ((ShareMetadata, Share?, Error?) -> Void)? = nil\n    var acceptSharesCompletionBlock: ((Error?) -> Void)? = nil\n\n    init(error: Error? = nil) {\n        self.error = error\n        super.init()\n    }\n\n    override func main() {\n        acceptSharesCompletionBlock?(error)\n    }\n}\n\nclass CKAcceptSharesOperationTests: CKProcedureTestCase {\n\n    var target: TestCKAcceptSharesOperation!\n    var operation: CKProcedure<TestCKAcceptSharesOperation>!\n\n    override func setUp() {\n        super.setUp()\n        target = TestCKAcceptSharesOperation()\n        operation = CKProcedure(operation: target)\n    }\n\n    override func tearDown() {\n        target = nil\n        operation = nil\n        super.tearDown()\n    }\n\n    func test__set_get__shareMetadatas() {\n        let shareMetaddatas = [ \"hello@world.com\" ]\n        operation.shareMetadatas = shareMetaddatas\n        XCTAssertEqual(operation.shareMetadatas, shareMetaddatas)\n        XCTAssertEqual(target.shareMetadatas, shareMetaddatas)\n    }\n\n    func test__set_get__perShareCompletionBlock() {\n        var setByCompletionBlock = false\n        let block: (String, String?, Error?) -> Void = { metadata, share, error in\n            setByCompletionBlock = true\n        }\n        operation.perShareCompletionBlock = block\n        XCTAssertNotNil(operation.perShareCompletionBlock)\n        target.perShareCompletionBlock?(\"hello@world.com\", \"share\", nil)\n        XCTAssertTrue(setByCompletionBlock)\n    }\n\n    func test__success_without_completion_block() {\n        wait(for: operation)\n        PKAssertProcedureFinished(operation)\n    }\n\n    func test__success_with_completion_block() {\n        var didExecuteBlock = false\n        operation.setAcceptSharesCompletionBlock { didExecuteBlock = true }\n        wait(for: operation)\n        PKAssertProcedureFinished(operation)\n        XCTAssertTrue(didExecuteBlock)\n    }\n\n    func test__error_without_completion_block() {\n        target.error = TestError()\n        wait(for: operation)\n        PKAssertProcedureFinished(operation)\n    }\n\n    func test__error_with_completion_block() {\n        var didExecuteBlock = false\n        operation.setAcceptSharesCompletionBlock { didExecuteBlock = true }\n        let error = TestError()\n        target.error = error\n        wait(for: operation)\n        PKAssertProcedureFinished(operation, withErrors: true)\n        XCTAssertFalse(didExecuteBlock)\n    }\n}\n\nclass CloudKitProcedureAcceptSharesOperationTests: CKProcedureTestCase {\n    typealias T = TestCKAcceptSharesOperation\n    var shareMetadatas: [T.ShareMetadata]!\n    var setByBlockPerShareCompletionBlock: Bool!\n    var cloudkit: CloudKitProcedure<T>!\n\n    override func setUp() {\n        super.setUp()\n        shareMetadatas = [ \"hello@world.com\" ]\n        setByBlockPerShareCompletionBlock = false\n        cloudkit = CloudKitProcedure(strategy: .immediate) { TestCKAcceptSharesOperation() }\n        cloudkit.container = container\n        cloudkit.shareMetadatas = shareMetadatas\n        cloudkit.perShareCompletionBlock = { [weak self] _, _, _ in\n            self?.setByBlockPerShareCompletionBlock = true\n        }\n    }\n\n    override func tearDown() {\n        shareMetadatas = nil\n        setByBlockPerShareCompletionBlock = false\n        cloudkit = nil\n        super.tearDown()\n    }\n\n    func test__set_get__errorHandlers() {\n        cloudkit.set(errorHandlers: [.internalError: cloudkit.passthroughSuggestedErrorHandler])\n        XCTAssertEqual(cloudkit.errorHandlers.count, 1)\n        XCTAssertNotNil(cloudkit.errorHandlers[.internalError])\n    }\n\n    func test__set_get_container() {\n        cloudkit.container = \"I'm a different container!\"\n        XCTAssertEqual(cloudkit.container, \"I'm a different container!\")\n    }\n\n    func test__set_get_shareMetadatas() {\n        cloudkit.shareMetadatas = [ \"hello-again@world.com\" ]\n        XCTAssertEqual(cloudkit.shareMetadatas, [ \"hello-again@world.com\" ])\n    }\n\n    func test__set_get_perShareCompletionBlock() {\n        XCTAssertNotNil(cloudkit.perShareCompletionBlock)\n        cloudkit.perShareCompletionBlock?(\"share metadata\", \"accepted share\", nil)\n        XCTAssertTrue(setByBlockPerShareCompletionBlock)\n    }\n\n    func test__cancellation() {\n        cloudkit.cancel()\n        wait(for: cloudkit)\n        PKAssertProcedureCancelled(cloudkit)\n    }\n\n    func test__success_without_completion_block_set() {\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n    }\n\n    func test__success_with_completion_block_set() {\n        var didExecuteBlock = false\n        cloudkit.setAcceptSharesCompletionBlock { didExecuteBlock = true }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n        XCTAssertTrue(didExecuteBlock)\n    }\n\n    func test__error_without_completion_block_set() {\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let operation = TestCKAcceptSharesOperation()\n            operation.error = NSError(domain: CKErrorDomain, code: CKError.internalError.rawValue, userInfo: nil)\n            return operation\n        }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n    }\n\n    func test__error_with_completion_block_set() {\n        let error = NSError(domain: CKErrorDomain, code: CKError.internalError.rawValue, userInfo: nil)\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let operation = TestCKAcceptSharesOperation()\n            operation.error = error\n            return operation\n        }\n        var didExecuteBlock = false\n        cloudkit.setAcceptSharesCompletionBlock { didExecuteBlock = true }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit, withErrors: true)\n        XCTAssertFalse(didExecuteBlock)\n    }\n\n    func test__error_which_retries_using_retry_after_key() {\n        var shouldError = true\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let op = TestCKAcceptSharesOperation()\n            if shouldError {\n                let userInfo = [CKErrorRetryAfterKey: NSNumber(value: 0.001)]\n                op.error = NSError(domain: CKErrorDomain, code: CKError.Code.serviceUnavailable.rawValue, userInfo: userInfo)\n                shouldError = false\n            }\n            return op\n        }\n        var didExecuteBlock = false\n        cloudkit.setAcceptSharesCompletionBlock { didExecuteBlock = true }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n        XCTAssertTrue(didExecuteBlock)\n    }\n\n    func test__error_which_retries_using_custom_handler() {\n        var shouldError = true\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let op = TestCKAcceptSharesOperation()\n            if shouldError {\n                op.error = NSError(domain: CKErrorDomain, code: CKError.Code.limitExceeded.rawValue, userInfo: nil)\n                shouldError = false\n            }\n            return op\n        }\n        var didRunCustomHandler = false\n        cloudkit.set(errorHandlerForCode: .limitExceeded) { _, _, _, suggestion in\n            didRunCustomHandler = true\n            return suggestion\n        }\n\n        var didExecuteBlock = false\n        cloudkit.setAcceptSharesCompletionBlock { didExecuteBlock = true }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n        XCTAssertTrue(didExecuteBlock)\n        XCTAssertTrue(didRunCustomHandler)\n    }\n}\n\n#endif\n\n"
  },
  {
    "path": "Tests/ProcedureKitCloudTests/CKDatabaseOperationTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport ProcedureKit\nimport TestingProcedureKit\n@testable import ProcedureKitCloud\n\nclass TestCKDatabaseOperation: TestCKOperation, CKDatabaseOperationProtocol, CKPreviousServerChangeToken, CKResultsLimit, CKMoreComing, CKDesiredKeys {\n    typealias Database = String\n\n    var database: String?\n    var previousServerChangeToken: ServerChangeToken? = nil\n    var resultsLimit: Int = 100\n    var moreComing: Bool = false\n    var desiredKeys: [String]? = nil\n}\n\nclass CKDatabaseOperationTests: CKProcedureTestCase {\n\n    var target: TestCKDatabaseOperation!\n    var operation: CKProcedure<TestCKDatabaseOperation>!\n\n    override func setUp() {\n        super.setUp()\n        target = TestCKDatabaseOperation()\n        operation = CKProcedure(operation: target)\n    }\n\n    override func tearDown() {\n        target = nil\n        operation = nil\n        super.tearDown()\n    }\n\n    func test__set_get__database() {\n        let database = \"I'm a cloud kit database\"\n        operation.database = database\n        XCTAssertEqual(operation.database, database)\n        XCTAssertEqual(target.database, database)\n    }\n\n    func test__set_get__previousServerChangeToken() {\n        let token = \"I'm a server change token\"\n        operation.previousServerChangeToken = token\n        XCTAssertEqual(operation.previousServerChangeToken, token)\n        XCTAssertEqual(target.previousServerChangeToken, token)\n    }\n\n    func test__set_get__resultsLimits() {\n        let limit: Int = 100\n        operation.resultsLimit = limit\n        XCTAssertEqual(operation.resultsLimit, limit)\n        XCTAssertEqual(target.resultsLimit, limit)\n    }\n\n    func test__get__moreComing() {\n        target.moreComing = true\n        XCTAssertTrue(operation.moreComing)\n        target.moreComing = false\n        XCTAssertFalse(operation.moreComing)\n\n    }\n\n    func test__set_get__desiredKeys() {\n        let keys = [ \"desired-key-1\",  \"desired-key-2\" ]\n        operation.desiredKeys = keys\n        XCTAssertEqual(operation.desiredKeys ?? [], keys)\n        XCTAssertEqual(target.desiredKeys ?? [], keys)\n    }\n}\n"
  },
  {
    "path": "Tests/ProcedureKitCloudTests/CKDiscoverAllUserIdentitiesOperationTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n#if !os(tvOS)\n\nimport XCTest\nimport CloudKit\nimport ProcedureKit\nimport TestingProcedureKit\n@testable import ProcedureKitCloud\n\nclass TestCKDiscoverAllUserIdentitiesOperation: TestCKOperation, CKDiscoverAllUserIdentitiesOperationProtocol, AssociatedErrorProtocol {\n    typealias AssociatedError = PKCKError\n\n    var error: Error?\n    var userIdentityDiscoveredBlock: ((UserIdentity) -> Void)? = nil\n    var discoverAllUserIdentitiesCompletionBlock: ((Error?) -> Void)? = nil\n\n    init(error: Error? = nil) {\n        self.error = error\n        super.init()\n    }\n\n    override func main() {\n        discoverAllUserIdentitiesCompletionBlock?(error)\n    }\n}\n\nclass CKDiscoverAllUserIdentitiesOperationTests: CKProcedureTestCase {\n\n    var target: TestCKDiscoverAllUserIdentitiesOperation!\n    var operation: CKProcedure<TestCKDiscoverAllUserIdentitiesOperation>!\n\n    override func setUp() {\n        super.setUp()\n        target = TestCKDiscoverAllUserIdentitiesOperation()\n        operation = CKProcedure(operation: target)\n    }\n\n    override func tearDown() {\n        target = nil\n        operation = nil\n        super.tearDown()\n    }\n\n    func test__set_get__userIdentityDiscoveredBlock() {\n        var setByCompletionBlock = false\n        let block: (String) -> Void = { identity in\n            setByCompletionBlock = true\n        }\n        operation.userIdentityDiscoveredBlock = block\n        XCTAssertNotNil(operation.userIdentityDiscoveredBlock)\n        target.userIdentityDiscoveredBlock?(\"hello@world.com\")\n        XCTAssertTrue(setByCompletionBlock)\n    }\n\n    func test__success_without_completion_block() {\n        wait(for: operation)\n        PKAssertProcedureFinished(operation)\n    }\n\n    func test__success_with_completion_block() {\n        var didExecuteBlock = false\n        operation.setDiscoverAllUserIdentitiesCompletionBlock { didExecuteBlock = true }\n        wait(for: operation)\n        PKAssertProcedureFinished(operation)\n        XCTAssertTrue(didExecuteBlock)\n    }\n\n    func test__error_without_completion_block() {\n        target.error = TestError()\n        wait(for: operation)\n        PKAssertProcedureFinished(operation)\n    }\n\n    func test__error_with_completion_block() {\n        var didExecuteBlock = false\n        operation.setDiscoverAllUserIdentitiesCompletionBlock { didExecuteBlock = true }\n        let error = TestError()\n        target.error = error\n        wait(for: operation)\n        PKAssertProcedureFinished(operation, withErrors: true)\n        XCTAssertFalse(didExecuteBlock)\n    }\n}\n\nclass CloudKitProcedureDiscoverAllUserIdentitiesOperationTests: CKProcedureTestCase {\n\n    var setByUserIdentityDiscoveredBlock = false\n    var cloudkit: CloudKitProcedure<TestCKDiscoverAllUserIdentitiesOperation>!\n\n    override func setUp() {\n        super.setUp()\n        cloudkit = CloudKitProcedure(strategy: .immediate) { TestCKDiscoverAllUserIdentitiesOperation() }\n        cloudkit.container = container\n        cloudkit.userIdentityDiscoveredBlock = { [weak self] _ in\n            self?.setByUserIdentityDiscoveredBlock = true\n        }\n    }\n\n    override func tearDown() {\n        setByUserIdentityDiscoveredBlock = false\n        cloudkit = nil\n        super.tearDown()\n    }\n\n    func test__set_get__errorHandlers() {\n        cloudkit.set(errorHandlers: [.internalError: cloudkit.passthroughSuggestedErrorHandler])\n        XCTAssertEqual(cloudkit.errorHandlers.count, 1)\n        XCTAssertNotNil(cloudkit.errorHandlers[.internalError])\n    }\n\n    func test__set_get_container() {\n        cloudkit.container = \"I'm a different container!\"\n        XCTAssertEqual(cloudkit.container, \"I'm a different container!\")\n    }\n\n    func test__set_get_userIdentityDiscoveredBlock() {\n        XCTAssertNotNil(cloudkit.userIdentityDiscoveredBlock)\n        cloudkit.userIdentityDiscoveredBlock?(\"user identity\")\n        XCTAssertTrue(setByUserIdentityDiscoveredBlock)\n    }\n\n    func test__cancellation() {\n        cloudkit.cancel()\n        wait(for: cloudkit)\n        PKAssertProcedureCancelled(cloudkit)\n    }\n\n    func test__success_without_completion_block_set() {\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n    }\n\n    func test__success_with_completion_block_set() {\n        var didExecuteBlock = false\n        cloudkit.setDiscoverAllUserIdentitiesCompletionBlock {\n            didExecuteBlock = true\n        }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n        XCTAssertTrue(didExecuteBlock)\n    }\n\n    func test__error_without_completion_block_set() {\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let operation = TestCKDiscoverAllUserIdentitiesOperation()\n            operation.error = NSError(domain: CKErrorDomain, code: CKError.internalError.rawValue, userInfo: nil)\n            return operation\n        }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n    }\n\n    func test__error_with_completion_block_set() {\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let operation = TestCKDiscoverAllUserIdentitiesOperation()\n            operation.error = NSError(domain: CKErrorDomain, code: CKError.internalError.rawValue, userInfo: nil)\n            return operation\n        }\n\n        var didExecuteBlock = false\n        cloudkit.setDiscoverAllUserIdentitiesCompletionBlock {\n            didExecuteBlock = true\n        }\n\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit, withErrors: true)\n        XCTAssertFalse(didExecuteBlock)\n    }\n\n    func test__error_which_retries_using_retry_after_key() {\n        var shouldError = true\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let op = TestCKDiscoverAllUserIdentitiesOperation()\n            if shouldError {\n                let userInfo = [CKErrorRetryAfterKey: NSNumber(value: 0.001)]\n                op.error = NSError(domain: CKErrorDomain, code: CKError.Code.serviceUnavailable.rawValue, userInfo: userInfo)\n                shouldError = false\n            }\n            return op\n        }\n        var didExecuteBlock = false\n        cloudkit.setDiscoverAllUserIdentitiesCompletionBlock { didExecuteBlock = true }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n        XCTAssertTrue(didExecuteBlock)\n    }\n\n    func test__error_which_retries_using_custom_handler() {\n        var shouldError = true\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let op = TestCKDiscoverAllUserIdentitiesOperation()\n            if shouldError {\n                op.error = NSError(domain: CKErrorDomain, code: CKError.Code.limitExceeded.rawValue, userInfo: nil)\n                shouldError = false\n            }\n            return op\n        }\n        var didRunCustomHandler = false\n        cloudkit.set(errorHandlerForCode: .limitExceeded) { _, _, _, suggestion in\n            didRunCustomHandler = true\n            return suggestion\n        }\n\n        var didExecuteBlock = false\n        cloudkit.setDiscoverAllUserIdentitiesCompletionBlock { didExecuteBlock = true }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n        XCTAssertTrue(didExecuteBlock)\n        XCTAssertTrue(didRunCustomHandler)\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Tests/ProcedureKitCloudTests/CKDiscoverUserIdentitiesOperationTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport CloudKit\nimport ProcedureKit\nimport TestingProcedureKit\n@testable import ProcedureKitCloud\n\nclass TestCKDiscoverUserIdentitiesOperation: TestCKOperation, CKDiscoverUserIdentitiesOperationProtocol, AssociatedErrorProtocol {\n    typealias AssociatedError = PKCKError\n\n    var error: Error?\n    var userIdentityLookupInfos: [UserIdentityLookupInfo] = []\n    var userIdentityDiscoveredBlock: ((UserIdentity, UserIdentityLookupInfo) -> Void)? = nil\n    var discoverUserIdentitiesCompletionBlock: ((Error?) -> Void)? = nil\n\n    init(error: Error? = nil) {\n        self.error = error\n        super.init()\n    }\n\n    override func main() {\n        discoverUserIdentitiesCompletionBlock?(error)\n    }\n}\n\nclass CKDiscoverUserIdentitiesOperationTests: CKProcedureTestCase {\n\n    var target: TestCKDiscoverUserIdentitiesOperation!\n    var operation: CKProcedure<TestCKDiscoverUserIdentitiesOperation>!\n\n    override func setUp() {\n        super.setUp()\n        target = TestCKDiscoverUserIdentitiesOperation()\n        operation = CKProcedure(operation: target)\n    }\n\n    override func tearDown() {\n        target = nil\n        operation = nil\n        super.tearDown()\n    }\n\n    func test__set_get__userIdentityLookupInfos() {\n        let userIdentityLookupInfos = [ \"hello@world.com\" ]\n        operation.userIdentityLookupInfos = userIdentityLookupInfos\n        XCTAssertEqual(operation.userIdentityLookupInfos, userIdentityLookupInfos)\n        XCTAssertEqual(target.userIdentityLookupInfos, userIdentityLookupInfos)\n    }\n\n    func test__set_get__userIdentityDiscoveredBlock() {\n        var setByCompletionBlock = false\n        let block: (String, String) -> Void = { identity, lookupInfo in\n            setByCompletionBlock = true\n        }\n        operation.userIdentityDiscoveredBlock = block\n        XCTAssertNotNil(operation.userIdentityDiscoveredBlock)\n        target.userIdentityDiscoveredBlock?(\"Example\", \"hello@world.com\")\n        XCTAssertTrue(setByCompletionBlock)\n    }\n\n    func test__success_without_completion_block() {\n        wait(for: operation)\n        PKAssertProcedureFinished(operation)\n    }\n\n    func test__success_with_completion_block() {\n        var didExecuteBlock = false\n        operation.setDiscoverUserIdentitiesCompletionBlock { didExecuteBlock = true }\n        wait(for: operation)\n        PKAssertProcedureFinished(operation)\n        XCTAssertTrue(didExecuteBlock)\n    }\n\n    func test__error_without_completion_block() {\n        target.error = TestError()\n        wait(for: operation)\n        PKAssertProcedureFinished(operation)\n    }\n\n    func test__error_with_completion_block() {\n        var didExecuteBlock = false\n        operation.setDiscoverUserIdentitiesCompletionBlock { didExecuteBlock = true }\n        target.error = TestError()\n        wait(for: operation)\n        PKAssertProcedureFinished(operation, withErrors: true)\n        XCTAssertFalse(didExecuteBlock)\n    }\n}\n\nclass CloudKitProcedureDiscoverUserIdentitiesOperationTests: CKProcedureTestCase {\n\n    var setByUserIdentityDiscoveredBlock = false\n    var cloudkit: CloudKitProcedure<TestCKDiscoverUserIdentitiesOperation>!\n\n    override func setUp() {\n        super.setUp()\n        cloudkit = CloudKitProcedure(strategy: .immediate) { TestCKDiscoverUserIdentitiesOperation() }\n        cloudkit.container = container\n        cloudkit.userIdentityLookupInfos = [ \"user lookup info\" ]\n        cloudkit.userIdentityDiscoveredBlock = { [weak self] _, _ in\n            self?.setByUserIdentityDiscoveredBlock = true\n        }\n    }\n\n    override func tearDown() {\n        setByUserIdentityDiscoveredBlock = false\n        cloudkit = nil\n        super.tearDown()\n    }\n\n    func test__set_get__errorHandlers() {\n        cloudkit.set(errorHandlers: [.internalError: cloudkit.passthroughSuggestedErrorHandler])\n        XCTAssertEqual(cloudkit.errorHandlers.count, 1)\n        XCTAssertNotNil(cloudkit.errorHandlers[.internalError])\n    }\n\n    func test__set_get_container() {\n        cloudkit.container = \"I'm a different container!\"\n        XCTAssertEqual(cloudkit.container, \"I'm a different container!\")\n    }\n\n    func test__set_get_userIdentityLookupInfos() {\n        cloudkit.userIdentityLookupInfos = [ \"user lookup info\" ]\n        XCTAssertEqual(cloudkit.userIdentityLookupInfos, [ \"user lookup info\" ])\n    }\n\n    func test__set_get_userIdentityDiscoveredBlock() {\n        XCTAssertNotNil(cloudkit.userIdentityDiscoveredBlock)\n        cloudkit.userIdentityDiscoveredBlock?(\"user identity\", \"user lookup info\")\n        XCTAssertTrue(setByUserIdentityDiscoveredBlock)\n    }\n\n    func test__cancellation() {\n        cloudkit.cancel()\n        wait(for: cloudkit)\n        PKAssertProcedureCancelled(cloudkit)\n    }\n\n    func test__success_without_completion_block_set() {\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n    }\n\n    func test__success_with_completion_block_set() {\n        var didExecuteBlock = false\n        cloudkit.setDiscoverUserIdentitiesCompletionBlock {\n            didExecuteBlock = true\n        }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n        XCTAssertTrue(didExecuteBlock)\n    }\n\n    func test__error_without_completion_block_set() {\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let operation = TestCKDiscoverUserIdentitiesOperation()\n            operation.error = NSError(domain: CKErrorDomain, code: CKError.internalError.rawValue, userInfo: nil)\n            return operation\n        }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n    }\n\n    func test__error_with_completion_block_set() {\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let operation = TestCKDiscoverUserIdentitiesOperation()\n            operation.error = NSError(domain: CKErrorDomain, code: CKError.internalError.rawValue, userInfo: nil)\n            return operation\n        }\n\n        var didExecuteBlock = false\n        cloudkit.setDiscoverUserIdentitiesCompletionBlock {\n            didExecuteBlock = true\n        }\n\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit, withErrors: true)\n        XCTAssertFalse(didExecuteBlock)\n    }\n\n    func test__error_which_retries_using_retry_after_key() {\n        var shouldError = true\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let op = TestCKDiscoverUserIdentitiesOperation()\n            if shouldError {\n                let userInfo = [CKErrorRetryAfterKey: NSNumber(value: 0.001)]\n                op.error = NSError(domain: CKErrorDomain, code: CKError.Code.serviceUnavailable.rawValue, userInfo: userInfo)\n                shouldError = false\n            }\n            return op\n        }\n        var didExecuteBlock = false\n        cloudkit.setDiscoverUserIdentitiesCompletionBlock { didExecuteBlock = true }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n        XCTAssertTrue(didExecuteBlock)\n    }\n\n    func test__error_which_retries_using_custom_handler() {\n        var shouldError = true\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let op = TestCKDiscoverUserIdentitiesOperation()\n            if shouldError {\n                op.error = NSError(domain: CKErrorDomain, code: CKError.Code.limitExceeded.rawValue, userInfo: nil)\n                shouldError = false\n            }\n            return op\n        }\n        var didRunCustomHandler = false\n        cloudkit.set(errorHandlerForCode: .limitExceeded) { _, _, _, suggestion in\n            didRunCustomHandler = true\n            return suggestion\n        }\n\n        var didExecuteBlock = false\n        cloudkit.setDiscoverUserIdentitiesCompletionBlock { didExecuteBlock = true }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n        XCTAssertTrue(didExecuteBlock)\n        XCTAssertTrue(didRunCustomHandler)\n    }\n    \n}\n"
  },
  {
    "path": "Tests/ProcedureKitCloudTests/CKFetchAllChangesTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport ProcedureKit\nimport TestingProcedureKit\n@testable import ProcedureKitCloud\n\nclass TestCKFetchAllChangesOperation: TestCKOperation, CKFetchAllChanges {\n    var fetchAllChanges: Bool = true\n}\n\nclass CKFetchAllChangesOperationTests: CKProcedureTestCase {\n\n    var target: TestCKFetchAllChangesOperation!\n    var operation: CKProcedure<TestCKFetchAllChangesOperation>!\n\n    override func setUp() {\n        super.setUp()\n        target = TestCKFetchAllChangesOperation()\n        operation = CKProcedure(operation: target)\n    }\n\n    override func tearDown() {\n        target = nil\n        operation = nil\n        super.tearDown()\n    }\n\n    func test__set_get__fetchAllChanges() {\n        var fetchAllChanges = false\n        operation.fetchAllChanges = fetchAllChanges\n        XCTAssertEqual(operation.fetchAllChanges, fetchAllChanges)\n        XCTAssertEqual(target.fetchAllChanges, fetchAllChanges)\n        fetchAllChanges = true\n        operation.fetchAllChanges = fetchAllChanges\n        XCTAssertEqual(operation.fetchAllChanges, fetchAllChanges)\n        XCTAssertEqual(target.fetchAllChanges, fetchAllChanges)\n    }\n}\n"
  },
  {
    "path": "Tests/ProcedureKitCloudTests/CKFetchDatabaseChangesOperationTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport CloudKit\nimport ProcedureKit\nimport TestingProcedureKit\n@testable import ProcedureKitCloud\n\nclass TestCKFetchDatabaseChangesOperation: TestCKDatabaseOperation, CKFetchDatabaseChangesOperationProtocol, AssociatedErrorProtocol {\n    typealias AssociatedError = FetchDatabaseChangesError<ServerChangeToken>\n\n    var token: String?\n    var error: Error?\n    var fetchAllChanges: Bool = true\n    var recordZoneWithIDChangedBlock: ((RecordZoneID) -> Void)? = nil\n    var recordZoneWithIDWasDeletedBlock: ((RecordZoneID) -> Void)? = nil\n    var changeTokenUpdatedBlock: ((ServerChangeToken) -> Void)? = nil\n    var fetchDatabaseChangesCompletionBlock: ((ServerChangeToken?, Bool, Error?) -> Void)? = nil\n\n    init(token: String? = \"new-token\", moreComing: Bool = false, error: Error? = nil) {\n        self.token = token\n        self.error = error\n        super.init()\n        self.moreComing = moreComing\n    }\n\n    override func main() {\n        fetchDatabaseChangesCompletionBlock?(token, moreComing, error)\n    }\n}\n\nclass CKFetchDatabaseChangesOperationTests: CKProcedureTestCase {\n\n    var target: TestCKFetchDatabaseChangesOperation!\n    var operation: CKProcedure<TestCKFetchDatabaseChangesOperation>!\n\n    override func setUp() {\n        super.setUp()\n        target = TestCKFetchDatabaseChangesOperation()\n        operation = CKProcedure(operation: target)\n    }\n\n    override func tearDown() {\n        target = nil\n        operation = nil\n        super.tearDown()\n    }\n\n    // fetchAllChanges is tested by CKFetchAllChangesTests\n\n    func test__set_get__recordZoneWithIDChangedBlock() {\n        var setByBlock = false\n        let block: (String) -> Void = { zoneID in\n            setByBlock = true\n        }\n        operation.recordZoneWithIDChangedBlock = block\n        XCTAssertNotNil(operation.recordZoneWithIDChangedBlock)\n        target.recordZoneWithIDChangedBlock?(\"zoneID\")\n        XCTAssertTrue(setByBlock)\n    }\n\n    func test__set_get__recordZoneWithIDWasDeletedBlock() {\n        var setByBlock = false\n        let block: (String) -> Void = { zoneID in\n            setByBlock = true\n        }\n        operation.recordZoneWithIDWasDeletedBlock = block\n        XCTAssertNotNil(operation.recordZoneWithIDWasDeletedBlock)\n        target.recordZoneWithIDWasDeletedBlock?(\"zoneID\")\n        XCTAssertTrue(setByBlock)\n    }\n\n    func test__set_get__changeTokenUpdatedBlock() {\n        var setByBlock = false\n        let block: (String) -> Void = { serverChangeToken in\n            setByBlock = true\n        }\n        operation.changeTokenUpdatedBlock = block\n        XCTAssertNotNil(operation.changeTokenUpdatedBlock)\n        target.changeTokenUpdatedBlock?(\"I'm a server change token\")\n        XCTAssertTrue(setByBlock)\n    }\n\n    func test__success_without_completion_block() {\n        wait(for: operation)\n        PKAssertProcedureFinished(operation)\n    }\n\n    func test__success_with_completion_block() {\n        var didExecuteBlock = false\n        operation.setFetchDatabaseChangesCompletionBlock { _, _ in\n            didExecuteBlock = true\n        }\n        wait(for: operation)\n        PKAssertProcedureFinished(operation)\n        XCTAssertTrue(didExecuteBlock)\n    }\n\n    func test__error_without_completion_block() {\n        target.error = TestError()\n        wait(for: operation)\n        PKAssertProcedureFinished(operation)\n    }\n\n    func test__error_with_completion_block() {\n        var didExecuteBlock = false\n        operation.setFetchDatabaseChangesCompletionBlock { _, _ in\n            didExecuteBlock = true\n        }\n        let error = TestError()\n        target.error = error\n        wait(for: operation)\n        PKAssertProcedureFinished(operation, withErrors: true)\n        XCTAssertFalse(didExecuteBlock)\n    }\n}\n\nclass CloudKitProcedureFetchDatabaseChangesOperationTests: CKProcedureTestCase {\n\n    var cloudkit: CloudKitProcedure<TestCKFetchDatabaseChangesOperation>!\n\n    var setByRecordZoneWithIDChangedBlock: TestCKFetchDatabaseChangesOperation.RecordZoneID!\n    var setByRecordZoneWithIDWasDeletedBlock: TestCKFetchDatabaseChangesOperation.RecordZoneID!\n    var setByChangeTokenUpdatedBlock: TestCKFetchDatabaseChangesOperation.ServerChangeToken!\n\n    override func setUp() {\n        super.setUp()\n        cloudkit = CloudKitProcedure(strategy: .immediate) { TestCKFetchDatabaseChangesOperation() }\n        cloudkit.container = container\n        cloudkit.database = database\n        cloudkit.previousServerChangeToken = token\n        cloudkit.resultsLimit = 10\n        cloudkit.fetchAllChanges = true\n        cloudkit.recordZoneWithIDChangedBlock = { [unowned self] recordZoneID in\n            self.setByRecordZoneWithIDChangedBlock = recordZoneID\n        }\n        cloudkit.recordZoneWithIDWasDeletedBlock = { [unowned self] recordZoneID in\n            self.setByRecordZoneWithIDWasDeletedBlock = recordZoneID\n        }\n        cloudkit.changeTokenUpdatedBlock = { [unowned self] token in\n            self.setByChangeTokenUpdatedBlock = token\n        }\n    }\n\n    override func tearDown() {\n        cloudkit = nil\n        setByRecordZoneWithIDChangedBlock = nil\n        setByRecordZoneWithIDWasDeletedBlock = nil\n        setByChangeTokenUpdatedBlock = nil\n        super.tearDown()\n    }\n\n    func test__set_get__errorHandlers() {\n        cloudkit.set(errorHandlers: [.internalError: cloudkit.passthroughSuggestedErrorHandler])\n        XCTAssertEqual(cloudkit.errorHandlers.count, 1)\n        XCTAssertNotNil(cloudkit.errorHandlers[.internalError])\n    }\n\n    func test__set_get_container() {\n        cloudkit.container = \"I'm a different container!\"\n        XCTAssertEqual(cloudkit.container, \"I'm a different container!\")\n    }\n\n    func test__set_get_database() {\n        cloudkit.database = \"I'm a different database!\"\n        XCTAssertEqual(cloudkit.database, \"I'm a different database!\")\n    }\n\n    func test__set_get_previousServerChangeToken() {\n        cloudkit.previousServerChangeToken = \"I'm a different token!\"\n        XCTAssertEqual(cloudkit.previousServerChangeToken, \"I'm a different token!\")\n    }\n\n    func test__set_get_resultsLimit() {\n        cloudkit.resultsLimit = 20\n        XCTAssertEqual(cloudkit.resultsLimit, 20)\n    }\n\n    func test__set_get_fetchAllChanges() {\n        cloudkit.fetchAllChanges = false\n        XCTAssertEqual(cloudkit.fetchAllChanges, false)\n    }\n\n    func test__set_get_recordZoneWithIDChangedBlock() {\n        XCTAssertNotNil(cloudkit.recordZoneWithIDChangedBlock)\n        cloudkit.recordZoneWithIDChangedBlock?(\"record zone ID\")\n        XCTAssertEqual(setByRecordZoneWithIDChangedBlock, \"record zone ID\")\n    }\n\n    func test__set_get_recordZoneWithIDWasDeletedBlock() {\n        XCTAssertNotNil(cloudkit.recordZoneWithIDWasDeletedBlock)\n        cloudkit.recordZoneWithIDWasDeletedBlock?(\"record zone ID\")\n        XCTAssertEqual(setByRecordZoneWithIDWasDeletedBlock, \"record zone ID\")\n    }\n\n    func test__set_get_changeTokenUpdatedBlock() {\n        XCTAssertNotNil(cloudkit.changeTokenUpdatedBlock)\n        cloudkit.changeTokenUpdatedBlock?(\"new change token\")\n        XCTAssertEqual(setByChangeTokenUpdatedBlock, \"new change token\")\n    }\n\n    func test__cancellation() {\n        cloudkit.cancel()\n        wait(for: cloudkit)\n        PKAssertProcedureCancelled(cloudkit)\n    }\n\n    func test__success_without_completion_block_set() {\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n    }\n\n    func test__success_with_completion_block_set() {\n        var didExecuteBlock = false\n        cloudkit.setFetchDatabaseChangesCompletionBlock { _, _ in\n            didExecuteBlock = true\n        }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n        XCTAssertTrue(didExecuteBlock)\n    }\n\n    func test__error_without_completion_block_set() {\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let operation = TestCKFetchDatabaseChangesOperation()\n            operation.error = NSError(domain: CKErrorDomain, code: CKError.internalError.rawValue, userInfo: nil)\n            return operation\n        }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n    }\n\n    func test__error_with_completion_block_set() {\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let operation = TestCKFetchDatabaseChangesOperation()\n            operation.error = NSError(domain: CKErrorDomain, code: CKError.internalError.rawValue, userInfo: nil)\n            return operation\n        }\n        var didExecuteBlock = false\n        cloudkit.setFetchDatabaseChangesCompletionBlock { _, _ in\n            didExecuteBlock = true\n        }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit, withErrors: true)\n        XCTAssertFalse(didExecuteBlock)\n    }\n\n    func test__error_which_retries_using_retry_after_key() {\n        var shouldError = true\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let op = TestCKFetchDatabaseChangesOperation()\n            if shouldError {\n                let userInfo = [CKErrorRetryAfterKey: NSNumber(value: 0.001)]\n                op.error = NSError(domain: CKErrorDomain, code: CKError.Code.serviceUnavailable.rawValue, userInfo: userInfo)\n                shouldError = false\n            }\n            return op\n        }\n        var didExecuteBlock = false\n        cloudkit.setFetchDatabaseChangesCompletionBlock { _, _ in didExecuteBlock = true }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n        XCTAssertTrue(didExecuteBlock)\n    }\n\n    func test__error_which_retries_using_custom_handler() {\n        var shouldError = true\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let op = TestCKFetchDatabaseChangesOperation()\n            if shouldError {\n                op.error = NSError(domain: CKErrorDomain, code: CKError.Code.limitExceeded.rawValue, userInfo: nil)\n                shouldError = false\n            }\n            return op\n        }\n        var didRunCustomHandler = false\n        cloudkit.set(errorHandlerForCode: .limitExceeded) { _, _, _, suggestion in\n            didRunCustomHandler = true\n            return suggestion\n        }\n\n        var didExecuteBlock = false\n        cloudkit.setFetchDatabaseChangesCompletionBlock { _, _ in didExecuteBlock = true }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n        XCTAssertTrue(didExecuteBlock)\n        XCTAssertTrue(didRunCustomHandler)\n    }\n    \n}\n"
  },
  {
    "path": "Tests/ProcedureKitCloudTests/CKFetchNotificationChangesOperationTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport CloudKit\nimport ProcedureKit\nimport TestingProcedureKit\n@testable import ProcedureKitCloud\n\nclass TestCKFetchNotificationChangesOperation: TestCKOperation, CKFetchNotificationChangesOperationProtocol, AssociatedErrorProtocol {\n    typealias AssociatedError = FetchNotificationChangesError<ServerChangeToken>\n\n    var error: Error? = nil\n    var finalPreviousServerChangeToken: ServerChangeToken? = nil\n    var changedNotifications: [Notification]? = nil\n    var previousServerChangeToken: ServerChangeToken? = nil\n    var resultsLimit: Int = 100\n    var moreComing: Bool = false\n    var notificationChangedBlock: ((Notification) -> Void)? = nil\n    var fetchNotificationChangesCompletionBlock: ((ServerChangeToken?, Error?) -> Void)? = nil\n\n    init(token: ServerChangeToken? = nil, error: Error? = nil) {\n        self.finalPreviousServerChangeToken = token\n        self.error = error\n        super.init()\n    }\n\n    override func main() {\n        if let changes = changedNotifications, let block = notificationChangedBlock {\n            if changes.count > 0 {\n                changes.forEach(block)\n            }\n        }\n        fetchNotificationChangesCompletionBlock?(finalPreviousServerChangeToken, error)\n    }\n}\n\nclass CKFetchNotificationChangesOperationTests: CKProcedureTestCase {\n\n    var target: TestCKFetchNotificationChangesOperation!\n    var operation: CKProcedure<TestCKFetchNotificationChangesOperation>!\n\n    override func setUp() {\n        super.setUp()\n        target = TestCKFetchNotificationChangesOperation()\n        operation = CKProcedure(operation: target)\n    }\n\n    override func tearDown() {\n        target = nil\n        operation = nil\n        super.tearDown()\n    }\n\n    func test__set_get__previousServerChangeToken() {\n        let previousServerChangeToken: String = \"I'm a server token\"\n        operation.previousServerChangeToken = previousServerChangeToken\n        XCTAssertEqual(operation.previousServerChangeToken, previousServerChangeToken)\n        XCTAssertEqual(target.previousServerChangeToken, previousServerChangeToken)\n    }\n    \n    func test__set_get__resultsLimits() {\n        let limit: Int = 100\n        operation.resultsLimit = limit\n        XCTAssertEqual(operation.resultsLimit, limit)\n        XCTAssertEqual(target.resultsLimit, limit)\n    }\n\n    func test__get__moreComing() {\n        target.moreComing = true\n        XCTAssertTrue(operation.moreComing)\n        target.moreComing = false\n        XCTAssertFalse(operation.moreComing)\n    }\n\n    func test__set_get__notificationChangedBlock() {\n        var setByBlock = false\n        let block: (String) -> Void = { notification in\n            setByBlock = true\n        }\n        operation.notificationChangedBlock = block\n        XCTAssertNotNil(operation.notificationChangedBlock)\n        target.notificationChangedBlock?(\"notification\")\n        XCTAssertTrue(setByBlock)\n    }\n\n    func test__success_without_completion_block() {\n        wait(for: operation)\n        PKAssertProcedureFinished(operation)\n    }\n\n    func test__success_with_completion_block() {\n        var didExecuteBlock = false\n        operation.setFetchNotificationChangesCompletionBlock { _ in\n            didExecuteBlock = true\n        }\n        wait(for: operation)\n        PKAssertProcedureFinished(operation)\n        XCTAssertTrue(didExecuteBlock)\n    }\n\n    func test__error_without_completion_block() {\n        target.error = TestError()\n        wait(for: operation)\n        PKAssertProcedureFinished(operation)\n    }\n\n    func test__error_with_completion_block() {\n        var didExecuteBlock = false\n        operation.setFetchNotificationChangesCompletionBlock { _ in\n            didExecuteBlock = true\n        }\n        target.error = TestError()\n        wait(for: operation)\n        PKAssertProcedureFinished(operation, withErrors: true)\n        XCTAssertFalse(didExecuteBlock)\n    }\n}\n\nclass CloudKitProcedureFetchNotificationChangesOperationTests: CKProcedureTestCase {\n\n    var cloudkit: CloudKitProcedure<TestCKFetchNotificationChangesOperation>!\n\n    var setByNotificationChangedBlock: TestCKFetchNotificationChangesOperation.Notification!\n\n    override func setUp() {\n        super.setUp()\n        cloudkit = CloudKitProcedure(strategy: .immediate) { TestCKFetchNotificationChangesOperation() }\n        cloudkit.container = container\n        cloudkit.previousServerChangeToken = token\n        cloudkit.resultsLimit = 10\n        cloudkit.notificationChangedBlock = { [unowned self] notification in\n            self.setByNotificationChangedBlock = notification\n        }\n    }\n\n    override func tearDown() {\n        cloudkit = nil\n        setByNotificationChangedBlock = nil\n        super.tearDown()\n    }\n\n    func test__set_get__errorHandlers() {\n        cloudkit.set(errorHandlers: [.internalError: cloudkit.passthroughSuggestedErrorHandler])\n        XCTAssertEqual(cloudkit.errorHandlers.count, 1)\n        XCTAssertNotNil(cloudkit.errorHandlers[.internalError])\n    }\n\n    func test__set_get_container() {\n        cloudkit.container = \"I'm a different container!\"\n        XCTAssertEqual(cloudkit.container, \"I'm a different container!\")\n    }\n\n    func test__set_get_previousServerChangeToken() {\n        cloudkit.previousServerChangeToken = \"I'm a different token!\"\n        XCTAssertEqual(cloudkit.previousServerChangeToken, \"I'm a different token!\")\n    }\n\n    func test__set_get_resultsLimit() {\n        cloudkit.resultsLimit = 20\n        XCTAssertEqual(cloudkit.resultsLimit, 20)\n    }\n\n    func test__set_get_notificationChangedBlock() {\n        XCTAssertNotNil(cloudkit.notificationChangedBlock)\n        cloudkit.notificationChangedBlock?(\"a notification\")\n        XCTAssertEqual(setByNotificationChangedBlock, \"a notification\")\n    }\n\n    func test__cancellation() {\n        cloudkit.cancel()\n        wait(for: cloudkit)\n        PKAssertProcedureCancelled(cloudkit)\n    }\n\n    func test__success_without_completion_block_set() {\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n    }\n\n    func test__success_with_completion_block_set() {\n        var didExecuteBlock = false\n        cloudkit.setFetchNotificationChangesCompletionBlock { _ in\n            didExecuteBlock = true\n        }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n        XCTAssertTrue(didExecuteBlock)\n    }\n\n    func test__error_without_completion_block_set() {\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let operation = TestCKFetchNotificationChangesOperation()\n            operation.error = NSError(domain: CKErrorDomain, code: CKError.internalError.rawValue, userInfo: nil)\n            return operation\n        }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n    }\n\n    func test__error_with_completion_block_set() {\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let operation = TestCKFetchNotificationChangesOperation()\n            operation.error = NSError(domain: CKErrorDomain, code: CKError.internalError.rawValue, userInfo: nil)\n            return operation\n        }\n\n        var didExecuteBlock = false\n        cloudkit.setFetchNotificationChangesCompletionBlock { _ in\n            didExecuteBlock = true\n        }\n\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit, withErrors: true)\n        XCTAssertFalse(didExecuteBlock)\n    }\n\n    func test__error_which_retries_using_retry_after_key() {\n        var shouldError = true\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let op = TestCKFetchNotificationChangesOperation()\n            if shouldError {\n                let userInfo = [CKErrorRetryAfterKey: NSNumber(value: 0.001)]\n                op.error = NSError(domain: CKErrorDomain, code: CKError.Code.serviceUnavailable.rawValue, userInfo: userInfo)\n                shouldError = false\n            }\n            return op\n        }\n        var didExecuteBlock = false\n        cloudkit.setFetchNotificationChangesCompletionBlock { _ in didExecuteBlock = true }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n        XCTAssertTrue(didExecuteBlock)\n    }\n\n    func test__error_which_retries_using_custom_handler() {\n        var shouldError = true\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let op = TestCKFetchNotificationChangesOperation()\n            if shouldError {\n                op.error = NSError(domain: CKErrorDomain, code: CKError.Code.limitExceeded.rawValue, userInfo: nil)\n                shouldError = false\n            }\n            return op\n        }\n        var didRunCustomHandler = false\n        cloudkit.set(errorHandlerForCode: .limitExceeded) { _, _, _, suggestion in\n            didRunCustomHandler = true\n            return suggestion\n        }\n\n        var didExecuteBlock = false\n        cloudkit.setFetchNotificationChangesCompletionBlock { _ in didExecuteBlock = true }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n        XCTAssertTrue(didExecuteBlock)\n        XCTAssertTrue(didRunCustomHandler)\n    }\n    \n}\n"
  },
  {
    "path": "Tests/ProcedureKitCloudTests/CKFetchRecordZoneChangesOperationTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport CloudKit\nimport ProcedureKit\nimport TestingProcedureKit\n@testable import ProcedureKitCloud\n\nclass TestCKFetchRecordZoneChangesOperation: TestCKDatabaseOperation, CKFetchRecordZoneChangesOperationProtocol, AssociatedErrorProtocol {\n\n    typealias AssociatedError = PKCKError\n    typealias FetchRecordZoneChangesOptions = String\n    typealias FetchRecordZoneChangesConfiguration = String\n    typealias ResponseSimulationBlock = ((TestCKFetchRecordZoneChangesOperation) -> Error?)\n    typealias RecordZoneIDsPropertyType = Array<RecordZoneID>\n\n    var responseSimulationBlock: ResponseSimulationBlock? = nil\n    var fetchAllChanges: Bool = true\n    var recordZoneIDs: [RecordZoneID] = [\"zone-id\"]\n    var optionsByRecordZoneID: [RecordZoneID: String]? = nil\n    var configurationsByRecordZoneID: [String : String]?\n    var recordChangedBlock: ((Record) -> Void)? = nil\n    var recordWithIDWasDeletedBlock: ((RecordID, String) -> Void)? = nil\n    var recordZoneChangeTokensUpdatedBlock: ((RecordZoneID, ServerChangeToken?, Data?) -> Void)? = nil\n    var recordZoneFetchCompletionBlock: ((RecordZoneID, ServerChangeToken?, Data?, Bool, Error?) -> Void)? = nil\n    var fetchRecordZoneChangesCompletionBlock: ((Error?) -> Void)? = nil\n\n    init(responseSimulationBlock: ResponseSimulationBlock? = nil) {\n        self.responseSimulationBlock = responseSimulationBlock\n        super.init()\n    }\n\n    override func main() {\n        let outputError = responseSimulationBlock?(self)\n        fetchRecordZoneChangesCompletionBlock?(outputError)\n    }\n\n    func setSimulationOutputError(error: Error) {\n        responseSimulationBlock = { operation in\n            return error\n        }\n    }\n}\n\nclass CKFetchRecordZoneChangesOperationTests: CKProcedureTestCase {\n\n    typealias RecordZoneID = TestCKFetchRecordZoneChangesOperation.RecordZoneID\n\n    var target: TestCKFetchRecordZoneChangesOperation!\n    var operation: CKProcedure<TestCKFetchRecordZoneChangesOperation>!\n\n    override func setUp() {\n        super.setUp()\n        target = TestCKFetchRecordZoneChangesOperation()\n        operation = CKProcedure(operation: target)\n    }\n\n    override func tearDown() {\n        target = nil\n        operation = nil\n        super.tearDown()\n    }\n\n    func test__set_get__recordZoneIDs() {\n        let recordZoneIDs: [RecordZoneID] = [\"I'm a record zone ID\"]\n        operation.recordZoneIDs = recordZoneIDs\n        XCTAssertEqual(operation.recordZoneIDs, recordZoneIDs)\n        XCTAssertEqual(target.recordZoneIDs, recordZoneIDs)\n    }\n\n    @available(iOS, introduced: 10.0, deprecated: 12.0)\n    @available(OSX, introduced: 10.12, deprecated: 10.14)\n    @available(tvOS, introduced: 10.0, deprecated: 12.0)\n    @available(watchOS, introduced: 3.0, deprecated: 5.0)\n    func test__set_get__optionsByRecordZoneID() {\n        let optionsByRecordZoneID = [\"zone-id\": \"testoption\"]\n        operation.optionsByRecordZoneID = optionsByRecordZoneID\n        XCTAssertNotNil(operation.optionsByRecordZoneID)\n        XCTAssertEqual(operation.optionsByRecordZoneID!, optionsByRecordZoneID)\n        XCTAssertNotNil(target.optionsByRecordZoneID)\n        XCTAssertEqual(target.optionsByRecordZoneID!, optionsByRecordZoneID)\n    }\n\n    func test__set_get__recordChangedBlock() {\n        var setByBlock = false\n        let block: (String) -> Void = { record in\n            setByBlock = true\n        }\n        operation.recordChangedBlock = block\n        XCTAssertNotNil(operation.recordChangedBlock)\n        target.recordChangedBlock?(\"I'm a record\")\n        XCTAssertTrue(setByBlock)\n    }\n\n    func test__set_get__recordWithIDWasDeletedBlock() {\n        var setByBlock = false\n        let block: (String, String) -> Void = { recordID, recordType in\n            setByBlock = true\n        }\n        operation.recordWithIDWasDeletedBlock = block\n        XCTAssertNotNil(operation.recordWithIDWasDeletedBlock)\n        target.recordWithIDWasDeletedBlock?(\"I'm a record ID\", \"ExampleType\")\n        XCTAssertTrue(setByBlock)\n    }\n\n    func test__set_get__recordZoneChangeTokensUpdatedBlock() {\n        var setByBlock = false\n        let block: (String, String?, Data?) -> Void = { recordZoneID, serverChangeToken, clientChangeTokenData in\n            setByBlock = true\n        }\n        operation.recordZoneChangeTokensUpdatedBlock = block\n        XCTAssertNotNil(operation.recordZoneChangeTokensUpdatedBlock)\n        target.recordZoneChangeTokensUpdatedBlock?(\"I'm a record ID\", \"I'm a server change token\", nil)\n        XCTAssertTrue(setByBlock)\n    }\n\n    func test__set_get__recordZoneFetchCompletionBlock() {\n        var setByBlock = false\n        let block: (String, String?, Data?, Bool, Error?) -> Void = { recordZoneID, serverChangeToken, clientChangeTokenData, moreComing, recordZoneError in\n            setByBlock = true\n        }\n        operation.recordZoneFetchCompletionBlock = block\n        XCTAssertNotNil(operation.recordZoneFetchCompletionBlock)\n        target.recordZoneFetchCompletionBlock?(\"I'm a record ID\", \"I'm a server change token\", nil, false, nil)\n        XCTAssertTrue(setByBlock)\n    }\n\n    func test__success_without_completion_block() {\n        wait(for: operation)\n        PKAssertProcedureFinished(operation)\n    }\n\n    func test__success_with_completion_block() {\n        var didExecuteBlock = false\n        operation.setFetchRecordZoneChangesCompletionBlock { didExecuteBlock = true }\n        wait(for: operation)\n        PKAssertProcedureFinished(operation)\n        XCTAssertTrue(didExecuteBlock)\n    }\n\n    func test__error_without_completion_block() {\n        target.setSimulationOutputError(error: TestError())\n        wait(for: operation)\n        PKAssertProcedureFinished(operation)\n    }\n\n    func test__error_with_completion_block() {\n        var didExecuteBlock = false\n        operation.setFetchRecordZoneChangesCompletionBlock { didExecuteBlock = true }\n        target.setSimulationOutputError(error: TestError())\n        wait(for: operation)\n        PKAssertProcedureFinished(operation, withErrors: true)\n        XCTAssertFalse(didExecuteBlock)\n    }\n}\n\nclass CloudKitProcedureFetchRecordZoneChangesOperationTests: CKProcedureTestCase {\n    typealias T = TestCKFetchRecordZoneChangesOperation\n    var cloudkit: CloudKitProcedure<T>!\n\n    var setByRecordChangedBlock: T.Record!\n    var setByRecordWithIDWasDeletedBlock: (T.RecordID, String)!\n    var setByRecordZoneChangeTokensUpdatedBlock: (T.RecordZoneID, T.ServerChangeToken?, Data?)!\n    var setByRecordZoneFetchCompletionBlock: (T.RecordZoneID, T.ServerChangeToken?, Data?, Bool, Error?)!\n\n    override func setUp() {\n        super.setUp()\n        cloudkit = CloudKitProcedure(strategy: .immediate) { TestCKFetchRecordZoneChangesOperation() }\n        cloudkit.container = container\n        cloudkit.previousServerChangeToken = token\n        cloudkit.resultsLimit = 10\n        cloudkit.recordZoneIDs = [ \"record zone 1 id\", \"record zone 2 id\" ]\n        if #available(iOS 12.0, OSX 10.14, tvOS 12.0, watchOS 5.0, *) {\n            cloudkit.configurationsByRecordZoneID = [ \"record zone 1 id\": \"configuration 1\", \"record zone 2 id\": \"configuration 2\" ]\n        }\n        else if #available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *) {\n            cloudkit.optionsByRecordZoneID = [ \"record zone 1 id\": \"option 1\", \"record zone 2 id\": \"option 2\" ]\n        }\n        cloudkit.fetchAllChanges = false\n        cloudkit.recordChangedBlock = { [unowned self] record in\n            self.setByRecordChangedBlock = record\n        }\n        cloudkit.recordWithIDWasDeletedBlock = { [unowned self] recordId, type in\n            self.setByRecordWithIDWasDeletedBlock = (recordId, type)\n        }\n        cloudkit.recordZoneChangeTokensUpdatedBlock = { [unowned self] zoneId, token, data in\n            self.setByRecordZoneChangeTokensUpdatedBlock = (zoneId, token, data)\n        }\n        cloudkit.recordZoneFetchCompletionBlock = { [unowned self] zoneId, token, data, isComplete, error in\n            self.setByRecordZoneFetchCompletionBlock = (zoneId, token, data, isComplete, error)\n        }\n    }\n\n    override func tearDown() {\n        cloudkit = nil\n        setByRecordChangedBlock = nil\n        setByRecordWithIDWasDeletedBlock = nil\n        setByRecordZoneChangeTokensUpdatedBlock = nil\n        setByRecordZoneFetchCompletionBlock = nil\n        super.tearDown()\n    }\n\n    func test__set_get__errorHandlers() {\n        cloudkit.set(errorHandlers: [.internalError: cloudkit.passthroughSuggestedErrorHandler])\n        XCTAssertEqual(cloudkit.errorHandlers.count, 1)\n        XCTAssertNotNil(cloudkit.errorHandlers[.internalError])\n    }\n\n    func test__set_get_container() {\n        cloudkit.container = \"I'm a different container!\"\n        XCTAssertEqual(cloudkit.container, \"I'm a different container!\")\n    }\n\n    func test__set_get_previousServerChangeToken() {\n        cloudkit.previousServerChangeToken = \"I'm a different token!\"\n        XCTAssertEqual(cloudkit.previousServerChangeToken, \"I'm a different token!\")\n    }\n\n    func test__set_get_resultsLimit() {\n        cloudkit.resultsLimit = 20\n        XCTAssertEqual(cloudkit.resultsLimit, 20)\n    }\n\n    func test__set_get_fetchAllChanges() {\n        cloudkit.fetchAllChanges = true\n        XCTAssertEqual(cloudkit.fetchAllChanges, true)\n    }\n\n    func test__set_get_recordZoneIDs() {\n        cloudkit.recordZoneIDs = [ \"record zone 1 id\", \"record zone 2 id\" ]\n        XCTAssertEqual(cloudkit.recordZoneIDs, [ \"record zone 1 id\", \"record zone 2 id\" ])\n    }\n\n    @available(iOS, introduced: 10.0, deprecated: 12.0)\n    @available(OSX, introduced: 10.12, deprecated: 10.14)\n    @available(tvOS, introduced: 10.0, deprecated: 12.0)\n    @available(watchOS, introduced: 3.0, deprecated: 5.0)\n    func test__set_get_optionsByRecordZoneID() {\n        cloudkit.optionsByRecordZoneID = [ \"record zone 1 id\": \"option 1\", \"record zone 2 id\": \"option 2\" ]\n        XCTAssertEqual(cloudkit.optionsByRecordZoneID ?? [:], [ \"record zone 1 id\": \"option 1\", \"record zone 2 id\": \"option 2\" ])\n    }\n\n    @available(iOS 12.0, OSX 10.14, tvOS 12.0, watchOS 5.0, *)\n    func test__set_get_configurationsByRecordZoneID() {\n        cloudkit.configurationsByRecordZoneID = [ \"record zone 1 id\": \"configuration 1\", \"record zone 2 id\": \"configuration 2\" ]\n        XCTAssertEqual(cloudkit.configurationsByRecordZoneID ?? [:], [ \"record zone 1 id\": \"configuration 1\", \"record zone 2 id\": \"configuration 2\" ])\n    }\n\n    func test__set_get_recordChangedBlock() {\n        XCTAssertNotNil(cloudkit.recordChangedBlock)\n        cloudkit.recordChangedBlock?(\"a record\")\n        XCTAssertEqual(setByRecordChangedBlock, \"a record\")\n    }\n\n    func test__set_get_recordWithIDWasDeletedBlock() {\n        XCTAssertNotNil(cloudkit.recordWithIDWasDeletedBlock)\n        cloudkit.recordWithIDWasDeletedBlock?(\"a record id\", \"record type\")\n        XCTAssertEqual(setByRecordWithIDWasDeletedBlock?.0, \"a record id\")\n        XCTAssertEqual(setByRecordWithIDWasDeletedBlock?.1, \"record type\")\n    }\n\n    func test__set_get_recordZoneChangeTokensUpdatedBlock() {\n        XCTAssertNotNil(cloudkit.recordZoneChangeTokensUpdatedBlock)\n        cloudkit.recordZoneChangeTokensUpdatedBlock?(\"zone id\", \"token\", nil)\n        XCTAssertEqual(setByRecordZoneChangeTokensUpdatedBlock?.0, \"zone id\")\n        XCTAssertEqual(setByRecordZoneChangeTokensUpdatedBlock?.1, \"token\")\n        XCTAssertNil(setByRecordZoneChangeTokensUpdatedBlock?.2)\n    }\n\n    func test__set_get_recordZoneFetchCompletionBlock() {\n        XCTAssertNotNil(cloudkit.recordZoneFetchCompletionBlock)\n        let error = TestError()\n        cloudkit.recordZoneFetchCompletionBlock?(\"zone id\", \"token\", nil, false, error)\n        XCTAssertEqual(setByRecordZoneFetchCompletionBlock?.0, \"zone id\")\n        XCTAssertEqual(setByRecordZoneFetchCompletionBlock?.1, \"token\")\n        XCTAssertNil(setByRecordZoneFetchCompletionBlock?.2)\n        XCTAssertFalse(setByRecordZoneFetchCompletionBlock?.3 ?? true)\n        XCTAssertEqual(setByRecordZoneFetchCompletionBlock?.4 as? TestError ?? TestError(), error)\n    }\n\n    func test__cancellation() {\n        cloudkit.cancel()\n        wait(for: cloudkit)\n        PKAssertProcedureCancelled(cloudkit)\n    }\n\n    func test__success_without_completion_block_set() {\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n    }\n\n    func test__success_with_completion_block_set() {\n        var didExecuteBlock = false\n        cloudkit.setFetchRecordZoneChangesCompletionBlock {\n            didExecuteBlock = true\n        }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n        XCTAssertTrue(didExecuteBlock)\n    }\n\n    func test__error_without_completion_block_set() {\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            return TestCKFetchRecordZoneChangesOperation { _ in\n                NSError(domain: CKErrorDomain, code: CKError.internalError.rawValue, userInfo: nil)\n            }\n        }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n    }\n\n    func test__error_with_completion_block_set() {\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            return TestCKFetchRecordZoneChangesOperation { _ in\n                NSError(domain: CKErrorDomain, code: CKError.internalError.rawValue, userInfo: nil)\n            }\n        }\n\n        var didExecuteBlock = false\n        cloudkit.setFetchRecordZoneChangesCompletionBlock { \n            didExecuteBlock = true\n        }\n\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit, withErrors: true)\n        XCTAssertFalse(didExecuteBlock)\n    }\n}\n\n"
  },
  {
    "path": "Tests/ProcedureKitCloudTests/CKFetchRecordZonesOperationTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport CloudKit\nimport ProcedureKit\nimport TestingProcedureKit\n@testable import ProcedureKitCloud\n\nclass TestCKFetchRecordZonesOperation: TestCKDatabaseOperation, CKFetchRecordZonesOperationProtocol, AssociatedErrorProtocol {\n    typealias AssociatedError = FetchRecordZonesError<RecordZone, RecordZoneID>\n\n    var zonesByID: [RecordZoneID: RecordZone]? = nil\n    var error: Error? = nil\n    var recordZoneIDs: [RecordZoneID]? = nil\n    var fetchRecordZonesCompletionBlock: (([RecordZoneID: RecordZone]?, Error?) -> Void)? = nil\n\n    init(zonesByID: [RecordZoneID: RecordZone]? = nil, error: Error? = nil) {\n        self.zonesByID = zonesByID\n        self.error = error\n        super.init()\n    }\n\n    override func main() {\n        fetchRecordZonesCompletionBlock?(zonesByID, error)\n    }\n}\n\nclass CKFetchRecordZonesOperationTests: CKProcedureTestCase {\n\n    var target: TestCKFetchRecordZonesOperation!\n    var operation: CKProcedure<TestCKFetchRecordZonesOperation>!\n\n    override func setUp() {\n        super.setUp()\n        target = TestCKFetchRecordZonesOperation()\n        operation = CKProcedure(operation: target)\n    }\n\n    override func tearDown() {\n        target = nil\n        operation = nil\n        super.tearDown()\n    }\n\n    func test__set_get__recordZoneIDs() {\n        let recordZoneIDs = [ \"a-zone-id\", \"another-zone-id\" ]\n        operation.recordZoneIDs = recordZoneIDs\n        XCTAssertNotNil(operation.recordZoneIDs)\n        XCTAssertEqual(operation.recordZoneIDs!, recordZoneIDs)\n        XCTAssertNotNil(target.recordZoneIDs)\n        XCTAssertEqual(target.recordZoneIDs!, recordZoneIDs)\n    }\n\n    func test__success_without_completion_block() {\n        wait(for: operation)\n        PKAssertProcedureFinished(operation)\n    }\n\n    func test__success_with_completion_block() {\n        var didExecuteBlock = false\n        operation.setFetchRecordZonesCompletionBlock { _ in\n            didExecuteBlock = true\n        }\n        wait(for: operation)\n        PKAssertProcedureFinished(operation)\n        XCTAssertTrue(didExecuteBlock)\n    }\n\n    func test__error_without_completion_block() {\n        target.error = TestError()\n        wait(for: operation)\n        PKAssertProcedureFinished(operation)\n    }\n\n    func test__error_with_completion_block() {\n        var didExecuteBlock = false\n        operation.setFetchRecordZonesCompletionBlock { _ in\n            didExecuteBlock = true\n        }\n        let error = TestError()\n        target.error = error\n        wait(for: operation)\n        PKAssertProcedureFinished(operation, withErrors: true)\n        XCTAssertFalse(didExecuteBlock)\n    }\n}\n\nclass CloudKitProcedureFetchRecordZonesOperationTests: CKProcedureTestCase {\n    typealias T = TestCKFetchRecordZonesOperation\n    var cloudkit: CloudKitProcedure<T>!\n\n    override func setUp() {\n        super.setUp()\n        cloudkit = CloudKitProcedure(strategy: .immediate) { TestCKFetchRecordZonesOperation() }\n        cloudkit.container = container\n        cloudkit.previousServerChangeToken = token\n        cloudkit.resultsLimit = 10\n        cloudkit.recordZoneIDs = [ \"record zone 1 id\", \"record zone 2 id\" ]\n    }\n\n    override func tearDown() {\n        cloudkit = nil\n        super.tearDown()\n    }\n\n    func test__set_get__errorHandlers() {\n        cloudkit.set(errorHandlers: [.internalError: cloudkit.passthroughSuggestedErrorHandler])\n        XCTAssertEqual(cloudkit.errorHandlers.count, 1)\n        XCTAssertNotNil(cloudkit.errorHandlers[.internalError])\n    }\n\n    func test__set_get_container() {\n        cloudkit.container = \"I'm a different container!\"\n        XCTAssertEqual(cloudkit.container, \"I'm a different container!\")\n    }\n\n    func test__set_get_previousServerChangeToken() {\n        cloudkit.previousServerChangeToken = \"I'm a different token!\"\n        XCTAssertEqual(cloudkit.previousServerChangeToken, \"I'm a different token!\")\n    }\n\n    func test__set_get_resultsLimit() {\n        cloudkit.resultsLimit = 20\n        XCTAssertEqual(cloudkit.resultsLimit, 20)\n    }\n\n    func test__set_get_recordZoneIDs() {\n        cloudkit.recordZoneIDs = [ \"record zone 1 id\", \"record zone 2 id\" ]\n        XCTAssertEqual(cloudkit.recordZoneIDs ?? [], [ \"record zone 1 id\", \"record zone 2 id\" ])\n    }\n\n    func test__cancellation() {\n        cloudkit.cancel()\n        wait(for: cloudkit)\n        PKAssertProcedureCancelled(cloudkit)\n    }\n\n    func test__success_without_completion_block_set() {\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n    }\n\n    func test__success_with_completion_block_set() {\n        var didExecuteBlock = false\n        cloudkit.setFetchRecordZonesCompletionBlock { _ in\n            didExecuteBlock = true\n        }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n        XCTAssertTrue(didExecuteBlock)\n    }\n\n    func test__error_without_completion_block_set() {\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let operation = TestCKFetchRecordZonesOperation()\n            operation.error = NSError(domain: CKErrorDomain, code: CKError.internalError.rawValue, userInfo: nil)\n            return operation\n        }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n    }\n\n    func test__error_with_completion_block_set() {\n        let error = NSError(domain: CKErrorDomain, code: CKError.internalError.rawValue, userInfo: nil)\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let operation = TestCKFetchRecordZonesOperation()\n            operation.error = error\n            return operation\n        }\n\n        var didExecuteBlock = false\n        cloudkit.setFetchRecordZonesCompletionBlock { _ in\n            didExecuteBlock = true\n        }\n\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit, withErrors: true)\n        XCTAssertFalse(didExecuteBlock)\n    }\n\n    func test__error_which_retries_using_retry_after_key() {\n        var shouldError = true\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let op = TestCKFetchRecordZonesOperation()\n            if shouldError {\n                let userInfo = [CKErrorRetryAfterKey: NSNumber(value: 0.001)]\n                op.error = NSError(domain: CKErrorDomain, code: CKError.Code.serviceUnavailable.rawValue, userInfo: userInfo)\n                shouldError = false\n            }\n            return op\n        }\n        var didExecuteBlock = false\n        cloudkit.setFetchRecordZonesCompletionBlock { _ in didExecuteBlock = true }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n        XCTAssertTrue(didExecuteBlock)\n    }\n\n    func test__error_which_retries_using_custom_handler() {\n        var shouldError = true\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let op = TestCKFetchRecordZonesOperation()\n            if shouldError {\n                op.error = NSError(domain: CKErrorDomain, code: CKError.Code.limitExceeded.rawValue, userInfo: nil)\n                shouldError = false\n            }\n            return op\n        }\n        var didRunCustomHandler = false\n        cloudkit.set(errorHandlerForCode: .limitExceeded) { _, _, _, suggestion in\n            didRunCustomHandler = true\n            return suggestion\n        }\n\n        var didExecuteBlock = false\n        cloudkit.setFetchRecordZonesCompletionBlock { _ in didExecuteBlock = true }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n        XCTAssertTrue(didExecuteBlock)\n        XCTAssertTrue(didRunCustomHandler)\n    }\n    \n}\n\n"
  },
  {
    "path": "Tests/ProcedureKitCloudTests/CKFetchRecordsOperationTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport CloudKit\nimport ProcedureKit\nimport TestingProcedureKit\n@testable import ProcedureKitCloud\n\nclass TestCKFetchRecordsOperation: TestCKDatabaseOperation, CKFetchRecordsOperationProtocol, AssociatedErrorProtocol {\n    typealias AssociatedError = FetchRecordsError<Record, RecordID>\n\n    var recordsByID: [RecordID: Record]? = nil\n    var error: Error? = nil\n    var recordIDs: [RecordID]? = nil\n    var perRecordProgressBlock: ((RecordID, Double) -> Void)? = nil\n    var perRecordCompletionBlock: ((Record?, RecordID?, Error?) -> Void)? = nil\n    var fetchRecordsCompletionBlock: (([RecordID: Record]?, Error?) -> Void)? = nil\n\n    init(recordsByID: [RecordID: Record]? = nil, error: Error? = nil) {\n        self.recordsByID = recordsByID\n        self.error = error\n        super.init()\n    }\n\n    override func main() {\n        fetchRecordsCompletionBlock?(recordsByID, error)\n    }\n}\n\nclass CKFetchRecordsOperationTests: CKProcedureTestCase {\n\n    var target: TestCKFetchRecordsOperation!\n    var operation: CKProcedure<TestCKFetchRecordsOperation>!\n\n    override func setUp() {\n        super.setUp()\n        target = TestCKFetchRecordsOperation()\n        operation = CKProcedure(operation: target)\n    }\n\n    override func tearDown() {\n        target = nil\n        operation = nil\n        super.tearDown()\n    }\n\n    func test__set_get__recordIDs() {\n        let recordIDs: [String] = [\"I'm a record ID\"]\n        operation.recordIDs = recordIDs\n        XCTAssertNotNil(operation.recordIDs)\n        XCTAssertEqual(operation.recordIDs!, recordIDs)\n        XCTAssertNotNil(target.recordIDs)\n        XCTAssertEqual(target.recordIDs!, recordIDs)\n    }\n\n    func test__set_get__perRecordProgressBlock() {\n        var setByBlock = false\n        let block: (String, Double) -> Void = { recordID, progress in\n            setByBlock = true\n        }\n        operation.perRecordProgressBlock = block\n        XCTAssertNotNil(operation.perRecordProgressBlock)\n        target.perRecordProgressBlock?(\"I'm a record ID\", 50.0)\n        XCTAssertTrue(setByBlock)\n    }\n\n    func test__set_get__perRecordCompletionBlock() {\n        var setByBlock = false\n        let block: (String?, String?, Error?) -> Void = { record, recordID, error in\n            setByBlock = true\n        }\n        operation.perRecordCompletionBlock = block\n        XCTAssertNotNil(operation.perRecordCompletionBlock)\n        target.perRecordCompletionBlock?(\"I'm a record\", \"I'm a record ID\", nil)\n        XCTAssertTrue(setByBlock)\n    }\n\n    func test__success_without_completion_block() {\n        wait(for: operation)\n        PKAssertProcedureFinished(operation)\n    }\n\n    func test__success_with_completion_block() {\n        var didExecuteBlock = false\n        operation.setFetchRecordsCompletionBlock { _ in\n            didExecuteBlock = true\n        }\n        wait(for: operation)\n        PKAssertProcedureFinished(operation)\n        XCTAssertTrue(didExecuteBlock)\n    }\n\n    func test__error_without_completion_block() {\n        target.error = TestError()\n        wait(for: operation)\n        PKAssertProcedureFinished(operation)\n    }\n\n    func test__error_with_completion_block() {\n        var didExecuteBlock = false\n        operation.setFetchRecordsCompletionBlock { _ in\n            didExecuteBlock = true\n        }\n        target.error = TestError()\n        wait(for: operation)\n        PKAssertProcedureFinished(operation, withErrors: true)\n        XCTAssertFalse(didExecuteBlock)\n    }\n}\n\nclass CloudKitProcedureFetchRecordOperationTests: CKProcedureTestCase {\n\n    var cloudkit: CloudKitProcedure<TestCKFetchRecordsOperation>!\n\n    var setByPerRecordProgressBlock: (TestCKFetchRecordsOperation.RecordID, Double)!\n    var setByPerRecordCompletionBlock: (TestCKFetchRecordsOperation.Record?, TestCKFetchRecordsOperation.RecordID?, Error?)!\n\n    override func setUp() {\n        super.setUp()\n        cloudkit = CloudKitProcedure(strategy: .immediate) { TestCKFetchRecordsOperation() }\n        cloudkit.container = container\n        cloudkit.previousServerChangeToken = token\n        cloudkit.resultsLimit = 10\n        cloudkit.recordIDs = [ \"record 1\", \"record 2\" ]\n        cloudkit.perRecordProgressBlock = { [unowned self] record, progress in\n            self.setByPerRecordProgressBlock = (record, progress)\n        }\n        cloudkit.perRecordCompletionBlock = { [unowned self] record, recordID, error in\n            self.setByPerRecordCompletionBlock = (record, recordID, error)\n        }\n    }\n\n    override func tearDown() {\n        cloudkit = nil\n        setByPerRecordProgressBlock = nil\n        setByPerRecordCompletionBlock = nil\n        super.tearDown()\n    }\n\n    func test__set_get__errorHandlers() {\n        cloudkit.set(errorHandlers: [.internalError: cloudkit.passthroughSuggestedErrorHandler])\n        XCTAssertEqual(cloudkit.errorHandlers.count, 1)\n        XCTAssertNotNil(cloudkit.errorHandlers[.internalError])\n    }\n\n    func test__set_get_container() {\n        cloudkit.container = \"I'm a different container!\"\n        XCTAssertEqual(cloudkit.container, \"I'm a different container!\")\n    }\n\n    func test__set_get_previousServerChangeToken() {\n        cloudkit.previousServerChangeToken = \"I'm a different token!\"\n        XCTAssertEqual(cloudkit.previousServerChangeToken, \"I'm a different token!\")\n    }\n\n    func test__set_get_resultsLimit() {\n        cloudkit.resultsLimit = 20\n        XCTAssertEqual(cloudkit.resultsLimit, 20)\n    }\n\n    func test__set_get_recordIDs() {\n        cloudkit.recordIDs = [ \"record id 3\", \"record id 4\" ]\n        XCTAssertEqual(cloudkit.recordIDs ?? [], [ \"record id 3\", \"record id 4\" ])\n    }\n\n    func test__set_get_perRecordProgressBlock() {\n        XCTAssertNotNil(cloudkit.perRecordProgressBlock)\n        cloudkit.perRecordProgressBlock?(\"a record id\", 0.1)\n        XCTAssertEqual(setByPerRecordProgressBlock?.0, \"a record id\")\n        XCTAssertEqual(setByPerRecordProgressBlock?.1, 0.1)\n    }\n\n    func test__set_get_perRecordCompletionBlock() {\n        let error = TestError()\n        XCTAssertNotNil(cloudkit.perRecordCompletionBlock)\n        cloudkit.perRecordCompletionBlock?(\"a record\", \"a record id\", error)\n        XCTAssertEqual(setByPerRecordCompletionBlock?.0, \"a record\")\n        XCTAssertEqual(setByPerRecordCompletionBlock?.1, \"a record id\")\n        XCTAssertEqual(setByPerRecordCompletionBlock?.2 as? TestError ?? TestError(), error)\n    }\n\n    func test__cancellation() {\n        cloudkit.cancel()\n        wait(for: cloudkit)\n        PKAssertProcedureCancelled(cloudkit)\n    }\n\n    func test__success_without_completion_block_set() {\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n    }\n\n    func test__success_with_completion_block_set() {\n        var didExecuteBlock = false\n        cloudkit.setFetchRecordsCompletionBlock { _ in\n            didExecuteBlock = true\n        }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n        XCTAssertTrue(didExecuteBlock)\n    }\n\n    func test__error_without_completion_block_set() {\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let operation = TestCKFetchRecordsOperation()\n            operation.error = NSError(domain: CKErrorDomain, code: CKError.internalError.rawValue, userInfo: nil)\n            return operation\n        }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n    }\n\n    func test__error_with_completion_block_set() {\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let operation = TestCKFetchRecordsOperation()\n            operation.error = NSError(domain: CKErrorDomain, code: CKError.internalError.rawValue, userInfo: nil)\n            return operation\n        }\n\n        var didExecuteBlock = false\n        cloudkit.setFetchRecordsCompletionBlock { _ in\n            didExecuteBlock = true\n        }\n\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit, withErrors: true)\n        XCTAssertFalse(didExecuteBlock)\n    }\n\n    func test__error_which_retries_using_retry_after_key() {\n        var shouldError = true\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let op = TestCKFetchRecordsOperation()\n            if shouldError {\n                let userInfo = [CKErrorRetryAfterKey: NSNumber(value: 0.001)]\n                op.error = NSError(domain: CKErrorDomain, code: CKError.Code.serviceUnavailable.rawValue, userInfo: userInfo)\n                shouldError = false\n            }\n            return op\n        }\n        var didExecuteBlock = false\n        cloudkit.setFetchRecordsCompletionBlock { _ in didExecuteBlock = true }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n        XCTAssertTrue(didExecuteBlock)\n    }\n\n    func test__error_which_retries_using_custom_handler() {\n        var shouldError = true\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let op = TestCKFetchRecordsOperation()\n            if shouldError {\n                op.error = NSError(domain: CKErrorDomain, code: CKError.Code.limitExceeded.rawValue, userInfo: nil)\n                shouldError = false\n            }\n            return op\n        }\n        var didRunCustomHandler = false\n        cloudkit.set(errorHandlerForCode: .limitExceeded) { _, _, _, suggestion in\n            didRunCustomHandler = true\n            return suggestion\n        }\n\n        var didExecuteBlock = false\n        cloudkit.setFetchRecordsCompletionBlock { _ in didExecuteBlock = true }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n        XCTAssertTrue(didExecuteBlock)\n        XCTAssertTrue(didRunCustomHandler)\n    }\n    \n}\n"
  },
  {
    "path": "Tests/ProcedureKitCloudTests/CKFetchShareMetadataOperationTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport CloudKit\nimport ProcedureKit\nimport TestingProcedureKit\n@testable import ProcedureKitCloud\n\nclass TestCKFetchShareMetadataOperation: TestCKOperation, CKFetchShareMetadataOperationProtocol, AssociatedErrorProtocol {\n    typealias AssociatedError = PKCKError\n\n    var error: Error?\n    var shareURLs: [URL] = []\n    var shouldFetchRootRecord: Bool = false\n    var rootRecordDesiredKeys: [String]? = nil\n    var perShareMetadataBlock: ((URL, ShareMetadata?, Error?) -> Void)? = nil\n    var fetchShareMetadataCompletionBlock: ((Error?) -> Void)? = nil\n\n    init(error: Error? = nil) {\n        self.error = error\n        super.init()\n    }\n\n    override func main() {\n        fetchShareMetadataCompletionBlock?(error)\n    }\n}\n\nclass CKFetchShareMetadataOperationTests: CKProcedureTestCase {\n\n    var target: TestCKFetchShareMetadataOperation!\n    var operation: CKProcedure<TestCKFetchShareMetadataOperation>!\n\n    override func setUp() {\n        super.setUp()\n        target = TestCKFetchShareMetadataOperation()\n        operation = CKProcedure(operation: target)\n    }\n\n    override func tearDown() {\n        target = nil\n        operation = nil\n        super.tearDown()\n    }\n\n    func test__set_get__shareURLs() {\n        let shareURLs = [ URL(string: \"http://example.com\")! ]\n        operation.shareURLs = shareURLs\n        XCTAssertEqual(operation.shareURLs, shareURLs)\n        XCTAssertEqual(target.shareURLs, shareURLs)\n    }\n\n    func test__set_get__shouldFetchRootRecord() {\n        var shouldFetchRootRecord = true\n        operation.shouldFetchRootRecord = shouldFetchRootRecord\n        XCTAssertEqual(operation.shouldFetchRootRecord, shouldFetchRootRecord)\n        XCTAssertEqual(target.shouldFetchRootRecord, shouldFetchRootRecord)\n        shouldFetchRootRecord = false\n        operation.shouldFetchRootRecord = shouldFetchRootRecord\n        XCTAssertEqual(operation.shouldFetchRootRecord, shouldFetchRootRecord)\n        XCTAssertEqual(target.shouldFetchRootRecord, shouldFetchRootRecord)\n    }\n\n    func test__set_get__rootRecordDesiredKeys() {\n        let rootRecordDesiredKeys = [ \"recordKeyExample\" ]\n        operation.rootRecordDesiredKeys = rootRecordDesiredKeys\n        XCTAssertNotNil(operation.rootRecordDesiredKeys)\n        XCTAssertEqual(operation.rootRecordDesiredKeys ?? [], rootRecordDesiredKeys)\n        XCTAssertNotNil(target.rootRecordDesiredKeys)\n        XCTAssertEqual(target.rootRecordDesiredKeys ?? [], rootRecordDesiredKeys)\n    }\n\n    func test__set_get__perShareMetadataBlock() {\n        var setByCompletionBlock = false\n        let block: (URL, String?, Error?) -> Void = { shareURL, shareMetadata, error in\n            setByCompletionBlock = true\n        }\n        operation.perShareMetadataBlock = block\n        XCTAssertNotNil(operation.perShareMetadataBlock)\n        target.perShareMetadataBlock?(URL(string: \"http://example.com\")!, \"share metadata\", nil)\n        XCTAssertTrue(setByCompletionBlock)\n    }\n\n    func test__success_without_completion_block() {\n        wait(for: operation)\n        PKAssertProcedureFinished(operation)\n    }\n\n    func test__success_with_completion_block() {\n        var didExecuteBlock = false\n        operation.setFetchShareMetadataCompletionBlock { didExecuteBlock = true }\n        wait(for: operation)\n        PKAssertProcedureFinished(operation)\n        XCTAssertTrue(didExecuteBlock)\n    }\n\n    func test__error_without_completion_block() {\n        target.error = TestError()\n        wait(for: operation)\n        PKAssertProcedureFinished(operation)\n    }\n\n    func test__error_with_completion_block() {\n        var didExecuteBlock = false\n        operation.setFetchShareMetadataCompletionBlock { didExecuteBlock = true }\n        let error = TestError()\n        target.error = error\n        wait(for: operation)\n        PKAssertProcedureFinished(operation, withErrors: true)\n        XCTAssertFalse(didExecuteBlock)\n    }\n}\n\nclass CloudKitProcedureFetchShareMetadataOperationTests: CKProcedureTestCase {\n    typealias T = TestCKFetchShareMetadataOperation\n    var cloudkit: CloudKitProcedure<T>!\n\n    var setByPerShareMetadataBlock: (URL, T.ShareMetadata?, Error?)!\n\n    override func setUp() {\n        super.setUp()\n        cloudkit = CloudKitProcedure(strategy: .immediate) { TestCKFetchShareMetadataOperation() }\n        cloudkit.container = container\n        cloudkit.shareURLs = [ URL(string: \"http://url.com\")! ]\n        cloudkit.shouldFetchRootRecord = true\n        cloudkit.rootRecordDesiredKeys = [ \"key 1\" ]\n        cloudkit.perShareMetadataBlock = { [unowned self] url, metadata, error in\n            self.setByPerShareMetadataBlock = (url, metadata, error)\n        }\n    }\n\n    override func tearDown() {\n        cloudkit = nil\n        setByPerShareMetadataBlock = nil\n        super.tearDown()\n    }\n\n    func test__set_get__errorHandlers() {\n        cloudkit.set(errorHandlers: [.internalError: cloudkit.passthroughSuggestedErrorHandler])\n        XCTAssertEqual(cloudkit.errorHandlers.count, 1)\n        XCTAssertNotNil(cloudkit.errorHandlers[.internalError])\n    }\n\n    func test__set_get_container() {\n        cloudkit.container = \"I'm a different container!\"\n        XCTAssertEqual(cloudkit.container, \"I'm a different container!\")\n    }\n\n    func test__set_get_shareURLs() {\n        cloudkit.shareURLs = [ URL(string: \"http://different-url.com\")! ]\n        XCTAssertEqual(cloudkit.shareURLs, [ URL(string: \"http://different-url.com\")! ])\n    }\n\n    func test__set_get_shouldFetchRootRecord() {\n        cloudkit.shouldFetchRootRecord = false\n        XCTAssertEqual(cloudkit.shouldFetchRootRecord, false)\n    }\n\n    func test__set_get_rootRecordDesiredKeys() {\n        cloudkit.rootRecordDesiredKeys = [ \"key 1\", \"key 2\" ]\n        XCTAssertEqual(cloudkit.rootRecordDesiredKeys ?? [], [ \"key 1\", \"key 2\" ])\n    }\n\n    func test__set_get_perShareMetadataBlock() {\n        XCTAssertNotNil(cloudkit.perShareMetadataBlock)\n        let url = URL(string: \"http://different-url.com\")!\n        let error = TestError()\n        cloudkit.perShareMetadataBlock?(url, \"metadata\", error)\n        XCTAssertEqual(setByPerShareMetadataBlock?.0, url)\n        XCTAssertEqual(setByPerShareMetadataBlock?.1, \"metadata\")\n        XCTAssertEqual(setByPerShareMetadataBlock?.2 as? TestError ?? TestError(), error)\n    }\n\n    func test__cancellation() {\n        cloudkit.cancel()\n        wait(for: cloudkit)\n        PKAssertProcedureCancelled(cloudkit)\n    }\n\n    func test__success_without_completion_block_set() {\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n    }\n\n    func test__success_with_completion_block_set() {\n        var didExecuteBlock = false\n        cloudkit.setFetchShareMetadataCompletionBlock {\n            didExecuteBlock = true\n        }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n        XCTAssertTrue(didExecuteBlock)\n    }\n\n    func test__error_without_completion_block_set() {\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let operation = TestCKFetchShareMetadataOperation()\n            operation.error = NSError(domain: CKErrorDomain, code: CKError.internalError.rawValue, userInfo: nil)\n            return operation\n        }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n    }\n\n    func test__error_with_completion_block_set() {\n        let error = NSError(domain: CKErrorDomain, code: CKError.internalError.rawValue, userInfo: nil)\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let operation = TestCKFetchShareMetadataOperation()\n            operation.error = error\n            return operation\n        }\n\n        var didExecuteBlock = false\n        cloudkit.setFetchShareMetadataCompletionBlock {\n            didExecuteBlock = true\n        }\n\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit, withErrors: true)\n        XCTAssertFalse(didExecuteBlock)\n    }\n\n    func test__error_which_retries_using_retry_after_key() {\n        var shouldError = true\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let op = TestCKFetchShareMetadataOperation()\n            if shouldError {\n                let userInfo = [CKErrorRetryAfterKey: NSNumber(value: 0.001)]\n                op.error = NSError(domain: CKErrorDomain, code: CKError.Code.serviceUnavailable.rawValue, userInfo: userInfo)\n                shouldError = false\n            }\n            return op\n        }\n        var didExecuteBlock = false\n        cloudkit.setFetchShareMetadataCompletionBlock { didExecuteBlock = true }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n        XCTAssertTrue(didExecuteBlock)\n    }\n\n    func test__error_which_retries_using_custom_handler() {\n        var shouldError = true\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let op = TestCKFetchShareMetadataOperation()\n            if shouldError {\n                op.error = NSError(domain: CKErrorDomain, code: CKError.Code.limitExceeded.rawValue, userInfo: nil)\n                shouldError = false\n            }\n            return op\n        }\n        var didRunCustomHandler = false\n        cloudkit.set(errorHandlerForCode: .limitExceeded) { _, _, _, suggestion in\n            didRunCustomHandler = true\n            return suggestion\n        }\n\n        var didExecuteBlock = false\n        cloudkit.setFetchShareMetadataCompletionBlock { didExecuteBlock = true }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n        XCTAssertTrue(didExecuteBlock)\n        XCTAssertTrue(didRunCustomHandler)\n    }\n    \n}\n\n"
  },
  {
    "path": "Tests/ProcedureKitCloudTests/CKFetchShareParticipantsOperationTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport CloudKit\nimport ProcedureKit\nimport TestingProcedureKit\n@testable import ProcedureKitCloud\n\nclass TestCKFetchShareParticipantsOperation: TestCKOperation, CKFetchShareParticipantsOperationProtocol, AssociatedErrorProtocol {\n    typealias AssociatedError = PKCKError\n\n    var error: Error?\n    var userIdentityLookupInfos: [UserIdentityLookupInfo] = []\n    var shareParticipantFetchedBlock: ((ShareParticipant) -> Void)? = nil\n    var fetchShareParticipantsCompletionBlock: ((Error?) -> Void)? = nil\n\n    init(error: Error? = nil) {\n        self.error = error\n        super.init()\n    }\n\n    override func main() {\n        fetchShareParticipantsCompletionBlock?(error)\n    }\n}\n\nclass CKFetchShareParticipantsOperationTests: CKProcedureTestCase {\n\n    var target: TestCKFetchShareParticipantsOperation!\n    var operation: CKProcedure<TestCKFetchShareParticipantsOperation>!\n\n    override func setUp() {\n        super.setUp()\n        target = TestCKFetchShareParticipantsOperation()\n        operation = CKProcedure(operation: target)\n    }\n\n    override func tearDown() {\n        target = nil\n        operation = nil\n        super.tearDown()\n    }\n\n    func test__set_get__userIdentityLookupInfos() {\n        let userIdentityLookupInfos = [ \"hello@world.com\" ]\n        operation.userIdentityLookupInfos = userIdentityLookupInfos\n        XCTAssertEqual(operation.userIdentityLookupInfos, userIdentityLookupInfos)\n        XCTAssertEqual(target.userIdentityLookupInfos, userIdentityLookupInfos)\n    }\n\n    func test__set_get__shareParticipantFetchedBlock() {\n        var setByCompletionBlock = false\n        let block: (String) -> Void = { participant in\n            setByCompletionBlock = true\n        }\n        operation.shareParticipantFetchedBlock = block\n        XCTAssertNotNil(operation.shareParticipantFetchedBlock)\n        target.shareParticipantFetchedBlock?(\"hello@world.com\")\n        XCTAssertTrue(setByCompletionBlock)\n    }\n\n    func test__success_without_completion_block() {\n        wait(for: operation)\n        PKAssertProcedureFinished(operation)\n    }\n\n    func test__success_with_completion_block() {\n        var didExecuteBlock = false\n        operation.setFetchShareParticipantsCompletionBlock { didExecuteBlock = true }\n        wait(for: operation)\n        PKAssertProcedureFinished(operation)\n        XCTAssertTrue(didExecuteBlock)\n    }\n\n    func test__error_without_completion_block() {\n        target.error = TestError()\n        wait(for: operation)\n        PKAssertProcedureFinished(operation)\n    }\n\n    func test__error_with_completion_block() {\n        var didExecuteBlock = false\n        operation.setFetchShareParticipantsCompletionBlock { didExecuteBlock = true }\n        target.error = TestError()\n        wait(for: operation)\n        PKAssertProcedureFinished(operation, withErrors: true)\n        XCTAssertFalse(didExecuteBlock)\n    }\n}\n\nclass CloudKitProcedureFetchShareParticipantsOperationTests: CKProcedureTestCase {\n    typealias T = TestCKFetchShareParticipantsOperation\n    var cloudkit: CloudKitProcedure<T>!\n\n    var setByShareParticipantFetchedBlock: (T.ShareParticipant)!\n\n    override func setUp() {\n        super.setUp()\n        cloudkit = CloudKitProcedure(strategy: .immediate) { TestCKFetchShareParticipantsOperation() }\n        cloudkit.container = container\n        cloudkit.userIdentityLookupInfos = [ \"user lookup info\" ]\n        cloudkit.shareParticipantFetchedBlock = { self.setByShareParticipantFetchedBlock = $0 }\n    }\n\n    override func tearDown() {\n        cloudkit = nil\n        setByShareParticipantFetchedBlock = nil\n        super.tearDown()\n    }\n\n    func test__set_get__errorHandlers() {\n        cloudkit.set(errorHandlers: [.internalError: cloudkit.passthroughSuggestedErrorHandler])\n        XCTAssertEqual(cloudkit.errorHandlers.count, 1)\n        XCTAssertNotNil(cloudkit.errorHandlers[.internalError])\n    }\n\n    func test__set_get_container() {\n        cloudkit.container = \"I'm a different container!\"\n        XCTAssertEqual(cloudkit.container, \"I'm a different container!\")\n    }\n\n    func test__set_get_userIdentityLookupInfos() {\n        cloudkit.userIdentityLookupInfos = [ \"different user lookup info\" ]\n        XCTAssertEqual(cloudkit.userIdentityLookupInfos, [ \"different user lookup info\" ])\n    }\n\n    func test__set_get_shareParticipantFetchedBlock() {\n        XCTAssertNotNil(cloudkit.shareParticipantFetchedBlock)\n        cloudkit.shareParticipantFetchedBlock?(\"participant\")\n        XCTAssertEqual(setByShareParticipantFetchedBlock ?? \"incorrect\", \"participant\")\n    }\n\n    func test__cancellation() {\n        cloudkit.cancel()\n        wait(for: cloudkit)\n        PKAssertProcedureCancelled(cloudkit)\n    }\n\n    func test__success_without_completion_block_set() {\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n    }\n\n    func test__success_with_completion_block_set() {\n        var didExecuteBlock = false\n        cloudkit.setFetchShareParticipantsCompletionBlock {\n            didExecuteBlock = true\n        }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n        XCTAssertTrue(didExecuteBlock)\n    }\n\n    func test__error_without_completion_block_set() {\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let operation = TestCKFetchShareParticipantsOperation()\n            operation.error = NSError(domain: CKErrorDomain, code: CKError.internalError.rawValue, userInfo: nil)\n            return operation\n        }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n    }\n\n    func test__error_with_completion_block_set() {\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let operation = TestCKFetchShareParticipantsOperation()\n            operation.error = NSError(domain: CKErrorDomain, code: CKError.internalError.rawValue, userInfo: nil)\n            return operation\n        }\n\n        var didExecuteBlock = false\n        cloudkit.setFetchShareParticipantsCompletionBlock {\n            didExecuteBlock = true\n        }\n\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit, withErrors: true)\n        XCTAssertFalse(didExecuteBlock)\n    }\n\n    func test__error_which_retries_using_retry_after_key() {\n        var shouldError = true\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let op = TestCKFetchShareParticipantsOperation()\n            if shouldError {\n                let userInfo = [CKErrorRetryAfterKey: NSNumber(value: 0.001)]\n                op.error = NSError(domain: CKErrorDomain, code: CKError.Code.serviceUnavailable.rawValue, userInfo: userInfo)\n                shouldError = false\n            }\n            return op\n        }\n        var didExecuteBlock = false\n        cloudkit.setFetchShareParticipantsCompletionBlock { didExecuteBlock = true }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n        XCTAssertTrue(didExecuteBlock)\n    }\n\n    func test__error_which_retries_using_custom_handler() {\n        var shouldError = true\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let op = TestCKFetchShareParticipantsOperation()\n            if shouldError {\n                op.error = NSError(domain: CKErrorDomain, code: CKError.Code.limitExceeded.rawValue, userInfo: nil)\n                shouldError = false\n            }\n            return op\n        }\n        var didRunCustomHandler = false\n        cloudkit.set(errorHandlerForCode: .limitExceeded) { _, _, _, suggestion in\n            didRunCustomHandler = true\n            return suggestion\n        }\n\n        var didExecuteBlock = false\n        cloudkit.setFetchShareParticipantsCompletionBlock { didExecuteBlock = true }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n        XCTAssertTrue(didExecuteBlock)\n        XCTAssertTrue(didRunCustomHandler)\n    }\n    \n}\n"
  },
  {
    "path": "Tests/ProcedureKitCloudTests/CKFetchSubscriptionsOperationTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport CloudKit\nimport ProcedureKit\nimport TestingProcedureKit\n@testable import ProcedureKitCloud\n\nclass TestCKFetchSubscriptionsOperation: TestCKDatabaseOperation, CKFetchSubscriptionsOperationProtocol, AssociatedErrorProtocol {\n    typealias AssociatedError = FetchSubscriptionsError<Subscription>\n\n    var subscriptionsByID: [String: Subscription]? = nil\n    var error: Error? = nil\n    var subscriptionIDs: [String]? = nil\n    var fetchSubscriptionCompletionBlock: (([String: Subscription]?, Error?) -> Void)? = nil\n\n    init(subscriptionsByID: [String: Subscription]? = nil, error: Error? = nil) {\n        self.subscriptionsByID = subscriptionsByID\n        self.error = error\n        super.init()\n    }\n\n    override func main() {\n        fetchSubscriptionCompletionBlock?(subscriptionsByID, error)\n    }\n}\n\nclass CKFetchSubscriptionsOperationTests: CKProcedureTestCase {\n\n    var target: TestCKFetchSubscriptionsOperation!\n    var operation: CKProcedure<TestCKFetchSubscriptionsOperation>!\n\n    override func setUp() {\n        super.setUp()\n        target = TestCKFetchSubscriptionsOperation()\n        operation = CKProcedure(operation: target)\n    }\n\n    override func tearDown() {\n        target = nil\n        operation = nil\n        super.tearDown()\n    }\n\n    func test__set_get__subscriptionIDs() {\n        let subscriptionIDs = [ \"an-id\", \"another-id\" ]\n        operation.subscriptionIDs = subscriptionIDs\n        XCTAssertNotNil(operation.subscriptionIDs)\n        XCTAssertEqual(operation.subscriptionIDs ?? [], subscriptionIDs)\n        XCTAssertNotNil(target.subscriptionIDs)\n        XCTAssertEqual(target.subscriptionIDs ?? [], subscriptionIDs)\n    }\n\n    func test__success_without_completion_block() {\n        wait(for: operation)\n        PKAssertProcedureFinished(operation)\n    }\n\n    func test__success_with_completion_block() {\n        var didExecuteBlock = false\n        operation.setFetchSubscriptionCompletionBlock { subscriptionsBySubscriptionID in\n            didExecuteBlock = true\n        }\n        wait(for: operation)\n        PKAssertProcedureFinished(operation)\n        XCTAssertTrue(didExecuteBlock)\n    }\n\n    func test__error_without_completion_block() {\n        target.error = TestError()\n        wait(for: operation)\n        PKAssertProcedureFinished(operation)\n    }\n\n    func test__error_with_completion_block() {\n        var didExecuteBlock = false\n        operation.setFetchSubscriptionCompletionBlock { subscriptionsBySubscriptionID in\n            didExecuteBlock = true\n        }\n        let error = TestError()\n        target.error = error\n        wait(for: operation)\n        PKAssertProcedureFinished(operation, withErrors: true)\n        XCTAssertFalse(didExecuteBlock)\n    }\n}\n\nclass CloudKitProcedureFetchSubscriptionsOperationTests: CKProcedureTestCase {\n    typealias T = TestCKFetchSubscriptionsOperation\n    var cloudkit: CloudKitProcedure<T>!\n\n    override func setUp() {\n        super.setUp()\n        cloudkit = CloudKitProcedure(strategy: .immediate) { TestCKFetchSubscriptionsOperation() }\n        cloudkit.container = container\n        cloudkit.subscriptionIDs = [ \"subscription id 1\", \"subscription id 2\" ]\n    }\n\n    override func tearDown() {\n        cloudkit = nil\n        super.tearDown()\n    }\n\n    func test__set_get__errorHandlers() {\n        cloudkit.set(errorHandlers: [.internalError: cloudkit.passthroughSuggestedErrorHandler])\n        XCTAssertEqual(cloudkit.errorHandlers.count, 1)\n        XCTAssertNotNil(cloudkit.errorHandlers[.internalError])\n    }\n\n    func test__set_get_container() {\n        cloudkit.container = \"I'm a different container!\"\n        XCTAssertEqual(cloudkit.container, \"I'm a different container!\")\n    }\n\n    func test__set_get_subscriptionIDs() {\n        cloudkit.subscriptionIDs = [ \"subscription id 3\", \"subscription id 4\" ]\n        XCTAssertEqual(cloudkit.subscriptionIDs ?? [], [ \"subscription id 3\", \"subscription id 4\" ])\n    }\n\n    func test__cancellation() {\n        cloudkit.cancel()\n        wait(for: cloudkit)\n        PKAssertProcedureCancelled(cloudkit)\n    }\n\n    func test__success_without_completion_block_set() {\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n    }\n\n    func test__success_with_completion_block_set() {\n        var didExecuteBlock = false\n        cloudkit.setFetchSubscriptionCompletionBlock { _ in\n            didExecuteBlock = true\n        }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n        XCTAssertTrue(didExecuteBlock)\n    }\n\n    func test__error_without_completion_block_set() {\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let operation = TestCKFetchSubscriptionsOperation()\n            operation.error = NSError(domain: CKErrorDomain, code: CKError.internalError.rawValue, userInfo: nil)\n            return operation\n        }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n    }\n\n    func test__error_with_completion_block_set() {\n        let error = NSError(domain: CKErrorDomain, code: CKError.internalError.rawValue, userInfo: nil)\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let operation = TestCKFetchSubscriptionsOperation()\n            operation.error = error\n            return operation\n        }\n\n        var didExecuteBlock = false\n        cloudkit.setFetchSubscriptionCompletionBlock { _ in\n            didExecuteBlock = true\n        }\n\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit, withErrors: true)\n        XCTAssertFalse(didExecuteBlock)\n    }\n\n    func test__error_which_retries_using_retry_after_key() {\n        var shouldError = true\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let op = TestCKFetchSubscriptionsOperation()\n            if shouldError {\n                let userInfo = [CKErrorRetryAfterKey: NSNumber(value: 0.001)]\n                op.error = NSError(domain: CKErrorDomain, code: CKError.Code.serviceUnavailable.rawValue, userInfo: userInfo)\n                shouldError = false\n            }\n            return op\n        }\n        var didExecuteBlock = false\n        cloudkit.setFetchSubscriptionCompletionBlock { _ in didExecuteBlock = true }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n        XCTAssertTrue(didExecuteBlock)\n    }\n\n    func test__error_which_retries_using_custom_handler() {\n        var shouldError = true\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let op = TestCKFetchSubscriptionsOperation()\n            if shouldError {\n                op.error = NSError(domain: CKErrorDomain, code: CKError.Code.limitExceeded.rawValue, userInfo: nil)\n                shouldError = false\n            }\n            return op\n        }\n        var didRunCustomHandler = false\n        cloudkit.set(errorHandlerForCode: .limitExceeded) { _, _, _, suggestion in\n            didRunCustomHandler = true\n            return suggestion\n        }\n\n        var didExecuteBlock = false\n        cloudkit.setFetchSubscriptionCompletionBlock { _ in didExecuteBlock = true }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n        XCTAssertTrue(didExecuteBlock)\n        XCTAssertTrue(didRunCustomHandler)\n    }\n    \n}\n\n"
  },
  {
    "path": "Tests/ProcedureKitCloudTests/CKMarkNotificationsReadOperationTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport CloudKit\nimport ProcedureKit\nimport TestingProcedureKit\n@testable import ProcedureKitCloud\n\nclass TestCKMarkNotificationsReadOperation: TestCKOperation, CKMarkNotificationsReadOperationProtocol, AssociatedErrorProtocol {\n    typealias AssociatedError = MarkNotificationsReadError<String>\n\n    var notificationIDs: [String] = []\n    var error: Error? = nil\n    var markNotificationsReadCompletionBlock: (([String]?, Error?) -> Void)? = nil\n\n    init(markIDsToRead: [String] = [], error: Error? = nil) {\n        self.notificationIDs = markIDsToRead\n        self.error = error\n        super.init()\n    }\n\n    override func main() {\n        markNotificationsReadCompletionBlock?(notificationIDs, error)\n    }\n}\n\nclass CKMarkNotificationsReadOperationTests: CKProcedureTestCase {\n\n    var target: TestCKMarkNotificationsReadOperation!\n    var operation: CKProcedure<TestCKMarkNotificationsReadOperation>!\n    var toMark: [TestCKMarkNotificationsReadOperation.NotificationID]!\n\n    override func setUp() {\n        super.setUp()\n        toMark = [ \"this-is-an-id\", \"this-is-another-id\" ]\n        target = TestCKMarkNotificationsReadOperation(markIDsToRead: toMark)\n        operation = CKProcedure(operation: target)\n    }\n\n    override func tearDown() {\n        target = nil\n        operation = nil\n        super.tearDown()\n    }\n\n    func test__set_get__notificationIDs() {\n        let notificationIDs = [ \"an-id\", \"another-id\" ]\n        operation.notificationIDs = notificationIDs\n        XCTAssertEqual(operation.notificationIDs, notificationIDs)\n        XCTAssertEqual(target.notificationIDs, notificationIDs)\n    }\n\n    func test__success_without_completion_block() {\n        wait(for: operation)\n        PKAssertProcedureFinished(operation)\n    }\n\n    func test__success_with_completion_block() {\n        var didExecuteBlock = false\n        var receivedNotificationIDs: [String]?\n        operation.setMarkNotificationsReadCompletionBlock { notificationIDsMarkedRead in\n            didExecuteBlock = true\n            receivedNotificationIDs = notificationIDsMarkedRead\n        }\n        wait(for: operation)\n        PKAssertProcedureFinished(operation)\n        XCTAssertTrue(didExecuteBlock)\n        XCTAssertEqual(receivedNotificationIDs ?? [\"this is not the id you're looking for\"], toMark)\n    }\n\n    func test__error_without_completion_block() {\n        target.error = TestError()\n        wait(for: operation)\n        PKAssertProcedureFinished(operation)\n    }\n\n    func test__error_with_completion_block() {\n        var didExecuteBlock = false\n        operation.setMarkNotificationsReadCompletionBlock { notificationIDsMarkedRead in\n            didExecuteBlock = true\n        }\n        let error = TestError()\n        target.error = error\n        wait(for: operation)\n        PKAssertProcedureFinished(operation, withErrors: true)\n        XCTAssertFalse(didExecuteBlock)\n    }\n}\n\nclass CloudKitProcedureMarkNotificationsReadOperationTests: CKProcedureTestCase {\n    typealias T = TestCKMarkNotificationsReadOperation\n    var cloudkit: CloudKitProcedure<T>!\n\n    override func setUp() {\n        super.setUp()\n        cloudkit = CloudKitProcedure(strategy: .immediate) { TestCKMarkNotificationsReadOperation() }\n        cloudkit.container = container\n        cloudkit.notificationIDs = [ \"notification id 1\", \"notification id 2\" ]\n    }\n\n    override func tearDown() {\n        cloudkit = nil\n        super.tearDown()\n    }\n\n    func test__set_get__errorHandlers() {\n        cloudkit.set(errorHandlers: [.internalError: cloudkit.passthroughSuggestedErrorHandler])\n        XCTAssertEqual(cloudkit.errorHandlers.count, 1)\n        XCTAssertNotNil(cloudkit.errorHandlers[.internalError])\n    }\n\n    func test__set_get_container() {\n        cloudkit.container = \"I'm a different container!\"\n        XCTAssertEqual(cloudkit.container, \"I'm a different container!\")\n    }\n\n    func test__set_get__notificationIDs() {\n        cloudkit.notificationIDs = [ \"notification id 3\", \"notification id 4\" ]\n        XCTAssertEqual(cloudkit.notificationIDs, [ \"notification id 3\", \"notification id 4\" ])\n    }\n\n    func test__cancellation() {\n        cloudkit.cancel()\n        wait(for: cloudkit)\n        PKAssertProcedureCancelled(cloudkit)\n    }\n\n    func test__success_without_completion_block_set() {\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n    }\n\n    func test__success_with_completion_block_set() {\n        var didExecuteBlock = false\n        cloudkit.setMarkNotificationsReadCompletionBlock { _ in\n            didExecuteBlock = true\n        }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n        XCTAssertTrue(didExecuteBlock)\n    }\n\n    func test__error_without_completion_block_set() {\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let operation = TestCKMarkNotificationsReadOperation()\n            operation.error = NSError(domain: CKErrorDomain, code: CKError.internalError.rawValue, userInfo: nil)\n            return operation\n        }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n    }\n\n    func test__error_with_completion_block_set() {\n        let error = NSError(domain: CKErrorDomain, code: CKError.internalError.rawValue, userInfo: nil)\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let operation = TestCKMarkNotificationsReadOperation()\n            operation.error = error\n            return operation\n        }\n\n        var didExecuteBlock = false\n        cloudkit.setMarkNotificationsReadCompletionBlock { _ in\n            didExecuteBlock = true\n        }\n\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit, withErrors: true)\n        XCTAssertFalse(didExecuteBlock)\n    }\n\n    func test__error_which_retries_using_retry_after_key() {\n        var shouldError = true\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let op = TestCKMarkNotificationsReadOperation()\n            if shouldError {\n                let userInfo = [CKErrorRetryAfterKey: NSNumber(value: 0.001)]\n                op.error = NSError(domain: CKErrorDomain, code: CKError.Code.serviceUnavailable.rawValue, userInfo: userInfo)\n                shouldError = false\n            }\n            return op\n        }\n        var didExecuteBlock = false\n        cloudkit.setMarkNotificationsReadCompletionBlock { _ in didExecuteBlock = true }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n        XCTAssertTrue(didExecuteBlock)\n    }\n\n    func test__error_which_retries_using_custom_handler() {\n        var shouldError = true\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let op = TestCKMarkNotificationsReadOperation()\n            if shouldError {\n                op.error = NSError(domain: CKErrorDomain, code: CKError.Code.limitExceeded.rawValue, userInfo: nil)\n                shouldError = false\n            }\n            return op\n        }\n        var didRunCustomHandler = false\n        cloudkit.set(errorHandlerForCode: .limitExceeded) { _, _, _, suggestion in\n            didRunCustomHandler = true\n            return suggestion\n        }\n\n        var didExecuteBlock = false\n        cloudkit.setMarkNotificationsReadCompletionBlock { _ in didExecuteBlock = true }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n        XCTAssertTrue(didExecuteBlock)\n        XCTAssertTrue(didRunCustomHandler)\n    }\n    \n}\n\n"
  },
  {
    "path": "Tests/ProcedureKitCloudTests/CKModifyBadgeOperationTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport CloudKit\nimport ProcedureKit\nimport TestingProcedureKit\n@testable import ProcedureKitCloud\n\nclass TestCKModifyBadgeOperation: TestCKOperation, CKModifyBadgeOperationProtocol, AssociatedErrorProtocol {\n    typealias AssociatedError = PKCKError\n\n    var badgeValue: Int = 0\n    var error: Error? = nil\n    var modifyBadgeCompletionBlock: ((Error?) -> Void)? = nil\n\n    init(value: Int = 0, error: Error? = nil) {\n        self.badgeValue = value\n        self.error = error\n        super.init()\n    }\n\n    override func main() {\n        modifyBadgeCompletionBlock?(error)\n    }\n}\n\nclass CKModifyBadgeOperationTests: CKProcedureTestCase {\n\n    var target: TestCKModifyBadgeOperation!\n    var operation: CKProcedure<TestCKModifyBadgeOperation>!\n    var badge: Int!\n\n    override func setUp() {\n        super.setUp()\n        badge = 9\n        target = TestCKModifyBadgeOperation(value: badge)\n        operation = CKProcedure(operation: target)\n    }\n\n    override func tearDown() {\n        target = nil\n        operation = nil\n        badge = nil\n        super.tearDown()\n    }\n\n    func test__set_get__badgeValue() {\n        let badgeValue = 4\n        operation.badgeValue = badgeValue\n        XCTAssertEqual(operation.badgeValue, badgeValue)\n        XCTAssertEqual(target.badgeValue, badgeValue)\n    }\n\n    func test__success_without_completion_block() {\n        wait(for: operation)\n        PKAssertProcedureFinished(operation)\n    }\n\n    func test__success_with_completion_block() {\n        var didExecuteBlock = false\n        operation.setModifyBadgeCompletionBlock { didExecuteBlock = true }\n        wait(for: operation)\n        PKAssertProcedureFinished(operation)\n        XCTAssertTrue(didExecuteBlock)\n    }\n\n    func test__error_without_completion_block() {\n        target.error = TestError()\n        wait(for: operation)\n        PKAssertProcedureFinished(operation)\n    }\n\n    func test__error_with_completion_block() {\n        var didExecuteBlock = false\n        operation.setModifyBadgeCompletionBlock { didExecuteBlock = true }\n        let error = TestError()\n        target.error = error\n        wait(for: operation)\n        PKAssertProcedureFinished(operation, withErrors: true)\n        XCTAssertFalse(didExecuteBlock)\n    }\n}\n\nclass CloudKitProcedureModifyBadgeOperationTests: CKProcedureTestCase {\n    typealias T = TestCKModifyBadgeOperation\n    var cloudkit: CloudKitProcedure<T>!\n\n    override func setUp() {\n        super.setUp()\n        cloudkit = CloudKitProcedure(strategy: .immediate) { TestCKModifyBadgeOperation() }\n        cloudkit.container = container\n        cloudkit.badgeValue = 10\n    }\n\n    override func tearDown() {\n        cloudkit = nil\n        super.tearDown()\n    }\n\n    func test__set_get__errorHandlers() {\n        cloudkit.set(errorHandlers: [.internalError: cloudkit.passthroughSuggestedErrorHandler])\n        XCTAssertEqual(cloudkit.errorHandlers.count, 1)\n        XCTAssertNotNil(cloudkit.errorHandlers[.internalError])\n    }\n\n    func test__set_get_container() {\n        cloudkit.container = \"I'm a different container!\"\n        XCTAssertEqual(cloudkit.container, \"I'm a different container!\")\n    }\n\n    func test__set_get_badgeValue() {\n        cloudkit.badgeValue = 100\n        XCTAssertEqual(cloudkit.badgeValue, 100)\n    }\n\n    func test__cancellation() {\n        cloudkit.cancel()\n        wait(for: cloudkit)\n        PKAssertProcedureCancelled(cloudkit)\n    }\n\n    func test__success_without_completion_block_set() {\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n    }\n\n    func test__success_with_completion_block_set() {\n        var didExecuteBlock = false\n        cloudkit.setModifyBadgeCompletionBlock {\n            didExecuteBlock = true\n        }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n        XCTAssertTrue(didExecuteBlock)\n    }\n\n    func test__error_without_completion_block_set() {\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let operation = TestCKModifyBadgeOperation()\n            operation.error = NSError(domain: CKErrorDomain, code: CKError.internalError.rawValue, userInfo: nil)\n            return operation\n        }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n    }\n\n    func test__error_with_completion_block_set() {\n        let error = NSError(domain: CKErrorDomain, code: CKError.internalError.rawValue, userInfo: nil)\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let operation = TestCKModifyBadgeOperation()\n            operation.error = error\n            return operation\n        }\n\n        var didExecuteBlock = false\n        cloudkit.setModifyBadgeCompletionBlock {\n            didExecuteBlock = true\n        }\n\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit, withErrors: true)\n        XCTAssertFalse(didExecuteBlock)\n    }\n\n    func test__error_which_retries_using_retry_after_key() {\n        var shouldError = true\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let op = TestCKModifyBadgeOperation()\n            if shouldError {\n                let userInfo = [CKErrorRetryAfterKey: NSNumber(value: 0.001)]\n                op.error = NSError(domain: CKErrorDomain, code: CKError.Code.serviceUnavailable.rawValue, userInfo: userInfo)\n                shouldError = false\n            }\n            return op\n        }\n        var didExecuteBlock = false\n        cloudkit.setModifyBadgeCompletionBlock { didExecuteBlock = true }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n        XCTAssertTrue(didExecuteBlock)\n    }\n\n    func test__error_which_retries_using_custom_handler() {\n        var shouldError = true\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let op = TestCKModifyBadgeOperation()\n            if shouldError {\n                op.error = NSError(domain: CKErrorDomain, code: CKError.Code.limitExceeded.rawValue, userInfo: nil)\n                shouldError = false\n            }\n            return op\n        }\n        var didRunCustomHandler = false\n        cloudkit.set(errorHandlerForCode: .limitExceeded) { _, _, _, suggestion in\n            didRunCustomHandler = true\n            return suggestion\n        }\n\n        var didExecuteBlock = false\n        cloudkit.setModifyBadgeCompletionBlock { didExecuteBlock = true }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n        XCTAssertTrue(didExecuteBlock)\n        XCTAssertTrue(didRunCustomHandler)\n    }\n    \n}\n\n"
  },
  {
    "path": "Tests/ProcedureKitCloudTests/CKModifyRecordZonesOperationTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport CloudKit\nimport ProcedureKit\nimport TestingProcedureKit\n@testable import ProcedureKitCloud\n\nclass TestCKModifyRecordZonesOperation: TestCKDatabaseOperation, CKModifyRecordZonesOperationProtocol, AssociatedErrorProtocol {\n    typealias AssociatedError = ModifyRecordZonesError<RecordZone, RecordZoneID>\n\n    var saved: [RecordZone]? = nil\n    var deleted: [RecordZoneID]? = nil\n    var error: Error? = nil\n    var recordZonesToSave: [RecordZone]? = nil\n    var recordZoneIDsToDelete: [RecordZoneID]? = nil\n    var modifyRecordZonesCompletionBlock: (([RecordZone]?, [RecordZoneID]?, Error?) -> Void)? = nil\n\n    init(saved: [RecordZone]? = nil, deleted: [RecordZoneID]? = nil, error: Error? = nil) {\n        self.saved = saved\n        self.deleted = deleted\n        self.error = error\n        super.init()\n    }\n\n    override func main() {\n        modifyRecordZonesCompletionBlock?(saved, deleted, error)\n    }\n}\n\nclass CKModifyRecordZonesOperationTests: CKProcedureTestCase {\n\n    var target: TestCKModifyRecordZonesOperation!\n    var operation: CKProcedure<TestCKModifyRecordZonesOperation>!\n\n    override func setUp() {\n        super.setUp()\n        target = TestCKModifyRecordZonesOperation()\n        operation = CKProcedure(operation: target)\n    }\n\n    override func tearDown() {\n        target = nil\n        operation = nil\n        super.tearDown()\n    }\n\n    func test__set_get__recordZonesToSave() {\n        let recordZonesToSave = [ \"a-record-zone\", \"another-record-zone\" ]\n        operation.recordZonesToSave = recordZonesToSave\n        XCTAssertNotNil(operation.recordZonesToSave)\n        XCTAssertEqual(operation.recordZonesToSave ?? [], recordZonesToSave)\n        XCTAssertNotNil(target.recordZonesToSave)\n        XCTAssertEqual(target.recordZonesToSave ?? [], recordZonesToSave)\n    }\n\n    func test__set_get__recordZoneIDsToDelete() {\n        let recordZoneIDsToDelete = [ \"a-record-zone-id\", \"another-record-zone-id\" ]\n        operation.recordZoneIDsToDelete = recordZoneIDsToDelete\n        XCTAssertNotNil(operation.recordZoneIDsToDelete)\n        XCTAssertEqual(operation.recordZoneIDsToDelete ?? [], recordZoneIDsToDelete)\n        XCTAssertNotNil(target.recordZoneIDsToDelete)\n        XCTAssertEqual(target.recordZoneIDsToDelete ?? [], recordZoneIDsToDelete)\n    }\n\n    func test__success_without_completion_block() {\n        wait(for: operation)\n        PKAssertProcedureFinished(operation)\n    }\n\n    func test__success_with_completion_block() {\n        var didExecuteBlock = false\n        operation.setModifyRecordZonesCompletionBlock { savedRecordZones, deletedRecordZoneIDs in\n            didExecuteBlock = true\n        }\n        wait(for: operation)\n        PKAssertProcedureFinished(operation)\n        XCTAssertTrue(didExecuteBlock)\n    }\n\n    func test__error_without_completion_block() {\n        target.error = TestError()\n        wait(for: operation)\n        PKAssertProcedureFinished(operation)\n    }\n\n    func test__error_with_completion_block() {\n        var didExecuteBlock = false\n        operation.setModifyRecordZonesCompletionBlock { savedRecordZones, deletedRecordZoneIDs in\n            didExecuteBlock = true\n        }\n        let error = TestError()\n        target.error = error\n        wait(for: operation)\n        PKAssertProcedureFinished(operation, withErrors: true)\n        XCTAssertFalse(didExecuteBlock)\n    }\n}\n\nclass CloudKitProcedureModifyRecordZonesOperationTests: CKProcedureTestCase {\n    typealias T = TestCKModifyRecordZonesOperation\n    var cloudkit: CloudKitProcedure<T>!\n\n    override func setUp() {\n        super.setUp()\n        cloudkit = CloudKitProcedure(strategy: .immediate) { TestCKModifyRecordZonesOperation() }\n        cloudkit.container = container\n        cloudkit.recordZonesToSave = [ \"record zone 1\" ]\n        cloudkit.recordZoneIDsToDelete = [ \"record zone 2 ID\" ]\n    }\n\n    override func tearDown() {\n        cloudkit = nil\n        super.tearDown()\n    }\n\n    func test__set_get__errorHandlers() {\n        cloudkit.set(errorHandlers: [.internalError: cloudkit.passthroughSuggestedErrorHandler])\n        XCTAssertEqual(cloudkit.errorHandlers.count, 1)\n        XCTAssertNotNil(cloudkit.errorHandlers[.internalError])\n    }\n\n    func test__set_get_container() {\n        cloudkit.container = \"I'm a different container!\"\n        XCTAssertEqual(cloudkit.container, \"I'm a different container!\")\n    }\n\n    func test__set_get_database() {\n        cloudkit.database = \"I'm a different database!\"\n        XCTAssertEqual(cloudkit.database, \"I'm a different database!\")\n    }\n\n    func test__set_get_previousServerChangeToken() {\n        cloudkit.previousServerChangeToken = \"I'm a different token!\"\n        XCTAssertEqual(cloudkit.previousServerChangeToken, \"I'm a different token!\")\n    }\n\n    func test__set_get_resultsLimit() {\n        cloudkit.resultsLimit = 20\n        XCTAssertEqual(cloudkit.resultsLimit, 20)\n    }\n\n    func test__set_get_recordZonesToSave() {\n        cloudkit.recordZonesToSave = [ \"record zone 3\" ]\n        XCTAssertEqual(cloudkit.recordZonesToSave ?? [], [ \"record zone 3\" ])\n    }\n\n    func test__set_get_recordZoneIDsToDelete() {\n        cloudkit.recordZoneIDsToDelete = [ \"record zone 4 ID\" ]\n        XCTAssertEqual(cloudkit.recordZoneIDsToDelete ?? [], [ \"record zone 4 ID\" ])\n    }\n\n    func test__cancellation() {\n        cloudkit.cancel()\n        wait(for: cloudkit)\n        PKAssertProcedureCancelled(cloudkit)\n    }\n\n    func test__success_without_completion_block_set() {\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n    }\n\n    func test__success_with_completion_block_set() {\n        var didExecuteBlock = false\n        cloudkit.setModifyRecordZonesCompletionBlock { _, _ in\n            didExecuteBlock = true\n        }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n        XCTAssertTrue(didExecuteBlock)\n    }\n\n    func test__error_without_completion_block_set() {\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let operation = TestCKModifyRecordZonesOperation()\n            operation.error = NSError(domain: CKErrorDomain, code: CKError.internalError.rawValue, userInfo: nil)\n            return operation\n        }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n    }\n\n    func test__error_with_completion_block_set() {\n        let error = NSError(domain: CKErrorDomain, code: CKError.internalError.rawValue, userInfo: nil)\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let operation = TestCKModifyRecordZonesOperation()\n            operation.error = error\n            return operation\n        }\n\n        var didExecuteBlock = false\n        cloudkit.setModifyRecordZonesCompletionBlock { _, _ in\n            didExecuteBlock = true\n        }\n\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit, withErrors: true)\n        XCTAssertFalse(didExecuteBlock)\n    }\n\n    func test__error_which_retries_using_retry_after_key() {\n        var shouldError = true\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let op = TestCKModifyRecordZonesOperation()\n            if shouldError {\n                let userInfo = [CKErrorRetryAfterKey: NSNumber(value: 0.001)]\n                op.error = NSError(domain: CKErrorDomain, code: CKError.Code.serviceUnavailable.rawValue, userInfo: userInfo)\n                shouldError = false\n            }\n            return op\n        }\n        var didExecuteBlock = false\n        cloudkit.setModifyRecordZonesCompletionBlock { _, _ in didExecuteBlock = true }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n        XCTAssertTrue(didExecuteBlock)\n    }\n\n    func test__error_which_retries_using_custom_handler() {\n        var shouldError = true\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let op = TestCKModifyRecordZonesOperation()\n            if shouldError {\n                op.error = NSError(domain: CKErrorDomain, code: CKError.Code.limitExceeded.rawValue, userInfo: nil)\n                shouldError = false\n            }\n            return op\n        }\n        var didRunCustomHandler = false\n        cloudkit.set(errorHandlerForCode: .limitExceeded) { _, _, _, suggestion in\n            didRunCustomHandler = true\n            return suggestion\n        }\n\n        var didExecuteBlock = false\n        cloudkit.setModifyRecordZonesCompletionBlock { _, _ in didExecuteBlock = true }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n        XCTAssertTrue(didExecuteBlock)\n        XCTAssertTrue(didRunCustomHandler)\n    }\n    \n}\n\n"
  },
  {
    "path": "Tests/ProcedureKitCloudTests/CKModifyRecordsOperationTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport CloudKit\nimport ProcedureKit\nimport TestingProcedureKit\n@testable import ProcedureKitCloud\n\nclass TestCKModifyRecordsOperation: TestCKDatabaseOperation, CKModifyRecordsOperationProtocol, AssociatedErrorProtocol {\n    typealias AssociatedError = ModifyRecordsError<Record, RecordID>\n\n    var saved: [Record]?\n    var deleted: [RecordID]?\n    var error: Error?\n    var recordsToSave: [Record]? = nil\n    var recordIDsToDelete: [RecordID]? = nil\n    var savePolicy: RecordSavePolicy = 0\n    var clientChangeTokenData: Data? = nil\n    var isAtomic: Bool = true\n    var perRecordProgressBlock: ((Record, Double) -> Void)? = nil\n    var perRecordCompletionBlock: ((Record?, Error?) -> Void)? = nil\n    var modifyRecordsCompletionBlock: (([Record]?, [RecordID]?, Error?) -> Void)? = nil\n\n    init(saved: [Record]? = nil, deleted: [RecordID]? = nil, error: Error? = nil) {\n        self.saved = saved\n        self.deleted = deleted\n        self.error = error\n        super.init()\n    }\n\n    override func main() {\n        modifyRecordsCompletionBlock?(saved, deleted, error)\n    }\n}\n\nclass CKModifyRecordsOperationTests: CKProcedureTestCase {\n\n    var target: TestCKModifyRecordsOperation!\n    var operation: CKProcedure<TestCKModifyRecordsOperation>!\n\n    override func setUp() {\n        super.setUp()\n        target = TestCKModifyRecordsOperation()\n        operation = CKProcedure(operation: target)\n    }\n\n    override func tearDown() {\n        target = nil\n        operation = nil\n        super.tearDown()\n    }\n\n    func test__set_get__recordsToSave() {\n        let recordsToSave = [ \"a-record\", \"another-record\" ]\n        operation.recordsToSave = recordsToSave\n        XCTAssertNotNil(operation.recordsToSave)\n        XCTAssertEqual(operation.recordsToSave ?? [], recordsToSave)\n        XCTAssertNotNil(target.recordsToSave)\n        XCTAssertEqual(target.recordsToSave ?? [], recordsToSave)\n    }\n\n    func test__set_get__recordIDsToDelete() {\n        let recordIDsToDelete = [ \"a-record-id\", \"another-record-id\" ]\n        operation.recordIDsToDelete = recordIDsToDelete\n        XCTAssertNotNil(operation.recordIDsToDelete)\n        XCTAssertEqual(operation.recordIDsToDelete ?? [], recordIDsToDelete)\n        XCTAssertNotNil(target.recordIDsToDelete)\n        XCTAssertEqual(target.recordIDsToDelete ?? [], recordIDsToDelete)\n    }\n\n    func test__set_get__savePolicy() {\n        let savePolicy = 100\n        operation.savePolicy = savePolicy\n        XCTAssertEqual(operation.savePolicy, savePolicy)\n        XCTAssertEqual(target.savePolicy, savePolicy)\n    }\n\n    func test__set_get__clientChangeTokenData() {\n        let clientChangeTokenData = \"this-is-some-data\".data(using: .utf8)\n        operation.clientChangeTokenData = clientChangeTokenData\n        XCTAssertEqual(operation.clientChangeTokenData, clientChangeTokenData)\n        XCTAssertEqual(target.clientChangeTokenData, clientChangeTokenData)\n    }\n\n    func test__set_get__isAtomic() {\n        var isAtomic = true\n        operation.isAtomic = isAtomic\n        XCTAssertEqual(operation.isAtomic, isAtomic)\n        XCTAssertEqual(target.isAtomic, isAtomic)\n        isAtomic = false\n        operation.isAtomic = isAtomic\n        XCTAssertEqual(operation.isAtomic, isAtomic)\n        XCTAssertEqual(target.isAtomic, isAtomic)\n    }\n\n    func test__set_get__perRecordProgressBlock() {\n        var setByCompletionBlock = false\n        let block: (String, Double) -> Void = { record, progress in\n            setByCompletionBlock = true\n        }\n        operation.perRecordProgressBlock = block\n        XCTAssertNotNil(operation.perRecordProgressBlock)\n        target.perRecordProgressBlock?(\"a-record\", 50.0)\n        XCTAssertTrue(setByCompletionBlock)\n    }\n\n    func test__set_get__perRecordCompletionBlock() {\n        var setByCompletionBlock = false\n        let block: (String?, Error?) -> Void = { record, error in\n            setByCompletionBlock = true\n        }\n        operation.perRecordCompletionBlock = block\n        XCTAssertNotNil(operation.perRecordCompletionBlock)\n        target.perRecordCompletionBlock?(\"a-record\", nil)\n        XCTAssertTrue(setByCompletionBlock)\n    }\n\n    func test__success_without_completion_block() {\n        wait(for: operation)\n        PKAssertProcedureFinished(operation)\n    }\n\n    func test__success_with_completion_block() {\n        var didExecuteBlock = false\n        operation.setModifyRecordsCompletionBlock { savedRecords, deletedRecordIDs in\n            didExecuteBlock = true\n        }\n        wait(for: operation)\n        PKAssertProcedureFinished(operation)\n        XCTAssertTrue(didExecuteBlock)\n    }\n\n    func test__error_without_completion_block() {\n        target.error = TestError()\n        wait(for: operation)\n        PKAssertProcedureFinished(operation)\n    }\n\n    func test__error_with_completion_block() {\n        var didExecuteBlock = false\n        operation.setModifyRecordsCompletionBlock { savedRecords, deletedRecordIDs in\n            didExecuteBlock = true\n        }\n        target.error = TestError()\n        wait(for: operation)\n        PKAssertProcedureFinished(operation, withErrors: true)\n        XCTAssertFalse(didExecuteBlock)\n    }\n}\n\nclass CloudKitProcedureModifyRecordsOperationTests: CKProcedureTestCase {\n    typealias T = TestCKModifyRecordsOperation\n    var cloudkit: CloudKitProcedure<T>!\n\n    var setByPerRecordProgressBlock: CloudKitProcedure<T>.ModifyRecordsPerRecordProgress!\n    var setByPerRecordCompletionBlock: CloudKitProcedure<T>.ModifyRecordsPerRecordCompletion!\n\n    override func setUp() {\n        super.setUp()\n        cloudkit = CloudKitProcedure(strategy: .immediate) { TestCKModifyRecordsOperation() }\n        cloudkit.container = container\n        cloudkit.recordsToSave = [ \"record 1\" ]\n        cloudkit.recordIDsToDelete = [ \"record 2 ID\" ]\n        cloudkit.savePolicy = 1\n        cloudkit.clientChangeTokenData = \"hello-world\".data(using: .utf8)\n        cloudkit.isAtomic = true\n        cloudkit.perRecordProgressBlock = { self.setByPerRecordProgressBlock = ($0, $1) }\n        cloudkit.perRecordCompletionBlock = { self.setByPerRecordCompletionBlock = ($0, $1) }\n    }\n\n    override func tearDown() {\n        cloudkit = nil\n        setByPerRecordProgressBlock = nil\n        setByPerRecordCompletionBlock = nil\n        super.tearDown()\n    }\n\n    func test__set_get__errorHandlers() {\n        cloudkit.set(errorHandlers: [.internalError: cloudkit.passthroughSuggestedErrorHandler])\n        XCTAssertEqual(cloudkit.errorHandlers.count, 1)\n        XCTAssertNotNil(cloudkit.errorHandlers[.internalError])\n    }\n\n    func test__set_get_container() {\n        cloudkit.container = \"I'm a different container!\"\n        XCTAssertEqual(cloudkit.container, \"I'm a different container!\")\n    }\n\n    func test__set_get_database() {\n        cloudkit.database = \"I'm a different database!\"\n        XCTAssertEqual(cloudkit.database, \"I'm a different database!\")\n    }\n\n    func test__set_get_previousServerChangeToken() {\n        cloudkit.previousServerChangeToken = \"I'm a different token!\"\n        XCTAssertEqual(cloudkit.previousServerChangeToken, \"I'm a different token!\")\n    }\n\n    func test__set_get_resultsLimit() {\n        cloudkit.resultsLimit = 20\n        XCTAssertEqual(cloudkit.resultsLimit, 20)\n    }\n\n    func test__set_get_recordsToSave() {\n        cloudkit.recordsToSave = [ \"record 3\" ]\n        XCTAssertEqual(cloudkit.recordsToSave ?? [], [ \"record 3\" ])\n    }\n\n    func test__set_get_recordIDsToDelete() {\n        cloudkit.recordIDsToDelete = [ \"record 4 ID\" ]\n        XCTAssertEqual(cloudkit.recordIDsToDelete ?? [], [ \"record 4 ID\" ])\n    }\n\n    func test__set_get_savePolicy() {\n        cloudkit.savePolicy = 2\n        XCTAssertEqual(cloudkit.savePolicy, 2)\n    }\n\n    func test__set_get__clientChangeTokenData() {\n        let clientChangeTokenData = \"this-is-some-data\".data(using: .utf8)\n        cloudkit.clientChangeTokenData = clientChangeTokenData\n        XCTAssertEqual(cloudkit.clientChangeTokenData, clientChangeTokenData)\n    }\n\n    func test__set_get_isAtomic() {\n        cloudkit.isAtomic = false\n        XCTAssertEqual(cloudkit.isAtomic, false)\n    }\n\n    func test__set_get_perRecordProgressBlock() {\n        XCTAssertNotNil(cloudkit.perRecordProgressBlock)\n        cloudkit.perRecordProgressBlock?(\"record 1\", 0.5)\n        XCTAssertEqual(setByPerRecordProgressBlock?.0 ?? \"not record 1\", \"record 1\")\n        XCTAssertEqual(setByPerRecordProgressBlock?.1 ?? 0.1, 0.5)\n    }\n\n    func test__set_get_perRecordCompletionBlock() {\n        XCTAssertNotNil(cloudkit.perRecordCompletionBlock)\n        let anError = TestError()\n        cloudkit.perRecordCompletionBlock?(\"record 2\", anError)\n        XCTAssertEqual(setByPerRecordCompletionBlock?.0 ?? \"not record 2\", \"record 2\")\n        XCTAssertEqual(setByPerRecordCompletionBlock?.1 as? TestError ?? TestError(), anError)\n    }\n\n    func test__cancellation() {\n        cloudkit.cancel()\n        wait(for: cloudkit)\n        PKAssertProcedureCancelled(cloudkit)\n    }\n\n    func test__success_without_completion_block_set() {\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n    }\n\n    func test__success_with_completion_block_set() {\n        var didExecuteBlock = false\n        cloudkit.setModifyRecordsCompletionBlock { _, _ in\n            didExecuteBlock = true\n        }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n        XCTAssertTrue(didExecuteBlock)\n    }\n\n    func test__error_without_completion_block_set() {\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let operation = TestCKModifyRecordsOperation()\n            operation.error = NSError(domain: CKErrorDomain, code: CKError.internalError.rawValue, userInfo: nil)\n            return operation\n        }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n    }\n\n    func test__error_with_completion_block_set() {\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let operation = TestCKModifyRecordsOperation()\n            operation.error = NSError(domain: CKErrorDomain, code: CKError.internalError.rawValue, userInfo: nil)\n            return operation\n        }\n\n        var didExecuteBlock = false\n        cloudkit.setModifyRecordsCompletionBlock { _, _ in\n            didExecuteBlock = true\n        }\n\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit, withErrors: true)\n        XCTAssertFalse(didExecuteBlock)\n    }\n\n    func test__error_which_retries_using_retry_after_key() {\n        var shouldError = true\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let op = TestCKModifyRecordsOperation()\n            if shouldError {\n                let userInfo = [CKErrorRetryAfterKey: NSNumber(value: 0.001)]\n                op.error = NSError(domain: CKErrorDomain, code: CKError.Code.serviceUnavailable.rawValue, userInfo: userInfo)\n                shouldError = false\n            }\n            return op\n        }\n        var didExecuteBlock = false\n        cloudkit.setModifyRecordsCompletionBlock { _, _ in didExecuteBlock = true }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n        XCTAssertTrue(didExecuteBlock)\n    }\n\n    func test__error_which_retries_using_custom_handler() {\n        var shouldError = true\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let op = TestCKModifyRecordsOperation()\n            if shouldError {\n                op.error = NSError(domain: CKErrorDomain, code: CKError.Code.limitExceeded.rawValue, userInfo: nil)\n                shouldError = false\n            }\n            return op\n        }\n        var didRunCustomHandler = false\n        cloudkit.set(errorHandlerForCode: .limitExceeded) { _, _, _, suggestion in\n            didRunCustomHandler = true\n            return suggestion\n        }\n\n        var didExecuteBlock = false\n        cloudkit.setModifyRecordsCompletionBlock { _, _ in didExecuteBlock = true }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n        XCTAssertTrue(didExecuteBlock)\n        XCTAssertTrue(didRunCustomHandler)\n    }\n    \n}\n\n"
  },
  {
    "path": "Tests/ProcedureKitCloudTests/CKModifySubscriptionsOperationTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport CloudKit\nimport ProcedureKit\nimport TestingProcedureKit\n@testable import ProcedureKitCloud\n\nclass TestCKModifySubscriptionsOperation: TestCKDatabaseOperation, CKModifySubscriptionsOperationProtocol, AssociatedErrorProtocol {\n    typealias AssociatedError = ModifySubscriptionsError<Subscription, String>\n\n    var saved: [Subscription]? = nil\n    var deleted: [String]? = nil\n    var error: Error? = nil\n    var subscriptionsToSave: [Subscription]? = nil\n    var subscriptionIDsToDelete: [String]? = nil\n    var modifySubscriptionsCompletionBlock: (([Subscription]?, [String]?, Error?) -> Void)? = nil\n\n    init(saved: [Subscription]? = nil, deleted: [String]? = nil, error: Error? = nil) {\n        self.saved = saved\n        self.deleted = deleted\n        self.error = error\n        super.init()\n    }\n\n    override func main() {\n        modifySubscriptionsCompletionBlock?(saved, deleted, error)\n    }\n}\n\nclass CKModifySubscriptionsOperationTests: CKProcedureTestCase {\n    \n    var target: TestCKModifySubscriptionsOperation!\n    var operation: CKProcedure<TestCKModifySubscriptionsOperation>!\n    \n    override func setUp() {\n        super.setUp()\n        target = TestCKModifySubscriptionsOperation()\n        operation = CKProcedure(operation: target)\n    }\n\n    override func tearDown() {\n        target = nil\n        operation = nil\n        super.tearDown()\n    }\n\n    func test__set_get__subscriptionsToSave() {\n        let subscriptionsToSave = [ \"a-subscription\", \"another-subscription\" ]\n        operation.subscriptionsToSave = subscriptionsToSave\n        XCTAssertNotNil(operation.subscriptionsToSave)\n        XCTAssertEqual(operation.subscriptionsToSave ?? [], subscriptionsToSave)\n        XCTAssertNotNil(target.subscriptionsToSave)\n        XCTAssertEqual(target.subscriptionsToSave ?? [], subscriptionsToSave)\n    }\n    \n    func test__set_get__recordZoneIDsToDelete() {\n        let subscriptionIDsToDelete = [ \"a-subscription-id\", \"another-subscription-id\" ]\n        operation.subscriptionIDsToDelete = subscriptionIDsToDelete\n        XCTAssertNotNil(operation.subscriptionIDsToDelete)\n        XCTAssertEqual(operation.subscriptionIDsToDelete ?? [], subscriptionIDsToDelete)\n        XCTAssertNotNil(target.subscriptionIDsToDelete)\n        XCTAssertEqual(target.subscriptionIDsToDelete ?? [], subscriptionIDsToDelete)\n    }\n    \n    func test__success_without_completion_block() {\n        wait(for: operation)\n        PKAssertProcedureFinished(operation)\n    }\n    \n    func test__success_with_completion_block() {\n        var didExecuteBlock = false\n        operation.setModifySubscriptionsCompletionBlock { savedSubscriptions, deletedSubscriptionIDs in\n            didExecuteBlock = true\n        }\n        wait(for: operation)\n        PKAssertProcedureFinished(operation)\n        XCTAssertTrue(didExecuteBlock)\n    }\n    \n    func test__error_without_completion_block() {\n        target.error = TestError()\n        wait(for: operation)\n        PKAssertProcedureFinished(operation)\n    }\n    \n    func test__error_with_completion_block() {\n        var didExecuteBlock = false\n        operation.setModifySubscriptionsCompletionBlock { savedSubscriptions, deletedSubscriptionIDs in\n            didExecuteBlock = true\n        }\n        let error = TestError()\n        target.error = error\n        wait(for: operation)\n        PKAssertProcedureFinished(operation, withErrors: true)\n        XCTAssertFalse(didExecuteBlock)\n    }\n}\n\nclass CloudKitProcedureModifySubscriptionsOperationTests: CKProcedureTestCase {\n    typealias T = TestCKModifySubscriptionsOperation\n    var cloudkit: CloudKitProcedure<T>!\n\n    override func setUp() {\n        super.setUp()\n        cloudkit = CloudKitProcedure(strategy: .immediate) { TestCKModifySubscriptionsOperation() }\n        cloudkit.container = container\n        cloudkit.subscriptionsToSave = [ \"subscription 1\" ]\n        cloudkit.subscriptionIDsToDelete = [ \"subscription 2 ID\" ]\n    }\n\n    override func tearDown() {\n        cloudkit = nil\n        super.tearDown()\n    }\n\n    func test__set_get__errorHandlers() {\n        cloudkit.set(errorHandlers: [.internalError: cloudkit.passthroughSuggestedErrorHandler])\n        XCTAssertEqual(cloudkit.errorHandlers.count, 1)\n        XCTAssertNotNil(cloudkit.errorHandlers[.internalError])\n    }\n\n    func test__set_get_container() {\n        cloudkit.container = \"I'm a different container!\"\n        XCTAssertEqual(cloudkit.container, \"I'm a different container!\")\n    }\n\n    func test__set_get_database() {\n        cloudkit.database = \"I'm a different database!\"\n        XCTAssertEqual(cloudkit.database, \"I'm a different database!\")\n    }\n\n    func test__set_get_previousServerChangeToken() {\n        cloudkit.previousServerChangeToken = \"I'm a different token!\"\n        XCTAssertEqual(cloudkit.previousServerChangeToken, \"I'm a different token!\")\n    }\n\n    func test__set_get_resultsLimit() {\n        cloudkit.resultsLimit = 20\n        XCTAssertEqual(cloudkit.resultsLimit, 20)\n    }\n\n    func test__set_get_subscriptionsToSave() {\n        cloudkit.subscriptionsToSave = [ \"subscription 3\" ]\n        XCTAssertEqual(cloudkit.subscriptionsToSave ?? [], [ \"subscription 3\" ])\n    }\n\n    func test__set_get_subscriptionIDsToDelete() {\n        cloudkit.subscriptionIDsToDelete = [ \"subscription 2 ID\" ]\n        XCTAssertEqual(cloudkit.subscriptionIDsToDelete ?? [], [ \"subscription 2 ID\" ])\n    }\n\n    func test__cancellation() {\n        cloudkit.cancel()\n        wait(for: cloudkit)\n        PKAssertProcedureCancelled(cloudkit)\n    }\n\n    func test__success_without_completion_block_set() {\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n    }\n\n    func test__success_with_completion_block_set() {\n        var didExecuteBlock = false\n        cloudkit.setModifySubscriptionsCompletionBlock { _, _ in\n            didExecuteBlock = true\n        }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n        XCTAssertTrue(didExecuteBlock)\n    }\n\n    func test__error_without_completion_block_set() {\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let operation = TestCKModifySubscriptionsOperation()\n            operation.error = NSError(domain: CKErrorDomain, code: CKError.internalError.rawValue, userInfo: nil)\n            return operation\n        }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n    }\n\n    func test__error_with_completion_block_set() {\n        let error = NSError(domain: CKErrorDomain, code: CKError.internalError.rawValue, userInfo: nil)\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let operation = TestCKModifySubscriptionsOperation()\n            operation.error = error\n            return operation\n        }\n\n        var didExecuteBlock = false\n        cloudkit.setModifySubscriptionsCompletionBlock { _, _ in\n            didExecuteBlock = true\n        }\n\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit, withErrors: true)\n        XCTAssertFalse(didExecuteBlock)\n    }\n\n    func test__error_which_retries_using_retry_after_key() {\n        var shouldError = true\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let op = TestCKModifySubscriptionsOperation()\n            if shouldError {\n                let userInfo = [CKErrorRetryAfterKey: NSNumber(value: 0.001)]\n                op.error = NSError(domain: CKErrorDomain, code: CKError.Code.serviceUnavailable.rawValue, userInfo: userInfo)\n                shouldError = false\n            }\n            return op\n        }\n        var didExecuteBlock = false\n        cloudkit.setModifySubscriptionsCompletionBlock { _, _ in didExecuteBlock = true }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n        XCTAssertTrue(didExecuteBlock)\n    }\n\n    func test__error_which_retries_using_custom_handler() {\n        var shouldError = true\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let op = TestCKModifySubscriptionsOperation()\n            if shouldError {\n                op.error = NSError(domain: CKErrorDomain, code: CKError.Code.limitExceeded.rawValue, userInfo: nil)\n                shouldError = false\n            }\n            return op\n        }\n        var didRunCustomHandler = false\n        cloudkit.set(errorHandlerForCode: .limitExceeded) { _, _, _, suggestion in\n            didRunCustomHandler = true\n            return suggestion\n        }\n\n        var didExecuteBlock = false\n        cloudkit.setModifySubscriptionsCompletionBlock { _, _ in didExecuteBlock = true }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n        XCTAssertTrue(didExecuteBlock)\n        XCTAssertTrue(didRunCustomHandler)\n    }\n    \n}\n\n"
  },
  {
    "path": "Tests/ProcedureKitCloudTests/CKOperationTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport ProcedureKit\nimport TestingProcedureKit\n@testable import ProcedureKitCloud\n\nclass TestCKOperation: Operation, CKOperationProtocol {\n\n    typealias ServerChangeToken = String\n    typealias RecordZone = String\n    typealias RecordZoneID = String\n    typealias Notification = String\n    typealias NotificationID = String\n    typealias Record = String\n    typealias RecordID = String\n    typealias Subscription = String\n    typealias RecordSavePolicy = Int\n    typealias DiscoveredUserInfo = String\n    typealias Query = String\n    typealias QueryCursor = String\n\n    typealias UserIdentity = String\n    typealias UserIdentityLookupInfo = String\n    typealias Share = String\n    typealias ShareMetadata = String\n    typealias ShareParticipant = String\n\n    var container: String? // just a test\n    var allowsCellularAccess: Bool = true\n\n    //@available(iOS 9.3, tvOS 9.3, OSX 10.12, watchOS 2.3, *)\n    var operationID: String = \"\"\n    #if swift(>=3.2)\n        var isLongLived: Bool = false\n    #else // Swift 3.x\n        var longLived: Bool = false\n    #endif\n\n    var longLivedOperationWasPersistedBlock: () -> Void = { }\n\n    //@available(iOS 10.0, tvOS 10.0, OSX 10.12, watchOS 3.0, *)\n    var timeoutIntervalForRequest: TimeInterval = 0\n    var timeoutIntervalForResource: TimeInterval = 0\n}\n\nclass CKOperationTests: CKProcedureTestCase {\n\n    var target: TestCKOperation!\n    var operation: CKProcedure<TestCKOperation>!\n\n    override func setUp() {\n        super.setUp()\n        target = TestCKOperation()\n        operation = CKProcedure(operation: target)\n    }\n\n    override func tearDown() {\n        target = nil\n        operation = nil\n        super.tearDown()\n    }\n\n    func test__set_get__container() {\n        let container = \"I'm a cloud kit container\"\n        operation.container = container\n        XCTAssertEqual(operation.container, container)\n        XCTAssertEqual(target.container, container)\n    }\n\n    func test__set_get__allowsCellularAccess() {\n        let allowsCellularAccess = true\n        operation.allowsCellularAccess = allowsCellularAccess\n        XCTAssertEqual(operation.allowsCellularAccess, allowsCellularAccess)\n        XCTAssertEqual(target.allowsCellularAccess, allowsCellularAccess)\n    }\n\n    @available(iOS 9.3, tvOS 9.3, OSX 10.12, watchOS 2.3, *)\n    func test__get_operationID() {\n        let operationID = \"test operationID\"\n        target.operationID = operationID\n        XCTAssertEqual(operation.operationID, operationID)\n    }\n\n    @available(iOS 9.3, tvOS 9.3, OSX 10.12, watchOS 2.3, *)\n    func test__set_get__longLived() {\n        let longLived = true\n        #if swift(>=3.2)\n            operation.isLongLived = longLived\n            XCTAssertEqual(operation.isLongLived, longLived)\n            XCTAssertEqual(target.isLongLived, longLived)\n        #else // Swift < 3.2 (Xcode 8.x)\n            operation.longLived = longLived\n            XCTAssertEqual(operation.longLived, longLived)\n            XCTAssertEqual(target.longLived, longLived)\n        #endif\n    }\n\n    @available(iOS 9.3, tvOS 9.3, OSX 10.12, watchOS 2.3, *)\n    func test__set_get__longLivedOperationWasPersistedBlock() {\n        var setByBlock = false\n        let block: () -> Void = { setByBlock = true }\n        operation.longLivedOperationWasPersistedBlock = block\n        operation.longLivedOperationWasPersistedBlock()\n        XCTAssertTrue(setByBlock)\n    }\n\n    @available(iOS 10.0, tvOS 10.0, OSX 10.12, watchOS 3.0, *)\n    func test__set_get__timeoutIntervalForRequest() {\n        let timeout: TimeInterval = 42\n        operation.timeoutIntervalForRequest = timeout\n        XCTAssertEqual(operation.timeoutIntervalForRequest, timeout)\n        XCTAssertEqual(target.timeoutIntervalForRequest, timeout)\n    }\n\n    @available(iOS 10.0, tvOS 10.0, OSX 10.12, watchOS 3.0, *)\n    func test__set_get__timeoutIntervalForResource() {\n        let timeout: TimeInterval = 42\n        operation.timeoutIntervalForResource = timeout\n        XCTAssertEqual(operation.timeoutIntervalForResource, timeout)\n        XCTAssertEqual(target.timeoutIntervalForResource, timeout)\n    }\n}\n"
  },
  {
    "path": "Tests/ProcedureKitCloudTests/CKQueryOperationTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport CloudKit\nimport ProcedureKit\nimport TestingProcedureKit\n@testable import ProcedureKitCloud\n\nclass TestCKQueryOperation: TestCKDatabaseOperation, CKQueryOperationProtocol, AssociatedErrorProtocol {\n    typealias AssociatedError = QueryError<QueryCursor>\n\n    var error: Error? = nil\n    var query: Query? = nil\n    var cursor: QueryCursor? = nil\n    var zoneID: RecordZoneID? = nil\n    var recordFetchedBlock: ((Record) -> Void)? = nil\n    var queryCompletionBlock: ((QueryCursor?, Error?) -> Void)? = nil\n\n    init(error: Error? = nil) {\n        self.error = error\n        super.init()\n    }\n\n    override func main() {\n        queryCompletionBlock?(cursor, error)\n    }\n}\n\nclass CKQueryOperationTests: CKProcedureTestCase {\n\n    var target: TestCKQueryOperation!\n    var operation: CKProcedure<TestCKQueryOperation>!\n\n    override func setUp() {\n        super.setUp()\n        target = TestCKQueryOperation()\n        operation = CKProcedure(operation: target)\n    }\n\n    override func tearDown() {\n        target = nil\n        operation = nil\n        super.tearDown()\n    }\n\n    func test__set_get__query() {\n        let query = \"a-query\"\n        operation.query = query\n        XCTAssertNotNil(operation.query)\n        XCTAssertEqual(operation.query, query)\n        XCTAssertNotNil(target.query)\n        XCTAssertEqual(target.query, query)\n    }\n\n    func test__set_get__cursor() {\n        let cursor = \"a-cursor\"\n        operation.cursor = cursor\n        XCTAssertNotNil(operation.cursor)\n        XCTAssertEqual(operation.cursor, cursor)\n        XCTAssertNotNil(target.cursor)\n        XCTAssertEqual(target.cursor, cursor)\n    }\n\n    func test__set_get__zoneID() {\n        let zoneID = \"a-zone-id\"\n        operation.zoneID = zoneID\n        XCTAssertNotNil(operation.zoneID)\n        XCTAssertEqual(operation.zoneID, zoneID)\n        XCTAssertNotNil(target.zoneID)\n        XCTAssertEqual(target.zoneID, zoneID)\n    }\n\n    func test__set_get__recordFetchedBlock() {\n        var setByCompletionBlock = false\n        let block: (String) -> Void = { record in\n            setByCompletionBlock = true\n        }\n        operation.recordFetchedBlock = block\n        XCTAssertNotNil(operation.recordFetchedBlock)\n        target.recordFetchedBlock?(\"a-record\")\n        XCTAssertTrue(setByCompletionBlock)\n    }\n\n    func test__success_without_completion_block() {\n        wait(for: operation)\n        PKAssertProcedureFinished(operation)\n    }\n\n    func test__success_with_completion_block() {\n        var didExecuteBlock = false\n        operation.setQueryCompletionBlock { cursor in\n            didExecuteBlock = true\n        }\n        wait(for: operation)\n        PKAssertProcedureFinished(operation)\n        XCTAssertTrue(didExecuteBlock)\n    }\n\n    func test__error_without_completion_block() {\n        target.error = TestError()\n        wait(for: operation)\n        PKAssertProcedureFinished(operation)\n    }\n\n    func test__error_with_completion_block() {\n        var didExecuteBlock = false\n        operation.setQueryCompletionBlock { cursor in\n            didExecuteBlock = true\n        }\n        let error = TestError()\n        target.error = error\n        wait(for: operation)\n        PKAssertProcedureFinished(operation, withErrors: true)\n        XCTAssertFalse(didExecuteBlock)\n    }\n}\n\nclass CloudKitProcedureQueryOperationTests: CKProcedureTestCase {\n    typealias T = TestCKQueryOperation\n    var cloudkit: CloudKitProcedure<T>!\n\n    var setByQueryRecordFetchedBlock: T.Record!\n\n    override func setUp() {\n        super.setUp()\n        cloudkit = CloudKitProcedure(strategy: .immediate) { TestCKQueryOperation() }\n        cloudkit.container = container\n        cloudkit.query = \"a query\"\n        cloudkit.cursor = \"a cursor\"\n        cloudkit.zoneID = \"a zone 1 ID\"\n        cloudkit.recordFetchedBlock = { self.setByQueryRecordFetchedBlock = $0 }\n    }\n\n    override func tearDown() {\n        cloudkit = nil\n        setByQueryRecordFetchedBlock = nil\n        super.tearDown()\n    }\n\n    func test__set_get__errorHandlers() {\n        cloudkit.set(errorHandlers: [.internalError: cloudkit.passthroughSuggestedErrorHandler])\n        XCTAssertEqual(cloudkit.errorHandlers.count, 1)\n        XCTAssertNotNil(cloudkit.errorHandlers[.internalError])\n    }\n\n    func test__set_get_container() {\n        cloudkit.container = \"I'm a different container!\"\n        XCTAssertEqual(cloudkit.container, \"I'm a different container!\")\n    }\n\n    func test__set_get_database() {\n        cloudkit.database = \"I'm a different database!\"\n        XCTAssertEqual(cloudkit.database, \"I'm a different database!\")\n    }\n\n    func test__set_get_query() {\n        cloudkit.query = \"a query\"\n        XCTAssertEqual(cloudkit.query, \"a query\")\n    }\n\n    func test__set_get_cursor() {\n        cloudkit.cursor = \"a cursor\"\n        XCTAssertEqual(cloudkit.cursor, \"a cursor\")\n    }\n\n    func test__set_get_zoneID() {\n        cloudkit.zoneID = \"a zone 2 ID\"\n        XCTAssertEqual(cloudkit.zoneID, \"a zone 2 ID\")\n    }\n\n    func test__set_get_queryRecordFetchedBlock() {\n        XCTAssertNotNil(cloudkit.recordFetchedBlock)\n        cloudkit.recordFetchedBlock?(\"a record\")\n        XCTAssertEqual(setByQueryRecordFetchedBlock ?? \"incorrect\", \"a record\")\n    }\n\n    func test__cancellation() {\n        cloudkit.cancel()\n        wait(for: cloudkit)\n        PKAssertProcedureCancelled(cloudkit)\n    }\n\n    func test__success_without_completion_block_set() {\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n    }\n\n    func test__success_with_completion_block_set() {\n        var didExecuteBlock = false\n        cloudkit.setQueryCompletionBlock { _ in\n            didExecuteBlock = true\n        }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n        XCTAssertTrue(didExecuteBlock)\n    }\n\n    func test__error_without_completion_block_set() {\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let operation = TestCKQueryOperation()\n            operation.error = NSError(domain: CKErrorDomain, code: CKError.internalError.rawValue, userInfo: nil)\n            return operation\n        }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n    }\n\n    func test__error_with_completion_block_set() {\n        let error = NSError(domain: CKErrorDomain, code: CKError.internalError.rawValue, userInfo: nil)\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let operation = TestCKQueryOperation()\n            operation.error = error\n            return operation\n        }\n\n        var didExecuteBlock = false\n        cloudkit.setQueryCompletionBlock { _ in\n            didExecuteBlock = true\n        }\n\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit, withErrors: true)\n        XCTAssertFalse(didExecuteBlock)\n    }\n\n    func test__error_which_retries_using_retry_after_key() {\n        var shouldError = true\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let op = TestCKQueryOperation()\n            if shouldError {\n                let userInfo = [CKErrorRetryAfterKey: NSNumber(value: 0.001)]\n                op.error = NSError(domain: CKErrorDomain, code: CKError.Code.serviceUnavailable.rawValue, userInfo: userInfo)\n                shouldError = false\n            }\n            return op\n        }\n        var didExecuteBlock = false\n        cloudkit.setQueryCompletionBlock { _ in didExecuteBlock = true }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n        XCTAssertTrue(didExecuteBlock)\n    }\n\n    func test__error_which_retries_using_custom_handler() {\n        var shouldError = true\n        cloudkit = CloudKitProcedure(strategy: .immediate) {\n            let op = TestCKQueryOperation()\n            if shouldError {\n                op.error = NSError(domain: CKErrorDomain, code: CKError.Code.limitExceeded.rawValue, userInfo: nil)\n                shouldError = false\n            }\n            return op\n        }\n        var didRunCustomHandler = false\n        cloudkit.set(errorHandlerForCode: .limitExceeded) { _, _, _, suggestion in\n            didRunCustomHandler = true\n            return suggestion\n        }\n\n        var didExecuteBlock = false\n        cloudkit.setQueryCompletionBlock { _ in didExecuteBlock = true }\n        wait(for: cloudkit)\n        PKAssertProcedureFinished(cloudkit)\n        XCTAssertTrue(didExecuteBlock)\n        XCTAssertTrue(didRunCustomHandler)\n    }\n    \n}\n"
  },
  {
    "path": "Tests/ProcedureKitCloudTests/CloudKitCapabilityTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport ProcedureKit\nimport TestingProcedureKit\n@testable import ProcedureKitCloud\n\nclass CloudKitCapabilityTests: ProcedureKitTestCase {\n\n    var container: TestableCloudKitContainerRegistrar!\n    var capability: Capability.CloudKit!\n\n    override func setUp() {\n        super.setUp()\n        container = TestableCloudKitContainerRegistrar()\n        capability = Capability.CloudKit()\n        capability.storedRegistrar = container\n    }\n\n    override func tearDown() {\n        container = nil\n        capability = nil\n        super.tearDown()\n    }\n\n    func test__cloud_kit_is_available() {\n        XCTAssertTrue(capability.isAvailable())\n    }\n\n    // Getting status\n\n    func test__given_status_could_not_be_determined__authorization_status_queries_the_registrar() {\n        capability.getAuthorizationStatus { status in\n            XCTAssertEqual(status.account, .couldNotDetermine)\n            XCTAssertNil(status.permissions)\n            XCTAssertNil(status.error)\n        }\n        XCTAssertTrue(container.didGetAccountStatus)\n    }\n\n    func test__given_status_is_available_but_with_no_permissions__does_not_get_status_for_permissions() {\n        container.accountStatus = .available\n        capability.getAuthorizationStatus { status in\n            XCTAssertEqual(status.account, .available)\n            XCTAssertNil(status.permissions)\n            XCTAssertNil(status.error)\n        }\n        XCTAssertTrue(container.didGetAccountStatus)\n        XCTAssertFalse(container.didVerifyApplicationStatus)\n    }\n\n    func test__given_status_is_available_but_with_permissions__does_not_get_status_for_permissions() {\n        capability = Capability.CloudKit([ .userDiscoverability ])\n        capability.storedRegistrar = container\n        container.accountStatus = .available\n        capability.getAuthorizationStatus { status in\n            XCTAssertEqual(status.account, .available)\n            XCTAssertNotNil(status.permissions)\n            XCTAssertEqual(status.permissions, .initialState)\n            XCTAssertNil(status.error)\n        }\n        XCTAssertTrue(container.didGetAccountStatus)\n        XCTAssertTrue(container.didVerifyApplicationStatus)\n    }\n\n    func test__no_account_status() {\n        container.accountStatus = .noAccount\n        capability.getAuthorizationStatus { status in\n            XCTAssertEqual(status.account, .noAccount)\n            XCTAssertNil(status.permissions)\n            XCTAssertNil(status.error)\n        }\n        XCTAssertTrue(container.didGetAccountStatus)\n        XCTAssertFalse(container.didVerifyApplicationStatus)\n    }\n\n    func test__restricted_account_status() {\n        container.accountStatus = .restricted\n        capability.getAuthorizationStatus { status in\n            XCTAssertEqual(status.account, .restricted)\n            XCTAssertNil(status.permissions)\n            XCTAssertNil(status.error)\n        }\n        XCTAssertTrue(container.didGetAccountStatus)\n        XCTAssertFalse(container.didVerifyApplicationStatus)\n    }\n\n    // Requesting Authorization\n\n    func test__request_permissions() {\n        let exp = expectation(description: \"Test: \\(#function)\")\n        container.accountStatus = .available\n        capability = Capability.CloudKit([ .userDiscoverability ])\n        capability.storedRegistrar = container\n        capability.requestAuthorization {\n            DispatchQueue.main.async { exp.fulfill() }\n        }\n        waitForExpectations(timeout: 3)\n        XCTAssertTrue(container.didGetAccountStatus)\n        XCTAssertTrue(container.didVerifyApplicationStatus)\n        XCTAssertTrue(container.didRequestApplicationStatus)\n    }\n}\n\nclass CloudKitStatusTests: XCTestCase {\n    var error: Error!\n    var status: CloudKitStatus!\n\n    override func setUp() {\n        super.setUp()\n        error = TestError()\n    }\n\n    override func tearDown() {\n        error = nil\n        status = nil\n        super.tearDown()\n    }\n\n    func test__given_status_is_available__with_error__does_not_meet_requirements() {\n        status = CloudKitStatus(account: .available, permissions: nil, error: error)\n        XCTAssertFalse(status.meets(requirement: [.userDiscoverability]))\n    }\n\n    func test__given_status_is_available__with_error__does_not_meet_empty_requirements() {\n        status = CloudKitStatus(account: .available, permissions: nil, error: error)\n        XCTAssertFalse(status.meets(requirement: []))\n    }\n\n    func test__given_status_is_available__with_error__does_not_meet_nil_requirements() {\n        status = CloudKitStatus(account: .available, permissions: nil, error: error)\n        XCTAssertFalse(status.meets(requirement: nil))\n    }\n\n    func test__given_status_is_available__does_meet_empty_requirements() {\n        status = CloudKitStatus(account: .available, permissions: nil, error: nil)\n        XCTAssertTrue(status.meets(requirement: []))\n    }\n\n    func test__given_status_is_available__does_meet_nil_requirements() {\n        status = CloudKitStatus(account: .available, permissions: nil, error: nil)\n        XCTAssertTrue(status.meets(requirement: nil))\n    }\n\n    func test__given_status_is_available__with_granted_permissions__does_meet_requirements() {\n        status = CloudKitStatus(account: .available, permissions: .granted, error: nil)\n        XCTAssertTrue(status.meets(requirement: [.userDiscoverability]))\n    }\n\n    func test__given_status_is_available__with_granted_permissions__does_meet_empty_requirements() {\n        status = CloudKitStatus(account: .available, permissions: .granted, error: nil)\n        XCTAssertTrue(status.meets(requirement: []))\n    }\n\n    func test__given_status_is_available__with_granted_permissions__does_meet_nil_requirements() {\n        status = CloudKitStatus(account: .available, permissions: .granted, error: nil)\n        XCTAssertTrue(status.meets(requirement: nil))\n    }\n\n    func test__given_status_is_available__with_no_permissions__does_not_meet_requirements() {\n        status = CloudKitStatus(account: .noAccount, permissions: .denied, error: nil)\n        XCTAssertFalse(status.meets(requirement: [.userDiscoverability]))\n    }\n\n    func test__given_status_is_no_account__with_granted_permissions__does_not_meet_empty_requirements() {\n        status = CloudKitStatus(account: .noAccount, permissions: .granted, error: nil)\n        XCTAssertFalse(status.meets(requirement: []))\n    }\n}\n\n"
  },
  {
    "path": "Tests/ProcedureKitCloudTests/ProcedureKitCloudTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport CloudKit\nimport ProcedureKit\nimport TestingProcedureKit\n@testable import ProcedureKitCloud\n\nclass TestSuiteRuns: XCTestCase {\n\n    func test__suite_runs() {\n        XCTAssertTrue(true)\n    }\n}\n\nclass CloudKitTestCase: ProcedureKitTestCase {\n\n    var container: TestCKOperation.Container!\n    var database: TestCKDatabaseOperation.Database!\n    var token: TestCKOperation.ServerChangeToken!\n\n    override func setUp() {\n        super.setUp()\n        container = \"I'm a test container!\"\n        database = \"I'm a test database!\"\n        token = \"I'm a server change token!\"\n    }\n\n    override func tearDown() {\n        container = nil\n        database = nil\n        token = nil\n        super.tearDown()\n    }\n}\n\nclass CKProcedureTestCase: CloudKitTestCase { }\n\nextension CloudKitProcedure {\n\n    var passthroughSuggestedErrorHandler: ErrorHandler {\n        return { $3 }\n    }\n}\n"
  },
  {
    "path": "Tests/ProcedureKitCloudTests/TestableCloudKitContainer.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport CloudKit\nimport ProcedureKit\nimport TestingProcedureKit\n@testable import ProcedureKitCloud\n\nclass TestableCloudKitContainerRegistrar: CloudKitContainerRegistrar {\n\n    var accountStatus: CKAccountStatus = .couldNotDetermine\n    var accountStatusError: Error? = nil\n\n    var verifyApplicationPermissionStatus: CKContainer.Application.PermissionStatus = .initialState\n    var verifyApplicationPermissionsError: Error? = nil\n    var verifyApplicationPermissions: CKContainer.Application.Permissions? = nil\n\n    var requestApplicationPermissionStatus: CKContainer.Application.PermissionStatus = .granted\n    var requestApplicationPermissionsError: Error? = nil\n    var requestApplicationPermissions: CKContainer.Application.Permissions? = nil\n\n    var didGetAccountStatus = false\n    var didVerifyApplicationStatus = false\n    var didRequestApplicationStatus = false\n\n    func pk_accountStatus(withCompletionHandler completionHandler: @escaping (CKAccountStatus, Error?) -> Void) {\n        didGetAccountStatus = true\n        completionHandler(accountStatus, accountStatusError)\n    }\n\n    func pk_status(forApplicationPermission applicationPermission: CKContainer.Application.Permissions, completionHandler: @escaping CKContainer.Application.PermissionBlock) {\n        didVerifyApplicationStatus = true\n        verifyApplicationPermissions = applicationPermission\n        completionHandler(verifyApplicationPermissionStatus, verifyApplicationPermissionsError)\n    }\n\n    func pk_requestApplicationPermission(_ applicationPermission: CKContainer.Application.Permissions, completionHandler: @escaping CKContainer.Application.PermissionBlock) {\n        didRequestApplicationStatus = true\n        requestApplicationPermissions = applicationPermission\n        completionHandler(requestApplicationPermissionStatus, requestApplicationPermissionsError)\n    }\n}\n\n\n"
  },
  {
    "path": "Tests/ProcedureKitCoreDataTests/InsertManagedObjectsProcedureTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport ProcedureKit\nimport TestingProcedureKit\n@testable import ProcedureKitCoreData\n\nfinal class InsertManagedObjectsProcedureTests: ProcedureKitCoreDataTestCase {\n\n    func test__insert_multiple_items_and_save() {\n\n        let insert = TestInsert(items: items)\n            .injectResult(from: coreDataStack)\n\n        fetchTestEntities.addDependency(insert)\n\n        wait(for: coreDataStack, insert, fetchTestEntities)\n\n        PKAssertProcedureFinished(insert)\n\n        guard let names = fetchTestEntities.output.success?.map({ $0.name! }) else {\n            XCTFail(\"Did not fetch any test entities.\")\n            return\n        }\n\n        XCTAssertEqual(names.sorted(), [\"Bar\", \"Bat\", \"Foo\"])\n    }\n\n    func test__insert_empty_items() {\n\n        let insert = TestInsert(items: [])\n            .injectResult(from: coreDataStack)\n\n        fetchTestEntities.addDependency(insert)\n\n        wait(for: coreDataStack, insert, fetchTestEntities)\n\n        PKAssertProcedureFinished(insert)\n\n        guard let names = fetchTestEntities.output.success?.map({ $0.name! }) else {\n            XCTFail(\"Did not fetch any test entities.\")\n            return\n        }\n\n        XCTAssertEqual(names.count, 0)\n    }\n\n    func test__insert_multiple_items_dont_save() {\n\n        let insert = TestInsert(items: items, andSave: false)\n            .injectResult(from: coreDataStack)\n\n        fetchTestEntities.addDependency(insert)\n\n        wait(for: coreDataStack, insert, fetchTestEntities)\n\n        PKAssertProcedureFinished(insert)\n\n        guard let names = fetchTestEntities.output.success?.map({ $0.name! }) else {\n            XCTFail(\"Did not fetch any test entities.\")\n            return\n        }\n\n        XCTAssertEqual(names.count, 0)\n    }\n}\n"
  },
  {
    "path": "Tests/ProcedureKitCoreDataTests/LoadCoreDataProcedureTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport ProcedureKit\nimport TestingProcedureKit\n@testable import ProcedureKitCoreData\n\nfinal class LoadCoreDataProcedureTests: ProcedureKitCoreDataTestCase {\n\n    func test__load_core_data_stack_with_custom_model() {\n\n        wait(for: coreDataStack)\n\n        PKAssertProcedureFinished(coreDataStack)\n\n        guard let _ = coreDataStack.output.success else {\n            XCTFail(\"Did not load container\")\n            return\n        }\n    }\n}\n"
  },
  {
    "path": "Tests/ProcedureKitCoreDataTests/MakeFetchedResultsControllerProcedureTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport CoreData\nimport ProcedureKit\nimport TestingProcedureKit\n@testable import ProcedureKitCoreData\n\nfinal class MakeFetchedResultsControllerProcedureTests: ProcedureKitCoreDataTestCase {\n\n    func test__make_frc() {\n\n        let makeFRC = MakeFetchedResultControllerProcedure<TestEntity>().injectResult(from: coreDataStack)\n\n        wait(for: coreDataStack, makeFRC)\n\n        PKAssertProcedureFinished(makeFRC)\n\n        guard let _ = makeFRC.output.success else {\n            XCTFail(\"Did not make FRC\")\n            return\n        }\n    }\n}\n"
  },
  {
    "path": "Tests/ProcedureKitCoreDataTests/ProcedureKitCoreDataTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport ProcedureKit\nimport TestingProcedureKit\n@testable import ProcedureKitCoreData\n\nopen class ProcedureKitCoreDataTestCase: ProcedureKitTestCase {\n\n    typealias Insert = InsertManagedObjectsProcedure<TestEntityItem, TestEntity>\n\n    final class TestInsert: GroupProcedure, InputProcedure, OutputProcedure {\n        typealias Item = TestEntityItem\n\n        var input: Pending<NSPersistentContainer> = .pending\n        var output: Pending<ProcedureResult<[TestEntity]>> = .pending\n\n        let shouldSave: Bool\n        let download: ResultProcedure<[Item]>\n\n        init(items: [Item], andSave shouldSave: Bool = true) {\n            self.shouldSave = shouldSave\n            self.download = ResultProcedure { items }\n            super.init(operations: [download])\n        }\n\n        override func execute() {\n\n            guard let container = input.value else {\n                finish(with: ProcedureKitError.requirementNotSatisfied())\n                return\n            }\n\n            let insert = Insert(into: container, andSave: shouldSave) { (_, item, testEntity) in\n                testEntity.identifier = item.identity\n                testEntity.name = item.name\n            }\n\n            insert.injectResult(from: download)\n\n            insert.addWillFinishBlockObserver { [unowned self] (procedure, error, _) in\n\n                guard let managedObjectIDs = procedure.output.success else {\n                    self.output = .ready(.failure(procedure.output.error ?? ProcedureKitError.dependency(finishedWithError: error)))\n                    return\n                }\n\n                let moc = container.newBackgroundContext()\n                let managedObjects: [TestEntity] = managedObjectIDs.compactMap { moc.object(with: $0) as? TestEntity }\n\n                self.output = .ready(.success(managedObjects))\n            }\n\n            addChild(insert)\n\n            super.execute()\n        }\n    }\n\n    var managedObjectModel: NSManagedObjectModel {\n        let bundle = Bundle(for: type(of: self))\n        guard let model = NSManagedObjectModel.mergedModel(from: [bundle]) else {\n            fatalError(\"Unable to load TestDataModel.xcdatamodeld from test bundle.\")\n        }\n        return model\n    }\n\n    var persistentStoreDescriptions: [NSPersistentStoreDescription] {\n        let description = NSPersistentStoreDescription()\n        description.type = NSInMemoryStoreType\n        return [description]\n    }\n\n    var items: [TestEntityItem]!\n\n    var coreDataStack: LoadCoreDataProcedure!\n\n    var fetchTestEntities: TransformProcedure<NSPersistentContainer, [TestEntity]>!\n\n    open override func setUp() {\n        super.setUp()\n\n        items = [\n            TestEntityItem(identity: \"a-1\", name: \"Foo\"),\n            TestEntityItem(identity: \"b-2\", name: \"Bar\"),\n            TestEntityItem(identity: \"c-3\", name: \"Bat\")\n        ]\n\n\n        coreDataStack = LoadCoreDataProcedure(\n            name: \"TestDataModel\",\n            managedObjectModel: managedObjectModel,\n            persistentStoreDescriptions: persistentStoreDescriptions\n        )\n\n        coreDataStack.addWillFinishBlockObserver  { (procedure, error, _) in\n            guard error == nil, let container = procedure.output.success else { return }\n            container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy\n            container.viewContext.undoManager = nil\n            container.viewContext.shouldDeleteInaccessibleFaults = true\n            container.viewContext.automaticallyMergesChangesFromParent = true\n        }\n\n        fetchTestEntities = TransformProcedure<NSPersistentContainer, [TestEntity]> { (container) in\n            return try container.viewContext.fetch(TestEntity.fetchRequest())\n        }.injectResult(from: coreDataStack)\n\n    }\n\n    open override func tearDown() {\n        items = nil\n        coreDataStack = nil\n        fetchTestEntities = nil\n        super.tearDown()\n    }\n}\n\ninternal struct TestEntityItem: Identifiable {\n    let identity: String\n    let name: String\n}\n\nextension TestEntity: Identifiable {\n    public var identity: String {\n        return identifier! // Beware: it is not optional in core data, doesn't guarantee this.\n    }\n}\n\nclass TestSuiteRuns: XCTestCase {\n\n    func test__suite_runs() {\n        XCTAssertTrue(true)\n    }\n}\n"
  },
  {
    "path": "Tests/ProcedureKitCoreDataTests/SaveManagedObjectContextProcedureTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport CoreData\nimport ProcedureKit\nimport TestingProcedureKit\n@testable import ProcedureKitCoreData\n\nfinal class SaveManagedObjectContextProcedureTests: ProcedureKitCoreDataTestCase {\n\n    func test__inserting_and_saving() {\n\n        let insert = TransformProcedure<NSPersistentContainer, NSManagedObjectContext> { (container) in\n            let managedObjectContext = container.newBackgroundContext()\n\n            let managedObject = TestEntity(context: managedObjectContext)\n            managedObject.name = \"Hello World\"\n            managedObject.identifier = \"abc-123\"\n\n            return managedObjectContext\n        }.injectResult(from: coreDataStack)\n\n        let save = SaveManagedObjectContext().injectResult(from: insert)\n\n        fetchTestEntities.addDependency(save)\n\n        wait(for: coreDataStack, insert, save, fetchTestEntities)\n\n        PKAssertProcedureFinished(save)\n\n        guard let testEntity = fetchTestEntities.output.success?.first else {\n            XCTFail(\"Did not fetch any test entities.\")\n            return\n        }\n\n        XCTAssertEqual(testEntity.name, \"Hello World\")\n    }\n}\n\n"
  },
  {
    "path": "Tests/ProcedureKitCoreDataTests/TestDataModel.xcdatamodeld/TestDataModel.xcdatamodel/contents",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<model type=\"com.apple.IDECoreDataModeler.DataModel\" documentVersion=\"1.0\" lastSavedToolsVersion=\"14133\" systemVersion=\"17E202\" minimumToolsVersion=\"Automatic\" sourceLanguage=\"Swift\" userDefinedModelVersionIdentifier=\"\">\n    <entity name=\"TestEntity\" representedClassName=\"TestEntity\" syncable=\"YES\" codeGenerationType=\"class\">\n        <attribute name=\"identifier\" attributeType=\"String\" syncable=\"YES\"/>\n        <attribute name=\"name\" attributeType=\"String\" syncable=\"YES\"/>\n    </entity>\n    <elements>\n        <element name=\"TestEntity\" positionX=\"-63\" positionY=\"-18\" width=\"128\" height=\"75\"/>\n    </elements>\n</model>"
  },
  {
    "path": "Tests/ProcedureKitLocationTests/LocationCapabilityTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport CoreLocation\nimport MapKit\nimport ProcedureKit\nimport TestingProcedureKit\n@testable import ProcedureKitLocation\n\nclass CLLocationManagerTests: XCTestCase, CLLocationManagerDelegate {\n\n    func test__extension_set_delegate_works() {\n        let manager = CLLocationManager.make()\n        manager.pk_set(delegate: self)\n        XCTAssertNotNil(manager.delegate)\n        manager.pk_set(delegate: nil)\n        XCTAssertNil(manager.delegate)\n    }\n}\n\nclass CLAuthorizationStatusTests: XCTestCase {\n\n    func test__given_status_not_determined__requirements_not_met() {\n        let status = CLAuthorizationStatus.notDetermined\n        XCTAssertFalse(status.meets(requirement: .whenInUse))\n        XCTAssertFalse(status.meets(requirement: nil))\n    }\n\n    func test__given_status_restricted__requirements_not_met() {\n        let status = CLAuthorizationStatus.restricted\n        XCTAssertFalse(status.meets(requirement: .whenInUse))\n        XCTAssertFalse(status.meets(requirement: nil))\n    }\n\n    func test__given_status_denied__requirements_not_met() {\n        let status = CLAuthorizationStatus.denied\n        XCTAssertFalse(status.meets(requirement: .whenInUse))\n        XCTAssertFalse(status.meets(requirement: nil))\n    }\n\n    #if os(iOS)\n    func test__given_status_authorized_when_in_use__requirement_always_not_met() {\n        let status = CLAuthorizationStatus.authorizedWhenInUse\n        XCTAssertFalse(status.meets(requirement: .always))\n        XCTAssertFalse(status.meets(requirement: nil))\n    }\n\n    func test__given_status_authorized_when_in_use__requirement_when_in_use_met() {\n        let status = CLAuthorizationStatus.authorizedWhenInUse\n        XCTAssertTrue(status.meets(requirement: .whenInUse))\n        XCTAssertFalse(status.meets(requirement: nil))\n    }\n    #endif\n\n    @available(OSX 10.12, iOS 8.0, tvOS 8.0, watchOS 2.0, *)\n    func test__given_status_authorized_always__requirement_when_in_use_met() {\n        let status = CLAuthorizationStatus.authorizedAlways\n        XCTAssertTrue(status.meets(requirement: .whenInUse))\n        XCTAssertTrue(status.meets(requirement: nil))\n    }\n\n    @available(OSX 10.12, iOS 8.0, tvOS 8.0, watchOS 2.0, *)\n    func test__given_status_authorized_always__requirement_always_met() {\n        let status = CLAuthorizationStatus.authorizedAlways\n        XCTAssertTrue(status.meets(requirement: .always))\n        XCTAssertTrue(status.meets(requirement: nil))\n    }\n}\n\nclass LocationCapabilityTests: XCTestCase {\n\n    var registrar: TestableLocationServicesRegistrar!\n    var capability: Capability.Location!\n\n    override func setUp() {\n        super.setUp()\n        registrar = TestableLocationServicesRegistrar()\n        capability = Capability.Location()\n        capability.registrar = registrar\n    }\n\n    override func tearDown() {\n        registrar = nil\n        capability = nil\n        super.tearDown()\n    }\n\n    func test__requirement_is_set() {\n        XCTAssertEqual(capability.requirement, LocationUsage.whenInUse)\n    }\n\n    func test__is_available_queries_registrar() {\n        XCTAssertTrue(capability.isAvailable())\n        XCTAssertTrue(registrar.didCheckServiceEnabled)\n    }\n\n    func test__authorization_status_queries_register() {\n        capability.getAuthorizationStatus { XCTAssertEqual($0, CLAuthorizationStatus.notDetermined) }\n        XCTAssertTrue(registrar.didCheckAuthorizationStatus)\n    }\n\n    func test__given_service_disabled__requesting_authorization_returns_directly() {\n        registrar.servicesEnabled = false\n        var didComplete = false\n        capability.requestAuthorization { \n            didComplete = true\n        }\n        XCTAssertTrue(registrar.didCheckServiceEnabled)\n        XCTAssertFalse(registrar.didRequestAuthorization)\n        XCTAssertNil(registrar.didRequestAuthorizationForUsage)\n        XCTAssertTrue(didComplete)\n    }\n\n    func test__given_not_determined_request_authorization() {\n        weak var exp = expectation(description: \"Test: \\(#function)\")\n        var didComplete = false\n        capability.requestAuthorization {\n            didComplete = true\n            exp?.fulfill()\n        }\n        waitForExpectations(timeout: 3, handler: nil)\n        XCTAssertTrue(registrar.didCheckServiceEnabled)\n        XCTAssertTrue(registrar.didRequestAuthorization)\n        XCTAssertEqual(registrar.didRequestAuthorizationForUsage, .whenInUse)\n        XCTAssertTrue(registrar.didSetDelegate)\n        XCTAssertTrue(didComplete)\n    }\n\n    #if os(iOS)\n    func test__given_when_in_use_require_always_request_authorization() {\n        weak var exp = expectation(description: \"Test: \\(#function)\")\n        registrar.authorizationStatus = .authorizedWhenInUse\n        capability = Capability.Location(.always)\n        capability.registrar = registrar\n        var didComplete = false\n        capability.requestAuthorization {\n            didComplete = true\n            exp?.fulfill()\n        }\n        waitForExpectations(timeout: 3, handler: nil)\n        XCTAssertTrue(registrar.didCheckServiceEnabled)\n        XCTAssertTrue(registrar.didRequestAuthorization)\n        XCTAssertEqual(registrar.didRequestAuthorizationForUsage, .always)\n        XCTAssertTrue(registrar.didSetDelegate)\n        XCTAssertTrue(didComplete)\n    }\n    #endif\n\n    func test__given_denied_does_not_request_authorization() {\n        weak var exp = expectation(description: \"Test: \\(#function)\")\n        registrar.authorizationStatus = .denied\n        var didComplete = false\n        capability.requestAuthorization {\n            didComplete = true\n            exp?.fulfill()\n        }\n        waitForExpectations(timeout: 3, handler: nil)\n        XCTAssertFalse(registrar.didRequestAuthorization)\n        XCTAssertNil(registrar.didRequestAuthorizationForUsage)\n        XCTAssertTrue(didComplete)\n    }\n\n\n    func test__given_already_authorized_sufficiently_does_not_request_authorization() {\n        weak var exp = expectation(description: \"Test: \\(#function)\")\n        registrar.authorizationStatus = {\n            if #available(OSX 10.12, iOS 8.0, tvOS 8.0, watchOS 2.0, *) {\n                return CLAuthorizationStatus.authorizedAlways\n            }\n            else {\n                #if os(OSX)\n                    return CLAuthorizationStatus.authorized\n                #else\n                    return CLAuthorizationStatus.authorizedAlways\n                #endif\n            }\n        }()\n        capability = Capability.Location(.whenInUse)\n        capability.registrar = registrar\n        var didComplete = false\n        capability.requestAuthorization {\n            didComplete = true\n            exp?.fulfill()\n        }\n        waitForExpectations(timeout: 3, handler: nil)\n        XCTAssertFalse(registrar.didRequestAuthorization)\n        XCTAssertNil(registrar.didRequestAuthorizationForUsage)\n        XCTAssertTrue(didComplete)\n    }\n\n}\n"
  },
  {
    "path": "Tests/ProcedureKitLocationTests/ProcedureKitLocationTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport ProcedureKit\nimport TestingProcedureKit\n@testable import ProcedureKitLocation\n\nclass TestSuiteRuns: XCTestCase {\n\n    func test__suite_runs() {\n        XCTAssertTrue(true)\n    }\n}\n"
  },
  {
    "path": "Tests/ProcedureKitLocationTests/ReverseGeocodeProcedureTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport CoreLocation\nimport MapKit\nimport ProcedureKit\nimport TestingProcedureKit\n@testable import ProcedureKitLocation\n\nclass ReverseGeocodeProcedureTests: LocationProcedureTestCase {\n\n    func test__geocoder_starts() {\n        geocoder.placemarks = [placemark]\n        let procedure = ReverseGeocodeProcedure(location: location)\n        procedure.geocoder = geocoder\n        wait(for: procedure)\n        PKAssertProcedureFinished(procedure)\n        XCTAssertEqual(geocoder.didReverseGeocodeLocation, location)\n    }\n\n    func test__geocoder_returns_error_finishes_with_error() {\n        let error = TestError()\n        geocoder.error = error\n        let procedure = ReverseGeocodeProcedure(location: location)\n        procedure.geocoder = geocoder\n        wait(for: procedure)\n        PKAssertProcedureFinishedWithError(procedure, error)\n        XCTAssertEqual(geocoder.didReverseGeocodeLocation, location)\n    }\n\n    func test__geocoder_cancels_when_cancelled() {\n        let procedure = ReverseGeocodeProcedure(location: location)\n        procedure.geocoder = geocoder\n        check(procedure: procedure) { $0.cancel() }\n        XCTAssertTrue(geocoder.didCancel)\n    }\n\n    func test__result_is_set() {\n        geocoder.placemarks = [placemark]\n        let procedure = ReverseGeocodeProcedure(location: location)\n        procedure.geocoder = geocoder\n        wait(for: procedure)\n        PKAssertProcedureFinished(procedure)\n        XCTAssertNotNil(procedure.output.success)\n        XCTAssertEqual(procedure.output.success, geocoder.placemarks?.first)\n    }\n\n    func test__completion_is_executed_and_receives_placemark() {\n        weak var exp = expectation(description: \"Test: \\(#function)\")\n        var didReceivePlacemark: CLPlacemark? = nil\n        geocoder.placemarks = [placemark]\n        let procedure = ReverseGeocodeProcedure(location: location) { placemark in\n            didReceivePlacemark = placemark\n            exp?.fulfill()\n        }\n        procedure.geocoder = geocoder\n        wait(for: procedure)\n        PKAssertProcedureFinished(procedure)\n        XCTAssertNotNil(didReceivePlacemark)\n        XCTAssertEqual(didReceivePlacemark, geocoder.placemarks?.first)\n    }\n\n    func test__completion_is_executed_on_main_queue() {\n        weak var exp = expectation(description: \"Test: \\(#function)\")\n        var didRunCompletionBlockOnMainQueue = false\n        geocoder.placemarks = [placemark]\n        let procedure = ReverseGeocodeProcedure(location: location) { _ in\n            didRunCompletionBlockOnMainQueue = DispatchQueue.isMainDispatchQueue\n            exp?.fulfill()\n        }\n        procedure.geocoder = geocoder\n        wait(for: procedure)\n        PKAssertProcedureFinished(procedure)\n        XCTAssertTrue(didRunCompletionBlockOnMainQueue)\n    }\n}\n\n\n"
  },
  {
    "path": "Tests/ProcedureKitLocationTests/ReverseGeocodeUserLocationProcedureTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport ProcedureKit\nimport TestingProcedureKit\n@testable import ProcedureKitLocation\n\nclass ReverseGeocodeUserLocationProcedureTests: LocationProcedureTestCase {\n\n    func test__geocoder_starts() {\n        geocoder.placemarks = [placemark]\n        let procedure = ReverseGeocodeUserLocationProcedure().set(manager: manager).set(geocoder: geocoder)\n        wait(for: procedure)\n        PKAssertProcedureFinished(procedure)\n        XCTAssertEqual(geocoder.didReverseGeocodeLocation, location)\n    }\n\n    func test__completion_block_receives_placemark_and_location() {\n        geocoder.placemarks = [placemark]\n        let exp = expectation(description: \"Test: \\(#function)\")\n        var didReceiveUserLocationPlacemark: UserLocationPlacemark? = nil\n        let procedure = ReverseGeocodeUserLocationProcedure { result in\n            didReceiveUserLocationPlacemark = result\n            exp.fulfill()\n        }.set(manager: manager).set(geocoder: geocoder)\n        wait(for: procedure)\n        PKAssertProcedureFinished(procedure)\n        XCTAssertNotNil(didReceiveUserLocationPlacemark)\n        XCTAssertEqual(didReceiveUserLocationPlacemark, UserLocationPlacemark(location: location, placemark: placemark))\n    }\n\n    func test__user_location_returns_error_cancels_with_error() {\n        let error = TestError()\n        manager.returnedError = error\n        let procedure = ReverseGeocodeUserLocationProcedure().set(manager: manager).set(geocoder: geocoder)\n        wait(for: procedure)\n        // There are actually 3 errors here, because the UserLocation fails with\n        // an error, the procedures which depend on it then both cancel with errors\n        PKAssertProcedureFinished(procedure, withErrors: true)\n        PKAssertGroupErrors(procedure, contain: error)\n    }\n\n    func test__no_user_location_finishes_with_errors() {\n        manager.returnedLocation = nil\n        let procedure = ReverseGeocodeUserLocationProcedure(timeout: 1).set(manager: manager).set(geocoder: geocoder)\n        wait(for: procedure)\n        PKAssertProcedureCancelledWithError(procedure, ProcedureKitError.timedOut(with: .by(1)))\n    }\n}\n"
  },
  {
    "path": "Tests/ProcedureKitLocationTests/TestableLocationServices.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport MapKit\nimport ProcedureKit\nimport TestingProcedureKit\n@testable import ProcedureKitLocation\n\nfunc createLocation(withAccuracy accuracy: CLLocationAccuracy = 10) -> CLLocation {\n    return CLLocation(\n        coordinate: CLLocationCoordinate2DMake(0.0, 0.0),\n        altitude: 100,\n        horizontalAccuracy: accuracy,\n        verticalAccuracy: accuracy,\n        course: 0,\n        speed: 0,\n        timestamp: Date()\n    )\n}\n\nfunc createPlacemark(coordinate: CLLocationCoordinate2D) -> CLPlacemark {\n    return MKPlacemark(coordinate: coordinate, addressDictionary: [\"City\": \"London\"])\n}\n\nclass TestableLocationServicesRegistrar {\n    static let fake = CLLocationManager()\n\n    weak var delegate: CLLocationManagerDelegate? = nil\n    var servicesEnabled = true\n    var authorizationStatus: CLAuthorizationStatus = .notDetermined\n    var responseStatus: CLAuthorizationStatus = {\n        if #available(OSX 10.12, iOS 8.0, tvOS 8.0, watchOS 2.0, *) {\n            return CLAuthorizationStatus.authorizedAlways\n        }\n        else {\n            #if os(OSX)\n                return CLAuthorizationStatus.authorized\n            #else\n                return CLAuthorizationStatus.authorizedAlways\n            #endif\n        }\n    }()\n\n    var didCheckServiceEnabled = false\n    var didCheckAuthorizationStatus = false\n    var didSetDelegate = false\n    var didRequestAuthorization = false\n    var didRequestAuthorizationForUsage: LocationUsage? = nil\n}\n\nextension TestableLocationServicesRegistrar: LocationServicesRegistrarProtocol {\n\n    func pk_locationServicesEnabled() -> Bool {\n        didCheckServiceEnabled = true\n        return servicesEnabled\n    }\n\n    func pk_authorizationStatus() -> CLAuthorizationStatus {\n        didCheckAuthorizationStatus = true\n        return authorizationStatus\n    }\n\n    func pk_set(delegate aDelegate: CLLocationManagerDelegate?) {\n        didSetDelegate = true\n        delegate = aDelegate\n    }\n\n    func pk_requestAuthorization(withRequirement requirement: LocationUsage?) {\n        didRequestAuthorization = true\n        didRequestAuthorizationForUsage = requirement\n        // In some cases CLLocationManager will immediately send a .NotDetermined\n        delegate?.locationManager!(TestableLocationServicesRegistrar.fake, didChangeAuthorization: .notDetermined)\n        delegate?.locationManager!(TestableLocationServicesRegistrar.fake, didChangeAuthorization: responseStatus)\n    }\n}\n\nclass TestableLocationManager: TestableLocationServicesRegistrar {\n\n    var returnedLocation: CLLocation? = nil\n    var returnedError: Error? = nil\n    var returnAfterDelay: TimeInterval = 0.001\n\n    var didSetDesiredAccuracy: CLLocationAccuracy? = nil\n    var didStartUpdatingLocation = false\n    var didStopUpdatingLocation = false\n\n    fileprivate let updatingLocationGroup = DispatchGroup()\n    fileprivate let stateLock = PThreadMutex()\n    fileprivate var _didStartUpdatingLocationCount = 0\n\n    enum TimeoutResult {\n        case success\n        case timedOut\n\n        init(dispatchTimeoutResult: DispatchTimeoutResult) {\n            switch dispatchTimeoutResult{\n            case .success: self = .success\n            case .timedOut: self = .timedOut\n            }\n        }\n    }\n    func waitForDidStopUpdatingLocation(withTimeout timeout: TimeInterval) -> TimeoutResult {\n        let result = updatingLocationGroup.wait(timeout: .now() + timeout)\n        return TimeoutResult(dispatchTimeoutResult: result)\n    }\n}\n\nextension TestableLocationManager: LocationServicesProtocol {\n\n    func pk_set(desiredAccuracy: CLLocationAccuracy) {\n        didSetDesiredAccuracy = desiredAccuracy\n    }\n\n    func pk_startUpdatingLocation() {\n        stateLock.withCriticalScope {\n            _didStartUpdatingLocationCount += 1\n            updatingLocationGroup.enter()\n        }\n        didStartUpdatingLocation = true\n        if let error = returnedError {\n            delegate?.locationManager!(TestableLocationServicesRegistrar.fake, didFailWithError: error)\n        }\n        else {\n            DispatchQueue.main.asyncAfter(deadline: .now() + returnAfterDelay) {\n                self.delegate?.locationManager!(TestableLocationServicesRegistrar.fake, didUpdateLocations: self.returnedLocation.flatMap { [$0] } ?? [])\n            }\n        }\n    }\n\n    func pk_stopUpdatingLocation() {\n        stateLock.withCriticalScope {\n            guard _didStartUpdatingLocationCount > 0 else { return }\n            _didStartUpdatingLocationCount -= 1\n            updatingLocationGroup.leave()\n        }\n        didStopUpdatingLocation = true\n    }\n}\n\nclass TestableGeocoder: GeocodeProtocol {\n\n    var didCancel = false\n\n    func pk_cancel() {\n        didCancel = true\n    }\n}\n\nclass TestableReverseGeocoder: TestableGeocoder, ReverseGeocodeProtocol {\n\n    var didReverseGeocodeLocation: CLLocation? = nil\n\n    var placemarks: [CLPlacemark]? = nil\n    var error: Error? = nil\n\n    func pk_reverseGeocodeLocation(location: CLLocation, completionHandler completion: @escaping CLGeocodeCompletionHandler) {\n        didReverseGeocodeLocation = location\n        // To replicate CLGeocoder, the completion block must be called on the main thread\n        DispatchQueue.main.async { [weak self] in\n            guard let strongSelf = self else {\n                fatalError(\"TestableReverseGeocoder disappeared before completion was called\")\n            }\n            completion(strongSelf.placemarks, strongSelf.error)\n        }\n    }\n}\n\nclass LocationProcedureTestCase: ProcedureKitTestCase {\n\n    var location: CLLocation!\n    var placemark: CLPlacemark!    \n    let accuracy: CLLocationAccuracy = 10\n    var manager: TestableLocationManager!\n    var geocoder: TestableReverseGeocoder!\n\n    override func setUp() {\n        super.setUp()\n        location = createLocation(withAccuracy: accuracy)\n        placemark = createPlacemark(coordinate: location.coordinate)\n        manager = TestableLocationManager()\n        manager.authorizationStatus = {\n            if #available(OSX 10.12, iOS 8.0, tvOS 8.0, watchOS 2.0, *) {\n                return CLAuthorizationStatus.authorizedAlways\n            }\n            else {\n                #if os(OSX)\n                    return CLAuthorizationStatus.authorized\n                #else\n                    return CLAuthorizationStatus.authorizedAlways\n                #endif\n            }\n        }()\n        manager.returnedLocation = location\n        geocoder = TestableReverseGeocoder()\n    }\n\n    override func tearDown() {\n        location = nil\n        manager = nil\n        geocoder = nil\n        super.tearDown()\n    }\n}\n\n\n"
  },
  {
    "path": "Tests/ProcedureKitLocationTests/UserLocationProcedureTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport CoreLocation\nimport MapKit\nimport ProcedureKit\nimport TestingProcedureKit\n@testable import ProcedureKitLocation\n\nclass UserLocationProcedureTests: LocationProcedureTestCase {\n\n    func test__received_location_is_set() {\n        let procedure = UserLocationProcedure(accuracy: accuracy)\n        procedure.manager = manager\n        wait(for: procedure)\n        PKAssertProcedureFinished(procedure)\n        XCTAssertEqual(procedure.output.success, location)\n        XCTAssertEqual(manager.didSetDesiredAccuracy, accuracy)\n        XCTAssertTrue(manager.didSetDelegate)\n        XCTAssertTrue(manager.didStartUpdatingLocation)\n        XCTAssertTrue(manager.didStopUpdatingLocation)\n    }\n\n    func test__receives_location_in_completion_block() {\n        var receivedLocation: CLLocation? = nil\n        let procedure = UserLocationProcedure(accuracy: accuracy) { location in\n            receivedLocation = location\n        }\n        procedure.manager = manager\n        wait(for: procedure)\n        PKAssertProcedureFinished(procedure)\n        XCTAssertEqual(receivedLocation, location)\n        XCTAssertEqual(manager.didSetDesiredAccuracy, accuracy)\n        XCTAssertTrue(manager.didSetDelegate)\n        XCTAssertTrue(manager.didStartUpdatingLocation)\n        XCTAssertTrue(manager.didStopUpdatingLocation)\n    }\n\n    func test__updates_stop_when_cancelled() {\n        let procedure = UserLocationProcedure(accuracy: accuracy)\n        procedure.manager = manager\n        check(procedure: procedure) { $0.cancel() }\n        XCTAssertTrue(manager.didStopUpdatingLocation)\n    }\n\n    func test__updates_stop_when_deallocated() {\n        var tmp: UserLocationProcedure! = UserLocationProcedure(accuracy: accuracy)\n        tmp.manager = manager\n        tmp = nil\n        // because of the asynchronous nature of a Procedure, deinit could occur in\n        // another thread that is still finishing up a block and releases the last reference\n        // to `tmp` - therefore, wait for a short bit to allow for that case\n        XCTAssertEqual(manager.waitForDidStopUpdatingLocation(withTimeout: 0.5), .success)\n    }\n\n    func test__finishes_if_accuracy_is_best() {\n        let procedure = UserLocationProcedure(accuracy: kCLLocationAccuracyBestForNavigation)\n        procedure.manager = manager\n        wait(for: procedure)\n        PKAssertProcedureFinished(procedure)\n    }\n\n    func test__finishes_with_error_if_location_manager_fails() {\n        let error = TestError()\n        manager.returnedError = error\n        let procedure = UserLocationProcedure(accuracy: accuracy)\n        procedure.manager = manager\n        wait(for: procedure)\n        PKAssertProcedureFinishedWithError(procedure, error)\n    }\n\n    func test__cancels_with_timeout_if_location_manager_takes_too_long() {\n        manager.returnAfterDelay = 0.2\n        let procedure = UserLocationProcedure(timeout: 0.1, accuracy: accuracy)\n        procedure.manager = manager\n        wait(for: procedure)\n        PKAssertProcedureCancelledWithError(procedure, ProcedureKitError.timedOut(with: .by(0.1)))\n    }\n}\n\n\n"
  },
  {
    "path": "Tests/ProcedureKitMacTests/ProcedureKitMacTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport ProcedureKit\nimport TestingProcedureKit\n@testable import ProcedureKitMac\n\nclass TestSuiteRuns: XCTestCase {\n\n    func test__suite_runs() {\n        XCTAssertTrue(true)\n    }\n}\n"
  },
  {
    "path": "Tests/ProcedureKitMacTests/ProcessProcedureTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\n\nimport XCTest\nimport TestingProcedureKit\nimport Foundation\n@testable import ProcedureKitMac\n\nclass ProcessProcedureTests: ProcedureKitTestCase {\n\n    var process: Process!\n    var processProcedure: ProcessProcedure!\n\n    var launchPath: String!\n    var executableURL: URL!\n    var arguments: [String]!\n\n    let bash = \"/bin/bash\"\n    let bashWaitIndefinitelyForInput = \"read -n1 -r -p \\\"Wait indefinitely for input\\\" key\"\n\n    override func setUp() {\n        super.setUp()\n\n        launchPath = \"/bin/echo\"\n        executableURL = URL(fileURLWithPath: launchPath)\n        arguments = [ \"Hello World\" ]\n        processProcedure = ProcessProcedure(launchPath: launchPath, arguments: arguments)\n    }\n\n    func test__start_process() {\n        wait(for: processProcedure)\n        PKAssertProcedureFinished(processProcedure)\n    }\n\n    func test__start_process_with_executableurl() {\n        processProcedure = ProcessProcedure(executableURL: executableURL, arguments: arguments)\n        wait(for: processProcedure)\n        PKAssertProcedureFinished(processProcedure)\n    }\n\n    func test__start_process_with_launchpath_only() {\n        processProcedure = ProcessProcedure(launchPath: launchPath)\n        wait(for: processProcedure)\n        PKAssertProcedureFinished(processProcedure)\n    }\n\n    func test__start_process_with_executableurl_only() {\n        processProcedure = ProcessProcedure(executableURL: executableURL)\n        wait(for: processProcedure)\n        PKAssertProcedureFinished(processProcedure)\n    }\n\n    func test__start_process_with_non_existent_launchpath() {\n        let nonExistentLaunchPath = \"/bin/echo8procedurekit\"\n        guard !FileManager.default.isExecutableFile(atPath: nonExistentLaunchPath) else {\n            // the non-existent launch path used for this test exists on the local system\n            XCTFail(\"Cannot run test. The non-existent launch path exists on this system: \\(nonExistentLaunchPath)\")\n            return\n        }\n        processProcedure = ProcessProcedure(launchPath: nonExistentLaunchPath)\n        wait(for: processProcedure)\n        PKAssertProcedureFinishedWithError(processProcedure, ProcessProcedure.Error.invalidLaunchPath)\n    }\n\n    func test__start_process_with_non_existent_executableurl() {\n        let nonExistentExecutableURL = URL(fileURLWithPath: \"/bin/echo8procedurekit\")\n        guard !FileManager.default.isExecutableFile(atPath: nonExistentExecutableURL.path) else {\n            // the non-existent launch path used for this test exists on the local system\n            XCTFail(\"Cannot run test. The non-existent launch path exists on this system: \\(nonExistentExecutableURL)\")\n            return\n        }\n        processProcedure = ProcessProcedure(executableURL: nonExistentExecutableURL)\n        wait(for: processProcedure)\n        PKAssertProcedureFinishedWithError(processProcedure, ProcessProcedure.Error.invalidLaunchPath)\n    }\n\n    func test__cancel_process_before_launched() {\n        processProcedure.cancel()\n        wait(for: processProcedure)\n        PKAssertProcedureCancelled(processProcedure)\n    }\n\n    func test__cancel_process_after_launched() {\n        processProcedure = ProcessProcedure(launchPath: bash, arguments: [\"-c\", bashWaitIndefinitelyForInput], processDidLaunch: { processProcedure in\n                processProcedure.cancel()\n        })\n        wait(for: processProcedure, withTimeout: 1)\n        PKAssertProcedureCancelled(processProcedure)\n    }\n\n    func test__processIdentifier_before_launched() {\n        XCTAssertEqual(processProcedure.processIdentifier, 0)\n    }\n\n    func test__processIdentifier_after_launched() {\n        weak var didExecuteExpectation = expectation(description: \"DidExecute: \\(#function)\")\n        let processIdentifier = Protector<Int32>(-1)\n        processProcedure = ProcessProcedure(launchPath: bash, arguments: [\"-c\", \"sleep 1\"], processDidLaunch: { processProcedure in\n                let retrievedProcessIdentifier = processProcedure.processIdentifier\n                processIdentifier.overwrite(with: retrievedProcessIdentifier)\n                DispatchQueue.main.async {\n                    didExecuteExpectation?.fulfill()\n                }\n        })\n        wait(for: processProcedure)\n        XCTAssertGreaterThan(processIdentifier.access, 0)\n    }\n\n    func test__processIdentifier_after_finished() {\n        wait(for: processProcedure)\n        PKAssertProcedureFinished(processProcedure)\n        XCTAssertGreaterThan(processProcedure.processIdentifier, 0)\n    }\n\n    func test__suspend_before_launched_returns_false() {\n        weak var didSuspendExpectation = expectation(description: \"Did Suspend: \\(#function)\")\n        processProcedure = ProcessProcedure(launchPath: bash, arguments: [\"-c\", \"sleep 1\"])\n        processProcedure.suspend { success in\n            DispatchQueue.main.async {\n                XCTAssertFalse(success)\n                didSuspendExpectation?.fulfill()\n            }\n        }\n        waitForExpectations(timeout: 3, handler: nil)\n    }\n\n    func test__suspend_after_finished_returns_false() {\n        wait(for: processProcedure)\n        PKAssertProcedureFinished(processProcedure)\n        weak var didSuspendExpectation = expectation(description: \"Did Suspend: \\(#function)\")\n        processProcedure.suspend { success in\n            DispatchQueue.main.async {\n                XCTAssertFalse(success)\n                didSuspendExpectation?.fulfill()\n            }\n        }\n        waitForExpectations(timeout: 3, handler: nil)\n    }\n\n    func test__resume_before_launched_returns_false() {\n        weak var didResumeExpectation = expectation(description: \"Did Resume: \\(#function)\")\n        processProcedure = ProcessProcedure(launchPath: bash, arguments: [\"-c\", \"sleep 1\"])\n        processProcedure.resume { success in\n            DispatchQueue.main.async {\n                XCTAssertFalse(success)\n                didResumeExpectation?.fulfill()\n            }\n        }\n        waitForExpectations(timeout: 3, handler: nil)\n    }\n\n    func test__resume_after_finished_returns_false() {\n        wait(for: processProcedure)\n        PKAssertProcedureFinished(processProcedure)\n        weak var didResumeExpectation = expectation(description: \"Did Resume: \\(#function)\")\n        processProcedure.resume { success in\n            DispatchQueue.main.async {\n                XCTAssertFalse(success)\n                didResumeExpectation?.fulfill()\n            }\n        }\n        waitForExpectations(timeout: 3, handler: nil)\n    }\n\n    func test__suspend_resume_while_executing() {\n        // suspend\n        let didFinishGroup = DispatchGroup()\n        weak var didSuspendExpectation = expectation(description: \"Did Suspend: \\(#function)\")\n        weak var delayPassed = expectation(description: \"Delay Passed: \\(#function)\")\n        processProcedure = ProcessProcedure(launchPath: bash, arguments: [\"-c\", \"sleep 1\"], processDidLaunch: { processProcedure in\n                processProcedure.suspend { (success) in\n                    DispatchQueue.main.async {\n                        XCTAssertTrue(success)\n                        didSuspendExpectation?.fulfill()\n                    }\n                }\n                DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1.5) {\n                    delayPassed?.fulfill()\n                }\n        })\n        didFinishGroup.enter()\n        processProcedure.addDidFinishBlockObserver { procedure, _ in\n            didFinishGroup.leave()\n        }\n        run(operations: processProcedure)\n        waitForExpectations(timeout: 3, handler: nil)\n        XCTAssertFalse(processProcedure.isFinished)\n\n        // resume\n        weak var didFinishExpectation = expectation(description: \"Did Finish: \\(#function)\")\n        didFinishGroup.notify(queue: DispatchQueue.main) {\n            didFinishExpectation?.fulfill()\n        }\n        weak var didResumeExpectation = expectation(description: \"Did Resume: \\(#function)\")\n        processProcedure.resume { (success) in\n            DispatchQueue.main.async {\n                XCTAssertTrue(success)\n                didResumeExpectation?.fulfill()\n            }\n        }\n        waitForExpectations(timeout: 3, handler: nil)\n        XCTAssertTrue(processProcedure.isFinished)\n    }\n\n    // MARK: - ProcessDidExitCleanly closure\n\n    func test__process_did_exit_cleanly_closure_receives_expected_exit_status_input() {\n        let exitStatus: Int32 = 5\n        let receivedStatus = Protector<Int32?>(nil)\n        let receivedReason = Protector<Process.TerminationReason?>(nil)\n        processProcedure = ProcessProcedure(launchPath: bash, arguments: [\"-c\", \"exit \\(exitStatus)\"], processDidExitCleanly: { status, reason in\n            receivedStatus.overwrite(with: status)\n            receivedReason.overwrite(with: reason)\n            return false\n        })\n        wait(for: processProcedure)\n\n        guard let status = receivedStatus.access, let reason = receivedReason.access else {\n            XCTFail(\"processDidExitCleanly closure was not called. status and/or reason are nil.\")\n            return\n        }\n        XCTAssertEqual(status, exitStatus, \"processDidExitCleanly closure did not receive expected status (\\(exitStatus)); instead, received: \\(status))\")\n        XCTAssertEqual(reason, .exit, \"processDidExitCleanly closure did not receive expected reason (.exit); instead, received: \\(reason))\")\n        PKAssertProcedureFinishedWithError(processProcedure, ProcessProcedure.Error.didNotExitCleanly(exitStatus, .exit))\n    }\n\n    func test__process_did_exit_cleanly_closure_receives_expected_uncaught_signal_input() {\n        let receivedStatus = Protector<Int32?>(nil)\n        let receivedReason = Protector<Process.TerminationReason?>(nil)\n        processProcedure = ProcessProcedure(launchPath: bash, arguments: [\"-c\", bashWaitIndefinitelyForInput], processDidLaunch: { processProcedure in\n            guard let process = processProcedure.process else { assertionFailure(\"ProcessProcedure.process does not exist\"); return }\n            DispatchQueue.main.async {\n                // Send SIGTERM to the ProcessProcedure's internal Process\n                // NOTE: This is only for testing. User code should use `ProcessProcedure.cancel()`.\n                process.terminate()\n            }\n        }, processDidExitCleanly: { status, reason in\n            receivedStatus.overwrite(with: status)\n            receivedReason.overwrite(with: reason)\n            return false\n        })\n        wait(for: processProcedure)\n\n        guard let status = receivedStatus.access, let reason = receivedReason.access else {\n            XCTFail(\"processDidExitCleanly closure was not called. status and/or reason are nil.\")\n            return\n        }\n        XCTAssertEqual(status, SIGTERM, \"processDidExitCleanly closure did not receive expected status (\\(SIGTERM)); instead, received: \\(status))\")\n        XCTAssertEqual(reason, .uncaughtSignal, \"processDidExitCleanly closure did not receive expected reason (.uncaughtSignal); instead, received: \\(reason))\")\n        PKAssertProcedureFinishedWithError(processProcedure, ProcessProcedure.Error.didNotExitCleanly(SIGTERM, .uncaughtSignal))\n    }\n\n    // MARK: - Configuration Properties (Read-only)\n\n    func test__arguments() {\n        processProcedure = ProcessProcedure(launchPath: launchPath, arguments: arguments)\n        XCTAssertEqual(processProcedure.arguments ?? [], arguments)\n    }\n\n    func test__currentDirectoryURL() {\n        let currentDirectoryPath = \"/bin\"\n        processProcedure = ProcessProcedure(launchPath: launchPath, currentDirectoryPath: currentDirectoryPath)\n        XCTAssertEqual(processProcedure.currentDirectoryURL?.path, currentDirectoryPath)\n    }\n\n    func test__environment() {\n        var environment = ProcessInfo().environment\n        environment.updateValue(\"new\", forKey: \"procedurekittest\")\n        processProcedure = ProcessProcedure(launchPath: launchPath, environment: environment)\n        XCTAssertEqual(processProcedure.environment ?? [:], environment)\n    }\n\n    func test__executableURL() {\n        XCTAssertEqual(processProcedure.executableURL?.path, launchPath)\n    }\n\n    func test__standardError() {\n        let pipe = Pipe()\n        processProcedure = ProcessProcedure(launchPath: launchPath, standardError: pipe)\n        guard let readValue = processProcedure.standardError else {\n            XCTFail(\"standardError is nil\")\n            return\n        }\n        guard let readValueAsPipe = readValue as? Pipe else {\n            XCTFail(\"standardError is not expected type\")\n            return\n        }\n        XCTAssertEqual(readValueAsPipe, pipe)\n    }\n\n    func test__standardInput() {\n        let pipe = Pipe()\n        processProcedure = ProcessProcedure(launchPath: launchPath, standardInput: pipe)\n        guard let readValue = processProcedure.standardInput else {\n            XCTFail(\"standardInput is nil\")\n            return\n        }\n        guard let readValueAsPipe = readValue as? Pipe else {\n            XCTFail(\"standardInput is not expected type\")\n            return\n        }\n        XCTAssertEqual(readValueAsPipe, pipe)\n    }\n\n    func test__standardOutput() {\n        let pipe = Pipe()\n        processProcedure = ProcessProcedure(launchPath: launchPath, standardOutput: pipe)\n        guard let readValue = processProcedure.standardOutput else {\n            XCTFail(\"standardOutput is nil\")\n            return\n        }\n        guard let readValueAsPipe = readValue as? Pipe else {\n            XCTFail(\"standardOutput is not expected type\")\n            return\n        }\n        XCTAssertEqual(readValueAsPipe, pipe)\n    }\n\n    // MARK: - Finishing\n\n    func test__no_requirement__finishes_with_error() {\n        processProcedure = ProcessProcedure()\n        wait(for: processProcedure)\n        PKAssertProcedureFinishedWithError(processProcedure, ProcedureKitError.requirementNotSatisfied())\n    }\n\n    func test__process_exit_status_1__finishes_with_error() {\n        processProcedure = ProcessProcedure(launchPath: bash, arguments: [\"-c\", \"exit 1\"])\n        wait(for: processProcedure)\n        PKAssertProcedureFinishedWithError(processProcedure, ProcessProcedure.Error.didNotExitCleanly(1, .exit))\n    }\n\n    func test__process_terminated_with_uncaught_signal__finishes_with_error() {\n        processProcedure = ProcessProcedure(launchPath: bash, arguments: [\"-c\", bashWaitIndefinitelyForInput], processDidLaunch: { processProcedure in\n            guard let process = processProcedure.process else { assertionFailure(\"ProcessProcedure.process does not exist\"); return }\n            DispatchQueue.main.async {\n                // Send SIGTERM to the ProcessProcedure's internal Process\n                // NOTE: This is only for testing. User code should use `ProcessProcedure.cancel()`.\n                process.terminate()\n            }\n        })\n        wait(for: processProcedure)\n        PKAssertProcedureFinishedWithError(processProcedure, ProcessProcedure.Error.didNotExitCleanly(SIGTERM, .uncaughtSignal))\n    }\n\n    func test__process_did_exit_cleanly_closure_false__finishes_with_error() {\n        let didCallClosure = Protector(false)\n        processProcedure = ProcessProcedure(launchPath: bash, arguments: [\"-c\", \"exit 0\"], processDidExitCleanly: { _, _ in\n            didCallClosure.overwrite(with: true)\n            return false\n        })\n        wait(for: processProcedure)\n        XCTAssertTrue(didCallClosure.access, \"processDidExitCleanly closure was not called.\")\n        PKAssertProcedureFinishedWithError(processProcedure, ProcessProcedure.Error.didNotExitCleanly(0, .exit))\n    }\n\n    func test__process_did_exit_cleanly_closure_true__finishes_without_error() {\n        let didCallClosure = Protector(false)\n        processProcedure = ProcessProcedure(launchPath: bash, arguments: [\"-c\", \"exit 1\"], processDidExitCleanly: { _, _ in\n            didCallClosure.overwrite(with: true)\n            return true\n        })\n        wait(for: processProcedure)\n        XCTAssertTrue(didCallClosure.access, \"processDidExitCleanly closure was not called.\")\n        PKAssertProcedureFinished(processProcedure)\n    }\n}\n\nextension Process.TerminationReason: CustomStringConvertible {\n    public var description: String {\n        switch self {\n        case .exit: return \".exit\"\n        case .uncaughtSignal: return \".uncaughtSignal\"\n        }\n    }\n}\n"
  },
  {
    "path": "Tests/ProcedureKitMobileTests/AlertProcedureTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport ProcedureKit\nimport TestingProcedureKit\n@testable import ProcedureKitMobile\n\nclass AlertProcedureTests: ProcedureKitTestCase {\n\n    var title: String!\n    var message: String!\n    var presenting: TestablePresentingController!\n    var alert: AlertProcedure!\n\n    override func setUp() {\n        super.setUp()\n        title = \"This is the alert title\"\n        message = \"This is the alert message\"\n        presenting = TestablePresentingController()\n        alert = AlertProcedure(from: presenting)\n    }\n\n    override func tearDown() {\n        title = nil\n        message = nil\n        presenting = nil\n        alert = nil\n        super.tearDown()\n    }\n\n    func test__alert_style_set_default() {\n        XCTAssertEqual(alert.preferredStyle, UIAlertController.Style.alert)\n    }\n\n    func test__alert_title() {\n        alert.title = title\n        XCTAssertEqual(alert.title, title)\n    }\n\n    func test__alert_message() {\n        alert.message = message\n        XCTAssertEqual(alert.message, message)\n    }\n\n    func test__alert_add_textfield() {\n        alert.addTextField(configurationHandler: nil)\n        XCTAssertNotNil(alert.textFields)\n    }\n\n    func test__alert_actions() {\n        alert.add(actionWithTitle: \"OK\")\n        XCTAssertEqual(alert.actions.count, 1)\n    }\n\n    func test__alert_preferred_action() {\n        let action = alert.add(actionWithTitle: \"OK\", style: .default, isPreferred: true)\n        alert.add(actionWithTitle: \"Cancel\", style: .cancel)\n        XCTAssertEqual(alert.preferredAction?.title ?? \"Epic Fail\", action.title ?? \"Hello\")\n        XCTAssertNotNil(alert.preferredAction)\n    }\n\n    func test__alert_presents_alert_controller() {\n        alert = AlertProcedure(title: title, message: message, from: presenting, waitForDismissal: false)\n        presenting.check = { [unowned self] received in\n            guard let alertController = received as? UIAlertController else {\n                XCTFail(\"Did not receive an alert controller\")\n                return\n            }\n            XCTAssertEqual(alertController.title, self.title)\n            XCTAssertEqual(alertController.message, self.message)\n        }\n\n        wait(for: alert)\n        PKAssertProcedureFinished(alert)\n    }\n}\n"
  },
  {
    "path": "Tests/ProcedureKitMobileTests/BackgroundObserverTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport ProcedureKit\nimport TestingProcedureKit\n@testable import ProcedureKitMobile\n\nclass BackgroundObserverTests: ProcedureKitTestCase {\n\n    var backgroundTaskName: String!\n    var backgroundTaskIdentifier: UIBackgroundTaskIdentifier!\n    var endedBackgroundTaskIdentifier: UIBackgroundTaskIdentifier!\n\n    var didBeginTaskBlock: TestableUIApplication.DidBeginBackgroundTask!\n    var didEndTaskBlock: TestableUIApplication.DidEndBackgroundTask!\n    var taskGroup: DispatchGroup!\n    var observer: BackgroundObserver!\n\n    var testableApplication: TestableUIApplication!\n    var testableBackgroundManager: BackgroundManager!\n\n    var backgroundProcedure: WaitsToFinishProcedure!\n\n    // Does not finish until told to (by something external).\n    class WaitsToFinishProcedure: Procedure {\n        override func execute() {\n            // do nothing\n        }\n    }\n\n    override func setUp() {\n        super.setUp()\n        Log.enabled = true\n        backgroundProcedure = WaitsToFinishProcedure()\n        backgroundProcedure.log.writer = TestableLogWriter()\n        backgroundTaskName = \"Hello world\"\n        taskGroup = DispatchGroup()\n        didBeginTaskBlock = { name, identifier in\n            self.taskGroup.enter()\n            self.backgroundTaskName = name\n            self.backgroundTaskIdentifier = identifier\n        }\n        didEndTaskBlock = {\n            self.endedBackgroundTaskIdentifier = $0\n            self.taskGroup.leave()\n        }\n        testableApplication = TestableUIApplication(state: UIApplication.State.active, didBeginTask: didBeginTaskBlock, didEndTask: didEndTaskBlock)\n        testableBackgroundManager = BackgroundManager(app: testableApplication)\n    }\n\n    override func tearDown() {\n        if let backgroundProcedure = backgroundProcedure {\n            backgroundProcedure.cancel()\n        }\n        backgroundProcedure = nil\n        backgroundTaskName = nil\n        backgroundTaskIdentifier = nil\n        endedBackgroundTaskIdentifier = nil\n        didBeginTaskBlock = nil\n        didEndTaskBlock = nil\n        testableApplication = nil\n        testableBackgroundManager = nil\n        observer = nil\n        taskGroup = nil\n        super.tearDown()\n    }\n\n    private func waitForTaskGroup(withTimeout timeout: TimeInterval = 3) {\n        weak var exp = expectation(description: \"Task Group finished\")\n        taskGroup.notify(queue: DispatchQueue.main) {\n            exp?.fulfill()\n        }\n        waitForExpectations(timeout: timeout)\n    }\n\n    // Adds a BackgroundObserver to a Procedure and waits until the observer\n    // attempts to begin the background task for the Procedure.\n    private func add(backgroundObserver: BackgroundObserver, to procedure: Procedure) {\n        assert(Thread.isMainThread)\n\n        let didBeginTask = DispatchGroup()\n        didBeginTask.enter()\n\n        testableApplication.didBeginBackgroundTask = { taskName, identifier in\n            self.didBeginTaskBlock(taskName, identifier)\n            didBeginTask.leave()\n        }\n\n        // add the background observer\n        procedure.addObserver(backgroundObserver)\n\n        // wait for attaching the BackgroundObserver to attempt to begin the background task\n        weak var expDidBeginTask = expectation(description: \"Attaching BackgroundObserver did begin background task\")\n        didBeginTask.notify(queue: DispatchQueue.main) {\n            expDidBeginTask?.fulfill()\n        }\n        waitForExpectations(timeout: 3)\n        expDidBeginTask = nil\n\n        // reset\n        testableApplication.didBeginBackgroundTask = self.didBeginTaskBlock\n    }\n\n    // MARK: Basic Functionality\n\n    // TODO: @swiftlyfalling - These tests fail\n    func x_test__background_observer_starts_and_ends_background_task() {\n\n        let expectedBackgroundTaskName = BackgroundManager.backgroundTaskName(for: backgroundProcedure)\n\n        observer = BackgroundObserver(manager: testableBackgroundManager)\n\n        // add the background observer\n        add(backgroundObserver: observer, to: backgroundProcedure)\n\n        XCTAssertEqual(taskGroup.wait(timeout: .now()), .timedOut)\n        XCTAssertEqual(testableApplication.backgroundTasks.count, 1)\n        XCTAssertEqual(testableApplication.backgroundTasks[0].0, expectedBackgroundTaskName)\n        XCTAssertEqual(testableApplication.backgroundTasks[0].2, .running)\n\n        backgroundProcedure.addDidExecuteBlockObserver { backgroundProcedure in\n            // finish the background procedure once it executes\n            backgroundProcedure.finish()\n        }\n        wait(for: backgroundProcedure)\n        waitForTaskGroup()\n\n        PKAssertProcedureFinished(backgroundProcedure)\n        XCTAssertEqual(backgroundTaskName, expectedBackgroundTaskName)\n        XCTAssertNotEqual(backgroundTaskIdentifier, UIBackgroundTaskIdentifier.invalid)\n        XCTAssertEqual(backgroundTaskIdentifier, endedBackgroundTaskIdentifier)\n        XCTAssertEqual(testableApplication.backgroundTasks.count, 1)\n        XCTAssertEqual(testableApplication.backgroundTasks[0].0, expectedBackgroundTaskName)\n        XCTAssertEqual(testableApplication.backgroundTasks[0].2, .ended)\n    }\n\n    // MARK: When Background Execution is Unavailable\n\n    func test__background_observer__when_background_execution_is_unavailable() {\n\n        let expectedBackgroundTaskName = BackgroundManager.backgroundTaskName(for: backgroundProcedure)\n\n        // simulate the state in which running in the background is not possible\n        testableApplication.backgroundExecutionDisabled = true\n\n        observer = BackgroundObserver(manager: testableBackgroundManager)\n\n        // add the background observer\n        add(backgroundObserver: observer, to: backgroundProcedure)\n\n        // if background execution isn't possible...\n        // 1.) The Application should have received a request to begin a background task\n        XCTAssertEqual(testableApplication.backgroundTasks.count, 1)\n        XCTAssertEqual(testableApplication.backgroundTasks[0].0, expectedBackgroundTaskName)\n        // 2.) But beginBackgroundTask should have returned UIBackgroundTaskInvalid\n        XCTAssertEqual(backgroundTaskIdentifier, UIBackgroundTaskIdentifier.invalid)\n\n        // run and finish the Procedure\n        backgroundProcedure.addDidExecuteBlockObserver { backgroundProcedure in\n            // finish the background procedure once it executes\n            backgroundProcedure.finish()\n        }\n        wait(for: backgroundProcedure)\n\n        // the task group should never finish, since the BackgroundObserver did not successfully\n        // register a background task, and thus will never end a background task\n        XCTAssertEqual(taskGroup.wait(timeout: .now() + 0.3), .timedOut, \"The BackgroundObserver ended a background task - this should not happen, since its attempt at registering a background task should have been unsuccessful.\")\n        XCTAssertNil(endedBackgroundTaskIdentifier)\n\n        // clean-up - explicitly finish the task group\n        taskGroup.leave()\n\n        PKAssertProcedureFinished(backgroundProcedure)\n    }\n\n    // MARK: Cancellation Behavior: .never\n\n    // TODO: @swiftlyfalling - These tests fail\n    func x_test__background_observer__never_cancel_procedure() {\n\n        let expectedBackgroundTaskName = BackgroundManager.backgroundTaskName(for: backgroundProcedure)\n\n        let didCancel = DispatchGroup()\n        didCancel.enter()\n        backgroundProcedure.addDidCancelBlockObserver { backgroundProcedure, errors in\n            didCancel.leave()\n        }\n\n        observer = BackgroundObserver(manager: testableBackgroundManager, cancelProcedure: .never)\n\n        // add the background observer\n        add(backgroundObserver: observer, to: backgroundProcedure)\n\n        XCTAssertEqual(testableApplication.backgroundTasks.count, 1)\n        XCTAssertEqual(testableApplication.backgroundTasks[0].0, expectedBackgroundTaskName)\n        XCTAssertEqual(testableApplication.backgroundTasks[0].2, .running)\n\n        backgroundProcedure.addDidExecuteBlockObserver(synchronizedWith: DispatchQueue.main) { [testableApplication = testableApplication!] backgroundProcedure in\n            // enter the background while executing (should not trigger cancel)\n            testableApplication.enterBackground()\n            XCTAssertEqual(didCancel.wait(timeout: .now() + 0.2), .timedOut, \"The Procedure was cancelled after entering the background, even though `cancelProcedure: .never`.\")\n\n            // simulate the background execution time expiring while executing (should not trigger cancel)\n            testableApplication.simulateBackgroundTimeExpiration()\n            XCTAssertEqual(didCancel.wait(timeout: .now() + 0.2), .timedOut, \"The Procedure was cancelled after simulating background time expiration, even though `cancelProcedure: .never`.\")\n\n            // transition *back* to active (should not trigger cancel)\n            testableApplication.becomeActive()\n            XCTAssertEqual(didCancel.wait(timeout: .now() + 0.2), .timedOut, \"The Procedure was cancelled after leaving the background, even though `cancelProcedure: .never`.\")\n\n            backgroundProcedure.finish()\n        }\n        wait(for: backgroundProcedure)\n        waitForTaskGroup()\n\n        PKAssertProcedureFinished(backgroundProcedure)\n        XCTAssertEqual(backgroundTaskName, expectedBackgroundTaskName)\n        XCTAssertNotEqual(backgroundTaskIdentifier, UIBackgroundTaskIdentifier.invalid)\n        XCTAssertEqual(backgroundTaskIdentifier, endedBackgroundTaskIdentifier)\n        XCTAssertEqual(testableApplication.backgroundTasks.count, 1)\n        XCTAssertEqual(testableApplication.backgroundTasks[0].0, expectedBackgroundTaskName)\n        XCTAssertEqual(testableApplication.backgroundTasks[0].2, .ended)\n\n        // clean-up\n        guard !backgroundProcedure.isCancelled else { return }\n        didCancel.leave() // since the Procedure should never have been cancelled\n    }\n\n    // MARK: Cancellation Behavior: .whenAppIsBackgrounded\n\n    func test__background_observer__cancel_when_app_is_backgrounded__app_already_in_background() {\n\n        let expectedBackgroundTaskName = BackgroundManager.backgroundTaskName(for: backgroundProcedure)\n        testableApplication.enterBackground()\n\n        observer = BackgroundObserver(manager: testableBackgroundManager, cancelProcedure: .whenAppIsBackgrounded)\n\n        let didCancel = DispatchGroup()\n        let cancellationError = Protector<Error?>(nil)\n        didCancel.enter()\n        backgroundProcedure.addDidCancelBlockObserver { backgroundProcedure, error in\n            cancellationError.overwrite(with: error)\n            didCancel.leave()\n        }\n\n        // add the background observer\n        add(backgroundObserver: observer, to: backgroundProcedure)\n\n        weak var exp = expectation(description: \"Procedure was cancelled\")\n        didCancel.notify(queue: DispatchQueue.main) {\n            exp?.fulfill()\n        }\n        waitForExpectations(timeout: 3)\n\n        let receivedCancellationError = cancellationError.access\n        XCTAssertNotNil(receivedCancellationError)\n        XCTAssertTrue(receivedCancellationError is ProcedureKitError.AppWasBackgrounded)\n\n        XCTAssertEqual(testableApplication.backgroundTasks.count, 1)\n        XCTAssertEqual(testableApplication.backgroundTasks[0].0, expectedBackgroundTaskName)\n    }\n\n    func test__background_observer__cancel_when_app_is_backgrounded__app_transitions_to_background_while_executing() {\n\n        let expectedBackgroundTaskName = BackgroundManager.backgroundTaskName(for: backgroundProcedure)\n\n        observer = BackgroundObserver(manager: testableBackgroundManager, cancelProcedure: .whenAppIsBackgrounded)\n\n        let didCancel = DispatchGroup()\n        let cancellationError = Protector<Error?>(nil)\n        didCancel.enter()\n        backgroundProcedure.addDidCancelBlockObserver { backgroundProcedure, error in\n            cancellationError.overwrite(with: error)\n            didCancel.leave()\n        }\n\n        // add the background observer\n        add(backgroundObserver: observer, to: backgroundProcedure)\n\n        // verify that the Procedure isn't cancelled\n        XCTAssertEqual(didCancel.wait(timeout: .now() + 0.3), .timedOut)\n\n        // but there should already exist a background task for the Procedure\n        XCTAssertEqual(testableApplication.backgroundTasks.count, 1)\n        XCTAssertEqual(testableApplication.backgroundTasks[0].0, expectedBackgroundTaskName)\n        XCTAssertEqual(testableApplication.backgroundTasks[0].2, .running)\n\n        // simulate entering the background\n        testableApplication.enterBackground()\n\n        // wait for cancellation to occur\n        weak var exp = expectation(description: \"Procedure was cancelled\")\n        didCancel.notify(queue: DispatchQueue.main) {\n            exp?.fulfill()\n        }\n        waitForExpectations(timeout: 3)\n\n        let receivedCancellationError = cancellationError.access\n        XCTAssertNotNil(receivedCancellationError)\n        XCTAssertTrue(receivedCancellationError is ProcedureKitError.AppWasBackgrounded)\n    }\n\n    // TODO: @swiftlyfalling - These tests fail\n    func x_test__background_observer__cancel_when_app_is_backgrounded__app_is_active() {\n\n        let expectedBackgroundTaskName = BackgroundManager.backgroundTaskName(for: backgroundProcedure)\n\n        observer = BackgroundObserver(manager: testableBackgroundManager, cancelProcedure: .whenAppIsBackgrounded)\n\n        // add the background observer\n        add(backgroundObserver: observer, to: backgroundProcedure)\n\n        backgroundProcedure.addDidExecuteBlockObserver(synchronizedWith: DispatchQueue.main) { [testableApplication = testableApplication!] backgroundProcedure in\n            // verify that the Procedure isn't cancelled\n            XCTAssertFalse(backgroundProcedure.isCancelled)\n\n            // but there should already exist a background task for the Procedure\n            XCTAssertEqual(testableApplication.backgroundTasks.count, 1)\n            XCTAssertEqual(testableApplication.backgroundTasks[0].0, expectedBackgroundTaskName)\n            XCTAssertEqual(testableApplication.backgroundTasks[0].2, .running)\n\n            // finish the backgroundProcedure\n            backgroundProcedure.finish()\n        }\n\n        wait(for: backgroundProcedure)\n        waitForTaskGroup()\n\n        PKAssertProcedureFinished(backgroundProcedure)\n        XCTAssertEqual(backgroundTaskName, expectedBackgroundTaskName)\n        XCTAssertNotEqual(backgroundTaskIdentifier, UIBackgroundTaskIdentifier.invalid)\n        XCTAssertEqual(backgroundTaskIdentifier, endedBackgroundTaskIdentifier)\n        XCTAssertEqual(testableApplication.backgroundTasks.count, 1)\n        XCTAssertEqual(testableApplication.backgroundTasks[0].0, expectedBackgroundTaskName)\n        XCTAssertEqual(testableApplication.backgroundTasks[0].2, .ended)\n    }\n}\n"
  },
  {
    "path": "Tests/ProcedureKitMobileTests/PresentationProcedureTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport ProcedureKit\nimport TestingProcedureKit\n@testable import ProcedureKitMobile\n\n"
  },
  {
    "path": "Tests/ProcedureKitMobileTests/ProcedureKitMobileTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport ProcedureKit\nimport TestingProcedureKit\n@testable import ProcedureKitMobile\n\nclass TestSuiteRuns: XCTestCase {\n\n    func test__suite_runs() {\n        XCTAssertTrue(true)\n    }\n}\n"
  },
  {
    "path": "Tests/ProcedureKitMobileTests/TestableUIApplication.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport ProcedureKit\nimport TestingProcedureKit\n@testable import ProcedureKitMobile\n\nclass TestableUIApplication: BackgroundTaskApplicationProtocol {\n\n    typealias DidBeginBackgroundTask = (String?, UIBackgroundTaskIdentifier) -> Void\n    typealias DidEndBackgroundTask = (UIBackgroundTaskIdentifier) -> Void\n\n    enum BackgroundTaskState {\n        case running\n        case ended\n    }\n\n    /// (TaskName, Handler, TaskState)\n    typealias BackgroundTasks = [(String?, (() -> Void)?, BackgroundTaskState)]\n\n    let stateLock = PThreadMutex()\n\n    private var testableApplicationState: UIApplication.State { return stateLock.withCriticalScope { _testableApplicationState } }\n    var backgroundTasks: BackgroundTasks { return stateLock.withCriticalScope { _backgroundTasks } }\n    var didBeginBackgroundTask: DidBeginBackgroundTask? {\n        get { return stateLock.withCriticalScope { _didBeginBackgroundTask } }\n        set {\n            stateLock.withCriticalScope {\n                _didBeginBackgroundTask = newValue\n            }\n        }\n    }\n    var didEndBackgroundTask: DidEndBackgroundTask? {\n        get { return stateLock.withCriticalScope { _didEndBackgroundTask } }\n        set {\n            stateLock.withCriticalScope {\n                _didEndBackgroundTask = newValue\n            }\n        }\n    }\n    var backgroundExecutionDisabled: Bool {\n        get { return stateLock.withCriticalScope { _backgroundExecutionDisabled } }\n        set {\n            stateLock.withCriticalScope {\n                _backgroundExecutionDisabled = newValue\n            }\n        }\n    }\n\n    private var _didBeginBackgroundTask: DidBeginBackgroundTask?\n    private var _didEndBackgroundTask: DidEndBackgroundTask?\n    private var _backgroundExecutionDisabled: Bool = false\n    private var _testableApplicationState: UIApplication.State\n    private var _backgroundTasks: BackgroundTasks = []\n\n    init(state: UIApplication.State = .active, didBeginTask: DidBeginBackgroundTask? = nil, didEndTask: DidEndBackgroundTask? = nil) {\n        _testableApplicationState = state\n        didBeginBackgroundTask = didBeginTask\n        didEndBackgroundTask = didEndTask\n    }\n\n    /// - Requires: Must be called from the main thread / queue.\n    var applicationState: UIApplication.State {\n        guard Thread.isMainThread || DispatchQueue.isMainDispatchQueue else {\n            fatalError(\"applicationState must be read from the main thread (re: UIApplication thread-safety).\")\n        }\n        return stateLock.withCriticalScope { _testableApplicationState }\n    }\n\n    /// May be called from any thread.\n    func beginBackgroundTask(withName taskName: String?, expirationHandler handler: (() -> Void)?) -> UIBackgroundTaskIdentifier {\n        let identifier: UIBackgroundTaskIdentifier = stateLock.withCriticalScope {\n            _backgroundTasks.append((taskName, handler, .running))\n            guard !_backgroundExecutionDisabled else {\n                return UIBackgroundTaskIdentifier.invalid\n            }\n            let identifier = _backgroundTasks.count\n            assert(identifier != UIBackgroundTaskIdentifier.invalid.rawValue, \"Generated an identifier (\\(identifier)) == UIBackgroundTaskInvalid, which will break the internals of BackgroundObserver. The TestableUIApplication must be fixed.\")\n            return UIBackgroundTaskIdentifier(rawValue: identifier)\n        }\n        didBeginBackgroundTask?(taskName, identifier)\n        return identifier\n    }\n\n    /// May be called from any thread.\n    func endBackgroundTask(_ identifier: UIBackgroundTaskIdentifier) {\n        stateLock.withCriticalScope { // () -> Bool in\n            guard identifier != UIBackgroundTaskIdentifier.invalid else {\n                fatalError(\"Called endBackgroundTask with `UIBackgroundTaskInvalid`.\")\n            }\n            guard identifier.rawValue <= _backgroundTasks.count && identifier.rawValue > 0 else {\n                fatalError(\"Called endBackgroundTask with an invalid identifier.\")\n            }\n            let taskIndex = identifier.rawValue\n            guard _backgroundTasks.count > taskIndex else {\n                fatalError(\"Identifier not stored with background tasks.\")\n            }\n            _backgroundTasks[taskIndex].2 = .ended\n        }\n        didEndBackgroundTask?(identifier)\n    }\n\n    /// - Requires: Must be called from the main thread / queue.\n    func enterBackground() {\n        guard Thread.isMainThread || DispatchQueue.isMainDispatchQueue else {\n            fatalError(\"applicationState must be modified from the main thread (re: UIApplication thread-safety).\")\n        }\n        stateLock.withCriticalScope { _testableApplicationState = .background }\n        NotificationCenter.default.post(name: UIApplication.didEnterBackgroundNotification, object: self)\n    }\n\n    /// - Requires: Must be called from the main thread / queue.\n    func simulateBackgroundTimeExpiration() {\n        guard Thread.isMainThread || DispatchQueue.isMainDispatchQueue else {\n            fatalError(\"simulateBackgroundTimeExpiration() must be called from the main thread / queue.\")\n        }\n        guard self.testableApplicationState == .background else { fatalError(\"Cannot simulate background time expiration if the testable application state is not `.background`.\") }\n        // loop over all registered background tasks and call their expiration handlers\n        for (_, handler, state) in self.backgroundTasks {\n            guard state == .running else { continue }\n            // call expiration handler\n            handler?()\n        }\n    }\n\n    /// - Requires: Must be called from the main thread / queue.\n    func becomeActive() {\n        guard Thread.isMainThread || DispatchQueue.isMainDispatchQueue else {\n            fatalError(\"applicationState must be modified from the main thread (re: UIApplication thread-safety).\")\n        }\n        stateLock.withCriticalScope { _testableApplicationState = .active }\n        NotificationCenter.default.post(name: UIApplication.didBecomeActiveNotification, object: self)\n    }\n}\n"
  },
  {
    "path": "Tests/ProcedureKitMobileTests/UIProcedureTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport ProcedureKit\nimport TestingProcedureKit\n@testable import ProcedureKitMobile\n\nclass TestablePresentingController: NSObject, PresentingViewController {\n    typealias CheckBlockType = (UIViewController) -> Void\n\n    var check: CheckBlockType? = nil\n    var expectation: XCTestExpectation? = nil\n\n    func present(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Void)?) {\n        check?(viewControllerToPresent)\n        completion?()\n        expectation?.fulfill()\n    }\n\n    func show(_ viewControllerToShow: UIViewController, sender: Any?) {\n        check?(viewControllerToShow)\n        expectation?.fulfill()\n    }\n\n    func showDetailViewController(_ viewControllerToShow: UIViewController, sender: Any?) {\n        check?(viewControllerToShow)\n        expectation?.fulfill()\n    }\n}\n\nclass TestableDismissingViewController: UIViewController, DismissingViewController {\n    var didDismissViewControllerBlock: () -> Void = { }\n\n    func dismissTheViewController() {\n        didDismissViewControllerBlock()\n    }\n}\n\nclass UIProcedureTests: ProcedureKitTestCase {\n\n    var presenting: TestablePresentingController!\n    var presented: TestableDismissingViewController!\n\n    override func setUp() {\n        super.setUp()\n        presenting = TestablePresentingController()\n        presented = TestableDismissingViewController()\n    }\n\n    override func tearDown() {\n        presenting = nil\n        presented = nil\n        super.tearDown()\n    }\n\n    func checkReceivedViewController(inNavigationController: Bool) -> (UIViewController) -> Void {\n        return {  [unowned self] received in\n            if inNavigationController {\n                guard let nav = received as? UINavigationController else {\n                    XCTFail(\"Expected received view controller to be a UINavigationController\")\n                    return\n                }\n                XCTAssertEqual(nav.topViewController, self.presented)\n            }\n            else {\n                XCTAssertEqual(received, self.presented)\n            }\n        }\n    }\n\n    @available(*, deprecated, message: \"UIProcedure is now deprecated and will be removed\")\n    func test__present_style() {\n        presenting.check = checkReceivedViewController(inNavigationController: true)\n        let ui = UIProcedure(present: presented, from: presenting, withStyle: .present, sender: nil)\n        wait(for: ui)\n        PKAssertProcedureFinished(ui)\n    }\n\n    @available(*, deprecated, message: \"UIProcedure is now deprecated and will be removed\")\n    func test__present_style_without_navigation_controller() {\n        presenting.check = checkReceivedViewController(inNavigationController: false)\n        let ui = UIProcedure(present: presented, from: presenting, withStyle: .present, inNavigationController: false, sender: nil)\n        wait(for: ui)\n        PKAssertProcedureFinished(ui)\n    }\n\n    @available(*, deprecated, message: \"UIProcedure is now deprecated and will be removed\")\n    func test__show_style() {\n        presenting.check = checkReceivedViewController(inNavigationController: false)\n        let ui = UIProcedure(present: presented, from: presenting, withStyle: .show, sender: nil)\n        wait(for: ui)\n        PKAssertProcedureFinished(ui)\n    }\n\n    @available(*, deprecated, message: \"UIProcedure is now deprecated and will be removed\")\n    func test__show_detail_style() {\n        presenting.check = checkReceivedViewController(inNavigationController: false)\n        let ui = UIProcedure(present: presented, from: presenting, withStyle: .showDetail, sender: nil)\n        wait(for: ui)\n        PKAssertProcedureFinished(ui)\n    }\n\n    @available(*, deprecated, message: \"UIProcedure is now deprecated and will be removed\")\n    func test__present_dismissing_view_controller() {\n        presenting.check = checkReceivedViewController(inNavigationController: true)\n        let ui = UIProcedure(present: presented, from: presenting, withStyle: .present, sender: nil, waitForDismissal: true)\n        let delay = DelayProcedure(by: 0.1)\n        let dismiss = BlockProcedure { [unowned self] in self.presented.dismissTheViewController() }\n        dismiss.addDependency(delay)\n        wait(for: ui, delay, dismiss)\n        PKAssertProcedureFinished(ui)\n    }\n}\n"
  },
  {
    "path": "Tests/ProcedureKitNetworkTests/NetworkDataProcedureTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport ProcedureKit\nimport TestingProcedureKit\n@testable import ProcedureKitNetwork\n\nclass NetworkDataProcedureTests: ProcedureKitTestCase {\n\n    var url: URL!\n    var request: URLRequest!\n    var session: TestableURLSessionTaskFactory!\n    var download: NetworkDataProcedure!\n\n    override func setUp() {\n        super.setUp()\n        url = \"http://procedure.kit.run\"\n        request = URLRequest(url: url)\n        session = TestableURLSessionTaskFactory()\n        download = NetworkDataProcedure(session: session, request: request)\n    }\n\n    override func tearDown() {\n        url = nil\n        request = nil\n        session = nil\n        download = nil\n        super.tearDown()\n    }\n\n    func test__session_receives_request() {\n        wait(for: download)\n        PKAssertProcedureFinished(download)\n        XCTAssertEqual(session.didReceiveDataRequest?.url, url)\n    }\n\n    func test__session_creates_data_task() {\n        wait(for: download)\n        PKAssertProcedureFinished(download)\n        XCTAssertNotNil(session.didReturnDataTask)\n        XCTAssertEqual(session.didReturnDataTask, download.task as? TestableURLSessionTask)\n    }\n\n    func test__download_resumes_data_task() {\n        wait(for: download)\n        PKAssertProcedureFinished(download)\n        XCTAssertTrue(session.didReturnDataTask?.didResume ?? false)\n    }\n\n    // MARK: Cancellation\n\n    func test__download_cancels_data_task_is_cancelled() {\n        session.delay = 2.0\n        let delay = DelayProcedure(by: 0.1)\n        delay.addDidFinishBlockObserver { _, _ in\n            self.download.cancel()\n        }\n        wait(for: download, delay)\n        PKAssertProcedureCancelled(download)\n        XCTAssertTrue(session.didReturnDataTask?.didCancel ?? false)\n    }\n\n    func test__download_cancelled_while_executing() {\n        session.delay = 2.0\n        download.addDidExecuteBlockObserver { (procedure) in\n            procedure.cancel()\n        }\n        wait(for: download)\n        PKAssertProcedureCancelled(download)\n    }\n\n    func test__download_cancelled_does_not_call_completion_handler() {\n        session.delay = 2.0\n        var calledCompletionHandler = false\n        download = NetworkDataProcedure(session: session, request: request) { _ in\n            DispatchQueue.onMain {\n                calledCompletionHandler = true\n            }\n        }\n        download.addDidExecuteBlockObserver { (procedure) in\n            procedure.cancel()\n        }\n        wait(for: download)\n        PKAssertProcedureCancelled(download)\n        XCTAssertFalse(calledCompletionHandler)\n    }\n\n    // MARK: Finishing\n\n    func test__no_requirement__finishes_with_error() {\n        download = NetworkDataProcedure(session: session) { _ in }\n        wait(for: download)\n        PKAssertProcedureFinishedWithError(download, ProcedureKitError.requirementNotSatisfied())\n    }\n\n    func test__no_data__finishes_with_error() {\n        session.returnedData = nil\n        wait(for: download)\n        PKAssertProcedureFinishedWithError(download, ProcedureKitError.unknown)\n    }\n\n    func test__session_error__finishes_with_error() {\n        let error = NSError(domain: NSURLErrorDomain, code: NSURLErrorNotConnectedToInternet, userInfo: nil)\n        session.returnedError = error\n        wait(for: download)\n        XCTAssertNotNil(download.error)\n        PKAssertProcedureFinishedWithError(download, error)\n    }\n\n    func test__completion_handler_receives_data_and_response() {\n        var completionHandlerDidExecute = false\n        download = NetworkDataProcedure(session: session, request: request) { result in            \n            XCTAssertEqual(result.value?.payload, self.session.returnedData)\n            XCTAssertEqual(result.value?.response, self.session.returnedResponse)\n            completionHandlerDidExecute = true\n        }\n        wait(for: download)\n        PKAssertProcedureFinished(download)\n        XCTAssertTrue(completionHandlerDidExecute)\n    }\n}\n"
  },
  {
    "path": "Tests/ProcedureKitNetworkTests/NetworkDownloadProcedureTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\nimport XCTest\nimport ProcedureKit\nimport TestingProcedureKit\n@testable import ProcedureKitNetwork\n\nclass NetworkDownloadProcedureTests: ProcedureKitTestCase {\n\n    var url: URL!\n    var request: URLRequest!\n    var session: TestableURLSessionTaskFactory!\n    var download: NetworkDownloadProcedure!\n\n    override func setUp() {\n        super.setUp()\n        url = \"http://procedure.kit.run\"\n        request = URLRequest(url: url)\n        session = TestableURLSessionTaskFactory()\n        download = NetworkDownloadProcedure(session: session, request: request)\n    }\n\n    override func tearDown() {\n        url = nil\n        request = nil\n        session = nil\n        download = nil\n        super.tearDown()\n    }\n\n    func test__session_receive_request() {\n        wait(for: download)\n        PKAssertProcedureFinished(download)\n        XCTAssertEqual(session.didReceiveDownloadRequest?.url, url)\n    }\n\n    func test__session_creates_download_task() {\n        wait(for: download)\n        PKAssertProcedureFinished(download)\n        XCTAssertNotNil(session.didReturnDownloadTask)\n        XCTAssertEqual(session.didReturnDownloadTask, download.task as? TestableURLSessionTask)\n    }\n\n    func test__download_resumes_download_task() {\n        wait(for: download)\n        PKAssertProcedureFinished(download)\n        XCTAssertTrue(session.didReturnDownloadTask?.didResume ?? false)\n    }\n\n    // MARK: Cancellation\n\n    func test__download_cancels_data_download_is_cancelled() {\n        session.delay = 2.0\n        let delay = DelayProcedure(by: 0.1)\n        delay.addDidFinishBlockObserver { _, _ in\n            self.download.cancel()\n        }\n        wait(for: download, delay)\n        PKAssertProcedureCancelled(download)\n        XCTAssertTrue(session.didReturnDownloadTask?.didCancel ?? false)\n    }\n\n    func test__download_cancelled_while_executing() {\n        session.delay = 2.0\n        download.addDidExecuteBlockObserver { (procedure) in\n            procedure.cancel()\n        }\n        wait(for: download)\n        PKAssertProcedureCancelled(download)\n    }\n\n    func test__download_cancelled_does_not_call_completion_handler() {\n        session.delay = 2.0\n        var calledCompletionHandler = false\n        download = NetworkDownloadProcedure(session: session, request: request) { _ in\n            DispatchQueue.onMain {\n                calledCompletionHandler = true\n            }\n        }\n        download.addDidExecuteBlockObserver { (procedure) in\n            procedure.cancel()\n        }\n        wait(for: download)\n        PKAssertProcedureCancelled(download)\n        XCTAssertFalse(calledCompletionHandler)\n    }\n\n    // MARK: Finishing\n\n    func test__no_requirement__finishes_with_error() {\n        download = NetworkDownloadProcedure(session: session) { _ in }\n        wait(for: download)\n        PKAssertProcedureFinishedWithError(download, ProcedureKitError.requirementNotSatisfied())\n    }\n\n    func test__no_data__finishes_with_error() {\n        session.returnedURL = nil\n        wait(for: download)\n        PKAssertProcedureFinishedWithError(download, ProcedureKitError.unknown)\n    }\n\n    func test__session_error__finishes_with_error() {\n        let error = NSError(domain: NSURLErrorDomain, code: NSURLErrorNotConnectedToInternet, userInfo: nil)\n        session.returnedError = error\n        wait(for: download)\n        PKAssertProcedureFinishedWithError(download, error)\n    }\n\n    func test__completion_handler_receives_data_and_response() {\n        var completionHandlerDidExecute = false\n        download = NetworkDownloadProcedure(session: session, request: request) { result in\n            XCTAssertEqual(result.value?.payload, self.session.returnedURL)\n            XCTAssertEqual(result.value?.response, self.session.returnedResponse)\n            completionHandlerDidExecute = true\n        }\n        wait(for: download)\n        PKAssertProcedureFinished(download)\n        XCTAssertTrue(completionHandlerDidExecute)\n    }\n\n\n}\n"
  },
  {
    "path": "Tests/ProcedureKitNetworkTests/NetworkProcedureTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport SystemConfiguration\nimport ProcedureKit\nimport TestingProcedureKit\n@testable import ProcedureKitNetwork\n\nclass NetworkReachabilityWaitProcedureTests: ProcedureKitTestCase {\n\n    var network: TestableNetworkReachability!\n    var manager: Reachability.Manager!\n\n    override func setUp() {\n        super.setUp()\n        network = TestableNetworkReachability()\n        manager = Reachability.Manager(network)\n    }\n\n    override func tearDown() {\n        network = nil\n        manager = nil\n        super.tearDown()\n    }\n\n    func test__procedure_waits_until_network_is_reachable() {\n        network.flags = .connectionRequired\n        let procedure = NetworkReachabilityWaitProcedure(reachability: manager)\n        let delay = DelayProcedure(by: 0.1)\n        let makeNetworkReachable = BlockProcedure {\n            self.network.flags = .reachable\n        }\n        makeNetworkReachable.addDependency(delay)\n\n        wait(forAll: [delay, makeNetworkReachable, procedure])\n        PKAssertProcedureFinished(procedure)\n    }\n\n    #if os(iOS)\n    func test__procedure_waits_until_correct_network_connectivity_is_available() {\n        network.flags = .interventionRequired\n        let procedure = NetworkReachabilityWaitProcedure(reachability: manager, via: .wifi)\n\n        let delay1 = DelayProcedure(by: 0.1)\n        let changeNetwork1 = BlockProcedure {\n            self.network.flags = [ .reachable, .isWWAN ]\n        }\n        changeNetwork1.addDependency(delay1)\n\n        let delay2 = DelayProcedure(by: 0.2)\n        let changeNetwork2 = BlockProcedure {\n            self.network.flags = .reachable\n        }\n        changeNetwork2.addDependency(delay2)\n\n\n        wait(forAll: [delay1, changeNetwork1, delay2, changeNetwork2, procedure])\n        PKAssertProcedureFinished(procedure)\n    }\n    #endif\n\n}\n\nclass NetworkProcedureTests: ProcedureKitTestCase {\n\n    typealias Target = NetworkDataProcedure\n\n    var url: URL!\n    var request: URLRequest!\n    var resilience: DefaultNetworkResilience!\n    var session: TestableURLSessionTaskFactory!\n    var data: NetworkDataProcedure!\n    var network: TestableNetworkReachability!\n    var manager: Reachability.Manager!\n\n    override func setUp() {\n        super.setUp()\n        url = \"http://procedure.kit.run\"\n        request = URLRequest(url: url)\n        resilience = DefaultNetworkResilience(backoffStrategy: .constant(1.0), requestTimeout: 1.0)\n        session = TestableURLSessionTaskFactory()\n        data = NetworkDataProcedure(session: session, request: request)\n        network = TestableNetworkReachability()\n        manager = Reachability.Manager(network)\n    }\n\n    override func tearDown() {\n        network = nil\n        manager = nil\n        super.tearDown()\n    }\n\n    func createNetworkProcedure() -> Target {\n        return Target(session: session, request: request)\n    }\n\n    func test__reachable_network_does_not_start_notifier() {\n        let procedure = NetworkProcedure<Target>(body: createNetworkProcedure)\n        procedure.reachability = manager\n        wait(for: procedure)\n        PKAssertProcedureFinished(procedure)\n        XCTAssertFalse(network.didStartNotifier)\n    }\n\n    func test__waits_for_reachability_change_before_retrying() {\n        session.returnedError = NSError(domain: NSURLErrorDomain, code: NSURLErrorNotConnectedToInternet, userInfo: nil)\n        network.flags = .connectionRequired\n        let delay = DelayProcedure(by: 0.1)\n        let makeSessionSuccessful = BlockProcedure { self.session.returnedError = nil }\n        makeSessionSuccessful.addDependency(delay)\n        let makeNetworkReachable = BlockProcedure { self.network.flags = .reachable }\n        makeNetworkReachable.addDependency(makeSessionSuccessful)\n\n        let procedure = NetworkProcedure<Target>(resilience: resilience, body: createNetworkProcedure)\n        procedure.reachability = manager\n\n        wait(forAll: [procedure, delay, makeSessionSuccessful, makeNetworkReachable])\n        PKAssertProcedureFinished(procedure)\n        XCTAssertEqual(procedure.count, 2)\n        XCTAssertTrue(network.didStopNotifier)\n    }\n\n    func test__does_not_wait_for_reachability_if_transient_error() {\n        session.returnedError = NSError(domain: NSURLErrorDomain, code: NSURLErrorNetworkConnectionLost, userInfo: nil)\n\n        let delay = DelayProcedure(by: 0.1)\n        let makeSessionSuccessful = BlockProcedure { self.session.returnedError = nil }\n        makeSessionSuccessful.addDependency(delay)\n\n        let procedure = NetworkProcedure<Target>(resilience: resilience, body: createNetworkProcedure)\n        procedure.reachability = manager\n\n        wait(forAll: [procedure, delay, makeSessionSuccessful], withTimeout: 4)\n        PKAssertProcedureFinished(procedure)\n        XCTAssertEqual(procedure.count, 2)\n    }\n\n    func test__retry_server_error() {\n        session.returnedResponse = HTTPURLResponse(url: url, statusCode: 500, httpVersion: nil, headerFields: nil)\n\n        let delay = DelayProcedure(by: 0.1)\n        let makeSessionSuccessful = BlockProcedure { self.session.returnedResponse = HTTPURLResponse(url: self.url, statusCode: 200, httpVersion: nil, headerFields: nil) }\n        makeSessionSuccessful.addDependency(delay)\n\n        let procedure = NetworkProcedure<Target>(resilience: resilience, body: createNetworkProcedure)\n        procedure.reachability = manager\n\n        wait(forAll: [procedure, delay, makeSessionSuccessful], withTimeout: 4)\n        PKAssertProcedureFinished(procedure)\n        XCTAssertEqual(procedure.count, 2)\n    }\n\n    func test__retry_client_error_too_many_requests() {\n        session.returnedResponse = HTTPURLResponse(url: url, statusCode: HTTPStatusCode.tooManyRequests.rawValue, httpVersion: nil, headerFields: nil)\n\n        let delay = DelayProcedure(by: 0.1)\n        let makeSessionSuccessful = BlockProcedure { self.session.returnedResponse = HTTPURLResponse(url: self.url, statusCode: 200, httpVersion: nil, headerFields: nil) }\n        makeSessionSuccessful.addDependency(delay)\n\n        let procedure = NetworkProcedure<Target>(resilience: resilience, body: createNetworkProcedure)\n        procedure.reachability = manager\n\n        wait(forAll: [procedure, delay, makeSessionSuccessful], withTimeout: 4)\n        PKAssertProcedureFinished(procedure)\n        XCTAssertEqual(procedure.count, 2)\n    }\n\n    // Payload Injection\n\n    func test__payload_is_injected() {\n        let procedure = NetworkProcedure<Target>(body: createNetworkProcedure)\n        var didReceivePayload = false\n        let transform = TransformProcedure<Data, Bool> { data in\n            didReceivePayload = true\n            return true\n        }.injectPayload(fromNetwork: procedure)\n\n        wait(for: procedure, transform)\n        PKAssertProcedureFinished(procedure)\n        XCTAssertTrue(didReceivePayload)\n    }\n\n    func test__payload_injection_error() {\n        session.returnedData = nil\n        let procedure = NetworkProcedure<Target>(body: createNetworkProcedure)\n        var didReceivePayload = false\n        let transform = TransformProcedure<Data, Bool> { data in\n            didReceivePayload = true\n            return true\n        }.injectPayload(fromNetwork: procedure)\n\n        wait(for: procedure, transform)\n        PKAssertProcedureCancelledWithError(transform, ProcedureKitError.dependency(finishedWithError: procedure.error))\n        XCTAssertFalse(didReceivePayload)\n    }\n}\n"
  },
  {
    "path": "Tests/ProcedureKitNetworkTests/NetworkReachabilityTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport SystemConfiguration\nimport ProcedureKit\nimport TestingProcedureKit\n@testable import ProcedureKitNetwork\n\nclass ReachabilityManagerTests: ProcedureKitTestCase {\n\n    var network: TestableNetworkReachability!\n    var manager: Reachability.Manager!\n\n    override func setUp() {\n        super.setUp()\n        network = TestableNetworkReachability()\n        manager = Reachability.Manager(network)\n    }\n\n    override func tearDown() {\n        network = nil\n        manager = nil\n        super.tearDown()\n    }\n\n    func test__delegate_is_set() {\n        XCTAssertNotNil(network.delegate)\n    }\n\n    func test__when_connected_block_is_run() {\n        var didRunBlock = false\n        let exp = expectation(description: \"Test: \\(#function)\")\n\n        manager.whenReachable(via: .any) {\n            didRunBlock = true\n            exp.fulfill()\n        }\n\n        waitForExpectations(timeout: 3, handler: nil)\n        XCTAssertTrue(didRunBlock)\n        XCTAssertTrue(network.didStopNotifier)\n    }\n}\n\nclass DeviceReachabilityTests: XCTestCase, NetworkReachabilityDelegate {\n\n    var queue: DispatchQueue!\n    var device: Reachability.Device!\n    var testExpectation: XCTestExpectation? = nil\n    var delegateDidReceiveFlags: SCNetworkReachabilityFlags? = nil\n\n    override func setUp() {\n        super.setUp()\n        queue = DispatchQueue(label: \"run.kit.ProcedureKit.Network.Reachability.Testing\")\n        device = Reachability.Device()\n        device.delegate = self\n    }\n\n    override func tearDown() {\n        queue = nil\n        device = nil\n        testExpectation = nil\n        delegateDidReceiveFlags = nil\n        super.tearDown()\n    }\n\n    func test__notifierIsRunning_is_true_when_running() {\n        device.notifierIsRunning = true\n        XCTAssertTrue(device.notifierIsRunning)\n    }\n\n    func test__notifierIsRunning_is_false_when_not_running() {\n        device.notifierIsRunning = false\n        XCTAssertFalse(device.notifierIsRunning)\n    }\n\n    func test__did_change_reachability_informs_delegate() {\n        device.didChangeReachability(flags: .reachable)\n        XCTAssertEqual(delegateDidReceiveFlags ?? .connectionRequired, .reachable)\n    }\n\n    func didChangeReachability(flags: SCNetworkReachabilityFlags) {\n        delegateDidReceiveFlags = flags\n        testExpectation?.fulfill()\n    }\n\n    func test__check() {\n        testExpectation = expectation(description: \"Test: \\(#function)\")\n        let reachability = device.defaultRouteReachability\n        device.check(reachability: reachability, on: queue)\n        waitForExpectations(timeout: 3, handler: nil)\n        XCTAssertNotNil(delegateDidReceiveFlags)\n    }\n}\n"
  },
  {
    "path": "Tests/ProcedureKitNetworkTests/NetworkUploadProcedureTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport ProcedureKit\nimport TestingProcedureKit\n@testable import ProcedureKitNetwork\n\nclass NetworkUploadProcedureTests: ProcedureKitTestCase {\n    \n    var url: URL!\n    var request: URLRequest!\n    var sendingData: Data!\n    var session: TestableURLSessionTaskFactory!\n    var upload: NetworkUploadProcedure!\n\n    override func setUp() {\n        super.setUp()\n        url = \"http://procedure.kit.run\"\n        sendingData = \"hello world\".data(using: .utf8)\n\n        request = URLRequest(url: url)\n        session = TestableURLSessionTaskFactory()\n        upload = NetworkUploadProcedure(session: session, request: request, data: sendingData)\n    }\n\n    override func tearDown() {\n        url = nil\n        request = nil\n        session = nil\n        upload = nil\n        super.tearDown()\n    }\n\n    func test__session_receives_request() {\n        wait(for: upload)\n        PKAssertProcedureFinished(upload)\n        XCTAssertEqual(session.didReceiveUploadRequest?.url, url)\n    }\n\n    func test__session_creates_upload_task() {\n        wait(for: upload)\n        PKAssertProcedureFinished(upload)\n        XCTAssertNotNil(session.didReturnUploadTask)\n        XCTAssertEqual(session.didReturnUploadTask, upload.task as? TestableURLSessionTask)\n    }\n\n    func test__upload_resumes_data_task() {\n        wait(for: upload)\n        PKAssertProcedureFinished(upload)\n        XCTAssertTrue(session.didReturnUploadTask?.didResume ?? false)\n    }\n\n    // MARK: Cancellation\n\n    func test__upload_cancels_data_task_is_cancelled() {\n        session.delay = 2.0\n        let delay = DelayProcedure(by: 0.1)\n        delay.addDidFinishBlockObserver { _, _ in\n            self.upload.cancel()\n        }\n        wait(for: upload, delay)\n        PKAssertProcedureCancelled(upload)\n        XCTAssertTrue(session.didReturnUploadTask?.didCancel ?? false)\n    }\n\n    func test__upload_cancelled_while_executing() {\n        session.delay = 2.0\n        upload.addDidExecuteBlockObserver { (procedure) in\n            procedure.cancel()\n        }\n        wait(for: upload)\n        PKAssertProcedureCancelled(upload)\n    }\n\n    func test__upload_cancelled_does_not_call_completion_handler() {\n        session.delay = 2.0\n        var calledCompletionHandler = false\n        upload = NetworkUploadProcedure(session: session, request: request, data: sendingData) { _ in\n            DispatchQueue.onMain {\n                calledCompletionHandler = true\n            }\n        }\n        upload.addDidExecuteBlockObserver { (procedure) in\n            procedure.cancel()\n        }\n        wait(for: upload)\n        PKAssertProcedureCancelled(upload)\n        XCTAssertFalse(calledCompletionHandler)\n    }\n\n    // MARK: Finishing\n\n    func test__no_requirement__finishes_with_error() {\n        upload = NetworkUploadProcedure(session: session) { _ in }\n        wait(for: upload)\n        PKAssertProcedureFinishedWithError(upload, ProcedureKitError.requirementNotSatisfied())\n    }\n\n    func test__no_data__finishes_with_error() {\n        session.returnedData = nil\n        wait(for: upload)\n        PKAssertProcedureFinishedWithError(upload, ProcedureKitError.unknown)\n    }\n\n    func test__session_error__finishes_with_error() {\n        let error = NSError(domain: NSURLErrorDomain, code: NSURLErrorNotConnectedToInternet, userInfo: nil)\n        session.returnedError = error\n        wait(for: upload)\n        PKAssertProcedureFinishedWithError(upload, error)\n    }\n\n    func test__completion_handler_receives_data_and_response() {\n        var completionHandlerDidExecute = false\n        upload = NetworkUploadProcedure(session: session, request: request, data: sendingData) { result in\n            XCTAssertEqual(result.value?.payload, self.session.returnedData)\n            XCTAssertEqual(result.value?.response, self.session.returnedResponse)\n            completionHandlerDidExecute = true\n        }\n        wait(for: upload)\n        PKAssertProcedureFinished(upload)\n        XCTAssertTrue(completionHandlerDidExecute)\n    }\n\n}\n"
  },
  {
    "path": "Tests/ProcedureKitNetworkTests/ProcedureKitNetworkTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport ProcedureKit\nimport TestingProcedureKit\n@testable import ProcedureKitNetwork\n\nextension TestableURLSessionTask: URLSessionTaskProtocol, NetworkDataTask, NetworkDownloadTask, NetworkUploadTask { }\nextension TestableURLSessionTaskFactory: NetworkSession {\n    public func dataTask(with request: URLRequest, completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void) -> NetworkDataTask {\n        let task: TestableURLSessionTask = dataTask(with: request, completionHandler: completionHandler)\n        return task\n    }\n    \n    public func downloadTask(with request: URLRequest, completionHandler: @escaping (URL?, URLResponse?, Error?) -> Void) -> NetworkDownloadTask {\n        let task: TestableURLSessionTask = downloadTask(with: request, completionHandler: completionHandler)\n        return task\n    }\n    \n    public func uploadTask(with request: URLRequest, from bodyData: Data?, completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void) -> NetworkUploadTask {\n        let task: TestableURLSessionTask = uploadTask(with: request, from: bodyData, completionHandler: completionHandler)\n        return task\n    }\n}\n\nclass TestSuiteRuns: XCTestCase {\n\n    func test__suite_runs() {\n        XCTAssertTrue(true)\n    }\n}\n\n"
  },
  {
    "path": "Tests/ProcedureKitNetworkTests/URLTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport ProcedureKit\nimport TestingProcedureKit\n@testable import ProcedureKitNetwork\n\nclass URLTests: XCTestCase {\n\n    func test__url_is_expressible_by_string_literal() {\n        let url: URL = \"http://procedure.kit.run\"\n        XCTAssertEqual(url.host, \"procedure.kit.run\")\n    }\n\n    func test__url_is_expressible_by_extended_grapheme_cluster_literal() {\n        let url = URL(extendedGraphemeClusterLiteral: \"http://procedure.kit.run\")\n        XCTAssertEqual(url.host, \"procedure.kit.run\")\n    }\n\n    func test__url_is_expressible_by_unicode_scalar_literal() {\n        let url = URL(unicodeScalarLiteral: \"http://procedure.kit.run\")\n        XCTAssertEqual(url.host, \"procedure.kit.run\")\n    }\n}\n\n"
  },
  {
    "path": "Tests/ProcedureKitStressTests/BlockProcedureStressTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport TestingProcedureKit\n@testable import ProcedureKit\n\nclass CancelBlockProcedureStessTests: StressTestCase {\n\n    func test__cancel_block_procedure() {\n\n        stress(level: .custom(10, 5_000)) { batch, _ in\n            batch.dispatchGroup.enter() // enter once for cancel\n            batch.dispatchGroup.enter() // enter once for finish\n            let block = BlockProcedure { this in\n                // prevent the BlockProcedure from finishing before it is cancelled\n                while false == this.isCancelled {\n                    usleep(10)\n                }\n                this.finish()\n            }\n            block.addDidCancelBlockObserver { _, _ in\n                batch.dispatchGroup.leave() // leave once for cancel\n            }\n            block.addDidFinishBlockObserver { _, _ in\n                batch.dispatchGroup.leave() // leave once for finish\n            }\n            batch.queue.addOperation(block)\n            block.cancel()\n        }\n    }\n\n    func test_cancel_or_finish_block_procedure() {\n\n        // NOTE:\n        // It is possible for a BlockProcedure to finish prior to the call to\n        // `block.cancel()` (depending on timing) and thus not all of the\n        // BlockProcedures created below may be effectively cancelled.\n        // However, all of the BlockProcedures should finish.\n\n        stress(level: .custom(10, 5_000)) { batch, _ in\n            batch.dispatchGroup.enter()\n            let block = BlockProcedure { }\n            block.addDidFinishBlockObserver { _, _ in\n                batch.dispatchGroup.leave()\n            }\n            batch.queue.addOperation(block)\n            block.cancel()\n        }\n    }\n}\n"
  },
  {
    "path": "Tests/ProcedureKitStressTests/GroupStressTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport TestingProcedureKit\n@testable import ProcedureKit\n\nclass CancelGroupStressTests: StressTestCase {\n\n    func test__group_cancel() {\n\n        stress { batch, iteration in\n            batch.dispatchGroup.enter()\n            let group = TestGroupProcedure(operations: TestProcedure(delay: 0))\n            group.addDidFinishBlockObserver { _, _ in\n                batch.dispatchGroup.leave()\n            }\n            batch.queue.addOperation(group)\n            group.cancel()\n        }\n    }\n}\n\nclass GroupCancelAndAddOperationStressTests: StressTestCase {\n\n    final class TestGroupProcedureWhichAddsOperationsAfterSuperInit: GroupProcedure {\n        let operationsToAddOnExecute: [Operation]\n\n        init(operations: [Operation] = [TestProcedure(delay: 0)], operationsToAddOnExecute: [Operation] = [TestProcedure(delay: 0)]) {\n            self.operationsToAddOnExecute = operationsToAddOnExecute\n            super.init(operations: [])\n            name = \"TestGroupProcedureWhichAddsOperationsAfterSuperInit\"\n            addChildren(operations) // add operations during init, after super.init\n        }\n\n        override func execute() {\n            addChildren(operationsToAddOnExecute) // add operations during execute\n            super.execute()\n        }\n    }\n\n    func test__group_cancel_and_add() {\n\n        stress { batch, _ in\n            batch.dispatchGroup.enter()\n            let group = TestGroupProcedureWhichAddsOperationsAfterSuperInit()\n            group.addDidFinishBlockObserver { _, _ in\n                batch.dispatchGroup.leave()\n            }\n            batch.queue.addOperation(group)\n            group.cancel()\n        }\n    }\n}\n\nclass GroupDoesNotFinishBeforeChildOperationsAreFinished: StressTestCase {\n\n    func test__group_does_not_finish_before_child_operations_are_finished() {\n        stress { batch, _ in\n            batch.dispatchGroup.enter()\n\n            let child1 = TestProcedure(delay: 0.004)\n            let child2 = TestProcedure(delay: 0.006)\n            let group = GroupProcedure(operations: child1, child2)\n\n            group.addDidFinishBlockObserver { _, _ in\n                if child1.isFinished {\n                    batch.incrementCounter(named: \"child 1 finished\")\n                }\n                if child2.isFinished {\n                    batch.incrementCounter(named: \"child 2 finished\")\n                }\n                batch.dispatchGroup.leave()\n            }\n            batch.queue.addOperation(group)\n            group.cancel()\n        }\n    }\n\n    override func ended(batch: BatchProtocol) {\n        XCTAssertEqual(batch.counter(named: \"child 1 finished\"), batch.size)\n        XCTAssertEqual(batch.counter(named: \"child 2 finished\"), batch.size)\n        super.ended(batch: batch)\n    }\n}\n\nclass GroupCancellationHandlerConcurrencyTest: StressTestCase {\n\n    func test__cancelled_group_no_concurrent_events() {\n\n        stress(level: StressLevel.custom(2, 1000)) { batch, iteration in\n            batch.dispatchGroup.enter()\n            let group = EventConcurrencyTrackingGroupProcedure(operations: [TestProcedure(), TestProcedure()])\n            group.addDidFinishBlockObserver(block: { (group, error) in\n                DispatchQueue.main.async {\n                    self.PKAssertProcedureNoConcurrentEvents(group)\n                    batch.dispatchGroup.leave()\n                }\n            })\n            batch.queue.addOperation(group)\n            group.cancel()\n        }\n    }\n\n    func test__group_simultaneous_child_finish_no_concurrent_events() {\n\n        stress(level: StressLevel.custom(2, 50)) { batch, iteration in\n            batch.dispatchGroup.enter()\n            let children = (0..<3).map { i -> Procedure in\n                let procedure = BlockProcedure { }\n                procedure.name = \"Child: \\(i)\"\n                return procedure\n            }\n            let group = EventConcurrencyTrackingGroupProcedure(operations: children)\n            group.addDidFinishBlockObserver(block: { (group, error) in\n                DispatchQueue.main.async {\n                    self.PKAssertProcedureNoConcurrentEvents(group)\n                    batch.dispatchGroup.leave()\n                }\n            })\n            batch.queue.addOperation(group)\n        }\n    }\n\n    func test__group_add_child_no_concurrent_events() {\n\n        stress(level: StressLevel.custom(2, 50)) { batch, iteration in\n            batch.dispatchGroup.enter()\n            let additionalChildren = (1..<3).map { i -> Procedure in\n                let procedure = BlockProcedure { }\n                procedure.name = \"Child: \\(i)\"\n                return procedure\n            }\n            let group = EventConcurrencyTrackingGroupProcedure(operations: [])\n            let initialChild = BlockProcedure {\n                group.addChildren(additionalChildren)\n            }\n            initialChild.name = \"Child: 0 (initial)\"\n            group.addChild(initialChild)\n            group.addDidFinishBlockObserver(block: { (group, error) in\n                DispatchQueue.main.async {\n                    self.PKAssertProcedureNoConcurrentEvents(group)\n                    batch.dispatchGroup.leave()\n                }\n            })\n            batch.queue.addOperation(group)\n        }\n    }\n}\n"
  },
  {
    "path": "Tests/ProcedureKitStressTests/ProcedureKitStressTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport TestingProcedureKit\n@testable import ProcedureKit\n\nclass TestSuiteRuns: XCTestCase {\n\n    func test__suite_runs() {\n        XCTAssertTrue(true)\n    }\n}\n"
  },
  {
    "path": "Tests/ProcedureKitStressTests/ProcedureStressTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport TestingProcedureKit\n@testable import ProcedureKit\nimport Dispatch\n\nclass ProcedureCompletionBlockStressTest: StressTestCase {\n\n    func test__completion_blocks() {\n\n        stress { batch, iteration in\n            batch.dispatchGroup.enter()\n            let procedure = TestProcedure(name: \"Batch \\(batch.number), Iteration \\(iteration)\")\n            procedure.addCompletionBlock { batch.dispatchGroup.leave() }\n            batch.queue.addOperation(procedure)\n        }\n    }\n}\n\nclass CancelProcedureWithErrorsStressTest: StressTestCase {\n\n    func test__cancel_or_finish_with_errors() {\n\n        // NOTE: It is possible for a TestProcedure below to finish prior to being cancelled\n\n        stress { batch, iteration in\n            batch.dispatchGroup.enter()\n            let procedure = TestProcedure(name: \"Batch \\(batch.number), Iteration \\(iteration)\")\n            procedure.addDidFinishBlockObserver { _, _ in\n                batch.dispatchGroup.leave()\n            }\n            batch.queue.addOperation(procedure)\n            procedure.cancel(with: TestError())\n        }\n    }\n\n    func test__cancel_with_errors_prior_to_execute() {\n\n        stress { batch, iteration in\n            batch.dispatchGroup.enter()\n            let procedure = TestProcedure(name: \"Batch \\(batch.number), Iteration \\(iteration)\")\n            procedure.addDidFinishBlockObserver { _, error in\n                if error == nil {\n                    DispatchQueue.main.async {\n                        XCTAssertNil(error, \"error is nil - cancel errors were not propagated\")\n                        batch.dispatchGroup.leave()\n                    }\n                }\n                else {\n                    batch.dispatchGroup.leave()\n                }\n            }\n            procedure.cancel(with: TestError())\n            batch.queue.addOperation(procedure)\n        }\n    }\n\n    func test__cancel_with_errors_from_will_execute_observer() {\n\n        stress { batch, iteration in\n            batch.dispatchGroup.enter()\n            let procedure = TestProcedure(name: \"Batch \\(batch.number), Iteration \\(iteration)\")\n            procedure.addDidFinishBlockObserver { _, error in\n                if error == nil {\n                    DispatchQueue.main.async {\n                        XCTAssertNil(error, \"error is nil - cancel errors were not propagated\")\n                        batch.dispatchGroup.leave()\n                    }\n                }\n                else {\n                    batch.dispatchGroup.leave()\n                }\n            }\n            procedure.addWillExecuteBlockObserver { (procedure, _) in\n                procedure.cancel(with: TestError())\n            }\n            batch.queue.addOperation(procedure)\n        }\n    }\n}\n\nclass ProcedureConditionStressTest: StressTestCase {\n\n    func test__adding_many_conditions() {\n\n        StressLevel.custom(1, 10_000).forEach { _, _ in\n            procedure.addCondition(TrueCondition())\n        }\n        wait(for: procedure, withTimeout: 10)\n        PKAssertProcedureFinished(procedure)\n    }\n\n    func test__adding_many_conditions_each_with_single_dependency() {\n\n        StressLevel.custom(1, 10_000).forEach { _, _ in\n            procedure.addCondition(TestCondition(producedDependencies: [TestProcedure()]) { .success(true) })\n        }\n        wait(for: procedure, withTimeout: 10)\n        PKAssertProcedureFinished(procedure)\n    }\n\n    func test__dependencies_execute_before_condition_dependencies() {\n\n        var failures = Protector<[Int: [String]]>([:])\n        func appendFailure(batch: Int, _ failure: String) {\n            failures.write { (dict) in\n                if var existingFailures = dict[batch] {\n                    existingFailures.append(failure)\n                    dict[batch] = existingFailures\n                }\n                else {\n                    dict[batch] = [failure]\n                }\n            }\n        }\n\n        stress { batch, iteration in\n            batch.dispatchGroup.enter()\n            let procedure = TestProcedure(name: \"TestProcedure (\\(batch.number): \\(iteration))\")\n            procedure.addDidFinishBlockObserver { _, _ in\n                batch.dispatchGroup.leave()\n            }\n\n            let dependency1 = TestProcedure(name: \"Dependency 1 (\\(batch.number): \\(iteration))\")\n            let dependency2 = TestProcedure(name: \"Dependency 2 (\\(batch.number): \\(iteration))\")\n            procedure.addDependencies(dependency1, dependency2)\n\n            let conditionDependency1 = BlockOperation {\n                // dependency1 and dependency2 should be finished\n                let dep1Finished = dependency1.isFinished\n                let dep2Finished = dependency2.isFinished\n                if !dep1Finished { appendFailure(batch: batch.number, \"\\(dependency1.operationName) did not finish prior to condition-produced dependency\") }\n                if !dep2Finished { appendFailure(batch: batch.number, \"\\(dependency2.operationName) did not finish prior to condition-produced dependency\") }\n            }\n            conditionDependency1.name = \"Condition 1 Dependency\"\n\n            let condition1 = TrueCondition(name: \"Condition 1\")\n            condition1.produceDependency(conditionDependency1)\n\n            procedure.addCondition(condition1)\n\n            batch.queue.addOperations(dependency1, dependency2)\n            batch.queue.addOperation(procedure)\n        }\n\n        let finalFailures = failures.access\n        for (batch, failures) in finalFailures {\n            guard failures.isEmpty else {\n                XCTFail(\"Batch \\(batch) encountered \\(failures.count) failures:\\n\\t\\(failures.joined(separator: \"\\n\\t\"))\")\n                continue\n            }\n        }\n    }\n}\n\nclass ProcedureConditionsWillFinishObserverCancelThreadSafety: StressTestCase {\n\n    func test__conditions_do_not_fail_when_will_finish_observer_cancels_and_deallocates_procedure() {\n        // NOTES:\n        //      Previously, this test would fail in Condition.execute(),\n        //      where if `Condition.operation` was nil the following assertion would trigger:\n        //          assertionFailure(\"Condition executed before operation set.\")\n        //      However, this was not an accurate assert in all cases.\n        //\n        //      In this test case, all conditions have their .procedure properly set as a result of\n        //      `queue.addOperation(operation)`.\n        //\n        //      Calling `procedure.cancel()` results in the procedure deiniting prior to the access of the weak\n        //      `Condition.procedure` var, which was then nil (when accessed).\n        //\n        //      After removing this assert, the following additional race condition was triggered:\n        //      \"attempted to retain deallocated object\" (EXC_BREAKPOINT)\n        //      in the Procedure.EvaluateConditions's WillFinishObserver\n        //      Associated Report: https://github.com/ProcedureKit/ProcedureKit/issues/416\n        //\n        //      This was caused by a race condition between the procedure deiniting and the\n        //      EvaluateConditions's WillFinishObserver accessing `unowned self`,\n        //      which is easily triggerable by the following test case.\n        //\n        //      This test should now pass without error.\n\n        stress { batch, iteration in\n            batch.dispatchGroup.enter()\n            let procedure = TestProcedure()\n            procedure.addCondition(FalseCondition())\n            procedure.addDidFinishBlockObserver { _, _ in\n                batch.dispatchGroup.leave()\n            }\n            batch.queue.addOperation(procedure)\n            procedure.cancel()\n        }\n    }\n\n    func test__conditions_queue_suspension_safety() {\n        let numberOfQueueIsSuspendedCycles = Protector<Int>(0)\n        var lastBatchStopQueueSuspensionLoop = Protector<Bool>(false)\n        let procedures = Protector<[Procedure]>([])\n\n        stress { batch, iteration in\n            if (iteration == 0) {\n                // On the first iteration in a batch\n                // Stop the prior batch's loop\n                lastBatchStopQueueSuspensionLoop.overwrite(with: true)\n\n                // Dispatch an asynchronous loop to toggle isSuspended on the batch's queue\n                lastBatchStopQueueSuspensionLoop = Protector<Bool>(false)\n                DispatchQueue.global(qos: .userInteractive).async { [stopLoop = lastBatchStopQueueSuspensionLoop, queue = batch.queue] in\n                    // constantly suspend/resume the queue\n                    repeat {\n                        queue.isSuspended = true\n                        queue.isSuspended = false\n                        numberOfQueueIsSuspendedCycles.write({ (number) in\n                            if number < Int.max { // ensure we don't overflow\n                                number += 1\n                            }\n                        })\n                    } while (!stopLoop.access)\n                }\n            }\n            batch.dispatchGroup.enter()\n            let procedure = TestProcedure()\n            procedure.addCondition(FalseCondition())\n            procedure.addDidFinishBlockObserver { _, _ in\n                batch.dispatchGroup.leave()\n            }\n            procedures.append(procedure)\n            batch.queue.addOperation(procedure)\n        }\n\n        lastBatchStopQueueSuspensionLoop.overwrite(with: true)\n\n        for procedure in procedures.access {\n            PKAssertProcedureCancelledWithError(procedure, ProcedureKitError.FalseCondition())\n        }\n        print (\"Queue isSuspended cycles (total, all batches): \\(numberOfQueueIsSuspendedCycles.access)\")\n    }\n}\n\nclass ProcedureFinishStressTest: StressTestCase {\n\n    class TestAttemptsMultipleFinishesProcedure: Procedure {\n        public init(name: String = \"Test Procedure\") {\n            super.init()\n            self.name = name\n        }\n        override func execute() {\n            DispatchQueue.global().async() {\n                self.finish()\n            }\n            DispatchQueue.global().async() {\n                self.finish()\n            }\n            DispatchQueue.global().async() {\n                self.finish()\n            }\n        }\n    }\n\n    func test__concurrent_calls_to_finish_only_first_succeeds() {\n        // NOTES:\n        //      This test should pass without any \"cyclic state transition: finishing -> finishing\" errors.\n\n        stress { batch, iteration in\n            batch.dispatchGroup.enter()\n            let procedure = TestAttemptsMultipleFinishesProcedure()\n            var didFinish = false\n            let lock = NSLock()\n            procedure.addDidFinishBlockObserver { _, _ in\n                let finishedMoreThanOnce = lock.withCriticalScope(block: { () -> Bool in\n                    guard !didFinish else {\n                        // procedure finishing more than once\n                        return true\n                    }\n                    didFinish = true\n                    return false\n                })\n                guard !finishedMoreThanOnce else {\n                    batch.incrementCounter(named: \"finishedProcedureMoreThanOnce\")\n                    return\n                }\n                // add small delay before leaving to increase the odds that concurrent finishes are caught\n                let deadline = DispatchTime(uptimeNanoseconds: UInt64(0.1 * Double(NSEC_PER_SEC)))\n                DispatchQueue.global().asyncAfter(deadline: deadline) {\n                    batch.dispatchGroup.leave()\n                }\n            }\n            batch.queue.addOperation(procedure)\n        }\n    }\n\n    override func ended(batch: BatchProtocol) {\n        XCTAssertEqual(batch.counter(named: \"finishedProcedureMoreThanOnce\"), 0)\n        super.ended(batch: batch)\n    }\n}\n\nclass ProcedureCancellationHandlerConcurrencyTest: StressTestCase {\n\n    func test__cancelled_procedure_no_concurrent_events() {\n\n        stress(level: StressLevel.custom(2, 1000)) { batch, iteration in\n            batch.dispatchGroup.enter()\n            let procedure = EventConcurrencyTrackingProcedure(execute: { procedure in\n                usleep(50000)\n                procedure.finish()\n            })\n            procedure.addDidFinishBlockObserver(block: { (procedure, error) in\n                DispatchQueue.main.async {\n                    self.PKAssertProcedureNoConcurrentEvents(procedure)\n                    batch.dispatchGroup.leave()\n                }\n            })\n            batch.queue.addOperation(procedure)\n            procedure.cancel()\n        }\n    }\n}\n\nclass ProcedureFinishHandlerConcurrencyTest: StressTestCase {\n\n    func test__finish_from_asynchronous_callback_while_execute_is_still_running() {\n        // NOTE: Do not use this test as an example of what to do.\n\n        stress(level: StressLevel.custom(2, 1000)) { batch, iteration in\n            batch.dispatchGroup.enter()\n            let procedure = EventConcurrencyTrackingProcedure(execute: { procedure in\n                assert(!DispatchQueue.isMainDispatchQueue)\n                let semaphore = DispatchSemaphore(value: 0)\n                // dispatch finish on another thread...\n                DispatchQueue.global().async { [unowned procedure] in\n                    procedure.finish()\n                    semaphore.signal()\n                }\n                // and block this thread until the call to finish() returns\n                semaphore.wait()\n            })\n            procedure.addDidFinishBlockObserver(block: { (procedure, error) in\n                DispatchQueue.main.async {\n                    self.PKAssertProcedureNoConcurrentEvents(procedure)\n                    batch.dispatchGroup.leave()\n                }\n            })\n            batch.queue.addOperation(procedure)\n            procedure.cancel()\n        }\n    }\n}\n"
  },
  {
    "path": "Tests/ProcedureKitStressTests/RepeatStressTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport TestingProcedureKit\n@testable import ProcedureKit\n\nclass RepeatStressTests: StressTestCase {\n\n    func test__repeat_procedure_cancel() {\n\n        stress { batch, i in\n            batch.dispatchGroup.enter()\n            let repeatProcedure = RepeatProcedure(wait: .immediate, iterator: AnyIterator { TestProcedure(delay: 1) })\n            repeatProcedure.qualityOfService = .default\n            repeatProcedure.name = \"RepeatProcedure \\(batch.number), \\(i)\"\n            repeatProcedure.addDidFinishBlockObserver { _, _ in\n                batch.dispatchGroup.leave()\n            }\n            batch.queue.addOperation(repeatProcedure)\n            repeatProcedure.cancel()\n        }\n    }\n}\n"
  },
  {
    "path": "Tests/ProcedureKitTVTests/ProcedureKitTVTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport ProcedureKit\nimport TestingProcedureKit\n@testable import ProcedureKitTV\n\nclass TestSuiteRuns: XCTestCase {\n\n    func test__suite_runs() {\n        XCTAssertTrue(true)\n    }\n}\n"
  },
  {
    "path": "Tests/ProcedureKitTests/AnyProcedureTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport TestingProcedureKit\n@testable import ProcedureKit\n\nclass Foo: Procedure, InputProcedure, OutputProcedure {\n    var input: Pending<String> = .ready(\"\")\n    var output: Pending<ProcedureResult<String>> = .pending\n    override func execute() {\n        if let input = input.value {\n            output = .ready(.success(\"\\(input)Foo\"))\n        } else {\n            output = .ready(.failure(ProcedureKitError.requirementNotSatisfied()))\n        }\n        finish()\n    }\n}\n\nclass Bar: Procedure, InputProcedure, OutputProcedure {\n    var input: Pending<String> = .ready(\"\")\n    var output: Pending<ProcedureResult<String>> = .pending\n    override func execute() {\n        if let input = input.value {\n            output = .ready(.success(\"\\(input)Bar\"))\n        } else {\n            output = .ready(.failure(ProcedureKitError.requirementNotSatisfied()))\n        }\n        finish()\n    }\n}\n\nclass Baz: Procedure, InputProcedure, OutputProcedure {\n    var input: Pending<String> = .ready(\"\")\n    var output: Pending<ProcedureResult<String>> = .pending\n    override func execute() {\n        if let input = input.value {\n            output = .ready(.success(\"\\(input)Baz\"))\n        } else {\n            output = .ready(.failure(ProcedureKitError.requirementNotSatisfied()))\n        }\n        finish()\n    }\n}\n\nclass BaseAnyProcedureTests: ProcedureKitTestCase {\n    func test__any_procedure(_ anyProcedure: Procedure) {\n        wait(for: anyProcedure)\n        PKAssertProcedureFinished(procedure)\n        PKAssertProcedureFinished(anyProcedure)\n    }\n\n    func test__any_procedure_get_correct_result<P: OutputProcedure>(_ anyProcedure: P) where P: Procedure, P.Output == String {\n        wait(for: anyProcedure)\n        PKAssertProcedureFinished(procedure)\n        PKAssertProcedureFinished(anyProcedure)\n        XCTAssertEqual(anyProcedure.output.success, \"Hello World\")\n    }\n\n    func test__array_of_any_procedures<P: OutputProcedure>(_ procedures: [P]) where P: Procedure, P.Output == String {\n        let group = GroupProcedure(operations: procedures)\n        wait(for: group)\n        PKAssertProcedureFinished(group)\n        XCTAssertEqual(procedures.map { $0.output.success ?? \"\" }, [\"Foo\", \"Bar\", \"Baz\"])\n    }\n\n    func test__setting_requirement<A: InputProcedure, P: InputProcedure>(anyProcedure: A, boxedProcedure: P)\n                                                                where A: Procedure, P: Procedure , A.Input == String{\n        anyProcedure.input = .ready(\"Hello \")\n        wait(for: anyProcedure)\n        PKAssertProcedureFinished(boxedProcedure)\n        PKAssertProcedureFinished(anyProcedure)\n    }\n\n    func test__not_setting_requirement<A: InputProcedure, P: InputProcedure>(anyProcedure: A, boxedProcedure: P)\n        where A: Procedure, P: Procedure {\n            anyProcedure.input = .pending\n            wait(for: anyProcedure)\n            PKAssertProcedureFinished(boxedProcedure)\n            PKAssertProcedureFinished(anyProcedure)\n    }\n}\n\nclass AnyProcedureTests: BaseAnyProcedureTests {\n\n    func test__any_procedure() {\n        let anyProcedure = AnyProcedure(procedure)\n        self.test__any_procedure(anyProcedure)\n    }\n\n    func test__any_procedure_get_correct_result() {\n        let anyProcedure = AnyProcedure(procedure)\n        self.test__any_procedure_get_correct_result(anyProcedure)\n    }\n\n    func test__array_of_any_procedures() {\n        let procedures = [AnyProcedure(Foo()), AnyProcedure(Bar()), AnyProcedure(Baz())]\n        self.test__array_of_any_procedures(procedures)\n    }\n\n    func test__setting_requirement() {\n        let foo = Foo()\n        let anyProcedure = AnyProcedure(foo)\n        test__setting_requirement(anyProcedure: anyProcedure, boxedProcedure: foo)\n    }\n\n    func test__not_setting_requirement() {\n        let foo = Foo()\n        let anyProcedure = AnyProcedure(foo)\n        self.test__not_setting_requirement(anyProcedure: anyProcedure, boxedProcedure: foo)\n    }\n}\n\nclass AnyInputProcedureTests: BaseAnyProcedureTests {\n\n    func test__any_procedure() {\n        let anyProcedure = AnyInputProcedure(procedure)\n        self.test__any_procedure(anyProcedure)\n    }\n\n    func test__setting_requirement() {\n        let foo = Foo()\n        let anyProcedure = AnyInputProcedure(foo)\n        test__setting_requirement(anyProcedure: anyProcedure, boxedProcedure: foo)\n    }\n\n    func test__not_setting_requirement() {\n        let foo = Foo()\n        let anyProcedure = AnyInputProcedure(foo)\n        self.test__not_setting_requirement(anyProcedure: anyProcedure, boxedProcedure: foo)\n    }\n}\n\nclass AnyOutputProcedureTests: BaseAnyProcedureTests {\n\n    func test__any_procedure() {\n        let anyProcedure = AnyOutputProcedure(procedure)\n        self.test__any_procedure(anyProcedure)\n    }\n\n    func test__any_procedure_get_correct_result() {\n        let anyProcedure = AnyOutputProcedure(procedure)\n        self.test__any_procedure_get_correct_result(anyProcedure)\n    }\n\n    func test__array_of_any_procedures() {\n        let procedures = [AnyOutputProcedure(Foo()), AnyOutputProcedure(Bar()), AnyOutputProcedure(Baz())]\n        self.test__array_of_any_procedures(procedures)\n    }\n}\n\n\n"
  },
  {
    "path": "Tests/ProcedureKitTests/BatchTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport TestingProcedureKit\n@testable import ProcedureKit\n\nclass BatchProcedureTests: ProcedureKitTestCase {\n\n    class Greeter: TransformProcedure<String, String> {\n        init() {\n            super.init { \"Hello \\($0)\" }\n        }\n    }\n\n    typealias Batch = BatchProcedure<Greeter>\n\n    func test__batch() {\n\n        let beatles = ResultProcedure { [\"John\", \"Paul\", \"George\", \"Ringo\"] }\n        let greetings = Batch { Greeter() }.injectResult(from: beatles)\n\n        wait(for: beatles, greetings)\n\n        PKAssertProcedureFinished(greetings)\n        guard let result = greetings.output.success else {\n            XCTFail(\"Batch did not finish with successful output.\")\n            return\n        }\n        XCTAssertEqual(result, [\"Hello John\", \"Hello Paul\", \"Hello George\", \"Hello Ringo\"])\n    }\n\n    func test__batch_cancel_if_input_not_ready() {\n\n        let beatles = ResultProcedure<[String]> { throw ProcedureKitError.unknown }\n        let greetings = Batch { Greeter() }.injectResult(from: beatles)\n\n        wait(for: beatles, greetings)\n\n        PKAssertProcedureCancelledWithError(greetings, ProcedureKitError.dependency(finishedWithError: ProcedureKitError.unknown))\n    }\n}\n"
  },
  {
    "path": "Tests/ProcedureKitTests/BlockConditionTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport TestingProcedureKit\n@testable import ProcedureKit\n\nclass BlockConditionTests: ProcedureKitTestCase {\n\n    func test__procedure_with_successfull_block_finishes() {\n        procedure.addCondition(BlockCondition { true })\n        wait(for: procedure)\n        PKAssertProcedureFinished(procedure)\n    }\n\n    func test__procedure_with_unsuccessful_block_cancels_without_errors() {\n        procedure.addCondition(BlockCondition { false })\n        wait(for: procedure)\n        PKAssertProcedureCancelled(procedure)\n    }\n\n    func test__procedure_with_throwing_block_cancels_with_error() {\n        let error = TestError()\n        procedure.addCondition(BlockCondition { throw error })\n        wait(for: procedure)\n        PKAssertProcedureCancelledWithError(procedure, ProcedureKitError.conditionFailed(with: error))\n    }\n}\n\n"
  },
  {
    "path": "Tests/ProcedureKitTests/BlockObserverTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport TestingProcedureKit\n@testable import ProcedureKit\nimport Dispatch\n\nclass BlockObserverTests: ProcedureKitTestCase {\n\n    func test__did_attach_is_called() {\n        let didAttachCalled = Protector<Procedure?>(nil)\n        procedure.addObserver(BlockObserver(didAttach: { didAttachCalled.overwrite(with: $0) }))\n        wait(for: procedure)\n        XCTAssertEqual(didAttachCalled.access, procedure)\n    }\n\n    func test__will_execute_is_called() {\n        let willExecuteCalled = Protector<Procedure?>(nil)\n        procedure.addObserver(BlockObserver(willExecute: { procedure, _ in\n            willExecuteCalled.overwrite(with: procedure)\n        }))\n        wait(for: procedure)\n        XCTAssertEqual(willExecuteCalled.access, procedure)\n    }\n\n    func test__did_execute_is_called() {\n        let didExecuteCalled = Protector<Procedure?>(nil)\n        procedure.addObserver(BlockObserver(didExecute: { didExecuteCalled.overwrite(with: $0) }))\n        wait(for: procedure)\n        XCTAssertEqual(didExecuteCalled.access, procedure)\n    }\n\n    func test__did_cancel_is_called() {\n        let didCancelCalled = Protector<(Procedure, Error?)?>(nil)\n        let error = TestError()\n        let cancelWaitGroup = DispatchGroup()\n        cancelWaitGroup.enter()\n        let procedure = BlockProcedure { this in\n            // Wait for the Procedure to be cancelled by the test\n            // (and for all didCancel observers to be triggered)\n            // to avoid a race condition in which the Procedure finishes\n            // before the check block below can cancel it and/or the DidCancel\n            // observers can be called.\n            cancelWaitGroup.notify(queue: DispatchQueue.global()) {\n                this.finish()\n            }\n        }\n        procedure.addObserver(BlockObserver(didCancel: {\n            didCancelCalled.overwrite(with: ($0, $1))\n            cancelWaitGroup.leave()\n        }))\n        check(procedure: procedure) { procedure in\n            procedure.cancel(with: error)\n        }\n        XCTAssertEqual(didCancelCalled.access?.0, procedure)\n        XCTAssertEqual(didCancelCalled.access?.1 as? TestError, error)\n    }\n\n    func test__will_add_operation_is_called() {\n        let willAddCalled = Protector<(Procedure, Operation)?>(nil)\n        var didExecuteProducedOperation = false\n        let producingProcedure = TestProcedure(produced: BlockOperation { didExecuteProducedOperation = true })\n        producingProcedure.addObserver(BlockObserver(willAdd: { willAddCalled.overwrite(with: ($0, $1)) }))\n        wait(for: producingProcedure)\n        XCTAssertTrue(didExecuteProducedOperation)\n        XCTAssertEqual(willAddCalled.access?.0, producingProcedure)\n        XCTAssertNotNil(willAddCalled.access?.1)\n    }\n\n    func test__did_add_operation_is_called() {\n        let didAddCalled = Protector<(Procedure, Operation)?>(nil)\n        var didExecuteProducedOperation = false\n        let producingProcedure = TestProcedure(produced: BlockOperation { didExecuteProducedOperation = true })\n        producingProcedure.addObserver(BlockObserver(didAdd: { didAddCalled.overwrite(with: ($0, $1)) }))\n        wait(for: producingProcedure)\n        XCTAssertTrue(didExecuteProducedOperation)\n        XCTAssertEqual(didAddCalled.access?.0, producingProcedure)\n        XCTAssertNotNil(didAddCalled.access?.1)\n    }\n\n    func test__will_finish_is_called() {\n        let willFinishCalled = Protector<(Procedure, Error?)?>(nil)\n        procedure.addObserver(BlockObserver(willFinish: { procedure, error, _ in\n            willFinishCalled.overwrite(with: (procedure, error))\n        }))\n        wait(for: procedure)\n        XCTAssertEqual(willFinishCalled.access?.0, procedure)\n    }\n\n    func test__did_finish_is_called() {\n        let didFinishCalled = Protector<(Procedure, Error?)?>(nil)\n        procedure.addObserver(BlockObserver(didFinish: { didFinishCalled.overwrite(with: ($0, $1)) }))\n        wait(for: procedure)\n        XCTAssertEqual(didFinishCalled.access?.0, procedure)\n    }\n}\n\nclass BlockObserverSynchronizationTests: ProcedureKitTestCase {\n\n    func test__will_add_observer_synchronized_with_parent_group() {\n        class CustomGroup: GroupProcedure {\n            let child1 = TestProcedure()\n            init() {\n                super.init(operations: [child1])\n                child1.addWillAddOperationBlockObserver(synchronizedWith: self) { _, _ in\n                    // do something on the Group's EventQueue\n                    print(\"in observer\")\n                }\n            }\n            override func execute() {\n                super.execute()\n                // call child1.produce from within the Group's execute(),\n                // which is on the Group's EventQueue\n                //\n                // the resulting willAddOperationBlockObserver is set to\n                // also be synchronized with the Group's EventQueue\n                //\n                // this should succeed without any deadlock\n                try! child1.produce(operation: TestProcedure())\n            }\n        }\n\n        let group = CustomGroup()\n        wait(for: group)\n    }\n\n    class QueueIdentity {\n        let key: DispatchSpecificKey<UInt8>\n        let value: UInt8 = 1\n        init(queue: DispatchQueue) {\n            key = DispatchSpecificKey()\n            queue.setSpecific(key: key, value: value)\n        }\n        var isOnQueue: Bool {\n            guard let retrieved = DispatchQueue.getSpecific(key: key) else { return false }\n            return value == retrieved\n        }\n    }\n\n    private func syncTest(block: (QueueProvider, @escaping () -> Bool) -> Void ) {\n        // sync with other Procedure (i.e. the other Procedure's eventQueue)\n        let otherProcedure = TestProcedure()\n        block(otherProcedure, { return otherProcedure.eventQueue.isOnQueue })\n\n        // sync with other EventQueue\n        let otherEventQueue = EventQueue(label: \"run.kit.procedure.ProcedureKit.Testing.OtherEventQueue\")\n        block(otherEventQueue, { return otherEventQueue.isOnQueue })\n\n        // sync with DispatchQueue (serial)\n        let otherQueue = DispatchQueue(label: \"run.kit.procedure.ProcedureKit.Testing.SerialDispatchQueue\")\n        let otherQueueIdentity = QueueIdentity(queue: otherQueue)\n        block(otherQueue, { return otherQueueIdentity.isOnQueue })\n\n        // sync with DispatchQueue (concurrent)\n        let otherConcurrentQueue = DispatchQueue(label: \"run.kit.procedure.ProcedureKit.Testing.ConcurrentDispatchQueue\", attributes: [.concurrent])\n        let otherConcurrentQueueIdentity = QueueIdentity(queue: otherConcurrentQueue)\n        block(otherConcurrentQueue, { return otherConcurrentQueueIdentity.isOnQueue })\n    }\n\n    func test__did_attach_synchronized() {\n        syncTest { syncObject, isSynced in\n            let didAttachCalled_BlockObserver = Protector<(Procedure, Bool)?>(nil)\n            let procedure = TestProcedure()\n            procedure.addObserver(BlockObserver(synchronizedWith: syncObject, didAttach: { didAttachCalled_BlockObserver.overwrite(with: ($0, isSynced())) }))\n            wait(for: procedure)\n            XCTAssertEqual(didAttachCalled_BlockObserver.access?.0, procedure)\n            XCTAssertTrue(didAttachCalled_BlockObserver.access?.1 ?? false, \"Was not synchronized on \\(syncObject).\") // was synchronized\n        }\n    }\n\n    func test__will_execute_synchronized() {\n        syncTest { syncObject, isSynced in\n            let willExecuteCalled_addBlock = Protector<(Procedure, Bool)?>(nil)\n            let willExecuteCalled_BlockObserver = Protector<(Procedure, Bool)?>(nil)\n            let procedure = TestProcedure()\n            procedure.addWillExecuteBlockObserver(synchronizedWith: syncObject) { procedure, _ in\n                willExecuteCalled_addBlock.overwrite(with: (procedure, isSynced()))\n            }\n            procedure.addObserver(BlockObserver(synchronizedWith: syncObject, willExecute: { procedure, _ in\n                willExecuteCalled_BlockObserver.overwrite(with: (procedure, isSynced()))\n            }))\n            wait(for: procedure)\n            XCTAssertEqual(willExecuteCalled_addBlock.access?.0, procedure)\n            XCTAssertTrue(willExecuteCalled_addBlock.access?.1 ?? false, \"Was not synchronized on \\(syncObject).\") // was synchronized\n            XCTAssertEqual(willExecuteCalled_BlockObserver.access?.0, procedure)\n            XCTAssertTrue(willExecuteCalled_BlockObserver.access?.1 ?? false, \"Was not synchronized on \\(syncObject).\") // was synchronized\n        }\n    }\n\n    func test__did_execute_synchronized() {\n        syncTest { syncObject, isSynced in\n            let didExecuteCalled_addBlock = Protector<(Procedure, Bool)?>(nil)\n            let didExecuteCalled_BlockObserver = Protector<(Procedure, Bool)?>(nil)\n            let procedure = TestProcedure()\n            procedure.addDidExecuteBlockObserver(synchronizedWith: syncObject) { procedure in\n                didExecuteCalled_addBlock.overwrite(with: (procedure, isSynced()))\n            }\n            procedure.addObserver(BlockObserver(synchronizedWith: syncObject, didExecute: { didExecuteCalled_BlockObserver.overwrite(with: ($0, isSynced())) }))\n            wait(for: procedure)\n            XCTAssertEqual(didExecuteCalled_addBlock.access?.0, procedure)\n            XCTAssertTrue(didExecuteCalled_addBlock.access?.1 ?? false, \"Was not synchronized on \\(syncObject).\") // was synchronized\n            XCTAssertEqual(didExecuteCalled_BlockObserver.access?.0, procedure)\n            XCTAssertTrue(didExecuteCalled_BlockObserver.access?.1 ?? false, \"Was not synchronized on \\(syncObject).\") // was synchronized\n        }\n    }\n\n    func test__did_cancel_synchronized() {\n        syncTest { syncObject, isSynced in\n            let error = TestError()\n            let didCancelCalled_addBlock = Protector<(Procedure, Error?, Bool)?>(nil)\n            let didCancelCalled_BlockObserver = Protector<(Procedure, Error?, Bool)?>(nil)\n            let cancelWaitGroup = DispatchGroup()\n            cancelWaitGroup.enter()\n            cancelWaitGroup.enter()\n            let procedure = BlockProcedure { this in\n                // Wait for the Procedure to be cancelled by the test\n                // (and for all didCancel observers to be triggered)\n                // to avoid a race condition in which the Procedure finishes\n                // before the check block below can cancel it and/or the DidCancel\n                // observers can be called.\n                cancelWaitGroup.notify(queue: DispatchQueue.global()) {\n                    this.finish()\n                }\n            }\n            procedure.addDidCancelBlockObserver(synchronizedWith: syncObject) { procedure, error in\n                didCancelCalled_addBlock.overwrite(with: (procedure, error, isSynced()))\n                cancelWaitGroup.leave() // A\n            }\n            procedure.addObserver(BlockObserver(synchronizedWith: syncObject, didCancel: {\n                didCancelCalled_BlockObserver.overwrite(with: ($0, $1, isSynced()))\n                cancelWaitGroup.leave() // B\n            }))\n            check(procedure: procedure) { procedure in\n                procedure.cancel(with: error)\n            }\n            XCTAssertEqual(didCancelCalled_addBlock.access?.0, procedure)\n            XCTAssertEqual(didCancelCalled_addBlock.access?.1 as? TestError, error)\n            XCTAssertTrue(didCancelCalled_addBlock.access?.2 ?? false, \"Was not synchronized on \\(syncObject).\") // was synchronized\n            XCTAssertEqual(didCancelCalled_BlockObserver.access?.0, procedure)\n            XCTAssertEqual(didCancelCalled_BlockObserver.access?.1 as? TestError, error)\n            XCTAssertTrue(didCancelCalled_BlockObserver.access?.2 ?? false, \"Was not synchronized on \\(syncObject).\") // was synchronized\n        }\n    }\n\n    func test__will_add_synchronized() {\n        syncTest { syncObject, isSynced in\n            let didExecuteProducedOperation = Protector(false)\n            let willAddOperationCalled_addBlock = Protector<(Procedure, Operation, Bool)?>(nil)\n            let willAddOperationCalled_BlockObserver = Protector<(Procedure, Operation, Bool)?>(nil)\n            let producedOperation = BlockProcedure { didExecuteProducedOperation.overwrite(with: true) }\n            addCompletionBlockTo(procedure: producedOperation)\n            let producingProcedure = TestProcedure(produced: producedOperation)\n            producingProcedure.addWillAddOperationBlockObserver(synchronizedWith: syncObject) {\n                willAddOperationCalled_addBlock.overwrite(with: ($0, $1, isSynced()))\n            }\n            producingProcedure.addObserver(BlockObserver(synchronizedWith: syncObject, willAdd: { willAddOperationCalled_BlockObserver.overwrite(with: ($0, $1, isSynced())) }))\n            wait(for: producingProcedure)\n            XCTAssertTrue(didExecuteProducedOperation.access)\n            XCTAssertEqual(willAddOperationCalled_addBlock.access?.0, producingProcedure)\n            XCTAssertEqual(willAddOperationCalled_addBlock.access?.1, producedOperation)\n            XCTAssertTrue(willAddOperationCalled_addBlock.access?.2 ?? false, \"Was not synchronized on \\(syncObject).\") // was synchronized\n            XCTAssertEqual(willAddOperationCalled_BlockObserver.access?.0, producingProcedure)\n            XCTAssertEqual(willAddOperationCalled_BlockObserver.access?.1, producedOperation)\n            XCTAssertTrue(willAddOperationCalled_BlockObserver.access?.2 ?? false, \"Was not synchronized on \\(syncObject).\") // was synchronized\n        }\n    }\n\n    func test__did_add_synchronized() {\n        syncTest { syncObject, isSynced in\n            let didAddGroup = DispatchGroup()\n            let didExecuteProducedOperation = Protector(false)\n            let didAddOperationCalled_addBlock = Protector<(Procedure, Operation, Bool)?>(nil)\n            let didAddOperationCalled_BlockObserver = Protector<(Procedure, Operation, Bool)?>(nil)\n            let producedOperation = BlockProcedure { didExecuteProducedOperation.overwrite(with: true) }\n            addCompletionBlockTo(procedure: producedOperation)\n            let producingProcedure = TestProcedure(produced: producedOperation)\n            didAddGroup.enter()\n            producingProcedure.addDidAddOperationBlockObserver(synchronizedWith: syncObject) {\n                didAddOperationCalled_addBlock.overwrite(with: ($0, $1, isSynced()))\n                didAddGroup.leave()\n            }\n            didAddGroup.enter()\n            producingProcedure.addObserver(BlockObserver(synchronizedWith: syncObject, didAdd: {\n                didAddOperationCalled_BlockObserver.overwrite(with: ($0, $1, isSynced()))\n                didAddGroup.leave()\n            }))\n            wait(for: producingProcedure)\n\n            // DidAdd events are only guaranteed to happen at *some point after* the operation is added.\n            // Thus, wait on both observers to be called before proceeding.\n            weak var expDidAddObserverFired = expectation(description: \"DidAddObservers were fired\")\n            didAddGroup.notify(queue: DispatchQueue.main) {\n                expDidAddObserverFired?.fulfill()\n            }\n            waitForExpectations(timeout: 2)\n\n            XCTAssertTrue(didExecuteProducedOperation.access)\n            XCTAssertEqual(didAddOperationCalled_addBlock.access?.0, producingProcedure)\n            XCTAssertEqual(didAddOperationCalled_addBlock.access?.1, producedOperation)\n            XCTAssertTrue(didAddOperationCalled_addBlock.access?.2 ?? false, \"Was not synchronized on \\(syncObject).\") // was synchronized\n            XCTAssertEqual(didAddOperationCalled_BlockObserver.access?.0, producingProcedure)\n            XCTAssertEqual(didAddOperationCalled_BlockObserver.access?.1, producedOperation)\n            XCTAssertTrue(didAddOperationCalled_BlockObserver.access?.2 ?? false, \"Was not synchronized on \\(syncObject).\") // was synchronized\n        }\n    }\n\n    func test__will_finish_synchronized() {\n        syncTest { syncObject, isSynced in\n            let willFinishCalled_addBlock = Protector<(Procedure, Error?, Bool)?>(nil)\n            let willFinishCalled_BlockObserver = Protector<(Procedure, Error?, Bool)?>(nil)\n            let procedure = TestProcedure()\n            procedure.addWillFinishBlockObserver(synchronizedWith: syncObject) { procedure, error, _ in\n                willFinishCalled_addBlock.overwrite(with: (procedure, error, isSynced()))\n            }\n            procedure.addObserver(BlockObserver(synchronizedWith: syncObject, willFinish: { procedure, error, _ in\n                willFinishCalled_BlockObserver.overwrite(with: (procedure, error, isSynced()))\n            }))\n            wait(for: procedure)\n            XCTAssertEqual(willFinishCalled_addBlock.access?.0, procedure)\n            XCTAssertTrue(willFinishCalled_addBlock.access?.2 ?? false, \"Was not synchronized on \\(syncObject).\") // was synchronized\n            XCTAssertEqual(willFinishCalled_BlockObserver.access?.0, procedure)\n            XCTAssertTrue(willFinishCalled_BlockObserver.access?.2 ?? false, \"Was not synchronized on \\(syncObject).\") // was synchronized\n        }\n    }\n\n    func test__did_finish_synchronized() {\n        syncTest { syncObject, isSynced in\n            let didFinishGroup = DispatchGroup()\n            let didFinishCalled_addBlock = Protector<(Procedure, Error?, Bool)?>(nil)\n            let didFinishCalled_BlockObserver = Protector<(Procedure, Error?, Bool)?>(nil)\n            let procedure = TestProcedure()\n            didFinishGroup.enter()\n            procedure.addDidFinishBlockObserver(synchronizedWith: syncObject) { procedure, error in\n                didFinishCalled_addBlock.overwrite(with: (procedure, error, isSynced()))\n                didFinishGroup.leave()\n            }\n            didFinishGroup.enter()\n            procedure.addObserver(BlockObserver(synchronizedWith: syncObject, didFinish: { didFinishCalled_BlockObserver.overwrite(with: ($0, $1, isSynced()))\n                didFinishGroup.leave()\n            }))\n            wait(for: procedure)\n\n            // Because Procedure signals isFinished KVO *prior* to calling DidFinish observers,\n            // the above wait() may return before either observer is called to record the\n            // DidFinish event.\n            // Thus, wait on both observers to be called before proceeding.\n            weak var expDidFinishObserverFired = expectation(description: \"DidFinishObservers were fired\")\n            didFinishGroup.notify(queue: DispatchQueue.main) {\n                expDidFinishObserverFired?.fulfill()\n            }\n            waitForExpectations(timeout: 2)\n\n            XCTAssertEqual(didFinishCalled_addBlock.access?.0, procedure)\n            XCTAssertTrue(didFinishCalled_addBlock.access?.2 ?? false, \"Was not synchronized on \\(syncObject).\") // was synchronized\n            XCTAssertEqual(didFinishCalled_BlockObserver.access?.0, procedure)\n            XCTAssertTrue(didFinishCalled_BlockObserver.access?.2 ?? false, \"Was not synchronized on \\(syncObject).\") // was synchronized\n        }\n    }\n}\n"
  },
  {
    "path": "Tests/ProcedureKitTests/BlockProcedureTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport TestingProcedureKit\n@testable import ProcedureKit\n\nclass BlockProcedureTests: ProcedureKitTestCase {\n\n    func test__void_block_procedure() {\n        var blockDidExecute = false\n        let block = BlockProcedure { blockDidExecute = true }\n        wait(for: block)\n        XCTAssertTrue(blockDidExecute)\n        PKAssertProcedureFinished(block)\n    }\n\n    func test__self_block_procedure() {\n        var blockDidExecute = false\n        let block = BlockProcedure { (procedure) in\n            blockDidExecute = true\n            procedure.log.debug.message(\"Hello world\")\n            procedure.finish()\n        }\n        wait(for: block)\n        XCTAssertTrue(blockDidExecute)\n        PKAssertProcedureFinished(block)\n    }\n\n    func test__block_does_not_execute_if_cancelled() {\n        var blockDidExecute = false\n        let block = BlockProcedure { blockDidExecute = true }\n        block.cancel()\n        wait(for: block)\n        XCTAssertFalse(blockDidExecute)\n        PKAssertProcedureCancelled(block)\n    }\n\n    func test__block_which_throws_finishes_with_error() {\n        let error = TestError()\n        let block = BlockProcedure { throw error }\n        wait(for: block)\n        PKAssertProcedureFinishedWithError(block, error)\n    }\n\n    func test__block_did_execute_observer() {\n        let block = BlockProcedure { /* does nothing */ }\n        var didExecuteBlockObserver = false\n        block.addDidExecuteBlockObserver { procedure in\n            didExecuteBlockObserver = true\n        }\n        wait(for: block)\n        XCTAssertTrue(didExecuteBlockObserver)\n        PKAssertProcedureFinished(block)\n    }\n}\n\nclass AsyncBlockProcedureTests: ProcedureKitTestCase {\n\n    var dispatchQueue: DispatchQueue!\n\n    override func setUp() {\n        super.setUp()\n        dispatchQueue = DispatchQueue.initiated\n    }\n\n    override func tearDown() {\n        dispatchQueue = nil\n        super.tearDown()\n    }\n\n    func test__block_executes() {\n        var blockDidExecute = false\n        let block = BlockProcedure { this in\n            self.dispatchQueue.async {\n                blockDidExecute = true\n                this.finish()\n            }\n        }\n        wait(for: block)\n        XCTAssertTrue(blockDidExecute)\n        PKAssertProcedureFinished(block)\n    }\n\n    func test__block_does_not_execute_if_cancelled() {\n        var blockDidExecute = false\n        let block = BlockProcedure { this in\n            self.dispatchQueue.async {\n                blockDidExecute = true\n                this.finish()\n            }\n        }\n        block.cancel()\n        wait(for: block)\n        XCTAssertFalse(blockDidExecute)\n        PKAssertProcedureCancelled(block)\n    }\n\n    func test__block_which_finishes_with_error() {\n        let error = TestError()\n        let block = BlockProcedure { this in\n            self.dispatchQueue.async {\n                this.finish(with: error)\n            }\n        }\n        wait(for: block)\n        PKAssertProcedureFinishedWithError(block, error)\n    }\n\n    func test__block_did_execute_observer() {\n        let block = BlockProcedure { this in\n            self.dispatchQueue.async {\n                this.finish()\n            }\n        }\n        var didExecuteBlockObserver = false\n        block.addDidExecuteBlockObserver { procedure in\n            didExecuteBlockObserver = true\n        }\n        wait(for: block)\n        XCTAssertTrue(didExecuteBlockObserver)\n        PKAssertProcedureFinished(block)\n    }\n}\n\nclass UIBlockProcedureTests: ProcedureKitTestCase {\n\n    func test__block_executes() {\n        var blockDidExecute = false\n        let block = UIBlockProcedure {\n            blockDidExecute = true\n        }\n        wait(for: block)\n        XCTAssertTrue(blockDidExecute)\n        PKAssertProcedureFinished(block)\n    }\n\n    func test__block_executes_on_main_queue() {\n        var blockDidExecuteOnMainQueue = false\n        let block = UIBlockProcedure {\n            blockDidExecuteOnMainQueue = DispatchQueue.isMainDispatchQueue\n        }\n        wait(for: block)\n        XCTAssertTrue(blockDidExecuteOnMainQueue)\n        PKAssertProcedureFinished(block)\n    }\n\n    func test__willFinishObserversCalled() {\n        var blockDidExecute = false\n        var observerDidExecute = false\n        let block = UIBlockProcedure {\n            blockDidExecute = true\n        }\n        block.addWillFinishBlockObserver { (_, _, pendingFinish) in\n            pendingFinish.doBeforeEvent {\n                observerDidExecute = true\n            }\n        }\n        var dependencyDidExecute = false\n        let dep = BlockProcedure {\n            dependencyDidExecute = true\n        }\n        block.addDependency(dep)\n        wait(for: block, dep)\n        XCTAssertTrue(blockDidExecute)\n        XCTAssertTrue(observerDidExecute)\n        XCTAssertTrue(dependencyDidExecute)\n        PKAssertProcedureFinished(block)\n        PKAssertProcedureFinished(dep)\n    }\n}\n\nclass ResultProcedureTests: ProcedureKitTestCase {\n\n    func test__throwing_output() {\n        typealias TypeUnderTest = ResultProcedure<String>\n        var blockDidExecute = false\n\n        let result = TypeUnderTest { (_) -> String in\n            blockDidExecute = true\n            return \"Hello World\"\n        }\n\n        wait(for: result)\n        XCTAssertTrue(blockDidExecute)\n        PKAssertProcedureOutput(result, \"Hello World\")\n    }\n}\n"
  },
  {
    "path": "Tests/ProcedureKitTests/CancellationTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport TestingProcedureKit\n@testable import ProcedureKit\n\n\nclass CancellationTests: ProcedureKitTestCase {\n\n    func test__procedure_cancel_with_nil_error() {\n        procedure.cancel(with: nil)\n        XCTAssertFalse(procedure.didExecute)\n        XCTAssertTrue(procedure.isCancelled)\n        XCTAssertFalse(procedure.failed)\n    }\n\n    func test__procedure_cancel_with_error() {\n        procedure.cancel(with: TestError())\n        XCTAssertFalse(procedure.didExecute)\n        XCTAssertTrue(procedure.isCancelled)\n        XCTAssertTrue(procedure.failed)\n    }\n\n    func test__procedure_did_cancel_called_after_cancelled() {\n        var observerCalled = false\n        procedure.addDidCancelBlockObserver { procedure, _ in\n            XCTAssertTrue(procedure.isCancelled)\n            XCTAssertTrue(procedure.procedureDidCancelCalled)\n            observerCalled = true\n        }\n        procedure.cancel()\n        wait(for: procedure)\n        XCTAssertTrue(observerCalled)\n    }\n\n    func test__procedured_cancelled_before_running_is_not_set_to_finished_until_started() {\n\n        let didCancelCalled = DispatchSemaphore(value: 0)\n        procedure.addDidCancelBlockObserver { _, _ in\n            didCancelCalled.signal()\n        }\n        procedure.cancel()\n\n        XCTAssertTrue(procedure.isCancelled)\n        XCTAssertFalse(procedure.didExecute)\n        XCTAssertFalse(procedure.procedureWillFinishCalled)\n        XCTAssertFalse(procedure.procedureDidFinishCalled)\n        XCTAssertFalse(procedure.isFinished)\n\n        XCTAssertEqual(didCancelCalled.wait(timeout: .now() + 1.0), DispatchTimeoutResult.success)\n\n        XCTAssertTrue(procedure.procedureDidCancelCalled)\n        XCTAssertFalse(procedure.didExecute)\n        XCTAssertFalse(procedure.procedureWillFinishCalled)\n        XCTAssertFalse(procedure.procedureDidFinishCalled)\n        XCTAssertFalse(procedure.isFinished)\n\n        wait(for: procedure)\n\n        XCTAssertTrue(procedure.procedureDidFinishCalled)\n        XCTAssertTrue(procedure.isFinished)\n    }\n\n    func test__procedure_with_disables_automatic_finishing_does_not_finish_automatically_when_cancelled() {\n\n        class TestHandlesFinishOperation: Procedure {\n            override init() {\n                super.init(disableAutomaticFinishing: true)\n            }\n\n            override func execute() {\n                // deliberately does not finish\n            }\n            \n            func triggerFinish() {\n                self.finish()\n            }\n        }\n\n        let special = TestHandlesFinishOperation()\n\n        let _ = addCompletionBlockTo(procedure: special)\n        run(operation: special)\n\n        special.cancel()\n\n        XCTAssertTrue(special.isCancelled)\n        XCTAssertFalse(special.isFinished)\n        sleep(1)\n        XCTAssertFalse(special.isFinished)\n\n        special.triggerFinish()\n\n        waitForExpectations(timeout: 3, handler: nil)\n\n        XCTAssertTrue(special.isFinished)\n    }\n\n    func test__procedure_cancelled_then_finished_from_within_execute() {\n\n        class TestCancelFinishFromExecuteProcedure: Procedure {\n            var didCancel = Protector((false, false))\n            let expectedError = TestError()\n            override func execute() {\n                cancel()\n                finish(with: expectedError)\n            }\n            override func procedureDidCancel(with: Error?) {\n                didCancel.overwrite(with: (true, isFinished))\n            }\n        }\n\n        let special = TestCancelFinishFromExecuteProcedure()\n\n        wait(for: special)\n\n        XCTAssertTrue(special.didCancel.access.0)\n        XCTAssertFalse(special.didCancel.access.1)  // isFinished should be false when the didcancel observers run\n        PKAssertProcedureCancelled(special, withErrors: true)\n    }\n\n    func test__procedure_cancelled_then_finished_async_during_execute() {\n\n        class TestCancelFinishAsyncFromExecuteProcedure: Procedure {\n            var didCancel = Protector(false)\n            override func execute() {\n                let semaphore = DispatchSemaphore(value: 0)\n                DispatchQueue.global().async { [unowned self] in\n                    self.cancel()\n                    self.finish()\n                    semaphore.signal()\n                }\n                semaphore.wait()\n            }\n            override func procedureDidCancel(with: Error?) {\n                didCancel.overwrite(with: true)\n            }\n        }\n\n        let special = TestCancelFinishAsyncFromExecuteProcedure()\n\n        wait(for: special)\n\n        XCTAssertTrue(special.didCancel.access)\n        PKAssertProcedureCancelled(special)\n    }\n\n    func test__procedure_finished_then_cancelled_from_within_execute() {\n\n        class TestFinishCancelFromExecuteProcedure: Procedure {\n            var didCancel = Protector(false)\n            override func execute() {\n                finish()\n                cancel()\n            }\n            override func procedureDidCancel(with: Error?) {\n                didCancel.overwrite(with: true)\n            }\n        }\n\n        let special = TestFinishCancelFromExecuteProcedure()\n\n        wait(for: special)\n\n        PKAssertProcedureFinished(special)\n        XCTAssertFalse(special.didCancel.access)\n        XCTAssertFalse(special.isCancelled)\n    }\n\n    func test__procedure_finished_then_cancelled_async_during_execute() {\n\n        class TestFinishCancelAsyncFromExecuteProcedure: Procedure {\n            var didCancel = Protector(false)\n            override func execute() {\n                let semaphore = DispatchSemaphore(value: 0)\n                DispatchQueue.global().async { [unowned self] in\n                    self.finish()\n                    self.cancel()\n                    semaphore.signal()\n                }\n                semaphore.wait()\n            }\n            override func procedureDidCancel(with: Error?) {\n                didCancel.overwrite(with: true)\n            }\n        }\n\n        let special = TestFinishCancelAsyncFromExecuteProcedure()\n\n        wait(for: special)\n\n        PKAssertProcedureFinished(special)\n        XCTAssertFalse(special.didCancel.access)\n        XCTAssertFalse(special.isCancelled)\n    }\n\n    func test__cancel_from_didcancel_observer_is_ignored() {\n\n        enum ShouldNotHappen: Error {\n            case cancelledFromWithinDidCancel\n        }\n\n        procedure.addDidCancelBlockObserver { procedure, error in\n            procedure.cancel(with: ShouldNotHappen.cancelledFromWithinDidCancel)\n        }\n\n        procedure.cancel()\n        wait(for: procedure)\n        PKAssertProcedureCancelled(procedure)\n    }\n\n    func test__cancel_from_willfinish_observer_is_ignored() {\n\n        enum ShouldNotHappen: Error {\n            case cancelledFromWithinWillFinish\n        }\n        \n        procedure.addWillFinishBlockObserver { procedure, error, _ in\n            procedure.cancel(with: ShouldNotHappen.cancelledFromWithinWillFinish)\n        }\n\n        wait(for: procedure)\n        PKAssertProcedureFinished(procedure)\n    }\n}\n"
  },
  {
    "path": "Tests/ProcedureKitTests/CapabilityTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport TestingProcedureKit\n@testable import ProcedureKit\n\nclass GetAuthorizationStatusTests: TestableCapabilityTestCase {\n\n    func test__sets_result() {\n        wait(for: getAuthorizationStatus)\n        XCTAssertGetAuthorizationStatus(getAuthorizationStatus.output.success, expected: (true, .unknown))\n        XCTAssertTestCapabilityStatusChecked()\n    }\n\n    func test__async_sets_result() {\n        capability.isAsynchronous = true\n        wait(for: getAuthorizationStatus)\n        XCTAssertGetAuthorizationStatus(getAuthorizationStatus.output.success, expected: (true, .unknown))\n        XCTAssertTestCapabilityStatusChecked()\n    }\n\n    func test__runs_completion_block() {\n        var completedWithResult: GetAuthorizationStatusProcedure<TestableCapability.Status>.Output = (false, .unknown)\n        getAuthorizationStatus = GetAuthorizationStatusProcedure(capability) { completedWithResult = $0 }\n\n        wait(for: getAuthorizationStatus)\n        XCTAssertGetAuthorizationStatus(completedWithResult, expected: (true, .unknown))\n        XCTAssertTestCapabilityStatusChecked()\n    }\n\n    func test__async_runs_completion_block() {\n        capability.isAsynchronous = true\n        var completedWithResult: GetAuthorizationStatusProcedure<TestableCapability.Status>.Output = (false, .unknown)\n\n        getAuthorizationStatus = GetAuthorizationStatusProcedure(capability) { result in\n            completedWithResult = result\n        }\n\n        wait(for: getAuthorizationStatus)\n        XCTAssertGetAuthorizationStatus(completedWithResult, expected: (true, .unknown))\n        XCTAssertTestCapabilityStatusChecked()\n    }\n\n    func test__void_status_equal() {\n        XCTAssertEqual(Capability.VoidStatus(), Capability.VoidStatus())\n    }\n\n    func test__void_status_meets_requirements() {\n        XCTAssertTrue(Capability.VoidStatus().meets(requirement: ()))\n    }\n}\n\nclass AuthorizeTests: TestableCapabilityTestCase {\n\n    func test__authorize() {\n        wait(for: authorize)\n        XCTAssertTrue(capability.didRequestAuthorization)\n    }\n\n    func test__authorize_procedure_is_mutually_exclusive() {\n        // AuthorizeCapabilityProcedure should have a condition that is:\n        //  MutuallyExclusive<AuthorizeCapabilityProcedure<TestableCapability.Status>>\n        // with a mutually exclusive category of: \n        //  \"AuthorizeCapabilityProcedure(TestableCapability)\"\n\n        var foundMutuallyExclusiveCondition = false\n        for condition in authorize.conditions {\n            guard condition.isMutuallyExclusive else { continue }\n            guard condition is MutuallyExclusive<AuthorizeCapabilityProcedure<TestableCapability.Status>> else { continue }\n            guard condition.mutuallyExclusiveCategories == [\"AuthorizeCapabilityProcedure(TestableCapability)\"] else { continue }\n            foundMutuallyExclusiveCondition = true\n            break\n        }\n\n        XCTAssertTrue(foundMutuallyExclusiveCondition, \"Failed to find appropriate Mutual Exclusivity condition\")\n    }\n}\n\nclass AuthorizedForTests: TestableCapabilityTestCase {\n\n    func test__is_not_mututally_exclusive_by_default() {\n        // the AuthorizedFor condition itself does not confer mutual exclusivity by default\n        XCTAssertFalse(authorizedFor.isMutuallyExclusive)\n    }\n\n    func test__default_mututally_exclusive_category() {\n        XCTAssertTrue(authorizedFor.mutuallyExclusiveCategories.isEmpty)\n    }\n\n    func test__custom_mututally_exclusive_category() {\n        authorizedFor = AuthorizedFor(capability, category: \"testing\")\n        XCTAssertEqual(authorizedFor.mutuallyExclusiveCategories, [\"testing\"])\n    }\n\n    func test__has_authorize_dependency() {\n        guard let dependency = authorizedFor.producedDependencies.first else {\n            XCTFail(\"Condition did not return a dependency\")\n            return\n        }\n\n        guard let _ = dependency as? AuthorizeCapabilityProcedure<TestableCapability.Status> else {\n            XCTFail(\"Dependency is not the correct type\")\n            return\n        }\n    }\n\n    func test__fails_if_capability_is_not_available() {\n        capability.serviceIsAvailable = false\n        wait(for: procedure)\n        PKAssertConditionFailed(authorizedFor.output.value ?? .success(true), failedWithError: ProcedureKitError.capabilityUnavailable())\n        PKAssertProcedureCancelledWithError(procedure, ProcedureKitError.capabilityUnavailable())\n    }\n\n    func test__async_fails_if_capability_is_not_available() {\n        capability.isAsynchronous = true\n        capability.serviceIsAvailable = false\n        wait(for: procedure)\n        PKAssertConditionFailed(authorizedFor.output.value ?? .success(true), failedWithError: ProcedureKitError.capabilityUnavailable())\n        PKAssertProcedureCancelledWithError(procedure, ProcedureKitError.capabilityUnavailable())\n    }\n\n    func test__fails_if_requirement_is_not_met() {\n        capability.requirement = .maximum\n        capability.responseAuthorizationStatus = .minimumAuthorized\n        wait(for: procedure)\n        PKAssertConditionFailed(authorizedFor.output.value ?? .success(true), failedWithError: ProcedureKitError.capabilityUnauthorized())\n        PKAssertProcedureCancelledWithError(procedure, ProcedureKitError.capabilityUnauthorized())\n    }\n\n    func test__async_fails_if_requirement_is_not_met() {\n        capability.isAsynchronous = true\n        capability.requirement = .maximum\n        capability.responseAuthorizationStatus = .minimumAuthorized\n\n        wait(for: procedure)\n        PKAssertConditionFailed(authorizedFor.output.value ?? .success(true), failedWithError: ProcedureKitError.capabilityUnauthorized())\n        PKAssertProcedureCancelledWithError(procedure, ProcedureKitError.capabilityUnauthorized())\n    }\n\n    func test__suceeds_if_requirement_is_met() {\n        wait(for: procedure)\n        PKAssertProcedureFinished(procedure)\n        PKAssertConditionSatisfied(authorizedFor.output.value ?? .success(false))\n    }\n\n    func test__async_suceeds_if_requirement_is_met() {\n        capability.isAsynchronous = true\n        wait(for: procedure)\n        PKAssertProcedureFinished(procedure)\n        PKAssertConditionSatisfied(authorizedFor.output.value ?? .success(false))\n    }\n\n    func test__negated_authorized_for_and_no_failed_dependencies_succeeds() {\n        // See: Issue #515\n        // https://github.com/ProcedureKit/ProcedureKit/issues/515\n        //\n        // This test previously failed because dependencies of Conditions\n        // were incorporated into the dependencies of the parent Procedure\n        // and, thus, the NoFailedDependenciesCondition picked up the\n        // failing dependencies of the NegatedCondition.\n        //\n\n        // set the TestableCapability so it fails to meet the requirement\n        capability.requirement = .maximum\n        capability.responseAuthorizationStatus = .minimumAuthorized\n\n        let procedure = TestProcedure()\n        let authorizedCondition = AuthorizedFor(capability)\n\n        procedure.addCondition(NegatedCondition(authorizedCondition))\n        procedure.addCondition(NoFailedDependenciesCondition())\n\n        wait(for: procedure)\n        PKAssertProcedureFinished(procedure)\n    }\n}\n\n"
  },
  {
    "path": "Tests/ProcedureKitTests/ComposedProcedureTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport TestingProcedureKit\n@testable import ProcedureKit\n\npublic class ComposedProcedureTests: ProcedureKitTestCase {\n\n    func test__composed_procedure_is_cancelled() {\n        let didCancelCalled = DispatchSemaphore(value: 0)\n        procedure.addDidCancelBlockObserver { _, _ in\n            didCancelCalled.signal()\n        }\n        let composed = ComposedProcedure(procedure)\n        composed.cancel()\n        XCTAssertTrue(composed.isCancelled)\n\n        XCTAssertEqual(didCancelCalled.wait(timeout: .now() + 1.0), DispatchTimeoutResult.success)\n\n        XCTAssertTrue(composed.operation.isCancelled)\n        XCTAssertTrue(procedure.isCancelled)\n    }\n\n    func test__composed_operation_is_executed() {\n        var didExecute = false\n        let composed = ComposedProcedure(BlockOperation { didExecute = true })\n        wait(for: composed)\n        PKAssertProcedureFinished(composed)\n        XCTAssertTrue(didExecute)\n    }\n\n    func test__composed_procedure_is_executed() {\n        let composed = ComposedProcedure(procedure)\n        wait(for: composed)\n        PKAssertProcedureFinished(procedure)\n    }\n}\n\npublic class GatedProcedureTests: ProcedureKitTestCase {\n\n    func test__when_gate_is_closed_procedure_is_cancelled() {\n        let gated = GatedProcedure(procedure) { false }\n        wait(for: gated)\n        PKAssertProcedureCancelled(gated)\n    }\n\n    func test__when_gate_is_open_procedure_is_performed() {\n        let gated = GatedProcedure(procedure) { true }\n        wait(for: gated)\n        PKAssertProcedureFinished(gated)\n        PKAssertProcedureFinished(procedure)\n    }\n}\n\n"
  },
  {
    "path": "Tests/ProcedureKitTests/ConditionTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\n@testable import TestingProcedureKit\n@testable import ProcedureKit\n\nclass ConditionTests: ProcedureKitTestCase {\n\n    // MARK: - Condition Properties\n\n    func test__condition__produce_dependency() {\n        let condition = TrueCondition()\n        let dependency = TestProcedure()\n        condition.produceDependency(dependency)\n        XCTAssertEqual(condition.producedDependencies.count, 1)\n        XCTAssertEqual(condition.producedDependencies.first, dependency)\n        XCTAssertEqual(condition.dependencies.count, 0)\n    }\n\n    func test__condition__add_dependency() {\n        let condition = TrueCondition()\n        let dependency = TestProcedure()\n        condition.addDependency(dependency)\n        XCTAssertEqual(condition.dependencies.count, 1)\n        XCTAssertEqual(condition.dependencies.first, dependency)\n        XCTAssertEqual(condition.producedDependencies.count, 0)\n    }\n\n    func test__condition__remove_dependency() {\n        let condition = TrueCondition()\n        let dependency = TestProcedure()\n        let producedDependency = TestProcedure()\n        condition.addDependency(dependency)\n        condition.produceDependency(producedDependency)\n        XCTAssertEqual(condition.dependencies.count, 1)\n        XCTAssertEqual(condition.dependencies.first, dependency)\n        XCTAssertEqual(condition.producedDependencies.count, 1)\n        XCTAssertEqual(condition.producedDependencies.first, producedDependency)\n\n        condition.removeDependency(producedDependency)\n        XCTAssertEqual(condition.producedDependencies.count, 0, \"Produced dependency not removed.\")\n\n        condition.removeDependency(dependency)\n        XCTAssertEqual(condition.producedDependencies.count, 0, \"Dependency not removed.\")\n    }\n\n    func test__condition__name() {\n        let condition = TrueCondition()\n        let testName = \"Test Name\"\n        condition.name = testName\n        XCTAssertEqual(condition.name, testName)\n    }\n\n    func test__condition__mutually_exclusive_categories() {\n        let condition = TrueCondition()\n        XCTAssertTrue(condition.mutuallyExclusiveCategories.isEmpty)\n        let category1 = \"Test Category\"\n        let category2 = \"Test Category B\"\n\n        condition.addToAttachedProcedure(mutuallyExclusiveCategory: category1)\n        XCTAssertEqual(condition.mutuallyExclusiveCategories, Set([category1]))\n\n        condition.addToAttachedProcedure(mutuallyExclusiveCategory: category2)\n        XCTAssertEqual(condition.mutuallyExclusiveCategories, Set([category1, category2]))\n    }\n\n    func test__condition__equality() {\n        let condition1 = TrueCondition()\n        let condition1alias = condition1\n        let condition2 = TrueCondition()\n\n        XCTAssertEqual(condition1, condition1)\n        XCTAssertEqual(condition1, condition1alias)\n        XCTAssertNotEqual(condition1, condition2)\n        XCTAssertNotEqual(condition1alias, condition2)\n    }\n\n    // MARK: - Condition Unit Tests\n\n    func test__true_condition_is_satisfied() {\n        let condition = TrueCondition()\n        condition.evaluate(procedure: procedure) { result in\n            guard case .success(true) = result else {\n                XCTFail(\"TrueCondition did not evaluate as satisfied.\"); return\n            }\n        }\n    }\n\n    func test__false_condition_is_failed() {\n        let condition = FalseCondition()\n        condition.evaluate(procedure: procedure) { result in\n            guard case let .failure(error) = result else {\n                XCTFail(\"FalseCondition did not evaluate as failed.\"); return\n            }\n            XCTAssertTrue(error is ProcedureKitError.FalseCondition)\n        }\n    }\n\n    // MARK: - Single Attachment\n\n    func test__single_condition_which_is_satisfied() {\n        procedure.addCondition(TrueCondition())\n        wait(for: procedure)\n        PKAssertProcedureFinished(procedure)\n    }\n\n    func test__single_condition_which_is_failed() {\n        procedure.addCondition(FalseCondition())\n        wait(for: procedure)\n        PKAssertProcedureCancelledWithError(procedure, ProcedureKitError.FalseCondition())\n    }\n\n    // MARK: - Multiple Attachment\n\n    func test__multiple_conditions_where_all_are_satisfied() {\n        procedure.addCondition(TrueCondition())\n        procedure.addCondition(TrueCondition())\n        procedure.addCondition(TrueCondition())\n        wait(for: procedure)\n        PKAssertProcedureFinished(procedure)\n    }\n\n    func test__multiple_conditions_where_all_fail() {\n        procedure.addCondition(FalseCondition())\n        procedure.addCondition(FalseCondition())\n        procedure.addCondition(FalseCondition())\n        wait(for: procedure)\n        PKAssertProcedureCancelledWithError(procedure, ProcedureKitError.FalseCondition())\n    }\n\n    func test__multiple_conditions_where_one_succeeds() {\n        procedure.addCondition(TrueCondition())\n        procedure.addCondition(FalseCondition())\n        procedure.addCondition(FalseCondition())\n        wait(for: procedure)\n        PKAssertProcedureCancelledWithError(procedure, ProcedureKitError.FalseCondition())\n    }\n\n    func test__multiple_conditions_where_one_fails() {\n        procedure.addCondition(TrueCondition())\n        procedure.addCondition(TrueCondition())\n        procedure.addCondition(FalseCondition())\n        wait(for: procedure)\n        PKAssertProcedureCancelledWithError(procedure, ProcedureKitError.FalseCondition())\n    }\n\n    // MARK: - Shortcut Processing\n\n    func test__long_running_condition_with_dependency_is_cancelled_if_a_result_is_determined_by_another_condition() {\n        // Two conditions:\n        //  - One that is dependent on a long-running produced operation\n        //  - And a second that immediately returns false\n        //\n        // The Procedure should fail with the immediate failure of the second\n        // Condition, and not wait for the first Condition (and its\n        // long-running produced dependency) to also complete.\n        //\n        // Additionally, the long-running dependency should be cancelled\n        // once the overall condition evaluation result is known.\n\n        let longRunningCondition = TestCondition() {\n            return .success(true)\n        }\n        let didStartLongRunningDependencyGroup = DispatchGroup()\n        didStartLongRunningDependencyGroup.enter()\n        let longRunningDependency = BlockProcedure { this in\n            didStartLongRunningDependencyGroup.leave()\n            // never finishes by itself\n        }\n        longRunningDependency.addDidCancelBlockObserver { _, _ in\n            // finishes when cancelled\n            longRunningDependency.finish()\n        }\n        let dispatchGroup = DispatchGroup()\n        dispatchGroup.enter()\n        longRunningDependency.addDidFinishBlockObserver { _, _ in\n            dispatchGroup.leave()\n        }\n        longRunningCondition.produceDependency(longRunningDependency)\n\n        let failSecondCondition = AsyncTestCondition { completion in\n            // To ensure order of operations, finish this condition async once the\n            // longRunningCondition's long-running dependency has started.\n            //\n            // Otherwise, there is no guarantee that the `longRunningCondition` will\n            // be processed (and produce its dependencies) prior to being shortcut\n            // by the result of this condition.\n            didStartLongRunningDependencyGroup.notify(queue: DispatchQueue.global()) {\n                completion(.failure(ProcedureKitError.FalseCondition()))\n            }\n        }\n\n        procedure.addCondition(longRunningCondition)\n        procedure.addCondition(failSecondCondition)\n\n        wait(for: procedure, withTimeout: 2)\n\n        // ensure that the longRunningDependency is fairly quickly cancelled and finished\n        guard longRunningDependency.isEnqueued else {\n            XCTFail(\"The long-running dependency was not enqueued. This is unexpected, since the evaluation order should be guaranteed by the test.\")\n            return\n        }\n        // wait for the long-running dependency to be cancelled and finish\n        weak var expLongRunningProducedDependencyCancelled = expectation(description: \"did cancel and finish long-running produced dependency\")\n        dispatchGroup.notify(queue: DispatchQueue.main) {\n            expLongRunningProducedDependencyCancelled?.fulfill()\n        }\n        waitForExpectations(timeout: 2)\n        PKAssertProcedureCancelled(longRunningDependency)\n    }\n\n    // MARK: - Condition Dependency Requirement\n\n    func test__condition_dependency_requirement_none_still_evaluates_when_dependency_fails() {\n        XCTAssertEqual(Condition.DependencyRequirements.none, [])\n\n        let failingDependency = TestProcedure(error: TestError())\n        conditionDependencyRequirementTest(\n            requirements: .none,\n            conditionProducedDependency: failingDependency) { result in\n                XCTAssertTrue(result.didEvaluateCondition, \"Condition was not evaluated.\")\n                PKAssertProcedureFinished(result.procedure)\n        }\n    }\n\n    func test__condition_dependency_requirement_noFailed_skips_evaluate_when_dependency_fails() {\n        let failingDependency = TestProcedure(error: TestError())\n        conditionDependencyRequirementTest(\n            requirements: .noFailed,\n            conditionProducedDependency: failingDependency) { result in\n                XCTAssertFalse(result.didEvaluateCondition, \"Condition evaluate was called, despite dependency requirement and failed dependency.\")\n                PKAssertProcedureCancelledWithError(result.procedure, ProcedureKitError.ConditionDependenciesFailed(condition: result.condition))\n        }\n    }\n\n    func test__condition_dependency_requirement_noFailed_ignores_dependency_cancelled_without_errors() {\n        let cancelledDependency = TestProcedure()\n        cancelledDependency.cancel()\n        conditionDependencyRequirementTest(\n            requirements: .noFailed,\n            conditionProducedDependency: cancelledDependency) { result in\n                XCTAssertTrue(result.didEvaluateCondition)\n                PKAssertProcedureFinished(result.procedure)\n        }\n    }\n\n    func test__condition_dependency_requirement_noFailed_skips_evaluate_when_dependency_iscancelled_with_errors() {\n        let cancelledDependency = TestProcedure()\n        cancelledDependency.cancel(with: TestError())\n        conditionDependencyRequirementTest(\n            requirements: .noFailed,\n            conditionProducedDependency: cancelledDependency) { result in\n                XCTAssertFalse(result.didEvaluateCondition)\n                PKAssertProcedureCancelledWithError(result.procedure, ProcedureKitError.ConditionDependenciesFailed(condition: result.condition))\n        }\n    }\n\n    func test__condition_dependency_requirement_noCancelled_skips_evaluate_when_dependency_is_cancelled() {\n        let cancelledDependency = TestProcedure(error: TestError())\n        cancelledDependency.cancel()\n        conditionDependencyRequirementTest(\n            requirements: .noCancelled,\n            conditionProducedDependency: cancelledDependency) { result in\n                XCTAssertFalse(result.didEvaluateCondition, \"Condition evaluate was called, despite dependency requirement and cancelled dependency.\")\n                PKAssertProcedureCancelledWithError(result.procedure, ProcedureKitError.ConditionDependenciesCancelled(condition: result.condition))\n        }\n    }\n\n    func test__condition_dependency_requirement_noCancelled_ignores_non_cancelled_failures() {\n        let failedDependency = TestProcedure(error: TestError()) // failed, not cancelled\n        conditionDependencyRequirementTest(\n            requirements: .noCancelled,\n            conditionProducedDependency: failedDependency) { result in\n                XCTAssertTrue(result.didEvaluateCondition)\n                PKAssertProcedureFinished(result.procedure)\n        }\n    }\n\n    func test__condition_dependency_requirement_noFailed_with_ignoreCancellations() {\n        // cancelled failing dependency should be ignored - and evaluate should be called\n        let cancelledDependency = TestProcedure()\n        cancelledDependency.cancel(with: TestError())\n        conditionDependencyRequirementTest(\n            requirements: [.noFailed, .ignoreFailedIfCancelled],\n            conditionProducedDependency: cancelledDependency) { result in\n                XCTAssertTrue(result.didEvaluateCondition)\n                PKAssertProcedureFinished(result.procedure)\n        }\n\n        // whereas a non-cancelled failing dependency should still cause an immediate failure\n        let failingDependency = TestProcedure(error: TestError())\n        conditionDependencyRequirementTest(\n            requirements: [.noFailed, .ignoreFailedIfCancelled],\n            conditionProducedDependency: failingDependency) { result in\n                XCTAssertFalse(result.didEvaluateCondition)\n                PKAssertProcedureCancelledWithError(result.procedure, ProcedureKitError.ConditionDependenciesFailed(condition: result.condition))\n        }\n    }\n\n    private struct ConditionDependencyRequirementTestResult {\n        let procedure: Procedure\n        let didEvaluateCondition: Bool\n        let condition: Condition\n    }\n\n    private func conditionDependencyRequirementTest(\n        requirements: Condition.DependencyRequirements,\n        conditionProducedDependency dependency: Procedure,\n        withAdditionalConditions additionalConditions: [Condition] = [],\n        completion: (ConditionDependencyRequirementTestResult) -> Void) {\n        conditionDependencyRequirementTest(requirements: requirements,\n                                           conditionProducedDependencies: [dependency],\n                                           withAdditionalConditions: additionalConditions,\n                                           completion: completion)\n    }\n\n    private func conditionDependencyRequirementTest(\n        requirements: Condition.DependencyRequirements,\n        conditionProducedDependencies dependencies: [Procedure],\n        withAdditionalConditions additionalConditions: [Condition] = [],\n        completion: (ConditionDependencyRequirementTestResult) -> Void)\n    {\n        let procedure = TestProcedure()\n\n        let didEvaluateConditionGroup = DispatchGroup()\n        didEvaluateConditionGroup.enter()\n        let condition = TestCondition {\n            didEvaluateConditionGroup.leave()\n            return .success(true)\n        }\n        dependencies.forEach(condition.produceDependency)\n        condition.dependencyRequirements = requirements\n\n        procedure.addCondition(condition)\n        additionalConditions.forEach(procedure.addCondition)\n        wait(for: procedure)\n\n        let didEvaluateCondition = didEvaluateConditionGroup.wait(timeout: .now()) == .success\n\n        // clean-up\n        if !didEvaluateCondition {\n            didEvaluateConditionGroup.leave()\n        }\n\n        completion(ConditionDependencyRequirementTestResult(procedure: procedure, didEvaluateCondition: didEvaluateCondition, condition: condition))\n    }\n\n    // MARK: - Conditions with Dependencies\n\n    func test__dependencies_execute_before_condition_dependencies() {\n\n        let dependency1 = TestProcedure(name: \"Dependency 1\")\n        let dependency2 = TestProcedure(name: \"Dependency 2\")\n        procedure.addDependencies(dependency1, dependency2)\n\n        let conditionDependency1 = BlockOperation {\n            XCTAssertTrue(dependency1.isFinished)\n            XCTAssertTrue(dependency2.isFinished)\n        }\n        conditionDependency1.name = \"Condition 1 Dependency\"\n\n        let condition1 = TrueCondition(name: \"Condition 1\")\n        condition1.produceDependency(conditionDependency1)\n\n\n        let conditionDependency2 = BlockOperation {\n            XCTAssertTrue(dependency1.isFinished)\n            XCTAssertTrue(dependency2.isFinished)\n        }\n        conditionDependency2.name = \"Condition 2 Dependency\"\n\n        let condition2 = TrueCondition(name: \"Condition 2\")\n        condition2.produceDependency(conditionDependency2)\n\n        procedure.addCondition(condition1)\n        procedure.addCondition(condition2)\n\n        run(operations: dependency1, dependency2)\n        wait(for: procedure)\n\n        PKAssertProcedureFinished(dependency1)\n        PKAssertProcedureFinished(dependency2)\n        PKAssertProcedureFinished(procedure)\n    }\n\n    func test__procedure_dependencies_only_contain_direct_dependencies() {\n\n        let dependency1 = TestProcedure()\n        let dependency2 = TestProcedure()\n        let condition1 = TrueCondition(name: \"Condition 1\")\n        condition1.produceDependency(TestProcedure())\n        let condition2 = TrueCondition(name: \"Condition 2\")\n        condition2.produceDependency(TestProcedure())\n\n        procedure.addDependency(dependency1)\n        procedure.addDependency(dependency2)\n        procedure.addCondition(condition1)\n        procedure.addCondition(condition2)\n\n        run(operations: dependency1, dependency2)\n        wait(for: procedure)\n\n        XCTAssertEqual(procedure.dependencies.count, 2)\n    }\n\n    func test__target_and_condition_have_same_dependency() {\n        let dependency = TestProcedure()\n        let condition = TrueCondition(name: \"Condition\")\n        condition.addDependency(dependency)\n\n        procedure.addCondition(condition)\n        procedure.addDependency(dependency)\n\n        wait(for: dependency, procedure)\n\n        PKAssertProcedureFinished(dependency)\n        PKAssertProcedureFinished(procedure)\n    }\n\n    func test__procedure_is_direct_dependency_and_indirect_of_different_procedures() {\n        // See OPR-386\n        let dependency = TestProcedure(name: \"Dependency\")\n\n        let condition1 = TrueCondition(name: \"Condition 1\")\n        condition1.addDependency(dependency)\n\n        let procedure1 = TestProcedure(name: \"Procedure 1\")\n        procedure1.addCondition(condition1)\n        procedure1.addDependency(dependency)\n\n        let condition2 = TrueCondition(name: \"Condition 2\")\n        condition2.addDependency(dependency)\n\n        let procedure2 = TestProcedure(name: \"Procedure 2\")\n        procedure2.addCondition(condition2)\n        procedure2.addDependency(procedure1)\n\n        wait(for: procedure1, dependency, procedure2)\n\n        PKAssertProcedureFinished(dependency)\n        PKAssertProcedureFinished(procedure1)\n        PKAssertProcedureFinished(procedure2)\n    }\n\n    func test__dependency_added_by_queue_delegate_will_add_also_affects_evaluating_conditions() {\n        // A dependency that is added in a ProcedureQueue delegate's willAddProcedure method\n        // should also properly delay the evaluation of Conditions.\n\n        class CustomQueueDelegate: ProcedureQueueDelegate {\n            typealias DidAddProcedureBlock = (Procedure) -> Void\n            private let dependenciesToAddInWillAdd: [Operation]\n            private let didAddProcedureBlock: DidAddProcedureBlock\n            init(dependenciesToAddInWillAdd: [Operation], didAddProcedureBlock: @escaping DidAddProcedureBlock) {\n                self.dependenciesToAddInWillAdd = dependenciesToAddInWillAdd\n                self.didAddProcedureBlock = didAddProcedureBlock\n            }\n            func procedureQueue(_ queue: ProcedureQueue, willAddProcedure procedure: Procedure, context: Any?) -> ProcedureFuture? {\n                let promise = ProcedurePromise()\n                DispatchQueue.global().asyncAfter(deadline: .now() + 0.2) { [dependenciesToAddInWillAdd] in\n                    defer { promise.complete() }\n                    guard !dependenciesToAddInWillAdd.contains(procedure) else { return }\n                    procedure.addDependencies(dependenciesToAddInWillAdd)\n                }\n                return promise.future\n            }\n            func procedureQueue(_ queue: ProcedureQueue, didAddProcedure procedure: Procedure, context: Any?) {\n                didAddProcedureBlock(procedure)\n            }\n        }\n\n        let procedureDidFinishGroup = DispatchGroup()\n        let conditionEvaluatedGroup = DispatchGroup()\n        weak var expDependencyDidStart = expectation(description: \"Did Start Dependency\")\n        let dependency = BlockProcedure { this in\n            DispatchQueue.main.async {\n                expDependencyDidStart?.fulfill()\n            }\n            // does not finish - the test handles that later for timing reasons\n        }\n        let procedure = TestProcedure()\n        procedureDidFinishGroup.enter()\n        procedure.addDidFinishBlockObserver { _, _ in\n            procedureDidFinishGroup.leave()\n        }\n        conditionEvaluatedGroup.enter()\n        procedure.addCondition(TestCondition(evaluate: {\n            // signal when evaluated\n            conditionEvaluatedGroup.leave()\n            return .success(true)\n        }))\n\n        weak var expDidAddProcedure = expectation(description: \"Did Add Procedure to queue\")\n        let customDelegate = CustomQueueDelegate(dependenciesToAddInWillAdd: [dependency]) { addedProcedure in\n            // did add Procedure to queue\n            guard addedProcedure === procedure else { return }\n            DispatchQueue.main.async {\n                expDidAddProcedure?.fulfill()\n            }\n        }\n        queue.delegate = customDelegate\n        queue.addOperations(procedure, dependency)\n\n        // wait until the procedure has been added to the queue\n        // and the dependency has been started\n        waitForExpectations(timeout: 2)\n\n        // sleep for 0.05 seconds to give a chance for the Condition to be improperly evaluated\n        usleep(50000)\n\n        // verify that the procedure *and the Condition* are not ready to execute,\n        // nor executing, nor finished\n        // (they should both be waiting on the dependency added in the ProcedureQueue\n        // delegate's willAddProcedure handler, which won't finish until it's triggered)\n\n        XCTAssertProcedureIsWaiting(procedure, withDependency: dependency)\n        XCTAssertEqual(conditionEvaluatedGroup.wait(timeout: .now()), .timedOut, \"The Condition has already evaluated, and did not wait on the dependency.\")\n\n        // finish the dependency\n        dependency.finish()\n\n        // wait for the procedure to finish\n        weak var expProcedureDidFinish = expectation(description: \"test procedure Did Finish\")\n        procedureDidFinishGroup.notify(queue: DispatchQueue.main) {\n            expProcedureDidFinish?.fulfill()\n        }\n        waitForExpectations(timeout: 1)\n\n        XCTAssertEqual(conditionEvaluatedGroup.wait(timeout: .now()), .success, \"The Condition was never evaluated.\")\n    }\n\n    func test__dependency_added_before_another_dependency_finishes_also_affects_conditions() {\n        // A dependency that is added in (for example) an existing dependency's willFinish\n        // observer should also properly delay the evaluation of Conditions.\n\n        let procedure = TestProcedure()\n        let procedureDidFinishGroup = DispatchGroup()\n        let conditionEvaluatedGroup = DispatchGroup()\n\n        weak var expDependencyDidStart = expectation(description: \"Did Start additionalDependency\")\n        let dependency = TestProcedure()\n        let additionalDependency = BlockProcedure { this in\n            DispatchQueue.main.async {\n                expDependencyDidStart?.fulfill()\n            }\n            // does not finish\n        }\n        dependency.addWillFinishBlockObserver { _, _, _ in\n            // add another dependency, before the first dependency finishes\n            procedure.addDependency(additionalDependency)\n        }\n\n        weak var expDependencyDidFinish = expectation(description: \"First dependency did finish\")\n        dependency.addDidFinishBlockObserver { _, _ in\n            DispatchQueue.main.async {\n                expDependencyDidFinish?.fulfill()\n            }\n        }\n\n        procedureDidFinishGroup.enter()\n        procedure.addDidFinishBlockObserver { _, _ in\n            procedureDidFinishGroup.leave()\n        }\n        conditionEvaluatedGroup.enter()\n        procedure.addCondition(TestCondition(evaluate: {\n            // signal when evaluated\n            conditionEvaluatedGroup.leave()\n            return .success(true)\n        }))\n        procedure.addDependency(dependency)\n\n        queue.addOperations(procedure, dependency, additionalDependency)\n\n        // wait until the first dependency has finished,\n        // and the additionalDependency has started\n        waitForExpectations(timeout: 2)\n\n        // sleep for 0.05 seconds to give a chance for the Condition to be improperly evaluated\n        usleep(50000)\n\n        // verify that the procedure *and the Condition* are not ready to execute,\n        // nor executing, nor finished\n        // (they should both be waiting on the dependency added in the ProcedureQueue\n        // delegate's willAddProcedure handler, which won't finish until it's triggered)\n\n        XCTAssertProcedureIsWaiting(procedure, withDependency: dependency)\n        XCTAssertEqual(conditionEvaluatedGroup.wait(timeout: .now()), .timedOut, \"The Condition has already evaluated, and did not wait on the dependency.\")\n\n        // finish the additional dependency\n        additionalDependency.finish()\n\n        // wait for the procedure to finish\n        weak var expProcedureDidFinish = expectation(description: \"test procedure Did Finish\")\n        procedureDidFinishGroup.notify(queue: DispatchQueue.main) {\n            expProcedureDidFinish?.fulfill()\n        }\n        waitForExpectations(timeout: 1)\n\n        XCTAssertEqual(conditionEvaluatedGroup.wait(timeout: .now()), .success, \"The Condition was never evaluated.\")\n    }\n\n    // Verifies that a Procedure (and its condition evaluator) have a dependency and are waiting\n    private func XCTAssertProcedureIsWaiting<T: Procedure>(_ exp: @autoclosure () throws -> T, withDependency dependency: Operation, _ message: @autoclosure () -> String = \"\", file: StaticString = #file, line: UInt = #line) {\n        __XCTEvaluateAssertion(testCase: self, message(), file: file, line: line) {\n            let procedure = try exp()\n\n            guard procedure.isEnqueued else {\n                return .expectedFailure(\"\\(procedure.procedureName) has not been added to a queue yet.\")\n            }\n            guard procedure.dependencies.contains(dependency) else {\n                return .expectedFailure(\"\\(procedure.procedureName) does not have dependency: \\(dependency)\")\n            }\n            guard !procedure.isReady else {\n                return .expectedFailure(\"\\(procedure.procedureName) is ready\")\n            }\n            guard !procedure.isExecuting else {\n                return .expectedFailure(\"\\(procedure.procedureName) is executing\")\n            }\n            guard !procedure.isFinished else {\n                return .expectedFailure(\"\\(procedure.procedureName) is finished\")\n            }\n            if !procedure.conditions.isEmpty {\n                guard let conditionEvaluator = procedure.evaluateConditionsProcedure else {\n                    return .expectedFailure(\"Unable to obtain condition evaluator from the Procedure.\")\n                }\n                guard conditionEvaluator.dependencies.contains(dependency) else {\n                    return .expectedFailure(\"\\(procedure.procedureName)'s condition evaluator does not have dependency: \\(dependency)\")\n                }\n                guard !conditionEvaluator.isReady else {\n                    return .expectedFailure(\"\\(procedure.procedureName)'s condition evaluator is ready\")\n                }\n                guard !conditionEvaluator.isExecuting else {\n                    return .expectedFailure(\"\\(procedure.procedureName)'s condition evaluator is executing\")\n                }\n                guard !conditionEvaluator.isFinished else {\n                    return .expectedFailure(\"\\(procedure.procedureName)'s condition evaluator is finished\")\n                }\n            }\n\n            return .success\n        }\n    }\n\n    // MARK: - Ignored Conditions\n\n    func test__ignored_failing_condition_does_not_result_in_failure() {\n\n        let procedure1 = TestProcedure(name: \"Procedure 1\")\n        procedure1.addCondition(IgnoredCondition(FalseCondition()))\n\n        let procedure2 = TestProcedure(name: \"Procedure 2\")\n        procedure2.addCondition(FalseCondition())\n\n        wait(for: procedure1, procedure2)\n\n        PKAssertProcedureCancelled(procedure1)\n        PKAssertProcedureCancelledWithError(procedure2, ProcedureKitError.FalseCondition())\n    }\n\n    func test__ignored_satisfied_condition_does_not_result_in_failure() {\n        let procedure1 = TestProcedure(name: \"Procedure 1\")\n        procedure1.addCondition(IgnoredCondition(TrueCondition()))\n\n        let procedure2 = TestProcedure(name: \"Procedure 2\")\n        procedure2.addCondition(TrueCondition())\n\n        wait(for: procedure1, procedure2)\n\n        PKAssertProcedureFinished(procedure1)\n        PKAssertProcedureFinished(procedure2)\n    }\n\n    func test__ignored_ignored_condition_does_not_result_in_failure() {\n        procedure.addCondition(IgnoredCondition(IgnoredCondition(FalseCondition())))\n        wait(for: procedure)\n        PKAssertProcedureCancelled(procedure)\n    }\n\n    func test__ignored_failing_condition_plus_successful_condition_succeeds() {\n        // A Procedure with one or more ignored conditions and at least one\n        // successful condition should be allowed to proceed with execution.\n        let procedure1 = TestProcedure(name: \"Procedure 1\")\n        procedure1.addCondition(IgnoredCondition(FalseCondition()))\n        procedure1.addCondition(TrueCondition())\n\n        wait(for: procedure1)\n\n        PKAssertProcedureFinished(procedure1)\n    }\n    \n    // MARK: - Compound Conditions\n\n    func test__compound_condition_produced_dependencies() {\n        let conditions: [Condition] = (0..<3).map {\n            let condition = TrueCondition(name: \"Condition \\($0)\")\n            condition.produceDependency(TestProcedure())\n            return condition\n        }\n        let compoundCondition = CompoundCondition(andPredicateWith: conditions)\n        let nestedProducedDependencies = conditions.producedDependencies\n        XCTAssertEqual(nestedProducedDependencies.count, 3)\n        XCTAssertEqual(compoundCondition.producedDependencies.count, 0)\n\n        let producedDependency = TestProcedure()\n        compoundCondition.produceDependency(producedDependency)\n        XCTAssertTrue(Array(compoundCondition.producedDependencies) == [producedDependency])\n    }\n\n    func test__compound_condition_added_dependencies() {\n        let conditions: [Condition] = (0..<3).map {\n            let condition = TrueCondition(name: \"Condition \\($0)\")\n            condition.addDependency(TestProcedure())\n            return condition\n        }\n        let compoundCondition = CompoundCondition(andPredicateWith: conditions)\n        let nestedDependencies = conditions.dependencies\n        XCTAssertEqual(nestedDependencies.count, 3)\n        XCTAssertEqual(compoundCondition.dependencies.count, 0)\n\n        let dependency = TestProcedure()\n        compoundCondition.addDependency(dependency)\n        XCTAssertTrue(Array(compoundCondition.dependencies) == [dependency])\n    }\n\n    func test__compound_condition_mutually_exclusive_categories() {\n        // give all the conditions the same category\n        let conditions: [Condition] = (0..<3).map {\n            let condition = TrueCondition(name: \"Condition \\($0)\")\n            condition.addToAttachedProcedure(mutuallyExclusiveCategory: \"test\")\n            return condition\n        }\n        let compoundCondition = CompoundCondition(andPredicateWith: conditions)\n        XCTAssertEqual(compoundCondition.mutuallyExclusiveCategories, [\"test\"])\n\n        // give all the conditions different categories\n        let conditions2: [Condition] = (0..<3).map {\n            let condition = TrueCondition(name: \"Condition \\($0)\")\n            condition.addToAttachedProcedure(mutuallyExclusiveCategory: \"test\\($0)\")\n            return condition\n        }\n        let compoundCondition2 = CompoundCondition(andPredicateWith: conditions2)\n        XCTAssertEqual(compoundCondition2.mutuallyExclusiveCategories, [\"test0\", \"test1\", \"test2\"])\n    }\n\n    func test__compound_condition_and_predicate_filters_duplicates() {\n        let evaluationCount = Protector<Int>(0)\n        let condition1 = TestCondition() { evaluationCount.advance(by: 1); return .success(true) }\n        let compoundCondition = CompoundCondition(andPredicateWith: condition1, condition1, condition1)\n        procedure.addCondition(compoundCondition)\n        wait(for: procedure)\n        XCTAssertEqual(evaluationCount.access, 1)\n    }\n\n    func test__compound_condition_or_predicate_filters_duplicates() {\n        let evaluationCount = Protector<Int>(0)\n        let condition1 = TestCondition() { evaluationCount.advance(by: 1); return .success(false) }\n        let compoundCondition = CompoundCondition(orPredicateWith: condition1, condition1, condition1)\n        procedure.addCondition(compoundCondition)\n        wait(for: procedure)\n        XCTAssertEqual(evaluationCount.access, 1)\n    }\n\n    // MARK: - Compound Conditions - &&\n\n    func test__and_condition__with_no_conditions_cancels_without_errors() {\n        procedure.addCondition(AndCondition([]))\n        wait(for: procedure)\n        PKAssertProcedureCancelled(procedure)\n    }\n\n    func test__and_condition__with_single_successful_condition__succeeds() {\n        procedure.addCondition(AndCondition([TrueCondition()]))\n        wait(for: procedure)\n        PKAssertProcedureFinished(procedure)\n    }\n\n    func test__and_condition__with_single_failing_condition__fails() {\n        procedure.addCondition(AndCondition([FalseCondition()]))\n        wait(for: procedure)\n        PKAssertProcedureCancelledWithError(procedure, ProcedureKitError.FalseCondition())\n    }\n\n    func test__and_condition__with_single_ignored_condition__does_not_fail() {\n        procedure.addCondition(AndCondition([IgnoredCondition(FalseCondition())]))\n        wait(for: procedure)\n        PKAssertProcedureCancelled(procedure)\n    }\n\n    func test__and_condition__with_two_successful_conditions__succeeds() {\n        procedure.addCondition(AndCondition([TrueCondition(), TrueCondition()]))\n        wait(for: procedure)\n        PKAssertProcedureFinished(procedure)\n    }\n\n    func test__and_condition__with_successful_and_failing_conditions__fails() {\n        procedure.addCondition(AndCondition([TrueCondition(), FalseCondition()]))\n        wait(for: procedure)\n        PKAssertProcedureCancelledWithError(procedure, ProcedureKitError.FalseCondition())\n    }\n\n    func test__and_condition__with_failing_and_successful_conditions__fails() {\n        procedure.addCondition(AndCondition([FalseCondition(), TrueCondition()]))\n        wait(for: procedure)\n        PKAssertProcedureCancelledWithError(procedure, ProcedureKitError.FalseCondition())\n    }\n\n    func test__and_condition__with_successful_and_ignored_condition__does_not_fail() {\n        procedure.addCondition(AndCondition([IgnoredCondition(FalseCondition()), TrueCondition()]))\n        wait(for: procedure)\n        PKAssertProcedureFinished(procedure)\n    }\n\n    func test__and_condition__with_failing_and_ignored_condition__fails() {\n        procedure.addCondition(AndCondition([IgnoredCondition(FalseCondition()), FalseCondition()]))\n        wait(for: procedure)\n        PKAssertProcedureCancelledWithError(procedure, ProcedureKitError.FalseCondition())\n    }\n\n    func test__and_condition__with_two_ignored_conditions__does_not_fail() {\n        procedure.addCondition(AndCondition([IgnoredCondition(FalseCondition()), IgnoredCondition(FalseCondition())]))\n        wait(for: procedure)\n        PKAssertProcedureCancelled(procedure)\n    }\n\n    func test__nested_successful_and_conditions() {\n        procedure.addCondition(AndCondition([AndCondition([TrueCondition(), TrueCondition()]), AndCondition([TrueCondition(), TrueCondition()])]))\n        wait(for: procedure)\n        PKAssertProcedureFinished(procedure)\n    }\n\n    func test__nested_failing_and_conditions() {\n        procedure.addCondition(AndCondition([AndCondition([FalseCondition(), FalseCondition()]), AndCondition([FalseCondition(), FalseCondition()])]))\n        wait(for: procedure)\n        PKAssertProcedureCancelledWithError(procedure, ProcedureKitError.FalseCondition())\n    }\n\n    func test__ignored_and_condition_does_not_fail() {\n        procedure.addCondition(IgnoredCondition(AndCondition([TrueCondition(), FalseCondition()])))\n        wait(for: procedure)\n        PKAssertProcedureCancelled(procedure)\n    }\n\n    // MARK: - Compound Conditions - ||\n\n    func test__or_condition__with_no_conditions_cancels_without_errors() {\n        procedure.addCondition(OrCondition([]))\n        wait(for: procedure)\n        PKAssertProcedureCancelled(procedure)\n    }\n\n    func test__or_condition__with_single_successful_condition__succeeds() {\n        procedure.addCondition(OrCondition([TrueCondition()]))\n        wait(for: procedure)\n        PKAssertProcedureFinished(procedure)\n    }\n\n    func test__or_condition__with_single_failing_condition__fails() {\n        procedure.addCondition(OrCondition([FalseCondition()]))\n        wait(for: procedure)\n        PKAssertProcedureCancelledWithError(procedure, ProcedureKitError.FalseCondition())\n    }\n\n    func test__or_condition__with_single_ignored_condition__does_not_fail() {\n        procedure.addCondition(OrCondition([IgnoredCondition(FalseCondition())]))\n        wait(for: procedure)\n        PKAssertProcedureCancelled(procedure)\n    }\n\n    func test__or_condition__with_two_successful_conditions__succeeds() {\n        procedure.addCondition(OrCondition([TrueCondition(), TrueCondition()]))\n        wait(for: procedure)\n        PKAssertProcedureFinished(procedure)\n    }\n\n    func test__or_condition__with_successful_and_failing_conditions__succeeds() {\n        procedure.addCondition(OrCondition([TrueCondition(), FalseCondition()]))\n        wait(for: procedure)\n        PKAssertProcedureFinished(procedure)\n    }\n\n    func test__or_condition__with_failing_and_successful_conditions__succeeds() {\n        procedure.addCondition(OrCondition([FalseCondition(), TrueCondition()]))\n        wait(for: procedure)\n        PKAssertProcedureFinished(procedure)\n    }\n\n    func test__or_condition__with_successful_and_ignored_condition__succeeds() {\n        procedure.addCondition(OrCondition([IgnoredCondition(FalseCondition()), TrueCondition()]))\n        wait(for: procedure)\n        PKAssertProcedureFinished(procedure)\n    }\n\n    func test__or_condition__with_failing_and_ignored_condition__fails() {\n        procedure.addCondition(OrCondition([IgnoredCondition(FalseCondition()), FalseCondition()]))\n        wait(for: procedure)\n        PKAssertProcedureCancelledWithError(procedure, ProcedureKitError.FalseCondition())\n    }\n\n    func test__or_condition__with_two_ignored_conditions__does_not_fail() {\n        procedure.addCondition(OrCondition([IgnoredCondition(FalseCondition()), IgnoredCondition(FalseCondition())]))\n        wait(for: procedure)\n        PKAssertProcedureCancelled(procedure)\n    }\n\n    func test__nested_successful_or_conditions() {\n        procedure.addCondition(OrCondition([OrCondition([TrueCondition(), TrueCondition()]), OrCondition([TrueCondition(), TrueCondition()])]))\n        wait(for: procedure)\n        PKAssertProcedureFinished(procedure)\n    }\n\n    func test__nested_failing_or_conditions() {\n        procedure.addCondition(OrCondition([OrCondition([FalseCondition(), FalseCondition()]), OrCondition([FalseCondition(), FalseCondition()])]))\n        wait(for: procedure)\n        PKAssertProcedureCancelled(procedure, withErrors: true)\n    }\n\n    func test__ignored_or_condition_does_not_fail() {\n        procedure.addCondition(IgnoredCondition(OrCondition([FalseCondition()])))\n        wait(for: procedure)\n        PKAssertProcedureCancelled(procedure)\n    }\n\n    // MARK: - Concurrency\n\n    func test__procedure_cancelled_while_conditions_are_being_evaluated_finishes_before_blocked_condition() {\n\n        class CustomTestCondition: AsyncTestCondition {\n            typealias DeinitBlockType = () -> Void\n            var deinitBlock: DeinitBlockType? = nil\n            deinit {\n                deinitBlock?()\n            }\n        }\n\n        // to allow the Procedures to deallocate as soon as they are done\n        // the QueueTestDelegate must be removed (as it holds references)\n        queue.delegate = nil\n\n        [true, false].forEach { waitOnEvaluatorReference in\n\n            var procedure: TestProcedure? = TestProcedure()\n            let procedureDidFinishGroup = DispatchGroup()\n            let customQueue = DispatchQueue(label: \"test\")\n            let conditionGroup = DispatchGroup()\n            conditionGroup.enter()\n            var condition: CustomTestCondition? = CustomTestCondition { completion in\n                // only succeed once the group has been completed\n                conditionGroup.notify(queue: customQueue) {\n                    completion(.success(true))\n                }\n            }\n            let conditionWillDeinitGroup = DispatchGroup()\n            conditionWillDeinitGroup.enter()\n            condition!.deinitBlock = {\n                conditionWillDeinitGroup.leave()\n            }\n            procedureDidFinishGroup.enter()\n            procedure!.addDidFinishBlockObserver { _, _ in\n                procedureDidFinishGroup.leave()\n            }\n            procedure!.addCondition(condition!)\n\n            // remove local reference to the Condition\n            condition = nil\n\n            // then start the procedure\n            run(operation: procedure!)\n\n            var evaluateConditionsOperation: Procedure.EvaluateConditions? = nil\n            // obtain a reference to the EvaluateConditions operation\n            if waitOnEvaluatorReference {\n                guard let evaluator = procedure!.evaluateConditionsProcedure else {\n                    XCTFail(\"Unexpectedly no EvaluateConditions procedure\")\n                    return\n                }\n                evaluateConditionsOperation = evaluator\n            }\n\n            // the Procedure should not finish, as it should be waiting on the Condition to evaluate\n            XCTAssertEqual(procedureDidFinishGroup.wait(timeout: .now() + 0.2), .timedOut)\n\n            // cancel the Procedure, which should allow it to rapidly finish\n            // (despite the Condition *still* not being completed)\n            procedure!.cancel()\n\n            weak var expProcedureDidFinish = expectation(description: \"procedure did finish\")\n            procedureDidFinishGroup.notify(queue: DispatchQueue.main) {\n                expProcedureDidFinish?.fulfill()\n            }\n            waitForExpectations(timeout: 2)\n\n            PKAssertProcedureCancelled(procedure!)\n\n            // remove local reference to the Procedure\n            procedure = nil\n\n            // signal for the condition to finally complete\n            conditionGroup.leave()\n\n            if waitOnEvaluatorReference {\n                // wait for the Condition evaluation to complete\n                evaluateConditionsOperation!.waitUntilFinished()\n\n                // verify that the Condition Evaluator was cancelled\n                XCTAssertTrue(evaluateConditionsOperation!.isCancelled)\n            }\n            else {\n                // wait for the Condition to begin to deinit\n                weak var expConditionWillDeinit = expectation(description: \"condition will deinit\")\n                conditionWillDeinitGroup.notify(queue: DispatchQueue.main) {\n                    expConditionWillDeinit?.fulfill()\n                }\n                waitForExpectations(timeout: 1)\n\n                // then wait for an additional short delay to give the condition\n                // evaluator operation a chance to deinit\n                weak var expDelayPassed = expectation(description: \"delay passed\")\n                DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {\n                    expDelayPassed?.fulfill()\n                }\n                waitForExpectations(timeout: 1)\n\n                // nothing should have caused a crash\n                XCTAssertTrue(true)\n            }\n        }\n    }\n\n    func test__procedure_cancelled_while_conditions_are_being_evaluated_cancels_condition_produced_dependencies() {\n        let procedure = TestProcedure()\n\n        // The following order of operations is enforced below:\n        //  1. dependentCondition's `conditionProducedDependency` is produced by the dependentCondition,\n        //     and is executed (but does not finish)\n        //      AND\n        //     `normalDependency` is executed (but does not finish)\n        //  2. then, `cancelsProcedureCondition` cancels the procedure (while conditions are\n        //     being evaluated, and while the condition-produced `conditionProducedDependency` and\n        //     the (non-condition-produced) `normalDependency` are executing)\n\n        // The expected result is:\n        //  - `conditionProducedDependency` is cancelled (by the Procedure's cancellation propagating\n        //    through the active Condition Evaluation to cancel any active condition-produced\n        //    dependencies)\n        //  - `normalDependency` is not cancelled\n\n        let testDependencyExecutedGroup = DispatchGroup() // signaled once testDependency has executed\n        testDependencyExecutedGroup.enter()\n        let conditionProducedDependency = AsyncResultProcedure<Bool> { _ in\n            testDependencyExecutedGroup.leave()\n            // do not finish\n        }\n        conditionProducedDependency.addDidCancelBlockObserver { conditionProducedDependency, _ in\n            // only finish once cancelled\n            conditionProducedDependency.finish(withResult: .success(true))\n        }\n\n        testDependencyExecutedGroup.enter()\n        let normalDependency = BlockProcedure { this in\n            testDependencyExecutedGroup.leave()\n            // do not finish\n        }\n        let normalDependencyDidFinishGroup = DispatchGroup()\n        normalDependencyDidFinishGroup.enter()\n        normalDependency.addDidFinishBlockObserver { _, _ in\n            normalDependencyDidFinishGroup.leave()\n        }\n\n        let cancelsProcedureCondition = AsyncTestCondition { completion in\n            // do not do this - this is just to ensure that the procedure cancels in the middle of\n            // condition evaluation for this test\n            //\n            // wait for the dependencies of the other condition to be executed before\n            // cancelling the procedure and completing this condition\n            testDependencyExecutedGroup.notify(queue: DispatchQueue.global()) {\n                procedure.cancel()\n                completion(.success(true))\n            }\n        }\n\n        let dependentCondition = TrueCondition()\n        dependentCondition.produceDependency(conditionProducedDependency)\n        dependentCondition.addDependency(normalDependency)\n        procedure.addCondition(AndCondition(TrueCondition(), dependentCondition, cancelsProcedureCondition))\n\n        // wait on the conditionProducedDependency to finish - but since it is scheduled\n        // (and produced) by the dependentCondition, simply add a completion block\n        addCompletionBlockTo(procedure: conditionProducedDependency)\n\n        // normalDependency is not expected to finish (nor cancel), so run it and check\n        // finish status later (do not wait on it)\n        run(operation: normalDependency)\n\n        wait(for: procedure)\n\n        PKAssertProcedureCancelled(procedure)\n\n        // the condition-produced dependency should have been cancelled\n        PKAssertProcedureCancelled(conditionProducedDependency)\n        XCTAssertTrue(conditionProducedDependency.output.value?.value ?? false)\n\n        // whereas the non-condition-produced dependency should *not* be cancelled, nor finished\n        XCTAssertEqual(normalDependencyDidFinishGroup.wait(timeout: .now() + 0.1), .timedOut, \"The normal condition dependency finished. It should not be cancelled, nor finished.\")\n        XCTAssertFalse(normalDependency.isCancelled)\n\n        // clean-up: finish the normalDependency\n        normalDependency.finish()\n    }\n\n    // MARK: - Execution Timing\n\n    func test__conditions_are_not_evaluated_while_associated_procedurequeue_is_suspended() {\n\n        queue.isSuspended = true\n\n        let conditionWasEvaluatedGroup = DispatchGroup()\n        conditionWasEvaluatedGroup.enter()\n        let testCondition = TestCondition {\n            conditionWasEvaluatedGroup.leave()\n            return .success(true)\n        }\n\n        procedure.addCondition(testCondition)\n        addCompletionBlockTo(procedure: procedure)\n        queue.addOperation(procedure)\n\n        XCTAssertTrue(conditionWasEvaluatedGroup.wait(timeout: .now() + 1.0) == .timedOut, \"The condition was evaluated, despite the ProcedureQueue being suspended.\")\n\n        queue.isSuspended = false\n        waitForExpectations(timeout: 3) // wait for the Procedure to finish\n        \n        PKAssertProcedureFinished(procedure)\n        XCTAssertTrue(conditionWasEvaluatedGroup.wait(timeout: .now()) == .success, \"The condition was never evaluated.\")\n    }\n\n    func test__conditions_on_added_children_are_not_evaluated_before_parent_group_executes() {\n\n        let conditionWasEvaluatedGroup = DispatchGroup()\n        conditionWasEvaluatedGroup.enter()\n        let testCondition = TestCondition {\n            conditionWasEvaluatedGroup.leave()\n            return .success(true)\n        }\n\n        procedure.addCondition(testCondition)\n        let group = GroupProcedure(operations: [])\n        group.addChild(procedure) // deliberately use add(child:) to test the non-initializer path\n\n        XCTAssertTrue(conditionWasEvaluatedGroup.wait(timeout: .now() + 1.0) == .timedOut, \"The condition was evaluated, despite the ProcedureQueue being suspended.\")\n\n        wait(for: group)\n\n        PKAssertProcedureFinished(group)\n        PKAssertProcedureFinished(procedure)\n        XCTAssertTrue(conditionWasEvaluatedGroup.wait(timeout: .now()) == .success, \"The condition was never evaluated.\")\n    }\n}\n\n"
  },
  {
    "path": "Tests/ProcedureKitTests/DelayProcedureTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport TestingProcedureKit\n@testable import ProcedureKit\n\nclass DelayProcedureTests: ProcedureKitTestCase {\n\n    func test__with_interval_name() {\n        let delay = DelayProcedure(by: 1)\n        XCTAssertEqual(delay.name, \"Delay for 1.0 seconds\")\n    }\n\n    func test__with_date_name() {\n        let date = Date()\n        let delay = DelayProcedure(until: date)\n        XCTAssertEqual(delay.name, \"Delay until \\(DateFormatter().string(from: date))\")\n    }\n\n    func test__with_negative_time_interval_finishes_immediately() {\n        let delay = DelayProcedure(by: -9_000_000)\n        wait(for: delay)\n        XCTAssertTrue(delay.isFinished)\n    }\n\n    func test__with_distant_past_finishes_immediately() {\n        let delay = DelayProcedure(until: Date.distantPast)\n        wait(for: delay)\n        XCTAssertTrue(delay.isFinished)\n    }\n\n    func test__completes_after_interval() {\n        let interval: TimeInterval = 0.5\n        let delay = DelayProcedure(by: interval)\n        let started = Date()\n        delay.addDidFinishBlockObserver { _, _ in\n            let ended = Date()\n            let timeTaken = ended.timeIntervalSince(started)\n            XCTAssertGreaterThanOrEqual(timeTaken, interval)\n            XCTAssertLessThanOrEqual(timeTaken - interval, 1.0)\n        }\n        wait(for: delay)\n        XCTAssertTrue(delay.isFinished)\n    }\n\n    func test__timer_is_not_fired_when_cancelled() {\n        let interval: TimeInterval = 10\n        let delay = DelayProcedure(by: interval)\n        let started = Date()\n        delay.addDidFinishBlockObserver { _, _ in\n            let ended = Date()\n            let timeTaken = ended.timeIntervalSince(started)\n            XCTAssertLessThanOrEqual(timeTaken, interval)\n        }\n        delay.cancel()\n        wait(for: delay)\n        XCTAssertTrue(delay.isCancelled)\n    }\n\n    func test__timer_cancelled_after_execute_finishes_immediately() {\n        let interval: TimeInterval = 10\n        let delay = DelayProcedure(by: interval)\n        let started = Date()\n        delay.addDidExecuteBlockObserver { delay in\n            delay.cancel()\n        }\n        delay.addDidFinishBlockObserver { _, _ in\n            let ended = Date()\n            let timeTaken = ended.timeIntervalSince(started)\n            XCTAssertLessThanOrEqual(timeTaken, interval)\n        }\n        wait(for: delay)\n        XCTAssertTrue(delay.isCancelled)\n    }\n\n    func test__inject_delay_from_procedure_outputing_delay() {\n        let interval: TimeInterval = 0.5\n        let result = ResultProcedure { Delay.by(interval) }\n        let delay = DelayProcedure().injectResult(from: result)\n        let started = Date()\n        delay.addDidFinishBlockObserver { _, _ in\n            let ended = Date()\n            let timeTaken = ended.timeIntervalSince(started)\n            XCTAssertGreaterThanOrEqual(timeTaken, interval)\n            XCTAssertLessThanOrEqual(timeTaken - interval, 1.0)\n        }\n        wait(for: result, delay)\n        XCTAssertTrue(delay.isFinished)\n\n    }\n\n    func test__inject_delay_from_procedure_outputing_interval() {\n        let interval: TimeInterval = 0.5\n        let result = ResultProcedure { Delay.by(interval) }\n        let delay = DelayProcedure().injectDelay(from: result) { $0.interval }\n        let started = Date()\n        delay.addDidFinishBlockObserver { _, _ in\n            let ended = Date()\n            let timeTaken = ended.timeIntervalSince(started)\n            XCTAssertGreaterThanOrEqual(timeTaken, interval)\n            XCTAssertLessThanOrEqual(timeTaken - interval, 1.0)\n        }\n        wait(for: result, delay)\n        XCTAssertTrue(delay.isFinished)\n\n    }\n}\n\n"
  },
  {
    "path": "Tests/ProcedureKitTests/DispatchQueueExtensionsTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport TestingProcedureKit\n@testable import ProcedureKit\nimport Dispatch\n\nprivate let dispatchQosClassOrder: [DispatchQoS.QoSClass] = [.unspecified, .background, .utility, .default, .userInitiated, .userInteractive]\n\nclass DispatchQoSClassTests: XCTestCase {\n\n    func test_dispatchqos_qosclass_comparable() {\n        for (i, currentQoSClass) in dispatchQosClassOrder.enumerated() {\n            if i > 0 {\n                let qosClassesLessThanCurrent = dispatchQosClassOrder.prefix(i)\n                for qosClass in qosClassesLessThanCurrent {\n                    XCTAssertLessThan(qosClass, currentQoSClass)\n                }\n            }\n            XCTAssertEqual(currentQoSClass, currentQoSClass)\n            if i < dispatchQosClassOrder.count - 1 {\n                let qosClassesGreaterThanCurrent = dispatchQosClassOrder.suffix(dispatchQosClassOrder.count - i - 1)\n                for qosClass in qosClassesGreaterThanCurrent {\n                    XCTAssertGreaterThan(qosClass, currentQoSClass)\n                }\n            }\n        }\n    }\n}\n\nclass DispatchQoSTests: XCTestCase {\n\n    func test_dispatchqos_comparable() {\n        for (i, currentQoSClass) in dispatchQosClassOrder.enumerated() {\n            if i > 0 {\n                let qosClassesLessThanCurrent = dispatchQosClassOrder.prefix(i)\n                for qosClass in qosClassesLessThanCurrent {\n                    XCTAssertLessThan(DispatchQoS(qosClass: qosClass, relativePriority: 0), DispatchQoS(qosClass: currentQoSClass, relativePriority: 0))\n                }\n            }\n            XCTAssertLessThan(DispatchQoS(qosClass: currentQoSClass, relativePriority: 0), DispatchQoS(qosClass: currentQoSClass, relativePriority: 1))\n            XCTAssertEqual(DispatchQoS(qosClass: currentQoSClass, relativePriority: 0), DispatchQoS(qosClass: currentQoSClass, relativePriority: 0))\n            XCTAssertGreaterThan(DispatchQoS(qosClass: currentQoSClass, relativePriority: 1), DispatchQoS(qosClass: currentQoSClass, relativePriority: 0))\n            if i < dispatchQosClassOrder.count - 1 {\n                let qosClassesGreaterThanCurrent = dispatchQosClassOrder.suffix(dispatchQosClassOrder.count - i - 1)\n                for qosClass in qosClassesGreaterThanCurrent {\n                    XCTAssertGreaterThan(DispatchQoS(qosClass: qosClass, relativePriority: 0), DispatchQoS(qosClass: currentQoSClass, relativePriority: 0))\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Tests/ProcedureKitTests/FilterProcedureTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport TestingProcedureKit\n@testable import ProcedureKit\n\nclass FilterProcedureTests: ProcedureKitTestCase {\n\n    func test__requirement_is_filtered_to_result() {\n        let functional = FilterProcedure(source: [0,1,2,3,4,5,6,7]) { $0 % 2 == 0 }\n        wait(for: functional)\n        PKAssertProcedureOutput(functional, [0,2,4,6])\n    }\n\n    func test__finishes_with_error_if_block_throws() {\n        let error = TestError()\n        let functional = FilterProcedure(source: [0,1,2,3,4,5,6,7]) { _ in throw error }\n        wait(for: functional)\n        PKAssertProcedureFinishedWithError(functional, error)\n    }\n\n    func test__filter_dependency_which_finishes_without_errors() {\n        let numbers = NumbersProcedure()\n        let functional = numbers.filter { $0 % 2 == 0 }\n        wait(for: numbers, functional)\n        PKAssertProcedureFinished(numbers)\n        PKAssertProcedureOutput(functional, [0,2,4,6,8])\n    }\n\n    func test__filter_dependency_which_finishes_with_errors() {\n        let error = TestError()\n        let numbers = NumbersProcedure(error: error)\n        let functional = numbers.filter { $0 % 2 == 0 }\n        wait(for: numbers, functional)\n        PKAssertProcedureFinishedWithError(numbers, error)\n        PKAssertProcedureCancelledWithError(functional, ProcedureKitError.dependency(finishedWithError: error))\n    }\n}\n"
  },
  {
    "path": "Tests/ProcedureKitTests/FinishingTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport TestingProcedureKit\n@testable import ProcedureKit\n\nclass FinishingTests: ProcedureKitTestCase {\n\n    func test__procedure_will_finish_is_called() {\n        wait(for: procedure)\n        XCTAssertTrue(procedure.procedureWillFinishCalled)\n    }\n\n    func test__procedure_did_finish_is_called() {\n        wait(for: procedure)\n        XCTAssertTrue(procedure.procedureDidFinishCalled)\n    }\n\n    func test__procedure_with_disabled_automatic_finishing_manual_cancel_and_finish_on_will_execute_does_not_result_in_invalid_state_transition_to_executing() {\n\n        class TestOperation_CancelsAndManuallyFinishesOnWillExecute: Procedure {\n            override init() {\n                super.init(disableAutomaticFinishing: true) // <-- disableAutomaticFinishing\n                addWillExecuteBlockObserver { [weak self] _, _ in\n                    guard let strongSelf = self else { return }\n                    strongSelf.cancel()\n                    strongSelf.finish() // manually finishes after cancelling\n                }\n            }\n            override func execute() {\n                finish()\n            }\n        }\n\n        let special = TestOperation_CancelsAndManuallyFinishesOnWillExecute()\n\n        wait(for: special)\n\n        // Test initially failed with:\n        // assertion failed: Attempting to perform illegal cyclic state transition, Finished -> Executing for operation: Unnamed Operation #UUID.: file Operations/Sources/Core/Shared/Operation.swift, line 399\n        // This will crash the test execution if it happens.\n    }\n\n    func test__cancelled_procedure_finish_called_before_execute_eventually_finishes() {\n        // NOTE: Calling finish() prior to a Procedure being executed by a queue\n        //       should be safe to do *after* the Procedure is cancelled.\n        //\n        //       Internally, the Procedure should delay processing the finish\n        //       until it is started by the queue (which, if it is cancelled,\n        //       should not be waiting on any dependencies).\n\n        let error = TestError()\n        XCTAssertFalse(procedure.isFinished)\n        procedure.cancel()\n        XCTAssertTrue(procedure.isCancelled)\n        XCTAssertFalse(procedure.isFinished)\n        procedure.finish(with: error)\n        XCTAssertFalse(procedure.isFinished)\n        wait(for: procedure)\n        PKAssertProcedureCancelledWithError(procedure, error)\n    }\n\n    func test__cancelled_procedure_finish_called_before_execute_only_first_finish_succeeds() {\n        let error = TestError()\n        XCTAssertFalse(procedure.isFinished)\n        procedure.cancel()\n        XCTAssertTrue(procedure.isCancelled)\n        XCTAssertFalse(procedure.isFinished)\n        procedure.finish(with: error)\n        XCTAssertFalse(procedure.isFinished)\n        // calling finish a second time should be ignored - only the first call should succeed\n        procedure.finish()\n        XCTAssertFalse(procedure.isFinished)\n        wait(for: procedure)\n        // the procedure should be cancelled with 1 error - if there is no error, the second call to finish\n        // incorrectly succeeded\n        PKAssertProcedureCancelledWithError(procedure, error)\n    }\n\n    func test__cancelled_procedure_finish_before_execute_from_didcancel_observer() {\n\n        class FinishesFromDidCancelProcedure: Procedure {\n            let expectedError = TestError()\n            override init() {\n                super.init()\n                addDidCancelBlockObserver { procedure, _ in\n                    procedure.finish(with: procedure.expectedError)\n                }\n            }\n            override func execute() {\n                finish()\n            }\n        }\n        weak var expDidCancel = expectation(description: \"did cancel\")\n        let procedure = FinishesFromDidCancelProcedure()\n        procedure.addDidCancelBlockObserver { procedure, _ in\n            DispatchQueue.main.async {\n                expDidCancel?.fulfill()\n            }\n        }\n        procedure.cancel()\n        waitForExpectations(timeout: 3)\n        XCTAssertTrue(procedure.isCancelled)\n        XCTAssertFalse(procedure.isFinished)\n        wait(for: procedure)\n        PKAssertProcedureCancelledWithError(procedure, procedure.expectedError)\n    }\n\n    func test__procedure_finish_from_willexecute_observer() {\n        let error = TestError()\n        procedure.addWillExecuteBlockObserver { procedure, _ in\n            procedure.finish(with: error)\n        }\n        wait(for: procedure)\n        XCTAssertTrue(procedure.isFinished)\n        XCTAssertFalse(procedure.didExecute)\n        XCTAssertFalse(procedure.isCancelled)\n        XCTAssertTrue(procedure.failed)\n    }\n\n    func test__procedure_finish_after_cancel_from_willexecute_observer() {\n        let error = TestError()\n        procedure.addWillExecuteBlockObserver { procedure, _ in\n            procedure.cancel()\n            procedure.finish(with: error)\n        }\n        wait(for: procedure)\n        PKAssertProcedureCancelledWithError(procedure, error)\n        XCTAssertFalse(procedure.didExecute)\n    }\n\n    func test__finish_from_willfinish_observer_is_ignored() {\n\n        enum ShouldNotHappen: Error {\n            case finishedFromWithinWillFinish\n        }\n        procedure.addWillFinishBlockObserver { (procedure, error, _) in\n            procedure.finish(with: ShouldNotHappen.finishedFromWithinWillFinish)\n        }\n\n        wait(for: procedure)\n        PKAssertProcedureFinished(procedure)\n    }\n}\n\nclass FinishingConcurrencyTests: ProcedureKitTestCase {\n\n    func test__finish_on_other_thread_synchronously_from_execute() {\n        // This test should not result in deadlock.\n\n        class TestFinishSyncFromExecuteProcedure: Procedure {\n            override init() {\n                super.init()\n                self.name = \"TestFinishSyncFromExecuteProcedure\"\n            }\n            override func execute() {\n                guard !Thread.current.isMainThread else { fatalError(\"Procedure's execute() is on main thread.\") }\n                DispatchQueue.main.sync {\n                    assert(Thread.current.isMainThread)\n                    finish()\n                }\n            }\n        }\n\n        let procedure = TestFinishSyncFromExecuteProcedure()\n        wait(for: procedure, withTimeout: 3, handler: { (error) in\n            XCTAssertNil(error)\n        })\n        XCTAssertTrue(procedure.isFinished)\n    }\n}\n"
  },
  {
    "path": "Tests/ProcedureKitTests/GroupTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport TestingProcedureKit\n@testable import ProcedureKit\n\nclass GroupTests: GroupTestCase {\n\n    // MARK: - Execution\n\n    func test__group_children_are_executed() {\n        wait(for: group)\n\n        XCTAssertTrue(group.isFinished)\n        for child in group.children {\n            XCTAssertTrue(child.isFinished)\n        }\n        for testProcedures in group.children.compactMap({ $0 as? TestProcedure }) {\n            XCTAssertTrue(testProcedures.didExecute)\n        }\n    }\n\n    func test__group_adding_operation_to_running_group() {\n        let semaphore = DispatchSemaphore(value: 0)\n        group.addChild(BlockOperation {\n            // prevent the Group from finishing before an extra child is added\n            // after execute\n            semaphore.wait()\n        })\n        let extra = TestProcedure(name: \"Extra child\")\n\n        checkAfterDidExecute(procedure: group) {\n            $0.addChild(extra)\n            semaphore.signal()\n        }\n\n        XCTAssertTrue(group.isFinished)\n        XCTAssertTrue(extra.didExecute)\n    }\n\n    func test__group_only_adds_initial_operations_to_children_property_once() {\n        wait(for: group)\n        XCTAssertEqual(group.children, children)\n    }\n\n    func test__group_will_add_child_observer_is_called() {\n        var blockCalledWith: (GroupProcedure, Operation)? = nil\n        group = TestGroupProcedure(operations: [children[0]])\n        group.addWillAddOperationBlockObserver { group, child in\n            blockCalledWith = (group, child)\n        }\n        wait(for: group)\n        guard let (observedGroup, observedChild) = blockCalledWith else { XCTFail(\"Observer not called\"); return }\n        XCTAssertEqual(observedGroup, group)\n        XCTAssertEqual(observedChild, children[0])\n    }\n\n    func test__group_did_add_child_observer_is_called() {\n        var blockCalledWith: (GroupProcedure, Operation)? = nil\n        group = TestGroupProcedure(operations: [children[0]])\n        group.addDidAddOperationBlockObserver { group, child in\n            blockCalledWith = (group, child)\n        }\n        wait(for: group)\n        guard let (observedGroup, observedChild) = blockCalledWith else { XCTFail(\"Observer not called\"); return }\n        XCTAssertEqual(observedGroup, group)\n        XCTAssertEqual(observedChild, children[0])\n    }\n\n    func test__group_is_not_suspended_at_start() {\n        XCTAssertFalse(group.isSuspended)\n    }\n\n    func test__group_suspended_before_execute() {\n        let child = children[0]\n        group = TestGroupProcedure(operations: [child])\n        group.isSuspended = true\n\n        let childWillExecuteDispatchGroup = DispatchGroup()\n        childWillExecuteDispatchGroup.enter()\n        child.addWillExecuteBlockObserver { _, _ in\n            childWillExecuteDispatchGroup.leave()\n        }\n\n        checkAfterDidExecute(procedure: group) { group in\n\n            XCTAssertTrue(group.didExecute)\n            XCTAssertTrue(group.isExecuting)\n\n            XCTAssertNotEqual(childWillExecuteDispatchGroup.wait(timeout: DispatchTime.now() + 0.005), .success, \"Child executed when group was suspended\")\n\n            XCTAssertFalse(child.isFinished)\n            XCTAssertFalse(group.isFinished)\n\n            group.isSuspended = false\n        }\n\n        XCTAssertTrue(child.isFinished)\n        XCTAssertTrue(group.isFinished)\n    }\n\n    func test__group_suspended_during_execution_does_not_run_additional_children() {\n        let groupDidFinish = DispatchGroup()\n        let child1 = children[0]\n        let child2 = children[1]\n        child2.addDependency(child1)\n        group = TestGroupProcedure(operations: [child1, child2])\n\n        child1.addWillFinishBlockObserver { (_, _, _) in\n            self.group.isSuspended = true\n        }\n        addCompletionBlockTo(procedure: child1)\n\n        groupDidFinish.enter()\n        group.addDidFinishBlockObserver { _, _ in\n            groupDidFinish.leave()\n        }\n        run(operation: group)\n\n        waitForExpectations(timeout: 3)\n        usleep(500)\n\n        XCTAssertTrue(group.isSuspended)\n        XCTAssertFalse(group.isFinished)\n        XCTAssertTrue(child1.isFinished)\n        XCTAssertFalse(child2.isFinished)\n\n        weak var expGroupDidFinish = expectation(description: \"group did finish\")\n        group.isSuspended = false\n        groupDidFinish.notify(queue: DispatchQueue.main, execute: {\n            expGroupDidFinish?.fulfill()\n        })\n        waitForExpectations(timeout: 3, handler: nil)\n\n        XCTAssertFalse(group.isSuspended)\n        XCTAssertTrue(group.isFinished)\n        XCTAssertTrue(child2.isFinished)\n    }\n\n    func test__group_executes_on_procedure_queue_with_underlying_queue() {\n        // If a GroupProcedure is added to a ProcedureQueue with an `underlyingQueue` configured,\n        // the GroupProcedure's `execute()` function will run on the underlyingQueue.\n        // This should succeed - previously, an assert failed in debug mode.\n\n        class TestExecuteOnUnderlyingQueueGroupProcedure: GroupProcedure {\n            public typealias Block = () -> Void\n            private let block: Block\n\n            public init(dispatchQueue underlyingQueue: DispatchQueue? = nil, operations: [Operation], executeCheckBlock: @escaping Block) {\n                self.block = executeCheckBlock\n                super.init(dispatchQueue: underlyingQueue, operations: operations)\n            }\n            open override func execute() {\n                block()\n                super.execute()\n            }\n        }\n\n        let customDispatchQueueLabel = \"run.kit.procedure.ProcedureKit.Tests.TestUnderlyingQueue\"\n        let customDispatchQueue = DispatchQueue(label: customDispatchQueueLabel, attributes: [.concurrent])\n        let customScheduler = ProcedureKit.Scheduler(queue: customDispatchQueue)\n\n        let procedureQueue = ProcedureQueue()\n        procedureQueue.underlyingQueue = customDispatchQueue\n\n        let didExecuteOnDesiredQueue = Protector(false)\n        let child = TestProcedure()\n        let group = TestExecuteOnUnderlyingQueueGroupProcedure(operations: [child]) {\n            // inside execute()\n            if customScheduler.isOnScheduledQueue {\n                didExecuteOnDesiredQueue.overwrite(with: true)\n            }\n        }\n\n        addCompletionBlockTo(procedure: group)\n        procedureQueue.addOperation(group)\n        waitForExpectations(timeout: 3)\n\n        XCTAssertTrue(didExecuteOnDesiredQueue.access, \"execute() did not execute on the desired underlyingQueue\")\n        PKAssertProcedureFinished(group)\n        PKAssertProcedureFinished(child)\n    }\n}\n\n// MARK: - Error Tests\n\nextension GroupTests {\n\n    func test__group_exits_correctly_when_child_errors() {\n        children = createTestProcedures(shouldError: true)\n        group = TestGroupProcedure(operations: children)\n\n        wait(for: group)\n        PKAssertProcedureFinished(group, withErrors: true)\n        PKAssertGroupErrors(group, count: 5)\n    }\n\n    func test__group_exits_correctly_when_child_group_finishes_with_errors() {\n\n        children = createTestProcedures(shouldError: true)\n        let child = TestGroupProcedure(operations: children); child.name = \"Child Group\"\n        group = TestGroupProcedure(operations: child)\n\n        wait(for: group)\n        PKAssertProcedureFinished(group, withErrors: true)\n        PKAssertGroupErrors(group, count: 1)\n        PKAssertGroupErrors(child, count: 5)\n    }\n}\n\n// MARK: - Custom Error Handling Tests\n\nclass TestGroupChildWillFinishWithErrors: GroupProcedure {\n    enum WillFinishWithErrorsAction {\n        case none\n        case callSuperWithError(Error?)\n        case callSuperWithUnmodifiedInput\n    }\n    let receivedInput = Protector<[Procedure: Error?]>([:])\n    let didReceiveDuplicate = Protector(false)\n    let action: WillFinishWithErrorsAction\n    init(operations: [Operation], action: WillFinishWithErrorsAction) {\n        self.action = action\n        super.init(operations: operations)\n    }\n    open override func child(_ child: Procedure, willFinishWithError error: Error?) {\n\n        let hasExistingEntryForKey = receivedInput.write { ward in\n            return ward.updateValue(error, forKey: child) != nil\n        }\n        if hasExistingEntryForKey {\n            didReceiveDuplicate.overwrite(with: true)\n        }\n\n        // execute action\n        switch action {\n        case .callSuperWithError(let modifiedError):\n            super.child(child, willFinishWithError: modifiedError)\n        case .callSuperWithUnmodifiedInput:\n            super.child(child, willFinishWithError: error)\n        case .none: break\n        }\n    }\n}\n\nextension GroupTests {\n\n    func test__group__transform_child_errors_block_receives_children_and_errors() {\n\n        let receivedInput = Protector<[Procedure: Error?]>([:])\n        let didReceiveDuplicate = Protector(false)\n        children = createTestProcedures(shouldError: true)\n        group = TestGroupProcedure(operations: children)\n        group.transformChildErrorBlock = { (child, error) in\n            let hasExistingEntryForKey = receivedInput.write { ward in\n                return ward.updateValue(error, forKey: child) != nil\n            }\n            if hasExistingEntryForKey {\n                didReceiveDuplicate.overwrite(with: true)\n            }\n        }\n\n        wait(for: group)\n\n        XCTAssertFalse(receivedInput.access.isEmpty, \"transformChildErrorsBlock was not called\")\n        XCTAssertFalse(didReceiveDuplicate.access, \"transformChildErrorsBlock received a duplicate call for the same child\")\n\n        for child in children {\n            guard let error = receivedInput.access[child] else {\n                XCTFail(\"transformChildErrorsBlock was not called for child: \\(child)\")\n                continue\n            }\n\n            guard let blockError = error as? TestError else {\n                XCTFail(\"Error provided to block was not a TestError\")\n                continue\n            }\n            guard let childError = child.error as? TestError else {\n                XCTFail(\"Error in child was not a TestError\")\n                continue\n            }\n            XCTAssertEqual(blockError, childError)\n        }\n\n        PKAssertGroupErrors(group, count: children.count)\n    }\n\n    func test__group__transform_child_errors_block_removes_errors_from_child_willFinishWithError() {\n        let modifiedError = TestError()\n        children = createTestProcedures(shouldError: true)\n        let group = TestGroupChildWillFinishWithErrors(operations: children, action: .callSuperWithUnmodifiedInput)\n        let ignoredChild = children.first!\n        group.transformChildErrorBlock = { (child, error) in\n            if child === ignoredChild {\n                error = modifiedError\n            }\n        }\n\n        wait(for: group)\n\n        XCTAssertNotNil(group.receivedInput.access, \"child(_:willFinishWithError:) was not called\")\n        XCTAssertFalse(group.didReceiveDuplicate.access, \"child(_:willFinishWithError:) received a duplicate call for the same child\")\n        for child in children {\n            XCTAssertTrue(group.receivedInput.access.keys.contains(child), \"child(_:willFinishWithError:) was not called for child: \\(child)\")\n        }\n\n        PKAssertGroupErrors(group, count: children.count)\n\n        guard let receivedErrorsForIgnoredChild = group.receivedInput.access[ignoredChild] as? TestError else {\n            XCTFail(\"child(_:willFinishWithError:) was not called for the ignoredChild\")\n            return\n        }\n        XCTAssertEqual(receivedErrorsForIgnoredChild, modifiedError)\n    }\n\n    func test__group__child_willFinishWithError_does_not_call_super() {\n        children = createTestProcedures(shouldError: true)\n        let group = TestGroupChildWillFinishWithErrors(operations: children, action: .none)\n\n        wait(for: group)\n\n        XCTAssertFalse(group.receivedInput.access.isEmpty, \"child(_:willFinishWithError:) was not called\")\n        XCTAssertFalse(group.didReceiveDuplicate.access, \"child(_:willFinishWithError:) received a duplicate call for the same child\")\n        for child in children {\n            XCTAssertTrue(group.receivedInput.access.keys.contains(child), \"child(_:willFinishWithError:) was not called for child: \\(child)\")\n        }\n\n        PKAssertGroupErrors(group, count: 0)\n    }\n\n    func test__group__child_willFinishWithError_calls_super_with_modified_errors() {\n\n        children = createTestProcedures(shouldError: true)\n        let group = TestGroupChildWillFinishWithErrors(operations: children, action: .callSuperWithError(nil))\n\n        wait(for: group)\n\n        XCTAssertFalse(group.receivedInput.access.isEmpty, \"child(_:willFinishWithErrors:) was not called\")\n        XCTAssertFalse(group.didReceiveDuplicate.access, \"child(_:willFinishWithErrors:) received a duplicate call for the same child\")\n        for child in children {\n            XCTAssertTrue(group.receivedInput.access.keys.contains(child), \"child(_:willFinishWithErrors:) was not called for child: \\(child)\")\n        }\n\n        PKAssertGroupErrors(group, count: 0)\n    }\n}\n\n// MARK: - Cancellation Tests\n\nextension GroupTests {\n\n    func test__group_cancels_children() {\n        weak var cancelledExpectation = expectation(description: \"\\(#function): group did cancel\")\n        group.addDidCancelBlockObserver { _, _ in\n            DispatchQueue.main.async {\n                cancelledExpectation?.fulfill()\n            }\n        }\n        group.cancel()\n\n        waitForExpectations(timeout: 2, handler: nil)\n\n        for child in group.children {\n            XCTAssertTrue(child.isCancelled)\n        }\n    }\n\n    func test__group_cancels_children_when_running() {\n        checkAfterDidExecute(procedure: group) { $0.cancel() }\n        XCTAssertTrue(group.isCancelled)\n    }\n\n    func test__group_execute_is_called_when_cancelled_before_running() {\n        group.cancel()\n        XCTAssertFalse(group.didExecute)\n\n        wait(for: group)\n\n        XCTAssertTrue(group.isCancelled)\n        XCTAssertTrue(group.didExecute)\n        XCTAssertTrue(group.isFinished)\n    }\n\n    func test__group_cancel_with_errors_does_not_collect_errors_sent_to_children() {\n        let error = TestError()\n        check(procedure: group) { $0.cancel(with: error) }\n        PKAssertProcedureCancelledWithError(group, error)\n    }\n\n    func test__group_additional_children_are_cancelled_if_group_is_cancelled() {\n        group.cancel()\n        let additionalChild = TestProcedure(delay: 0)\n        group.addChild(additionalChild)\n        wait(for: group)\n        XCTAssertTrue(additionalChild.isCancelled)\n    }\n}\n\n// MARK: - Finishing Tests\n\nextension GroupTests {\n\n    func test__group_does_not_finish_before_all_children_finish() {\n        var didFinishBlockObserverWasCalled = false\n        group.addWillFinishBlockObserver { group, _, _ in\n            didFinishBlockObserverWasCalled = true\n            for child in group.children {\n                XCTAssertTrue(child.isFinished)\n            }\n        }\n        wait(for: group)\n        XCTAssertTrue(group.isFinished)\n        XCTAssertTrue(didFinishBlockObserverWasCalled)\n    }\n\n    func test__group_does_not_finish_before_child_operation_finishes() {\n        // The Group should always wait on an Operation added to its internal queue.\n        let child = BlockOperation {\n            // wait for 1 second before finishing\n            sleep(1)\n        }\n        let group = GroupProcedure(operations: [child])\n        wait(for: group)\n        XCTAssertTrue(child.isFinished)\n    }\n\n    // MARK: - ProcedureQueue Delegate Tests\n\n    func test__group_ignores_delegate_calls_from_other_queues() {\n        // The base GroupProcedure ProcedureQueue delegate implementation should ignore\n        // other queues' delegate callbacks, or various bad things may happen, including:\n        //  - Observers may be improperly notified\n        //  - The Group may wait to finish on non-child operations\n\n        group = TestGroupProcedure(operations: [])\n        let otherQueue = ProcedureQueue()\n        otherQueue.delegate = group.queueDelegate\n\n        var observerCalledFromGroupDelegate = false\n        group.addWillAddOperationBlockObserver { group, child in\n            observerCalledFromGroupDelegate = true\n        }\n        group.addDidAddOperationBlockObserver { group, child in\n            observerCalledFromGroupDelegate = true\n        }\n\n        // Adding a TestProcedure to the otherQueue should not result in the Group's\n        // Will/DidAddChild observers being called, nor should the Group wait\n        // on the other queue's TestProcedure to finish.\n        otherQueue.addOperation(TestProcedure())\n        wait(for: group)\n        XCTAssertTrue(group.isFinished)\n        XCTAssertFalse(observerCalledFromGroupDelegate)\n    }\n\n    // MARK: - Child Produce Operation Tests\n\n    func test__child_can_produce_operation() {\n        let producedOperation = TestProcedure(name: \"ProducedOperation\", delay: 0.05)\n        let child = TestProcedure(name: \"Child\", delay: 0.05, produced: producedOperation)\n        addCompletionBlockTo(procedure: child)\n        addCompletionBlockTo(procedure: producedOperation)\n        group = TestGroupProcedure(operations: child)\n        wait(for: group)\n        PKAssertProcedureFinished(group)\n        PKAssertProcedureFinished(child)\n        PKAssertProcedureFinished(producedOperation)\n    }\n\n    func test__group_does_not_finish_before_child_produced_operations_are_finished() {\n        let child = TestProcedure(name: \"Child\", delay: 0.01)\n        let childProducedOperation = TestProcedure(name: \"ChildProducedOperation\", delay: 0.2)\n        childProducedOperation.addDependency(child)\n        let group = GroupProcedure(operations: [child])\n        child.addWillExecuteBlockObserver { operation, pendingExecute in\n            try! operation.produce(operation: childProducedOperation, before: pendingExecute) // swiftlint:disable:this force_try\n        }\n        wait(for: group)\n        PKAssertProcedureFinished(group)\n        PKAssertProcedureFinished(childProducedOperation)\n    }\n\n    func test__group_children_array_receives_operations_produced_by_children() {\n        let child = TestProcedure(name: \"Child\", delay: 0.01)\n        let childProducedOperation = TestProcedure(name: \"ChildProducedOperation\", delay: 0.2)\n        childProducedOperation.addDependency(child)\n        let group = GroupProcedure(operations: [child])\n        child.addWillExecuteBlockObserver { operation, pendingExecute in\n            try! operation.produce(operation: childProducedOperation, before: pendingExecute) // swiftlint:disable:this force_try\n        }\n        wait(for: group)\n        XCTAssertEqual(group.children.count, 2)\n        XCTAssertTrue(group.children.contains(child))\n        XCTAssertTrue(group.children.contains(childProducedOperation))\n    }\n\n    // MARK: - Child Operation Added Operation\n\n    func test__group_child_operation_add_operation_subclass_via_operationqueue_current() {\n        // The Group should always wait on an Operation added to its internal queue.\n        //\n        // NOTE: Previously, the first Operation subclass was waited on as side-effect\n        // of the Group CanFinish handling, which picked up on the non-fishing operation\n        // that was added to the children array of the Group.\n        //\n        // But the Operation added after the start of the Group was *not* properly waited on\n        // because its willAddOperation event was not properly handled (for Operation - not\n        // Procedure - subclasses).\n        //\n        let childProducedOperation = BlockOperation {\n            // wait for 1 second before finishing\n            sleep(1)\n        }\n        let child = BlockOperation {\n            // Note: This is not recommended.\n            guard let currentQueue = OperationQueue.current else { fatalError(\"Couldn't get current queue\") }\n            currentQueue.addOperation(childProducedOperation)\n        }\n        let group = GroupProcedure(operations: [child])\n        wait(for: group)\n        XCTAssertTrue(childProducedOperation.isFinished)\n        XCTAssertEqual(group.children.count, 2)\n        XCTAssertTrue(group.children.contains(child))\n        XCTAssertTrue(group.children.contains(childProducedOperation))\n    }\n\n    // MARK: - Condition Tests\n\n    class CheckChildEventsGroupProcedure: GroupProcedure {\n\n        typealias ChildEventBlock = (GroupChildEvent, Operation) -> Void\n        fileprivate var childEventBlock: ChildEventBlock\n\n        enum GroupChildEvent {\n            case willAddOperationObserver\n            case didAddOperationObserver\n            case groupWillAdd\n            case childWillFinishWithError(Procedure, Error?)\n            case transformChildErrorBlock(Procedure, Error?)\n        }\n\n        init(operations: [Operation], childEventBlock: @escaping ChildEventBlock = { _,_ in }) {\n            self.childEventBlock = childEventBlock\n            super.init(operations: operations)\n            addWillAddOperationBlockObserver { group, child in\n                group.childEventBlock(.willAddOperationObserver, child)\n            }\n            addDidAddOperationBlockObserver { group, child in\n                group.childEventBlock(.didAddOperationObserver, child)\n            }\n            transformChildErrorBlock = { (child, error) in\n                childEventBlock(.transformChildErrorBlock(child, error), child)\n            }\n        }\n\n        // GroupProcedure Overrides\n        open override func groupWillAdd(child: Operation) {\n            childEventBlock(.groupWillAdd, child)\n            super.groupWillAdd(child: child)\n        }\n\n        open override func child(_ child: Procedure, willFinishWithError error: Error?) {\n            childEventBlock(.childWillFinishWithError(child, error), child)\n            return super.child(child, willFinishWithError: error)\n        }\n    }\n\n    class CheckForEvaluateConditionsGroupProcedure: CheckChildEventsGroupProcedure {\n        var childEventsForEvaluateConditionsProcedure: [CheckChildEventsGroupProcedure.GroupChildEvent] {\n            return _childEventsForEvaluateConditionsProcedure.access\n        }\n\n        private let _childEventsForEvaluateConditionsProcedure = Protector(Array<CheckChildEventsGroupProcedure.GroupChildEvent>())\n\n        init(operations: [Operation]) {\n            super.init(operations: operations)\n            childEventBlock = { event, child in\n                if child is Procedure.EvaluateConditions {\n                    self._childEventsForEvaluateConditionsProcedure.append(event)\n                }\n            }\n        }\n    }\n\n    func test__group_child_with_conditions_does_not_expose_evaluateconditions_procedure() {\n        // Adding a child with conditions to a Group results in ProcedureQueue *also* adding an internal\n        // \"EvaluateConditions\" Procedure to the Group's internal queue (to manage conditions).\n        //\n        // Ensure that this implementation detail is hidden from callbacks, observers, etc.\n\n        let childWithFailingCondition = TestProcedure()\n        childWithFailingCondition.addCondition(FalseCondition())\n        let childWithSucceedingCondition = TestProcedure()\n        childWithSucceedingCondition.addCondition(TrueCondition())\n\n        let group = CheckForEvaluateConditionsGroupProcedure(operations: [childWithFailingCondition, childWithSucceedingCondition])\n        wait(for: group)\n\n        XCTAssertTrue(group.childEventsForEvaluateConditionsProcedure.isEmpty, \"Received child event(s) for EvaluateConditions procedure: \\(group.childEventsForEvaluateConditionsProcedure)\")\n        let evaluateConditionsChildren = group.children.filter { $0 is Procedure.EvaluateConditions }\n        XCTAssertTrue(evaluateConditionsChildren.isEmpty, \"EvaluateConditions should not appear in group.children\")\n    }\n}\n\nclass GroupConcurrencyTests: GroupConcurrencyTestCase {\n\n    // MARK: - MaxConcurrentOperationCount Tests\n\n    func test__group_maxConcurrentOperationCount_1() {\n        let children: Int = 3\n        let delayMicroseconds: useconds_t = 200000 // 0.2 seconds\n        let timeout: TimeInterval = 4\n        let results = concurrencyTestGroup(children: children, withDelayMicroseconds: delayMicroseconds, withTimeout: timeout,\n            withConfigureBlock: { (group) in\n                group.maxConcurrentOperationCount = 1\n            },\n            withExpectations: Expectations(\n                checkMinimumDetected: 1,\n                checkMaximumDetected: 1,\n                checkAllProceduresFinished: true,\n                checkMinimumDuration: TimeInterval(useconds_t(children) * delayMicroseconds) / 1000000.0\n            )\n        )\n        XCTAssertEqual(results.group.maxConcurrentOperationCount, 1)\n    }\n\n    func test__group_operation_maxConcurrentOperationCount_2() {\n        let children: Int = 4\n        let delayMicroseconds: useconds_t = 200000 // 0.2 seconds\n        let timeout: TimeInterval = 3\n        let results = concurrencyTestGroup(children: children, withDelayMicroseconds: delayMicroseconds, withTimeout: timeout,\n            withConfigureBlock: { (group) in\n                group.maxConcurrentOperationCount = 2\n            },\n            withExpectations: Expectations(\n                checkMinimumDetected: 1,\n                checkMaximumDetected: 2,\n                checkAllProceduresFinished: true\n            )\n        )\n        XCTAssertEqual(results.group.maxConcurrentOperationCount, 2)\n    }\n}\n\nclass GroupEventConcurrencyTests: GroupTestCase {\n\n    let expectedEndingEvents: [EventConcurrencyTrackingRegistrar.ProcedureEvent] = [.override_procedureWillFinish, .observer_willFinish, .override_procedureDidFinish, .observer_didFinish]\n    var didFinishGroup: DispatchGroup!\n    var baseObserver: ConcurrencyTrackingObserver!\n\n    open override func setUp() {\n        super.setUp()\n        let didFinishGroup = DispatchGroup()\n        self.didFinishGroup = didFinishGroup\n        didFinishGroup.enter()\n        baseObserver = ConcurrencyTrackingObserver() { procedure, event in\n            assert(procedure is GroupProcedure)\n            if event == .observer_didFinish {\n                didFinishGroup.leave()\n            }\n        }\n    }\n\n    open override func tearDown() {\n        didFinishGroup = nil\n        baseObserver = nil\n        super.tearDown()\n    }\n\n    private func waitForBaseObserverDidFinish(timeout: TimeInterval) {\n        weak var expDidFinishObserverFired = expectation(description: \"DidFinishObserver was fired\")\n        didFinishGroup.notify(queue: DispatchQueue.main) {\n            expDidFinishObserverFired?.fulfill()\n        }\n        waitForExpectations(timeout: timeout)\n    }\n\n    func test_group_finish_no_concurrent_events() {\n        let group = EventConcurrencyTrackingGroupProcedure(operations: children, registrar: EventConcurrencyTrackingRegistrar(recordHistory: true), baseObserver: baseObserver)\n        wait(for: group)\n\n        // Because Procedure signals isFinished KVO *prior* to calling DidFinish observers,\n        // the above wait() may return before the ConcurrencyTrackingObserver is called to\n        // record the DidFinish event.\n        // Thus, wait for the Group's ConcurrencyTrackingObserver to receive the\n        // .observer_DidFinish event.\n        waitForBaseObserverDidFinish(timeout: 2)\n\n        PKAssertProcedureFinished(group)\n        PKAssertProcedureNoConcurrentEvents(group)\n\n        let expectedBeginningEvents: [EventConcurrencyTrackingRegistrar.ProcedureEvent] = [.observer_didAttach, .observer_willExecute, .do_Execute]\n        XCTAssertEqual(Array(group.concurrencyRegistrar.eventHistory?.prefix(expectedBeginningEvents.count) ?? []), expectedBeginningEvents)\n        XCTAssertEqual(Array(group.concurrencyRegistrar.eventHistory?.suffix(expectedEndingEvents.count) ?? []), expectedEndingEvents)\n    }\n\n    func test_group_cancel_no_concurrent_events() {\n        let group = EventConcurrencyTrackingGroupProcedure(operations: children, registrar: EventConcurrencyTrackingRegistrar(recordHistory: true), baseObserver: baseObserver)\n        group.cancel()\n        wait(for: group)\n\n        // Because Procedure signals isFinished KVO *prior* to calling DidFinish observers,\n        // the above wait() may return before the ConcurrencyTrackingObserver is called to\n        // record the DidFinish event.\n        // Thus, wait for the Group's ConcurrencyTrackingObserver to receive the\n        // .observer_DidFinish event.\n        waitForBaseObserverDidFinish(timeout: 2)\n\n        PKAssertProcedureCancelled(group)\n        PKAssertProcedureNoConcurrentEvents(group)\n\n        let expectedBeginningEvents: [EventConcurrencyTrackingRegistrar.ProcedureEvent] = [.observer_didAttach, .override_procedureDidCancel, .observer_didCancel, .observer_willExecute, .do_Execute]\n        XCTAssertEqual(Array(group.concurrencyRegistrar.eventHistory?.prefix(expectedBeginningEvents.count) ?? []), expectedBeginningEvents)\n        XCTAssertEqual(Array(group.concurrencyRegistrar.eventHistory?.suffix(expectedEndingEvents.count) ?? []), expectedEndingEvents)\n    }\n}\n\nclass GroupAddChildConcurrencyTests: ProcedureKitTestCase {\n\n    func test__group_add_child__prior_to_adding_group_to_queue() {\n        let child = BlockProcedure { usleep(5000) }\n        child.name = \"ChildProcedure\"\n        addCompletionBlockTo(procedure: child)\n        let group = EventConcurrencyTrackingGroupProcedure(operations: [], registrar: EventConcurrencyTrackingRegistrar(recordHistory: true))\n        group.addChild(child)\n        wait(for: group)\n        PKAssertProcedureFinished(child)\n        PKAssertProcedureFinished(group)\n        PKAssertProcedureNoConcurrentEvents(group)\n    }\n\n    func test__group_add_child_operation__prior_to_adding_group_to_queue() {\n        weak var expChildOperationFinished = expectation(description: \"child did finish\")\n        let child = BlockOperation { usleep(5000) }\n        child.name = \"ChildOperation\"\n        let childFinishedOperation = BlockProcedure { DispatchQueue.main.async { expChildOperationFinished?.fulfill() } }\n        childFinishedOperation.addDependency(child)\n        let group = EventConcurrencyTrackingGroupProcedure(operations: [], registrar: EventConcurrencyTrackingRegistrar(recordHistory: true))\n        group.addChild(child)\n        wait(for: group, childFinishedOperation)\n        XCTAssertTrue(child.isFinished)\n        PKAssertProcedureFinished(group)\n        PKAssertProcedureNoConcurrentEvents(group)\n    }\n\n    func test__group_add_child__from_an_observer_on_another_child() {\n        let addedChild = BlockProcedure { usleep(5000) }\n        addedChild.name = \"AddedChildProcedure\"\n        let initialChild = BlockProcedure { usleep(5000) }\n        initialChild.name = \"ChildProcedure\"\n        addCompletionBlockTo(procedure: initialChild)\n        addCompletionBlockTo(procedure: addedChild)\n        let group = EventConcurrencyTrackingGroupProcedure(operations: [initialChild], registrar: EventConcurrencyTrackingRegistrar(recordHistory: true))\n        initialChild.addWillExecuteBlockObserver { _, _ in\n            group.addChild(addedChild)\n        }\n        wait(for: group)\n        PKAssertProcedureFinished(initialChild)\n        PKAssertProcedureFinished(addedChild)\n        PKAssertProcedureFinished(group)\n        PKAssertProcedureNoConcurrentEvents(group)\n    }\n\n    func test__group_add_child__before_procedure_execute_async() {\n        var didExecuteWillAddObserverForAddedChildOperation = false\n        var procedureIsExecuting_InWillAddObserver = false\n        var procedureIsFinished_InWillAddObserver = false\n\n        let addedChild = BlockProcedure { usleep(5000) }\n        addedChild.name = \"AddedChildOperation\"\n        let group = TestGroupProcedure(operations: [])\n\n        // test if `procedure`'s execute can be properly delayed by group.add(child:before:)\n        let procedure = BlockProcedure { }\n        procedure.addWillExecuteBlockObserver { procedure, pendingExecute in\n            DispatchQueue.global().asyncAfter(deadline: .now() + 0.5) {\n                // despite this being executed long after the willExecute observer has returned\n                // (and a delay), by passing the pendingExecute event to the add(child:before:) function\n                // it should ensure that `procedure` does not execute until producing the\n                // operation succeeds (i.e. until all WillAdd observers have been fired and it's\n                // added to the group)\n                group.addChild(addedChild, before: pendingExecute)\n            }\n        }\n        group.addWillAddOperationBlockObserver { procedure, operation in\n            guard operation === addedChild else { return }\n            didExecuteWillAddObserverForAddedChildOperation = true\n            procedureIsExecuting_InWillAddObserver = procedure.isExecuting\n            procedureIsFinished_InWillAddObserver = procedure.isFinished\n        }\n        wait(for: procedure)\n        PKAssertProcedureFinished(procedure)\n        XCTAssertTrue(didExecuteWillAddObserverForAddedChildOperation, \"group never executed its WillAddOperation observer for the added child operation\")\n        XCTAssertFalse(procedureIsExecuting_InWillAddObserver, \"group was executing when its WillAddOperation observer was fired for the added child operation\")\n        XCTAssertFalse(procedureIsFinished_InWillAddObserver, \"group was finished when its WillAddOperation observer was fired for the added child operation\")\n    }\n\n    func test__group_add_child___before_procedure_finish_async() {\n        var didExecuteWillAddObserverForAddedChildOperation = false\n        var procedureIsExecuting_InWillAddObserver = false\n        var procedureIsFinished_InWillAddObserver = false\n\n        let addedChild = BlockProcedure { usleep(5000) }\n        addedChild.name = \"AddedChildOperation\"\n        let group = TestGroupProcedure(operations: [])\n\n        // test if `procedure`'s finish can be properly delayed by group.add(child:before:)\n        let procedure = BlockProcedure { }\n        procedure.addWillFinishBlockObserver { procedure, _, pendingFinish in\n            DispatchQueue.global().asyncAfter(deadline: .now() + 0.5) {\n                // despite this being executed long after the willFinish observer has returned\n                // (and a delay), by passing the pendingFinish event to the group's add(child:before:) function\n                // it should ensure that `procedure` does not finish until producing the\n                // operation succeeds (i.e. until all WillAdd observers have been fired and it's\n                // added to the group)\n                group.addChild(addedChild, before: pendingFinish)\n            }\n        }\n        group.addWillAddOperationBlockObserver { procedure, operation in\n            guard operation === addedChild else { return }\n            didExecuteWillAddObserverForAddedChildOperation = true\n            procedureIsExecuting_InWillAddObserver = procedure.isExecuting\n            procedureIsFinished_InWillAddObserver = procedure.isFinished\n        }\n        wait(for: procedure)\n        PKAssertProcedureFinished(procedure)\n        XCTAssertTrue(didExecuteWillAddObserverForAddedChildOperation, \"procedure never executed its WillAddOperation observer for the produced operation\")\n        XCTAssertFalse(procedureIsExecuting_InWillAddObserver, \"procedure was executing when its WillAddOperation observer was fired for the produced operation\")\n        XCTAssertFalse(procedureIsFinished_InWillAddObserver, \"procedure was finished when its WillAddOperation observer was fired for the produced operation\")\n    }\n}\n"
  },
  {
    "path": "Tests/ProcedureKitTests/IgnoreErrorsProcedureTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2016 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport TestingProcedureKit\n@testable import ProcedureKit\n\nclass IgnoreErrorsProcedureTests: ProcedureKitTestCase {\n\n    func test__procedure_which_errors_is_ignored() {\n\n        let procedure = IgnoreErrorsProcedure(ResultProcedure { throw ProcedureKitError.unknown })\n        wait(for: procedure)\n        PKAssertProcedureFinished(procedure)\n    }\n\n    func test__procedure_which_does_not_error() {\n\n        let procedure = IgnoreErrorsProcedure(ResultProcedure { \"Hello\" })\n        wait(for: procedure)\n        PKAssertProcedureFinished(procedure)\n    }\n\n    func test__procedure_output() {\n\n        let procedure = IgnoreErrorsProcedure(ResultProcedure { \"Hello\" })\n        wait(for: procedure)\n        PKAssertProcedureOutput(procedure, \"Hello\")\n    }\n}\n\n"
  },
  {
    "path": "Tests/ProcedureKitTests/JSONCodingTests.swift",
    "content": "//\n//  ProcedureKitTests\n//\n//  Copyright © 2019 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport TestingProcedureKit\n@testable import ProcedureKit\n\nclass JSONEncodingTests: ProcedureKitTestCase {\n\n    struct Person: Equatable, Codable {\n        let firstName: String\n        let lastName: String\n    }\n\n    final class CodingTestProcedure<T: Codable>: GroupProcedure, InputProcedure, OutputProcedure {\n\n        var input: Pending<T> = .pending\n        var output: Pending<ProcedureResult<T>> = .pending\n\n        init() {\n\n            let encode = EncodeJSONProcedure<T>()\n            let decode = DecodeJSONProcedure<T>().injectResult(from: encode)\n\n            super.init(operations: [encode, decode])\n\n            bind(to: encode)\n            bind(from: decode)\n        }\n    }\n\n    func test__coding_single_item() {\n\n        let john = Person(firstName: \"John\", lastName: \"Lennon\")\n        let input = ResultProcedure { john }\n        let coding = CodingTestProcedure<Person>().injectResult(from: input)\n\n        wait(for: coding, input)\n\n        PKAssertProcedureOutput(coding, john)\n    }\n\n    func test__coding_array_items() {\n        let beatles = [\n            Person(firstName: \"John\", lastName: \"Lennon\"),\n            Person(firstName: \"Paul\", lastName: \"McCartney\"),\n            Person(firstName: \"George\", lastName: \"Harrison\"),\n            Person(firstName: \"Ringo\", lastName: \"Starr\")\n        ]\n        let input = ResultProcedure { beatles }\n        let coding = CodingTestProcedure<[Person]>().injectResult(from: input)\n\n        wait(for: coding, input)\n\n        PKAssertProcedureOutput(coding, beatles)\n    }\n}\n"
  },
  {
    "path": "Tests/ProcedureKitTests/KVONotificationTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport TestingProcedureKit\n@testable import ProcedureKit\n\nclass KVOTests: ProcedureKitTestCase {\n\n    class NSOperationKVOObserver: NSObject {\n\n        let operation: Operation\n        private var removedObserved = false\n        private var isFinishedBlock: (() -> Void)?\n\n        enum KeyPath: String {\n            case cancelled = \"isCancelled\"\n            case asynchronous = \"isAsynchronous\"\n            case executing = \"isExecuting\"\n            case finished = \"isFinished\"\n            case ready = \"isReady\"\n            case dependencies = \"dependencies\"\n            case queuePriority = \"queuePriority\"\n            case completionBlock = \"completionBlock\"\n        }\n\n        struct KeyPathSets {\n            static let State = Set<String>([KeyPath.cancelled.rawValue, KeyPath.executing.rawValue, KeyPath.finished.rawValue, KeyPath.ready.rawValue])\n        }\n\n        struct KVONotification {\n            let keyPath: String\n            let time: TimeInterval\n            let old: Any?\n            let new: Any?\n        }\n        private var orderOfKVONotifications = Protector<[KVONotification]>([])\n\n        convenience init(operation: Operation, finishingExpectation: XCTestExpectation) {\n            self.init(operation: operation, isFinishedBlock: { [weak finishingExpectation] in\n                DispatchQueue.main.async {\n                    guard let finishingExpectation = finishingExpectation else { return }\n                    finishingExpectation.fulfill()\n                }\n            })\n        }\n\n        init(operation: Operation, isFinishedBlock: (() -> Void)? = nil) {\n            self.operation = operation\n            self.isFinishedBlock = isFinishedBlock\n            super.init()\n            let options: NSKeyValueObservingOptions = [.old, .new]\n            operation.addObserver(self, forKeyPath: KeyPath.cancelled.rawValue, options: options, context: &TestKVOOperationKVOContext)\n            operation.addObserver(self, forKeyPath: KeyPath.asynchronous.rawValue, options: options, context: &TestKVOOperationKVOContext)\n            operation.addObserver(self, forKeyPath: KeyPath.executing.rawValue, options: options, context: &TestKVOOperationKVOContext)\n            operation.addObserver(self, forKeyPath: KeyPath.finished.rawValue, options: options, context: &TestKVOOperationKVOContext)\n            operation.addObserver(self, forKeyPath: KeyPath.ready.rawValue, options: options, context: &TestKVOOperationKVOContext)\n            operation.addObserver(self, forKeyPath: KeyPath.dependencies.rawValue, options: options, context: &TestKVOOperationKVOContext)\n            operation.addObserver(self, forKeyPath: KeyPath.queuePriority.rawValue, options: options, context: &TestKVOOperationKVOContext)\n            operation.addObserver(self, forKeyPath: KeyPath.completionBlock.rawValue, options: options, context: &TestKVOOperationKVOContext)\n        }\n\n        deinit {\n            operation.removeObserver(self, forKeyPath: KeyPath.cancelled.rawValue)\n            operation.removeObserver(self, forKeyPath: KeyPath.asynchronous.rawValue)\n            operation.removeObserver(self, forKeyPath: KeyPath.executing.rawValue)\n            operation.removeObserver(self, forKeyPath: KeyPath.finished.rawValue)\n            operation.removeObserver(self, forKeyPath: KeyPath.ready.rawValue)\n            operation.removeObserver(self, forKeyPath: KeyPath.dependencies.rawValue)\n            operation.removeObserver(self, forKeyPath: KeyPath.queuePriority.rawValue)\n            operation.removeObserver(self, forKeyPath: KeyPath.completionBlock.rawValue)\n        }\n\n        var observedKVO: [KVONotification] {\n            return orderOfKVONotifications.read { array in return array }\n        }\n\n        func observedKVOFor(_ keyPaths: Set<String>) -> [KVONotification] {\n            return observedKVO.filter({ (notification) -> Bool in\n                keyPaths.contains(notification.keyPath)\n            })\n        }\n\n        var frequencyOfKVOKeyPaths: [String: Int] {\n            return observedKVO.reduce([:]) { (accu: [String: Int], element) in\n                let keyPath = element.keyPath\n                var accu = accu\n                accu[keyPath] = accu[keyPath]?.advanced(by: 1) ?? 1\n                return accu\n            }\n        }\n\n        override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {\n            \n            guard context == &TestKVOOperationKVOContext else {\n                super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)\n                return\n            }\n            guard object as AnyObject? === operation else { return }\n            guard let keyPath = keyPath else { return }\n            if let isFinishedBlock = self.isFinishedBlock, keyPath == KeyPath.finished.rawValue {\n                orderOfKVONotifications.write { (array) -> Void in\n                    array.append(KVONotification(keyPath: keyPath, time: NSDate().timeIntervalSinceReferenceDate, old: change?[.oldKey], new: change?[.newKey]))\n                    DispatchQueue.main.async {\n                        isFinishedBlock()\n                    }\n                }\n            }\n            else {\n                orderOfKVONotifications.write { (array) -> Void in\n                    array.append(KVONotification(keyPath: keyPath, time: NSDate().timeIntervalSinceReferenceDate, old: change?[.oldKey], new: change?[.newKey]))\n                }\n            }\n        }\n    }\n\n\n    func test__nsoperation_kvo__procedure_state_transition_from_initializing_to_pending() {\n        let kvoObserver = NSOperationKVOObserver(operation: procedure)\n        procedure.willEnqueue(on: queue) // trigger state transition from .initialized -> .willEnqueue\n        procedure.pendingQueueStart() // trigger state transition from .willEnqueue -> .pending\n        let observedKVO = kvoObserver.observedKVOFor(NSOperationKVOObserver.KeyPathSets.State)\n        XCTAssertEqual(observedKVO.count, 0)    // should be no KVO notification on any NSOperation keyPaths for this internal state transition\n    }\n\n    func test__nsoperation_kvo__procedure_state_transition_to_executing() {\n        class NoFinishOperation: Procedure {\n            override func execute() {\n                // do not finish\n            }\n        }\n        let procedure = NoFinishOperation()\n        weak var expDidExecute = expectation(description: \"\")\n        procedure.addDidExecuteBlockObserver { _ in\n            DispatchQueue.main.async {\n                expDidExecute?.fulfill()\n            }\n        }\n        let kvoObserver = NSOperationKVOObserver(operation: procedure)\n        procedure.willEnqueue(on: queue) // trigger state transition from .initialized -> .willEnqueue\n        procedure.pendingQueueStart() // trigger state transition from .willEnqueue -> .pending\n        procedure.start() // trigger state transition from .pending -> .executing\n\n        waitForExpectations(timeout: 3, handler: nil)\n\n        let observedKVO = kvoObserver.observedKVOFor(NSOperationKVOObserver.KeyPathSets.State)\n        // should be a single KVO notification for NSOperation keyPath \"isExecuting\" for this internal state transition\n        XCTAssertEqual(observedKVO.count, 1, \"ObservedKVO = \\(observedKVO)\")\n        XCTAssertEqual(observedKVO.get(safe: 0)?.keyPath, NSOperationKVOObserver.KeyPath.executing.rawValue)\n    }\n\n    func test__nsoperation_kvo__procedure_state_transition_to_executing_via_queue() {\n        class NoFinishOperation: Procedure {\n            var didExecuteExpectation: XCTestExpectation\n            init(didExecuteExpectation: XCTestExpectation) {\n                self.didExecuteExpectation = didExecuteExpectation\n                super.init()\n            }\n            override func execute() {\n                didExecuteExpectation.fulfill()\n                // do not finish\n            }\n        }\n        let didFinishGroup = DispatchGroup()\n        didFinishGroup.enter()\n        let didExecuteExpectation = expectation(description: \"Test: \\(#function); DidExecute\")\n        let operation = NoFinishOperation(didExecuteExpectation: didExecuteExpectation)\n        operation.addDidFinishBlockObserver { _, _ in\n            didFinishGroup.leave()\n        }\n        let kvoObserver = NSOperationKVOObserver(operation: operation)\n        run(operation: operation) // trigger state transition from .initialized -> .executing via the queue\n\n        waitForExpectations(timeout: 5, handler: nil)\n\n        let observedKVO = kvoObserver.observedKVOFor(NSOperationKVOObserver.KeyPathSets.State)\n        // should be a single KVO notification for NSOperation keyPath \"isExecuting\" for this internal state transition\n        XCTAssertEqual(observedKVO.count, 1)\n        XCTAssertEqual(observedKVO.get(safe: 0)?.keyPath, NSOperationKVOObserver.KeyPath.executing.rawValue)\n\n        weak var expDidFinish = expectation(description: \"Test: \\(#function); Did Complete Operation\")\n        didFinishGroup.notify(queue: DispatchQueue.main, execute: {\n            expDidFinish?.fulfill()\n        })\n        operation.finish()\n        waitForExpectations(timeout: 5, handler: nil)\n    }\n\n    private func verifyKVO_cancelledNotifications(_ observedKVO: [NSOperationKVOObserver.KVONotification]) -> (success: Bool, isReadyIndex: Int?, failureMessage: String?) {\n        // ensure that the observedKVO contains:\n        // \"isReady\", with at least one \"isCancelled\" before it\n        if let isReadyIndex = observedKVO.firstIndex(where: { $0.keyPath == NSOperationKVOObserver.KeyPath.ready.rawValue }) {\n            var foundIsCancelled = false\n            guard isReadyIndex > 0 else {\n                return (success: false, isReadyIndex: isReadyIndex, failureMessage: \"Found isReady KVO notification, but no isCancelled beforehand.\")\n            }\n            for idx in (0..<isReadyIndex) {\n                if observedKVO[idx].keyPath == NSOperationKVOObserver.KeyPath.cancelled.rawValue {\n                    guard let newBool = observedKVO[idx].new as? Bool, newBool == true else { continue }\n                    foundIsCancelled = true\n                    break\n                }\n            }\n            if foundIsCancelled {\n                return (success: true, isReadyIndex: isReadyIndex, failureMessage: nil)\n            }\n            else {\n                return (success: false, isReadyIndex: isReadyIndex, failureMessage: \"Found isReady KVO notification, but no isCancelled beforehand.\")\n            }\n        }\n        else {\n            return (success: false, isReadyIndex: nil, failureMessage: \"Did not find isReady KVO notification\")\n        }\n    }\n\n    func test__nsoperation_kvo__procedure_cancel_from_initialized() {\n        let kvoObserver = NSOperationKVOObserver(operation: procedure)\n        procedure.cancel()\n\n        let observedKVO = kvoObserver.observedKVOFor(NSOperationKVOObserver.KeyPathSets.State)\n        // NOTE: To fully match NSOperation, this should be 2 KVO notifications, in the order: isCancelled, isReady\n        // Because Operation handles cancelled status internally *and* calls super.cancel (to trigger Ready status change),\n        // a total of 3 KVO notifications are generated in the order: isCancelled, isCancelled, isReady\n        XCTAssertGreaterThanOrEqual(observedKVO.count, 2)\n        let cancelledVerifyResult = verifyKVO_cancelledNotifications(observedKVO)\n        XCTAssertTrue(cancelledVerifyResult.success, cancelledVerifyResult.failureMessage!)\n        XCTAssertLessThanOrEqual(cancelledVerifyResult.isReadyIndex ?? 0, 3)\n    }\n\n    func test__nsoperation_kvo__groupprocedure_cancel_from_initialized() {\n        let child = TestProcedure()\n        let group = GroupProcedure(operations: [child])\n        let kvoObserver = NSOperationKVOObserver(operation: group)\n        group.cancel()\n\n        let observedKVO = kvoObserver.observedKVOFor(NSOperationKVOObserver.KeyPathSets.State)\n        // NOTE: To fully match NSOperation, this should be 2 KVO notifications, in the order: isCancelled, isReady\n        // Because Operation handles cancelled status internally *and* calls super.cancel (to trigger Ready status change),\n        // a total of 3 KVO notifications are generated in the order: isCancelled, isCancelled, isReady\n        XCTAssertGreaterThanOrEqual(observedKVO.count, 2)\n        let cancelledVerifyResult = verifyKVO_cancelledNotifications(observedKVO)\n        XCTAssertTrue(cancelledVerifyResult.success, cancelledVerifyResult.failureMessage!)\n        XCTAssertLessThanOrEqual(cancelledVerifyResult.isReadyIndex ?? 0, 3)\n    }\n\n    func test__nsoperation_kvo__groupprocedure_child_cancel_from_initialized() {\n        let child = TestProcedure(delay: 1.0)\n        let group = GroupProcedure(operations: [child])\n        let kvoObserver = NSOperationKVOObserver(operation: child)\n        group.cancel()\n\n        let observedKVO = kvoObserver.observedKVOFor(NSOperationKVOObserver.KeyPathSets.State)\n        // NOTE: To fully match NSOperation, this should be 2 KVO notifications, in the order: isCancelled, isReady\n        // Because Operation handles cancelled status internally *and* calls super.cancel (to trigger Ready status change),\n        // a total of 3 KVO notifications are generated in the order: isCancelled, isCancelled, isReady\n        XCTAssertGreaterThanOrEqual(observedKVO.count, 2)\n        let cancelledVerifyResult = verifyKVO_cancelledNotifications(observedKVO)\n        XCTAssertTrue(cancelledVerifyResult.success, cancelledVerifyResult.failureMessage!)\n        XCTAssertLessThanOrEqual(cancelledVerifyResult.isReadyIndex ?? 0, 3)\n    }\n\n    func test__nsoperation_kvo__nsoperation_cancel_from_initialized() {\n        let operation = BlockOperation { }\n        let kvoObserver = NSOperationKVOObserver(operation: operation)\n        operation.cancel()\n\n        let observedKVO = kvoObserver.observedKVOFor(NSOperationKVOObserver.KeyPathSets.State)\n        XCTAssertEqual(observedKVO.count, 2)\n        XCTAssertEqual(observedKVO.get(safe: 0)?.keyPath, NSOperationKVOObserver.KeyPath.cancelled.rawValue)\n        XCTAssertEqual(observedKVO.get(safe: 1)?.keyPath, NSOperationKVOObserver.KeyPath.ready.rawValue)\n    }\n\n    func test__nsoperation_kvo__procedure_cancelled_to_completion() {\n        let expectationIsFinishedKVO = expectation(description: \"Test: \\(#function); Did Receive isFinished KVO Notification\")\n        let kvoObserver = NSOperationKVOObserver(operation: procedure, finishingExpectation: expectationIsFinishedKVO)\n        procedure.cancel()\n        wait(for: procedure)\n\n        let observedKVO = kvoObserver.observedKVOFor(NSOperationKVOObserver.KeyPathSets.State)\n        let keyPathFrequency = kvoObserver.frequencyOfKVOKeyPaths\n\n        XCTAssertGreaterThanOrEqual(observedKVO.count, 3)\n\n        // first three KVO notifications should contain isCancelled and isReady (in that order)\n        let cancelledVerifyResult = verifyKVO_cancelledNotifications(observedKVO)\n        XCTAssertTrue(cancelledVerifyResult.success, cancelledVerifyResult.failureMessage!)\n        XCTAssertLessThanOrEqual(cancelledVerifyResult.isReadyIndex ?? 0, 3)\n\n        // it is valid, but not necessary, for a cancelled operation to transition through isExecuting\n\n        // last KVO notification should always be isFinished\n        XCTAssertEqual(observedKVO.last?.keyPath, NSOperationKVOObserver.KeyPath.finished.rawValue, \"Notifications were: \\(observedKVO)\")\n\n        // isFinished should only be sent once\n        XCTAssertEqual(keyPathFrequency[NSOperationKVOObserver.KeyPath.finished.rawValue], 1)\n    }\n\n    func test__nsoperation_kvo__groupprocedure_cancelled_to_completion() {\n        let expectationIsFinishedKVO = expectation(description: \"Test: \\(#function); Did Receive isFinished KVO Notification\")\n        let child = TestProcedure(delay: 1.0)\n        let group = GroupProcedure(operations: [child])\n        let kvoObserver = NSOperationKVOObserver(operation: group, finishingExpectation: expectationIsFinishedKVO)\n        group.cancel()\n        wait(for: group)\n\n        let observedKVO = kvoObserver.observedKVOFor(NSOperationKVOObserver.KeyPathSets.State)\n        let keyPathFrequency = kvoObserver.frequencyOfKVOKeyPaths\n\n        XCTAssertGreaterThanOrEqual(observedKVO.count, 3)\n\n        // first three KVO notifications should contain isCancelled and isReady (in that order)\n        let cancelledVerifyResult = verifyKVO_cancelledNotifications(observedKVO)\n        XCTAssertTrue(cancelledVerifyResult.success, cancelledVerifyResult.failureMessage!)\n        XCTAssertLessThanOrEqual(cancelledVerifyResult.isReadyIndex ?? 0, 3)\n\n        // it is valid, but not necessary, for a cancelled operation to transition through isExecuting\n\n        // last KVO notification should always be isFinished\n        XCTAssertEqual(observedKVO.last?.keyPath, NSOperationKVOObserver.KeyPath.finished.rawValue)\n\n        // isFinished should only be sent once\n        XCTAssertEqual(keyPathFrequency[NSOperationKVOObserver.KeyPath.finished.rawValue], 1)\n    }\n\n    func test__nsoperation_kvo__procedure_execute_to_completion() {\n        let expectationIsFinishedKVO = expectation(description: \"Test: \\(#function); Did Receive isFinished KVO Notification\")\n        let kvoObserver = NSOperationKVOObserver(operation: procedure, finishingExpectation: expectationIsFinishedKVO)\n        wait(for: procedure)\n\n        let observedKVO = kvoObserver.observedKVOFor(NSOperationKVOObserver.KeyPathSets.State)\n        XCTAssertEqual(observedKVO.count, 3)\n        XCTAssertEqual(observedKVO.get(safe: 0)?.keyPath, NSOperationKVOObserver.KeyPath.executing.rawValue)\n        XCTAssertEqual(observedKVO.get(safe: 1)?.keyPath, NSOperationKVOObserver.KeyPath.executing.rawValue)\n        XCTAssertEqual(observedKVO.get(safe: 2)?.keyPath, NSOperationKVOObserver.KeyPath.finished.rawValue)\n    }\n\n    func test__nsoperation_kvo__groupprocedure_execute_to_completion() {\n        let expectationIsFinishedKVO = expectation(description: \"Test: \\(#function); Did Receive isFinished KVO Notification\")\n        let child = TestProcedure(delay: 1.0)\n        let group = GroupProcedure(operations: [child])\n        let kvoObserver = NSOperationKVOObserver(operation: group, finishingExpectation: expectationIsFinishedKVO)\n        wait(for: group)\n\n        let observedKVO = kvoObserver.observedKVOFor(NSOperationKVOObserver.KeyPathSets.State)\n        XCTAssertEqual(observedKVO.count, 3)\n        XCTAssertEqual(observedKVO.get(safe: 0)?.keyPath, NSOperationKVOObserver.KeyPath.executing.rawValue)\n        XCTAssertEqual(observedKVO.get(safe: 1)?.keyPath, NSOperationKVOObserver.KeyPath.executing.rawValue)\n        XCTAssertEqual(observedKVO.get(safe: 2)?.keyPath, NSOperationKVOObserver.KeyPath.finished.rawValue)\n    }\n\n    func test__nsoperation_kvo__procedure_execute_with_dependencies_to_completion() {\n        let expectationIsFinishedKVO = expectation(description: \"Test: \\(#function); Did Receive isFinished KVO Notification\")\n        let delay = DelayProcedure(by: 0.1)\n        let operation = TestProcedure()\n        let kvoObserver = NSOperationKVOObserver(operation: operation, finishingExpectation: expectationIsFinishedKVO)\n        operation.addDependency(delay)\n        wait(for: delay, operation)\n\n        let observedKVO = kvoObserver.observedKVOFor(NSOperationKVOObserver.KeyPathSets.State.union([NSOperationKVOObserver.KeyPath.dependencies.rawValue]))\n        XCTAssertEqual(observedKVO.count, 6)\n        XCTAssertEqual(observedKVO.get(safe: 0)?.keyPath, NSOperationKVOObserver.KeyPath.ready.rawValue)\n        XCTAssertEqual(observedKVO.get(safe: 1)?.keyPath, NSOperationKVOObserver.KeyPath.dependencies.rawValue)\n        XCTAssertEqual(observedKVO.get(safe: 2)?.keyPath, NSOperationKVOObserver.KeyPath.ready.rawValue)\n        XCTAssertEqual(observedKVO.get(safe: 3)?.keyPath, NSOperationKVOObserver.KeyPath.executing.rawValue)\n        XCTAssertEqual(observedKVO.get(safe: 4)?.keyPath, NSOperationKVOObserver.KeyPath.executing.rawValue)\n        XCTAssertEqual(observedKVO.get(safe: 5)?.keyPath, NSOperationKVOObserver.KeyPath.finished.rawValue)\n    }\n}\n\nextension Collection {\n    // Returns the element at the specified index iff it is within bounds, otherwise nil.\n    func get(safe index: Index) -> Iterator.Element? {\n        return indices.contains(index) ? self[index] : nil\n    }\n}\n\nprivate var TestKVOOperationKVOContext = 0\n"
  },
  {
    "path": "Tests/ProcedureKitTests/LoggingTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\n@testable import ProcedureKit\nimport TestingProcedureKit\n\nclass LogEntryTests: LoggingTestCase {\n\n    func test__trace_description() {\n        let payload: Log.Entry.Payload = .trace\n        XCTAssertEqual(payload.description, \"\")\n    }\n\n    func test__message_description() {\n        let payload: Log.Entry.Payload = .message(\"Hello World\")\n        XCTAssertEqual(payload.description, \"Hello World\")\n    }\n\n    func test__value_description() {\n        let payload: Log.Entry.Payload = .value(\"Hello World\")\n        XCTAssertEqual(payload.description, \"Hello World\")\n    }\n\n    func test__value_nil_description() {\n        let payload: Log.Entry.Payload = .value(nil)\n        XCTAssertEqual(payload.description, \"<nil-value>\")\n    }\n\n    func test__appendFormattedMetadata() {\n        let appended = entry\n            .append(formattedMetadata: \"Foo\")\n            .append(formattedMetadata: nil)\n            .append(formattedMetadata: \"\")\n            .append(formattedMetadata: \"   \")\n            .append(formattedMetadata: \"Bar\")\n        XCTAssertEqual(appended.formattedMetadata, \"Foo Bar\")\n        guard case let .message(text) = entry.payload else {\n            XCTFail(\"Entry did not have a message payload\"); return\n        }\n        XCTAssertEqual(text, \"Hello World\")\n    }\n}\n\nclass LogChannelTests: LoggingTestCase {\n\n    var channel: Log.Channel<TestableLogSettings>!\n\n    override func setUp() {\n        super.setUp()\n        channel = Log.Channel<TestableLogSettings>()\n    }\n\n    override func tearDown() {\n        channel = nil\n        super.tearDown()\n    }\n\n    func test__channel_enabled_initialized_from_settings() {\n        channel = Log.Channel<TestableLogSettings>()\n        XCTAssertEqual(channel.enabled, TestableLogSettings.enabled)\n        XCTAssertTrue(channel.enabled)\n    }\n\n    func test__channel_enabled_initialized_from_init() {\n        channel = Log.Channel<TestableLogSettings>(enabled: false)\n        XCTAssertNotEqual(channel.enabled, TestableLogSettings.enabled)\n        XCTAssertFalse(channel.enabled)\n    }\n\n    func test__channel_severity_initialized_from_settings() {\n        channel = Log.Channel<TestableLogSettings>()\n        XCTAssertEqual(channel.severity, TestableLogSettings.severity)\n        XCTAssertEqual(channel.severity, .verbose)\n    }\n\n    func test__channel_severity_initialized_from_init() {\n        channel = Log.Channel<TestableLogSettings>(severity: .debug)\n        XCTAssertNotEqual(channel.severity, TestableLogSettings.severity)\n        XCTAssertEqual(channel.severity, .debug)\n    }\n\n    func test__channel_shouldWrite_false_when_log_settings_disabled() {\n        Log.enabled = false\n        XCTAssertFalse(channel.shouldWrite(severity: .fatal))\n    }\n\n    func test__channel_shouldWrite_false_when_channel_disabled() {\n        channel.enabled = false\n        XCTAssertFalse(channel.shouldWrite(severity: .fatal))\n    }\n\n    func test__channel_shouldWrite_false_when_severity_less_than_channel_severity() {\n        channel.severity = .fatal\n        XCTAssertFalse(channel.shouldWrite(severity: .warning))\n    }\n\n    func test__channel_shouldWrite_false_when_severity_less_than_global_severity() {\n        Log.severity = .warning\n        XCTAssertFalse(channel.shouldWrite(severity: .info))\n    }\n\n    func test__writer_receives_log_entry_with_trace() {\n        guard let writer = TestableLogSettings.writer as? TestableLogWriter else {\n            XCTFail(\"Did not have a testable log writer\"); return\n        }\n        XCTAssertEqual(writer.entries.count, 0)\n        channel.trace()\n        XCTAssertEqual(writer.entries.count, 1)\n        guard let payload = writer.entries.first?.payload, case .trace = payload else {\n            XCTFail(\"Entry did not have a trace payload\"); return\n        }\n    }\n\n    func test__writer_does_not_receive_log_entry_with_trace_when_disabled() {\n        guard let writer = TestableLogSettings.writer as? TestableLogWriter else {\n            XCTFail(\"Did not have a testable log writer\"); return\n        }\n        channel.enabled = false\n        channel.trace()\n        XCTAssertEqual(writer.entries.count, 0)\n    }\n\n    func test__writer_receives_log_entry_with_message() {\n        guard let writer = TestableLogSettings.writer as? TestableLogWriter else {\n            XCTFail(\"Did not have a testable log writer\"); return\n        }\n        XCTAssertEqual(writer.entries.count, 0)\n        channel.message(\"Hello World\")\n        XCTAssertEqual(writer.entries.count, 1)\n        guard let payload = writer.entries.first?.payload, case let .message(text) = payload else {\n            XCTFail(\"Entry did not have a message payload\"); return\n        }\n        XCTAssertEqual(text, \"Hello World\")\n    }\n\n    func test__writer_does_not_receive_log_entry_with_message_when_disabled() {\n        guard let writer = TestableLogSettings.writer as? TestableLogWriter else {\n            XCTFail(\"Did not have a testable log writer\"); return\n        }\n        channel.enabled = false\n        channel.message(\"Hello World\")\n        XCTAssertEqual(writer.entries.count, 0)\n    }\n\n\n    func test__writer_receives_log_entry_with_value() {\n        guard let writer = TestableLogSettings.writer as? TestableLogWriter else {\n            XCTFail(\"Did not have a testable log writer\"); return\n        }\n        XCTAssertEqual(writer.entries.count, 0)\n        channel.value(\"Hello World\")\n        XCTAssertEqual(writer.entries.count, 1)\n        guard let payload = writer.entries.first?.payload, case let .value(value) = payload, let text = value as? String else {\n            XCTFail(\"Entry did not have a message payload\"); return\n        }\n        XCTAssertEqual(text, \"Hello World\")\n    }\n\n    func test__writer_does_not_receive_log_entry_with_value_when_disabled() {\n        guard let writer = TestableLogSettings.writer as? TestableLogWriter else {\n            XCTFail(\"Did not have a testable log writer\"); return\n        }\n        channel.enabled = false\n        channel.value(\"Hello World\")\n        XCTAssertEqual(writer.entries.count, 0)\n    }\n}\n\nclass LogChannelsTests: LoggingTestCase {\n\n    var channels: Log.Channels<TestableLogSettings>!\n\n    override func setUp() {\n        super.setUp()\n        channels = Log.Channels<TestableLogSettings>()\n    }\n\n    override func tearDown() {\n        channels = nil\n        super.tearDown()\n    }\n\n    func test__setting_enabled_sets_all_channels() {\n        channels.enabled = false\n        XCTAssertFalse(channels.verbose.enabled)\n        XCTAssertFalse(channels.info.enabled)\n        XCTAssertFalse(channels.event.enabled)\n        XCTAssertFalse(channels.debug.enabled)\n        XCTAssertFalse(channels.warning.enabled)\n        XCTAssertFalse(channels.fatal.enabled)\n        channels.enabled = true\n        XCTAssertTrue(channels.verbose.enabled)\n        XCTAssertTrue(channels.info.enabled)\n        XCTAssertTrue(channels.event.enabled)\n        XCTAssertTrue(channels.debug.enabled)\n        XCTAssertTrue(channels.warning.enabled)\n        XCTAssertTrue(channels.fatal.enabled)\n    }\n\n    func test__setting_writer() {\n        let writer = TestableLogWriter()\n        channels.writer = writer\n        channels.debug.message(\"Hello World\")\n        XCTAssertEqual(writer.entries.count, 1)\n        guard let payload = writer.entries.first?.payload, case let .message(text) = payload else {\n            XCTFail(\"Entry did not have a message payload\"); return\n        }\n        XCTAssertEqual(text, \"Hello World\")\n    }\n\n    func test__getting_current_channel() {\n        channels.severity = .verbose\n        XCTAssertEqual(channels.current.severity, .verbose)\n        channels.severity = .info\n        XCTAssertEqual(channels.current.severity, .info)\n        channels.severity = .event\n        XCTAssertEqual(channels.current.severity, .event)\n        channels.severity = .debug\n        XCTAssertEqual(channels.current.severity, .debug)\n        channels.severity = .warning\n        XCTAssertEqual(channels.current.severity, .warning)\n        channels.severity = .fatal\n        XCTAssertEqual(channels.current.severity, .fatal)\n    }\n}\n\nclass LogWriterTests: LoggingTestCase {\n\n    var channels: Log.Channels<TestableLogSettings>!\n\n    override func setUp() {\n        super.setUp()\n        channels = Log.Channels<TestableLogSettings>()\n    }\n\n    override func tearDown() {\n        channels = nil\n        super.tearDown()\n    }\n\n    func test__redirecting_log_writer() {\n        let writer = TestableLogWriter()\n        channels.writer = Log.Writers.Redirecting(writers: [writer])\n        channels.debug.message(\"Hello World\")\n        XCTAssertEqual(writer.entries.count, 1)\n        guard let payload = writer.entries.first?.payload, case let .message(text) = payload else {\n            XCTFail(\"Entry did not have a message payload\"); return\n        }\n        XCTAssertEqual(text, \"Hello World\")\n    }\n}\n"
  },
  {
    "path": "Tests/ProcedureKitTests/MapProcedureTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport TestingProcedureKit\n@testable import ProcedureKit\n\nclass MapProcedureTests: ProcedureKitTestCase {\n\n    func test__requirement_is_mapped_to_result() {\n        let functional = MapProcedure(source: [0,1,2,3,4,5,6,7]) { $0 * 2 }\n        wait(for: functional)\n        PKAssertProcedureFinished(functional)\n        PKAssertProcedureOutput(functional, [0,2,4,6,8,10,12,14])\n    }\n\n    func test__finishes_with_error_if_block_throws() {\n        let error = TestError()\n        let functional = MapProcedure(source: [0,1,2,3,4,5,6,7]) { _ in throw error }\n        wait(for: functional)\n        PKAssertProcedureFinishedWithError(functional, error)\n    }\n\n    func test__map_dependency_which_finishes_without_errors() {\n        let numbers = NumbersProcedure()\n        let functional = numbers.map { $0 * 2 }\n        wait(for: numbers, functional)\n        PKAssertProcedureFinished(numbers)\n        PKAssertProcedureFinished(functional)\n        PKAssertProcedureOutput(functional, [0,2,4,6,8,10,12,14,16,18])\n    }\n\n    func test__map_dependency_which_finishes_with_errors() {\n        let error = TestError()\n        let numbers = NumbersProcedure(error: error)\n        let functional = numbers.map { $0 * 2 }\n        wait(for: numbers, functional)\n        PKAssertProcedureFinishedWithError(numbers, error)\n        PKAssertProcedureCancelledWithError(functional, ProcedureKitError.dependency(finishedWithError: error))\n    }\n\n}\n\nclass FlatMapProcedureTests: ProcedureKitTestCase {\n\n    func test__requirement_is_flat_mapped_to_result() {\n        let functional = FlatMapProcedure(source: [0,1,2,3,4,5,6,7,8,9]) { (value: Int) -> Int? in\n            guard value % 2 == 0 else { return nil }\n            return value * 2\n        }\n        wait(for: functional)\n        PKAssertProcedureFinished(functional)\n        PKAssertProcedureOutput(functional, [0,4,8,12,16])\n    }\n\n    func test__finishes_with_error_if_block_throws() {\n        let error = TestError()\n        let functional = MapProcedure(source: [0,1,2,3,4,5,6,7,8,9]) { _ in throw error }\n        wait(for: functional)\n        PKAssertProcedureFinishedWithError(functional, error)\n    }\n\n    func test__flat_map_dependency_which_finishes_without_errors() {\n        let numbers = NumbersProcedure()\n        let functional = numbers.flatMap { (value: Int) -> Int? in\n            guard value % 2 == 0 else { return nil }\n            return value * 2\n        }\n        wait(for: numbers, functional)\n        PKAssertProcedureFinished(numbers)\n        PKAssertProcedureFinished(functional)\n        PKAssertProcedureOutput(functional, [0,4,8,12,16])\n    }\n\n    func test__flat_map_dependency_which_finishes_with_errors() {\n        let error = TestError()\n        let numbers = NumbersProcedure(error: error)\n        let functional = numbers.map { $0 * 2 }\n        wait(for: numbers, functional)\n        PKAssertProcedureFinishedWithError(numbers, error)\n        PKAssertProcedureCancelledWithError(functional, ProcedureKitError.dependency(finishedWithError: error))\n    }\n    \n}\n"
  },
  {
    "path": "Tests/ProcedureKitTests/MutualExclusivityTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport TestingProcedureKit\n@testable import ProcedureKit\n\nclass MutualExclusiveTests: ProcedureKitTestCase {\n\n    func test__mutual_exclusive_name() {\n        let condition = MutuallyExclusive<Procedure>()\n        XCTAssertEqual(condition.name, \"MutuallyExclusive<Procedure>\")\n    }\n\n    func test__mutual_exclusive_category() {\n        let condition = MutuallyExclusive<Procedure>(category: \"testing\")\n        XCTAssertEqual(condition.mutuallyExclusiveCategories, [\"testing\"])\n    }\n\n    func test__alert_presentation_is_mutually_exclusive() {\n        let condition = MutuallyExclusive<Procedure>()\n        XCTAssertTrue(condition.isMutuallyExclusive)\n    }\n\n    func test__alert_presentation_evaluation_satisfied() {\n        let condition = MutuallyExclusive<Procedure>()\n        condition.evaluate(procedure: TestProcedure()) { result in\n            switch result {\n            case .success(true):\n                return XCTAssertTrue(true)\n            default:\n                return XCTFail(\"Condition should evaluate true.\")\n            }\n        }\n    }\n\n    func test__mutually_exclusive_operations_can_be_executed() {\n        let procedure1 = TestProcedure()\n        procedure1.name = \"Procedure 1\"\n        procedure1.addCondition(MutuallyExclusive<TestProcedure>())\n\n        let procedure2 = TestProcedure()\n        procedure2.name = \"Procedure 2\"\n        procedure2.addCondition(MutuallyExclusive<TestProcedure>())\n\n        wait(for: procedure1, procedure2)\n    }\n\n    func test__procedure_mutual_exclusivity_internal_API_contract() {\n        class CustomProcedureQueue: ProcedureQueue {\n            typealias RequestLockObserver = (Set<String>) -> Void\n            typealias ProcedureClaimLockObserver = (ExclusivityLockTicket) -> Void\n            typealias UnlockObservers = (Set<String>) -> Void\n\n            private let requestLockCallback: RequestLockObserver\n            private let procedureClaimLockCallback: ProcedureClaimLockObserver\n            private let unlockCallback: UnlockObservers\n\n            init(requestLock: @escaping RequestLockObserver, procedureClaimLock: @escaping ProcedureClaimLockObserver, unlock: @escaping UnlockObservers) {\n                requestLockCallback = requestLock\n                procedureClaimLockCallback = procedureClaimLock\n                unlockCallback = unlock\n            }\n\n            internal override func requestLock(for mutuallyExclusiveCategories: Set<String>, completion: @escaping (ExclusivityLockTicket) -> Void) {\n                DispatchQueue.main.async {\n                    self.requestLockCallback(mutuallyExclusiveCategories)\n                    super.requestLock(for: mutuallyExclusiveCategories, completion: completion)\n                }\n            }\n\n            internal override func procedureClaimLock(withTicket ticket: ExclusivityLockTicket, completion: @escaping () -> Void) {\n                DispatchQueue.main.async {\n                    self.procedureClaimLockCallback(ticket)\n                    super.procedureClaimLock(withTicket: ticket, completion: completion)\n                }\n            }\n\n            internal override func unlock(mutuallyExclusiveCategories categories: Set<String>) {\n                DispatchQueue.main.async {\n                    self.unlockCallback(categories)\n                    super.unlock(mutuallyExclusiveCategories: categories)\n                }\n            }\n        }\n\n        struct DummyExclusivity { }\n\n        let calledRequestLock = Protector(false)\n        let calledProcedureClaimLock = Protector(false)\n        let calledUnlock = Protector(false)\n\n        let procedure = TestProcedure()\n        let mutuallyExclusiveConditions = [MutuallyExclusive<TestProcedure>(), MutuallyExclusive<DummyExclusivity>()]\n        let expectedMutuallyExclusiveCategories = Set(mutuallyExclusiveConditions.map { $0.mutuallyExclusiveCategories }.joined())\n        print(\"\\(expectedMutuallyExclusiveCategories)\")\n        mutuallyExclusiveConditions.forEach { procedure.addCondition($0) }\n\n        procedure.addWillExecuteBlockObserver(synchronizedWith: DispatchQueue.main) { procedure, _ in\n            // The Procedure should have called procedureClaimLock prior\n            // to dispatching willExecute observers\n            XCTAssertTrue(calledProcedureClaimLock.access)\n        }\n\n        let queue = CustomProcedureQueue(\n            requestLock: { mutuallyExclusiveCategories in\n                // Requesting the lock should occur *prior* to the Procedure being ready\n                XCTAssertFalse(procedure.isReady)\n\n                // And only once\n                let previouslyCalledRequestLock = calledRequestLock.write({ (value) -> Bool in\n                    let previousValue = value\n                    value = true\n                    return previousValue\n                })\n                XCTAssertFalse(previouslyCalledRequestLock)\n\n                // And should contain the expected set of categories\n                XCTAssertEqual(mutuallyExclusiveCategories, expectedMutuallyExclusiveCategories)\n        },\n            procedureClaimLock: { ticket in\n                // Should be called *after* requestLock was called\n                XCTAssertTrue(calledRequestLock.access)\n\n                // Should only be called once for the Procedure\n                let previouslyCalledProcedureClaimLock = calledProcedureClaimLock.write({ (value) -> Bool in\n                    let previousValue = value\n                    value = true\n                    return previousValue\n                })\n                XCTAssertFalse(previouslyCalledProcedureClaimLock)\n\n                // At the point the procedure claims the lock, it should no longer be pending\n                // (i.e. it should have been started by the queue) but it also should not yet\n                // be executing\n                XCTAssertFalse(procedure.isPending)\n                XCTAssertFalse(procedure.isExecuting)\n                XCTAssertFalse(procedure.isFinished)\n\n                // The ticket should contain the original categories\n                XCTAssertEqual(ticket.mutuallyExclusiveCategories, expectedMutuallyExclusiveCategories)\n        },\n            unlock: { categories in\n                // Should be called after the Procedure has finished\n                XCTAssertTrue(procedure.isFinished)\n\n                // And after the required prior calls to requestLock, procedureClaimLock\n                XCTAssertTrue(calledRequestLock.access)\n                XCTAssertTrue(calledProcedureClaimLock.access)\n\n                // And only once\n                let previouslyCalledUnlock = calledUnlock.write({ (value) -> Bool in\n                    let previousValue = value\n                    value = true\n                    return previousValue\n                })\n                XCTAssertFalse(previouslyCalledUnlock)\n\n                // Providing the original categories\n                XCTAssertEqual(categories, expectedMutuallyExclusiveCategories)\n        }\n        )\n\n        addCompletionBlockTo(procedure: procedure)\n        queue.addOperation(procedure)\n        waitForExpectations(timeout: 3)\n\n        PKAssertProcedureFinished(procedure)\n        XCTAssertTrue(calledRequestLock.access)\n        XCTAssertTrue(calledProcedureClaimLock.access)\n        XCTAssertTrue(calledUnlock.access)\n    }\n}\n\nclass MutualExclusiveConcurrencyTests: ConcurrencyTestCase {\n\n    func test__mutually_exclusive_operation_are_run_exclusively() {\n\n        let numOperations = 3\n        let delayMicroseconds: useconds_t = 500_000 // 0.5 seconds\n\n        queue.maxConcurrentOperationCount = numOperations\n\n        concurrencyTest(operations: numOperations, withDelayMicroseconds: delayMicroseconds, withTimeout: 3,\n            withConfigureBlock: { (testOp) in\n                let condition = MutuallyExclusive<TrackingProcedure>()\n                testOp.addCondition(condition)\n                return testOp\n            },\n            withExpectations: Expectations(\n                checkMinimumDetected: 1,\n                checkMaximumDetected: 1,\n                checkAllProceduresFinished: true,\n                checkMinimumDuration: TimeInterval(useconds_t(numOperations) * delayMicroseconds) / 1000000.0\n            )\n        )\n    }\n\n    func test__mutually_exclusive_operations_added_concurrently_are_run_exclusively() {\n        // Attempt to add mutually exclusive operations to a queue simultaneously.\n        // This should not affect their mutual exclusivity.\n        // Covers Issue: https://github.com/ProcedureKit/ProcedureKit/issues/543\n\n        let numOperations = 3\n        let delayMicroseconds: useconds_t = 500000 // 0.5 seconds\n\n        queue.maxConcurrentOperationCount = numOperations\n\n        let procedures: [TrackingProcedure] = create(procedures: numOperations, delayMicroseconds: delayMicroseconds, withRegistrar: registrar).map {\n            let condition = MutuallyExclusive<TrackingProcedure>()\n            $0.addCondition(condition)\n            addCompletionBlockTo(procedure: $0, withExpectationDescription: \"\\(String(describing: $0.name)), didFinish\")\n            return $0\n        }\n\n        let startTime = CFAbsoluteTimeGetCurrent()\n\n        // add procedures to the queue simultaneously\n        let dispatchQueue = DispatchQueue.global(qos: .userInitiated)\n        for procedure in procedures {\n            dispatchQueue.async { [weak weakQueue = self.queue] in\n                guard let queue = weakQueue else { return }\n                queue.addOperation(procedure)\n            }\n        }\n\n        waitForExpectations(timeout: TimeInterval(numOperations), handler: nil)\n\n        let endTime = CFAbsoluteTimeGetCurrent()\n        let duration = Double(endTime) - Double(startTime)\n\n        XCTAssertResults(TestResult(procedures: procedures, duration: duration, registrar: registrar),\n            matchExpectations: Expectations(\n                checkMinimumDetected: 1,\n                checkMaximumDetected: 1,\n                checkAllProceduresFinished: true,\n                checkMinimumDuration: TimeInterval(useconds_t(numOperations) * delayMicroseconds) / 1000000.0\n            )\n        )\n    }\n\n    func test__mutual_exclusivity_with_dependencies() {\n        // The expected result is that procedure1 will run first and, once procedure1\n        // has finished, procedure2 will run.\n        //\n        // Previously, this test resulted in neither procedure finishing (i.e. deadlock).\n\n        // Two procedures that are mutually-exclusive\n        let procedure1 = TestProcedure()\n        procedure1.addCondition(MutuallyExclusive<TestProcedure>())\n        let procedure2 = TestProcedure()\n        procedure2.addCondition(MutuallyExclusive<TestProcedure>())\n\n        addCompletionBlockTo(procedures: [procedure1, procedure2])\n\n        // procedure2 will not run until procedure1 is complete\n        procedure2.addDependency(procedure1)\n\n        // add procedure2 to the queue first\n        queue.addOperation(procedure2).then(on: DispatchQueue.main) { [weak weakQueue = self.queue] in\n            guard let queue = weakQueue else { return }\n            // then add procedure1 to the queue\n            queue.addOperation(procedure1)\n        }\n\n        waitForExpectations(timeout: 2)\n\n        XCTAssertTrue(procedure1.isFinished)\n        XCTAssertTrue(procedure2.isFinished)\n    }\n\n    func test__mutual_exclusivity_when_initial_reference_to_queue_goes_away() {\n\n        class DoesNotFinishByItselfProcedure: Procedure {\n            override func execute() {\n                // does not finish by itself - the test must call finish()\n            }\n        }\n\n        weak var weakQueue: ProcedureQueue?\n        let procedure1 = DoesNotFinishByItselfProcedure()\n\n        let procedureFinishedGroup = DispatchGroup()\n        procedureFinishedGroup.enter()\n        procedure1.addDidFinishBlockObserver { _, _ in\n            procedureFinishedGroup.leave()\n        }\n\n        procedure1.addWillFinishBlockObserver(synchronizedWith: DispatchQueue.main) { _, _, _ in\n            guard let _ = weakQueue else {\n                // Neither NSOperationInternal (nor Procedure) appears to be holding a strong\n                // reference to the OperationQueue while the Operation is executing (i.e. prior to finish)\n                //\n                // The current mutual exclusivity implementation requires this,\n                // so Procedure must hold onto its own strong reference.\n                //\n                XCTFail(\"ERROR: The Procedure is about to finish, but nothing has a strong reference to the ProcedureQueue it's executing \\\"on\\\". This needs to be resolved by modifying Procedure to maintain a strong reference to its queue through finish.\")\n                return\n            }\n        }\n\n        autoreleasepool {\n\n            var queue: ProcedureQueue? = ProcedureQueue()\n\n            procedure1.addCondition(MutuallyExclusive<TestProcedure>())\n\n            let expProcedureWasStarted = expectation(description: \"Procedure was started - execute was called\")\n            procedure1.addDidExecuteBlockObserver(synchronizedWith: DispatchQueue.main) { _ in\n                // the Procedure has been started\n                expProcedureWasStarted.fulfill()\n            }\n\n            queue!.addOperation(procedure1)\n            waitForExpectations(timeout: 3) // wait for the Procedure to be started by the queue\n\n            // store a weak reference to the ProcedureQueue\n            weakQueue = queue\n\n            // get rid of our strong reference to the ProcedureQueue\n            queue = nil\n\n        }\n\n        // verify that the weak reference to the ProcedureQueue still exists\n        guard let _ = weakQueue else {\n            // Neither NSOperationInternal (nor Procedure) appears to be holding a strong\n            // reference to the OperationQueue while the Operation is executing (i.e. prior to finish)\n            //\n            // The current mutual exclusivity implementation requires this,\n            // so Procedure must hold onto its own strong reference.\n            //\n            XCTFail(\"ERROR: The Procedure is still executing, but nothing has a strong reference to the ProcedureQueue it's executing \\\"on\\\". This needs to be resolved by modifying Procedure to maintain a strong reference to its queue through finish.\")\n            return\n        }\n\n        // then finish the testing procedure\n        procedure1.finish()\n\n        // and wait for it to finish\n        let expProcedureDidFinish = expectation(description: \"Procedure did finish\")\n        procedureFinishedGroup.notify(queue: DispatchQueue.main) {\n            expProcedureDidFinish.fulfill()\n        }\n        waitForExpectations(timeout: 3)\n\n        PKAssertProcedureFinished(procedure1)\n    }\n}\n\n\n\n"
  },
  {
    "path": "Tests/ProcedureKitTests/NegatedConditionTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport TestingProcedureKit\n@testable import ProcedureKit\n\nclass NegatedConditionTests: ProcedureKitTestCase {\n\n    func test__procedure_with_negated_successful_condition_fails() {\n        procedure.addCondition(NegatedCondition(TrueCondition()))\n        wait(for: procedure)\n        PKAssertProcedureCancelledWithError(procedure, ProcedureKitError.conditionFailed())\n    }\n\n    func test__procedure_with_negated_failed_condition_succeeds() {\n        procedure.addCondition(NegatedCondition(FalseCondition()))\n        wait(for: procedure)\n        PKAssertProcedureFinished(procedure)\n    }\n\n    func test__procedure_with_negated_ignored_condition_succeeds() {\n        procedure.addCondition(NegatedCondition(IgnoredCondition(FalseCondition())))\n        wait(for: procedure)\n        PKAssertProcedureFinished(procedure)\n    }\n\n    func test__negated_condition_name() {\n        let negated = NegatedCondition(FalseCondition())\n        XCTAssertEqual(negated.name, \"Not<FalseCondition>\")\n    }\n}\n"
  },
  {
    "path": "Tests/ProcedureKitTests/NetworkObserverTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport TestingProcedureKit\n@testable import ProcedureKit\n\nclass TestableNetworkActivityIndicator: NetworkActivityIndicatorProtocol {\n    typealias IndicatorVisibilityDidChange = (Bool) -> Void\n\n    let visibilityDidChange: IndicatorVisibilityDidChange\n\n    init(_ didChange: @escaping IndicatorVisibilityDidChange) {\n        visibilityDidChange = didChange\n    }\n\n    #if swift(>=3.2)\n        var isNetworkActivityIndicatorVisible = false {\n            didSet {\n                visibilityDidChange(isNetworkActivityIndicatorVisible)\n            }\n        }\n    #else // Swift < 3.2 (Xcode 8.x)\n        var networkActivityIndicatorVisible = false {\n            didSet {\n                visibilityDidChange(networkActivityIndicatorVisible)\n            }\n        }\n    #endif\n}\n\nclass NetworkObserverTests: ProcedureKitTestCase {\n    var controller: NetworkActivityController!\n    var indicator: TestableNetworkActivityIndicator!\n    var _changes: Protector<[Bool]>!\n\n    var changes: [Bool] {\n        return _changes.read { $0 }\n    }\n\n    override func setUp() {\n        super.setUp()\n        weak var indicatorExpectation = expectation(description: \"Indicator Expectation\")\n        _changes = Protector<[Bool]>([])\n        indicator = TestableNetworkActivityIndicator { [weak weakChanges = _changes] visibility in\n            guard let changes = weakChanges else { return }\n            changes.append(visibility)\n            if !visibility {\n                DispatchQueue.main.async {\n                    guard let indicatorExpectation = indicatorExpectation else { return }\n                    indicatorExpectation.fulfill()\n                }\n            }\n        }\n        controller = NetworkActivityController(indicator: indicator)\n    }\n\n    override func tearDown() {\n        _changes = nil\n        indicator = nil\n        controller = nil\n        super.tearDown()\n    }\n\n    func test__network_indicator_shows_when_procedure_starts() {\n        procedure.addObserver(NetworkObserver(controller: controller))\n        wait(for: procedure, withTimeout: 5) { _ in\n            self.PKAssertProcedureFinished(self.procedure)\n            XCTAssertTrue(self.changes.first ?? false)\n        }\n    }\n\n    func test__network_indicator_hides_after_short_delay_when_procedure_finishes() {\n        procedure.addObserver(NetworkObserver(controller: controller))\n        wait(for: procedure, withTimeout: procedure.delay + controller.interval + 1.0) { _ in\n            self.PKAssertProcedureFinished(self.procedure)\n            guard self.changes.count == 2 else {\n                XCTFail(\"Too few changes\"); return\n            }\n            XCTAssertTrue(self.changes[0])\n            XCTAssertFalse(self.changes[1])\n        }\n    }\n\n    func test__network_indicator_only_changes_once_when_multiple_procedures_start() {\n        let procedure1 = TestProcedure(delay: 0.1)\n        procedure1.addObserver(NetworkObserver(controller: controller))\n        let procedure2 = TestProcedure(delay: 0.1)\n        procedure2.addObserver(NetworkObserver(controller: controller))\n\n        wait(for: procedure1, procedure2, withTimeout: max(procedure1.delay, procedure2.delay) + controller.interval + 1.0) { _ in\n            self.PKAssertProcedureFinished(procedure1)\n            self.PKAssertProcedureFinished(procedure2)\n            XCTAssertEqual(self.changes, [true, false])\n        }\n    }\n\n    func test__network_indicator_does_not_hide_before_all_procedures_are_finished() {\n\n        let timerInterval = 1.0\n\n        //\n        // Definitions:\n        //  timerInterval = the interval used inside NetworkIndicatorController for its Timer\n        //\n        // This test uses the following 3 operations to affect the NetworkIndicator:\n        //\n        //              [startTime]                                         [duration]\n        // procedure1   immediately                                         0.1 seconds\n        // procedure2   operation1.endTime + 0.1 seconds                    2 x timerInterval\n        // procedure3   operation1.endTime + timerInterval + (a bit extra)  0.1 seconds\n        //\n        // procedure1\n        //      - started immediately (by itself), triggers the network indicator, ends, and causes\n        //        NetworkIndicatorController to queue a Timer to remove the network indicator\n        // procedure2\n        //      - a \"long-running\" operation, starts after procedure1 finishes, but before the\n        //        Timer that was queued as a result of procedure1 finishing fires\n        //      - this should result in the Timer being cancelled before it fires, and the network\n        //        activity indicator remaining visible for the duration of procedure2\n        //        (procedure2 is the last operation to finish)\n        // procedure3\n        //      - a short procedure that starts after procedure2 is running, after the original Timer\n        //        that procedure1 triggered would have fired (if it weren't cancelled), and\n        //        ends before procedure2 is finished\n        //      - this should not change the visible state of the network indicator, as it should still\n        //        be visible (as a result of procedure2)\n        //\n        // The expected output of this timing and sequence of operations is a network indicator that\n        // shows at the start of procedure1, and disappears \"timerInterval\" seconds after the end of\n        // procedure2. (i.e. 2 visibility changes: true, false)\n        //\n        // Previously, this test would fail by producing 4 visibility changes: (true, false, true, false)\n        //\n\n        let controller = NetworkActivityController(timerInterval: timerInterval, indicator: indicator)\n\n        let procedure1 = TestProcedure(delay: 0.1)\n        procedure1.addObserver(NetworkObserver(controller: controller))\n\n        let procedure2 = TestProcedure(delay: (timerInterval * 2.0))\n        procedure2.addObserver(NetworkObserver(controller: controller))\n        let delayForProcedure2 = DelayProcedure(by: 0.1)\n        procedure2.addDependency(delayForProcedure2)\n        addCompletionBlockTo(procedure: procedure2)\n\n        let procedure3 = TestProcedure(delay: 0.1)\n        procedure3.addObserver(NetworkObserver(controller: controller))\n        let delayForProcedure3 = DelayProcedure(by: (timerInterval + 0.2))\n        procedure3.addDependency(delayForProcedure3)\n        addCompletionBlockTo(procedure: procedure3)\n\n        let afterFirstGroup = GroupProcedure(operations: delayForProcedure2, procedure2, delayForProcedure3, procedure3)\n        afterFirstGroup.addDependency(procedure1)\n\n        // wait until all procedures have finished and the timer has invalidated the network indicator\n\n        wait(for: procedure1, afterFirstGroup, withTimeout: (timerInterval + 0.5) * 3.0 + (timerInterval * 2.0)) { _ in\n            self.PKAssertProcedureFinished(procedure1)\n            self.PKAssertProcedureFinished(procedure2)\n            self.PKAssertProcedureFinished(procedure3)\n            XCTAssertEqual(self.changes, [true, false])\n        }\n    }\n}\n\n"
  },
  {
    "path": "Tests/ProcedureKitTests/NoFailedDependenciesConditionTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport TestingProcedureKit\n@testable import ProcedureKit\n\nclass NoFailedDependenciesConditionTests: ProcedureKitTestCase {\n\n    func test__procedure_with_no_dependencies_succeeds() {\n        procedure.addCondition(NoFailedDependenciesCondition())\n        wait(for: procedure)\n        PKAssertProcedureFinished(procedure)\n    }\n\n    func test__procedure_with_successful_dependency_succeeds() {\n        let dependency = TestProcedure()\n        procedure.addDependency(dependency)\n        procedure.addCondition(NoFailedDependenciesCondition())\n        wait(for: procedure, dependency)\n        PKAssertProcedureFinished(procedure)\n    }\n\n    func test__procedure_with_cancelled_dependency_fails() {\n        let dependency = createCancellingProcedure()\n        procedure.addDependency(dependency)\n        procedure.addCondition(NoFailedDependenciesCondition())\n        wait(for: procedure, dependency)\n        PKAssertProcedureError(procedure, ProcedureKitError.dependenciesCancelled())\n    }\n\n    func test__procedure_with_mixture_fails() {\n        let dependency1 = TestProcedure()\n        let dependency2 = createCancellingProcedure()\n\n        procedure.addDependency(dependency1)\n        procedure.addDependency(dependency2)\n        procedure.addCondition(NoFailedDependenciesCondition())\n        wait(for: procedure, dependency1, dependency2)\n        PKAssertProcedureError(procedure, ProcedureKitError.dependenciesCancelled())\n    }\n\n    func test__procedure_with_errored_dependency_fails() {\n        let dependency = TestProcedure(error: TestError())\n        procedure.addDependency(dependency)\n        procedure.addCondition(NoFailedDependenciesCondition())\n        wait(for: procedure, dependency)\n        PKAssertProcedureError(procedure, ProcedureKitError.dependenciesFailed())\n    }\n\n    func test__procedure_with_group_dependency_with_errored_child_fails() {\n        let dependency = GroupProcedure(operations: [TestProcedure(error: TestError())])\n        procedure.addDependency(dependency)\n        procedure.addCondition(NoFailedDependenciesCondition())\n        wait(for: procedure, dependency)\n        PKAssertProcedureError(procedure, ProcedureKitError.dependenciesFailed())\n    }\n\n    func test__procedure_with_ignored_cancellations() {\n        let dependency = createCancellingProcedure()\n        procedure.addDependency(dependency)\n        procedure.addCondition(NoFailedDependenciesCondition(ignoreCancellations: true))\n        wait(for: procedure, dependency)\n        PKAssertProcedureCancelled(procedure)\n    }\n\n    func test__procedure_with_failures_and_cancellations_with_ignore_cancellations() {\n\n        let dependency1 = createCancellingProcedure()\n        procedure.addDependency(dependency1)\n\n        let dependency2 = TestProcedure(error: TestError())\n        procedure.addDependency(dependency2)\n\n        let dependency3 = TestProcedure()\n        procedure.addDependency(dependency3)\n\n        procedure.addCondition(NoFailedDependenciesCondition(ignoreCancellations: true))\n        wait(for: procedure, dependency1, dependency2, dependency3)\n        PKAssertProcedureCancelledWithError(procedure, ProcedureKitError.dependenciesFailed())\n    }\n}\n"
  },
  {
    "path": "Tests/ProcedureKitTests/ProcedureKitErrorTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport TestingProcedureKit\n@testable import ProcedureKit\n\nclass ProcedureKitErrorTests: XCTestCase {\n\n    struct TestComponent: ProcedureKitComponent {\n        let name = \"Test Component\"\n    }\n\n    var context: ProcedureKitError.Context!\n\n    func test__context_equality_capability() {\n        context = .capability(.unavailable)\n        XCTAssertEqual(context, ProcedureKitError.capabilityUnavailable().context)\n        XCTAssertNotEqual(context, ProcedureKitError.capabilityUnauthorized().context)\n        context = .capability(.unauthorized)\n        XCTAssertEqual(context, ProcedureKitError.capabilityUnauthorized().context)\n        XCTAssertNotEqual(context, ProcedureKitError.capabilityUnavailable().context)\n    }\n\n    func test__context_equality_component() {\n        context = .component(TestComponent())\n        XCTAssertEqual(context, ProcedureKitError.component(TestComponent(), error: TestError()).context)\n        XCTAssertNotEqual(context, ProcedureKitError.Context.unknown)\n    }\n\n    func test__context_equality_conditionFailed() {\n        context = .conditionFailed\n        XCTAssertEqual(context, ProcedureKitError.conditionFailed().context)\n        XCTAssertNotEqual(context, ProcedureKitError.Context.unknown)\n    }\n\n    func test__context_equality_dependenciesFailed() {\n        context = .dependenciesFailed\n        XCTAssertEqual(context, ProcedureKitError.dependenciesFailed().context)\n        XCTAssertNotEqual(context, ProcedureKitError.Context.unknown)\n    }\n\n    func test__context_equality_dependenciesCancelled() {\n        context = .dependenciesCancelled\n        XCTAssertEqual(context, ProcedureKitError.dependenciesCancelled().context)\n        XCTAssertNotEqual(context, ProcedureKitError.Context.unknown)\n    }\n\n    func test__context_equality_dependencyFinishedWithErrors() {\n        context = .dependencyFinishedWithError\n        XCTAssertEqual(context, ProcedureKitError.dependency(finishedWithError: TestError()).context)\n        XCTAssertNotEqual(context, ProcedureKitError.Context.unknown)\n    }\n\n    func test__context_equality_dependencyCancelledWithErrors() {\n        context = .dependencyCancelledWithError\n        XCTAssertEqual(context, ProcedureKitError.dependency(cancelledWithError: TestError()).context)\n        XCTAssertNotEqual(context, ProcedureKitError.Context.unknown)\n    }\n\n    func test__context_equality_noQueue() {\n        context = .noQueue\n        XCTAssertEqual(context, ProcedureKitError.noQueue().context)\n        XCTAssertNotEqual(context, ProcedureKitError.Context.unknown)\n    }\n\n    func test__context_equality_parentCancelledWithErrors() {\n        context = .parentCancelledWithError\n        XCTAssertEqual(context, ProcedureKitError.parent(cancelledWithError: TestError()).context)\n        XCTAssertNotEqual(context, ProcedureKitError.Context.unknown)\n    }\n\n    func test__context_equality_programmingError() {\n        context = .programmingError(\"Houston, we have a problem.\")\n        XCTAssertEqual(context, ProcedureKitError.programmingError(reason: \"Houston, we have a problem.\").context)\n        XCTAssertNotEqual(context, ProcedureKitError.programmingError(reason: \"Houston, we have a different problem.\").context)\n        XCTAssertNotEqual(context, ProcedureKitError.Context.unknown)\n    }\n\n    func test__context_equality_requirementNotSatisfied() {\n        context = .requirementNotSatisfied\n        XCTAssertEqual(context, ProcedureKitError.requirementNotSatisfied().context)\n        XCTAssertNotEqual(context, ProcedureKitError.Context.unknown)\n    }\n\n    func test__context_equality_timedOut() {\n        context = .timedOut(.by(10))\n        XCTAssertEqual(context, ProcedureKitError.timedOut(with: .by(10)).context)\n        XCTAssertNotEqual(context, ProcedureKitError.timedOut(with: .by(5)).context)\n        XCTAssertNotEqual(context, ProcedureKitError.Context.unknown)\n    }\n\n    func test__context_equality_unknown() {\n        context = .unknown\n        XCTAssertEqual(context, ProcedureKitError.unknown.context)\n    }\n\n}\n"
  },
  {
    "path": "Tests/ProcedureKitTests/ProcedureKitTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport TestingProcedureKit\n@testable import ProcedureKit\n\nclass TestSuiteRuns: XCTestCase {\n\n    func test__suite_runs() {\n        XCTAssertTrue(true)\n    }\n}\n"
  },
  {
    "path": "Tests/ProcedureKitTests/ProcedureTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport TestingProcedureKit\n@testable import ProcedureKit\n\nclass QueueDelegateTests: ProcedureKitTestCase {\n\n    class WeakExpectation {\n        private(set) weak var expectation: XCTestExpectation?\n        init(_ expectation: XCTestExpectation) {\n            self.expectation = expectation\n        }\n    }\n    var expectOperations: Protector<[Operation: WeakExpectation]>!\n    var expectProcedures: Protector<[Procedure: WeakExpectation]>!\n\n    open override func setUp() {\n        super.setUp()\n        let expectOperations = Protector<[Operation: WeakExpectation]>([:])\n        let expectProcedures = Protector<[Procedure: WeakExpectation]>([:])\n        self.expectOperations = expectOperations\n        self.expectProcedures = expectProcedures\n\n        set(queueDelegate: QueueTestDelegate() { callback in\n            switch callback {\n            case .didFinishOperation(_, let operation):\n                if let expForOperation = expectOperations.read({ (ward) -> WeakExpectation? in\n                    return ward[operation]\n                }) {\n                    DispatchQueue.main.async {\n                        expForOperation.expectation?.fulfill()\n                    }\n                }\n            case .didFinishProcedure(_, let procedure, _):\n                if let expForProcedure = expectProcedures.read({ (ward) -> WeakExpectation? in\n                    return ward[procedure]\n                }) {\n                    DispatchQueue.main.async {\n                        expForProcedure.expectation?.fulfill()\n                    }\n                }\n                break\n            default: break\n            }\n        })\n    }\n\n    open override func tearDown() {\n        expectOperations = nil\n        expectProcedures = nil\n        super.tearDown()\n    }\n\n    func expectQueueDelegateDidFinishFor(operations: [Operation] = [], procedures: [Procedure] = []) {\n        var operationExpectations = [Operation: WeakExpectation]()\n        operations.forEach {\n            assert(!($0 is Procedure), \"Passed a Procedure (\\($0)) to `operations:` - use `procedures:`. Different delegate callbacks are provided for Operations vs Procedures.\")\n            operationExpectations[$0] = WeakExpectation(expectation(description: \"Expecting \\($0.operationName) to generate didFinishOperation delegate callback.\"))\n        }\n        var procedureExpectations = [Procedure: WeakExpectation]()\n        procedures.forEach {\n            procedureExpectations[$0] = WeakExpectation(expectation(description: \"Expecting \\($0.operationName) to generate didFinishProcedure delegate callback.\"))\n        }\n\n        expectOperations.overwrite(with: operationExpectations)\n        expectProcedures.overwrite(with: procedureExpectations)\n    }\n\n    func test__delegate__operation_notifications() {\n\n        weak var expAddFinished = expectation(description: \"Test: \\(#function), queue.add did finish\")\n        weak var expOperationFinished = expectation(description: \"Test: \\(#function), Operation did finish\")\n        let operation = BlockOperation { }\n        let finishedProcedure = BlockProcedure { }\n        finishedProcedure.addDependency(operation)\n        finishedProcedure.addDidFinishBlockObserver { _, _ in\n            DispatchQueue.main.async {\n                expOperationFinished?.fulfill()\n            }\n        }\n\n        expectQueueDelegateDidFinishFor(operations: [operation], procedures: [finishedProcedure])\n\n        queue.addOperations([operation, finishedProcedure]).then(on: DispatchQueue.main) {\n            expAddFinished?.fulfill()\n        }\n        waitForExpectations(timeout: 3)\n\n        XCTAssertFalse(delegate.procedureQueueWillAddOperation.isEmpty)\n        XCTAssertFalse(delegate.procedureQueueDidAddOperation.isEmpty)\n        XCTAssertFalse(delegate.procedureQueueDidFinishOperation.isEmpty)\n    }\n\n    func test___delegate__procedure_notifications() {\n\n        weak var expAddFinished = expectation(description: \"Test: \\(#function), queue.add did finish\")\n        addCompletionBlockTo(procedure: procedure)\n\n        expectQueueDelegateDidFinishFor(procedures: [procedure])\n\n        queue.addOperation(procedure).then(on: DispatchQueue.main) {\n            expAddFinished?.fulfill()\n        }\n        waitForExpectations(timeout: 3)\n\n        XCTAssertFalse(delegate.procedureQueueWillAddProcedure.isEmpty)\n        XCTAssertFalse(delegate.procedureQueueDidAddProcedure.isEmpty)\n        XCTAssertFalse(delegate.procedureQueueWillFinishProcedure.isEmpty)\n        XCTAssertFalse(delegate.procedureQueueDidFinishProcedure.isEmpty)\n    }\n\n    func test__delegate__operationqueue_addoperation() {\n        // Testing OperationQueue's\n        // `open func addOperation(_ op: Operation)`\n        // on a ProcedureQueue to ensure that it goes through the\n        // overriden ProcedureQueue add path.\n\n        weak var didExecuteOperation = expectation(description: \"Test: \\(#function), did execute block\")\n        let operation = BlockOperation{\n            DispatchQueue.main.async {\n                didExecuteOperation?.fulfill()\n            }\n        }\n\n        expectQueueDelegateDidFinishFor(operations: [operation])\n\n        queue.addOperation(operation)\n\n        waitForExpectations(timeout: 3)\n\n        XCTAssertFalse(delegate.procedureQueueWillAddOperation.isEmpty)\n        XCTAssertFalse(delegate.procedureQueueDidAddOperation.isEmpty)\n        XCTAssertFalse(delegate.procedureQueueDidFinishOperation.isEmpty)\n    }\n\n    func test__delegate__operationqueue_addoperation_waituntilfinished() {\n        // Testing OperationQueue's\n        // `open func addOperations(_ ops: [Operation], waitUntilFinished wait: Bool)`\n        // on a ProcedureQueue to ensure that it goes through the\n        // overriden ProcedureQueue add path and that it *doesn't* wait.\n\n        weak var didExecuteOperation = expectation(description: \"Test: \\(#function), Operation did finish without being waited on by addOperations(_:waitUntilFinished:)\")\n        let operationCanProceed = DispatchSemaphore(value: 0)\n        let operation = BlockOperation{\n            guard operationCanProceed.wait(timeout: .now() + 1.0) == .success else {\n                // do not fulfill expectation, because main never signaled that this\n                // operation can proceed\n                return\n            }\n            DispatchQueue.main.async {\n                didExecuteOperation?.fulfill()\n            }\n        }\n\n        expectQueueDelegateDidFinishFor(operations: [operation])\n\n        queue.addOperations([operation], waitUntilFinished: true)\n        operationCanProceed.signal()\n\n        waitForExpectations(timeout: 2)\n\n        XCTAssertFalse(delegate.procedureQueueWillAddOperation.isEmpty)\n        XCTAssertFalse(delegate.procedureQueueDidAddOperation.isEmpty)\n        XCTAssertFalse(delegate.procedureQueueDidFinishOperation.isEmpty)\n    }\n\n    func test__delegate__operationqueue_addoperation_block() {\n        // Testing OperationQueue's\n        // `open func addOperation(_ block: @escaping () -> Swift.Void)`\n        // on a ProcedureQueue to ensure that it goes through the\n        // overriden ProcedureQueue add path.\n\n        weak var didExecuteBlock = expectation(description: \"Test: \\(#function), did execute block\")\n        queue.isSuspended = true\n        queue.addOperation({\n            DispatchQueue.main.async {\n                didExecuteBlock?.fulfill()\n            }\n        })\n\n        // check the queue to see if a new BlockOperation has been created\n        XCTAssertEqual(queue.operations.count, 1)\n        XCTAssertTrue(queue.operations[0] is BlockOperation, \"First item in Queue is not the expected BlockOperation\")\n\n        expectQueueDelegateDidFinishFor(operations: [queue.operations[0]])\n\n        // resume the queue and wait for the BlockOperation to finish\n        queue.isSuspended = false\n        waitForExpectations(timeout: 3)\n\n        XCTAssertFalse(delegate.procedureQueueWillAddOperation.isEmpty)\n        XCTAssertFalse(delegate.procedureQueueDidAddOperation.isEmpty)\n        XCTAssertFalse(delegate.procedureQueueDidFinishOperation.isEmpty)\n    }\n}\n\nclass ExecutionTests: ProcedureKitTestCase {\n\n    func test__procedure_executes() {\n        wait(for: procedure)\n        XCTAssertTrue(procedure.didExecute)\n    }\n\n    func test__procedure_add_multiple_completion_blocks() {\n        weak var expect = expectation(description: \"Test: \\(#function), \\(UUID())\")\n\n        var completionBlockOneDidRun = 0\n        procedure.addCompletionBlock {\n            completionBlockOneDidRun += 1\n        }\n\n        var completionBlockTwoDidRun = 0\n        procedure.addCompletionBlock {\n            completionBlockTwoDidRun += 1\n        }\n\n        var finalCompletionBlockDidRun = 0\n        procedure.addCompletionBlock {\n            finalCompletionBlockDidRun += 1\n            DispatchQueue.main.async {\n                guard let expect = expect else { print(\"Test: \\(#function): Finished expectation after timeout\"); return }\n                expect.fulfill()\n            }\n        }\n\n        wait(for: procedure)\n\n        XCTAssertEqual(completionBlockOneDidRun, 1)\n        XCTAssertEqual(completionBlockTwoDidRun, 1)\n        XCTAssertEqual(finalCompletionBlockDidRun, 1)\n    }\n\n    func test__enqueue_a_sequence_of_operations() {\n        addCompletionBlockTo(procedure: procedure, withExpectationDescription: \"\\(#function)\")\n        [procedure].enqueue()\n        waitForExpectations(timeout: 3, handler: nil)\n        PKAssertProcedureFinished(procedure)\n    }\n\n    func test__enqueue_a_sequence_of_operations_deallocates_queue() {\n        addCompletionBlockTo(procedure: procedure, withExpectationDescription: \"\\(#function)\")\n        var nilQueue: ProcedureQueue! = ProcedureQueue()\n        weak var weakQueue = nilQueue\n        [procedure].enqueue(on: weakQueue!)\n        nilQueue = nil\n        waitForExpectations(timeout: 3, handler: nil)\n        XCTAssertNil(nilQueue)\n        XCTAssertNil(weakQueue)\n    }\n\n    func test__procedure_executes_on_underlying_queue_of_procedurequeue() {\n        // If a Procedure is added to a ProcedureQueue with an `underlyingQueue` configured,\n        // the Procedure's `execute()` function should run on the underlyingQueue.\n\n        class TestExecuteOnUnderlyingQueueProcedure: Procedure {\n\n            public typealias Block = () -> Void\n            private let block: Block\n\n            public init(block: @escaping Block) {\n                self.block = block\n                super.init()\n            }\n\n            open override func execute() {\n                block()\n                finish()\n            }\n        }\n\n        let customDispatchQueueLabel = \"run.kit.procedure.ProcedureKit.Tests.TestUnderlyingQueue\"\n        let customDispatchQueue = DispatchQueue(label: customDispatchQueueLabel, attributes: [.concurrent])\n        let customScheduler = ProcedureKit.Scheduler(queue: customDispatchQueue)\n\n        let procedureQueue = ProcedureQueue()\n        procedureQueue.underlyingQueue = customDispatchQueue\n\n        let didExecuteOnDesiredQueue = Protector(false)\n        let procedure = TestExecuteOnUnderlyingQueueProcedure {\n            // inside execute()\n            if customScheduler.isOnScheduledQueue {\n                didExecuteOnDesiredQueue.overwrite(with: true)\n            }\n        }\n\n        addCompletionBlockTo(procedure: procedure)\n        procedureQueue.addOperation(procedure)\n        waitForExpectations(timeout: 3)\n\n        XCTAssertTrue(didExecuteOnDesiredQueue.access, \"execute() did not execute on the desired underlyingQueue\")\n    }\n}\n\nimport Dispatch\n\nclass QualityOfServiceTests: ProcedureKitTestCase {\n\n    private func testQoSClassLevels(_ block: (QualityOfService) -> Void) {\n        #if os(macOS)\n        block(.userInteractive)\n        block(.userInitiated)\n        #else\n        block(.userInteractive)\n        block(.userInitiated)\n        block(.`default`)\n        #endif\n    }\n\n    func test__procedure__set_quality_of_service__procedure_execute() {\n        testQoSClassLevels { desiredQoS in\n            let recordedQoSClass = Protector<DispatchQoS.QoSClass>(.unspecified)\n            let procedure = BlockProcedure {\n                recordedQoSClass.overwrite(with: DispatchQueue.currentQoSClass)\n            }\n            procedure.qualityOfService = desiredQoS\n            wait(for: procedure, withExpectationDescription: \"Procedure Did Finish (QoSClassLevel: \\(desiredQoS.qosClass))\")\n            XCTAssertEqual(recordedQoSClass.access, desiredQoS.qosClass)\n        }\n    }\n\n    func test__procedure__set_quality_of_service__will_execute_observer() {\n        testQoSClassLevels { desiredQoS in\n            let recordedQoSClass = Protector<DispatchQoS.QoSClass>(.unspecified)\n            let procedure = TestProcedure()\n            procedure.addWillExecuteBlockObserver { procedure, _ in\n                recordedQoSClass.overwrite(with: DispatchQueue.currentQoSClass)\n            }\n            procedure.qualityOfService = desiredQoS\n            wait(for: procedure, withExpectationDescription: \"Procedure Did Finish (QoSClassLevel: \\(desiredQoS.qosClass))\")\n            XCTAssertEqual(recordedQoSClass.access, desiredQoS.qosClass)\n        }\n    }\n\n    func test__procedure__set_quality_of_service__execute_after_will_execute_on_custom_queue() {\n        testQoSClassLevels { desiredQoS in\n            let recordedQoSClass_willExecute_otherQueue = Protector<DispatchQoS.QoSClass>(.unspecified)\n            let recordedQoSClass_willExecute = Protector<DispatchQoS.QoSClass>(.unspecified)\n            let recordedQoSClass_execute = Protector<DispatchQoS.QoSClass>(.unspecified)\n            let procedure = BlockProcedure {\n                recordedQoSClass_execute.overwrite(with: DispatchQueue.currentQoSClass)\n            }\n            // 1st WillExecute observer has a custom queue with no specified QoS level\n            // the submitted observer block should run with a QoS at least that of the desiredQoS level\n            let otherQueue = DispatchQueue(label: \"run.kit.procedure.ProcedureKit.Testing.OtherQueue\")\n            procedure.addWillExecuteBlockObserver(synchronizedWith: otherQueue) { procedure, _ in\n                recordedQoSClass_willExecute_otherQueue.overwrite(with: DispatchQueue.currentQoSClass)\n            }\n            // 2nd WillExecute observer has no custom queue (runs on the Procedure's EventQueue)\n            // the observer block should run with a QoS level equal to the desiredQoS level\n            procedure.addWillExecuteBlockObserver { procedure, _ in\n                recordedQoSClass_willExecute.overwrite(with: DispatchQueue.currentQoSClass)\n            }\n            procedure.qualityOfService = desiredQoS\n            wait(for: procedure, withExpectationDescription: \"Procedure Did Finish (QoSClassLevel: \\(desiredQoS.qosClass))\")\n            XCTAssertGreaterThanOrEqual(recordedQoSClass_willExecute_otherQueue.access, desiredQoS.qosClass)\n            XCTAssertEqual(recordedQoSClass_willExecute.access, desiredQoS.qosClass)\n            XCTAssertEqual(recordedQoSClass_execute.access, desiredQoS.qosClass)\n        }\n    }\n\n    func test__procedure__set_quality_of_service__did_cancel_observer() {\n        testQoSClassLevels { desiredQoS in\n            weak var expDidCancel = expectation(description: \"did cancel Procedure with qualityOfService: \\(desiredQoS.qosClass)\")\n            let recordedQoSClass = Protector<DispatchQoS.QoSClass>(.unspecified)\n            let procedure = TestProcedure()\n            procedure.addDidCancelBlockObserver { procedure, _ in\n                recordedQoSClass.overwrite(with: DispatchQueue.currentQoSClass)\n                DispatchQueue.main.async { expDidCancel?.fulfill() }\n            }\n            procedure.qualityOfService = desiredQoS\n            procedure.cancel()\n            waitForExpectations(timeout: 3)\n            // DidCancel observers should be executed with the qualityOfService of the Procedure\n            XCTAssertEqual(recordedQoSClass.access, desiredQoS.qosClass)\n        }\n    }\n}\n\nclass ProcedureTests: ProcedureKitTestCase {\n\n    func test__procedure_name() {\n        let block = BlockProcedure { }\n        XCTAssertEqual(block.name, \"BlockProcedure\")\n\n        let group = GroupProcedure(operations: [])\n        XCTAssertEqual(group.name, \"GroupProcedure\")\n\n        wait(for: group)\n    }\n\n    func test__identity_is_equatable() {\n        let identity1 = procedure.identity\n        let identity2 = procedure.identity\n        XCTAssertEqual(identity1, identity2)\n    }\n\n    func test__identity_description() {\n        XCTAssertTrue(procedure.identity.description.hasPrefix(\"TestProcedure #\"))\n        procedure.name = nil\n        XCTAssertTrue(procedure.identity.description.hasPrefix(\"Unnamed Procedure #\"))\n    }\n}\n\nclass DependencyTests: ProcedureKitTestCase {\n\n    func test__operation_added_using_then_follows_receiver() {\n        let another = TestProcedure()\n        let operations = procedure.then(do: another)\n        XCTAssertEqual(operations, [procedure, another])\n        wait(for: procedure, another)\n        XCTAssertLessThan(procedure.executedAt, another.executedAt)\n    }\n\n    func test__operation_added_using_then_via_closure_follows_receiver() {\n        let another = TestProcedure()\n        let operations = procedure.then { another }\n        XCTAssertEqual(operations, [procedure, another])\n        wait(for: procedure, another)\n        XCTAssertLessThan(procedure.executedAt, another.executedAt)\n    }\n\n    func test__operation_added_using_then_via_closure_returning_nil() {\n        XCTAssertEqual(procedure.then { nil }, [procedure])\n    }\n\n    func test__operation_added_using_then_via_closure_throwing_error() {\n        do {\n            let _ = try procedure.then { throw TestError() }\n        }\n        catch is TestError { }\n        catch { XCTFail(\"Caught unexpected error.\") }\n    }\n\n    func test__operation_added_to_array_using_then() {\n        let one = TestProcedure()\n        let two = TestProcedure(delay: 1)\n        let didFinishAnother = DispatchGroup()\n        didFinishAnother.enter()\n        let another = TestProcedure()\n        another.addDidFinishBlockObserver { _, _ in\n            didFinishAnother.leave()\n        }\n        let all = [one, two, procedure].then(do: another)\n        XCTAssertEqual(all.count, 4)\n        run(operation: another)\n        wait(for: procedure)\n        // wait should time out because all of `one`, `two`, `procedure` should be waited on to start `another`\n        XCTAssertEqual(didFinishAnother.wait(timeout: .now() + 0.1), .timedOut)\n\n        weak var expDidFinishAnother = expectation(description: \"DidFinish: another\")\n        didFinishAnother.notify(queue: DispatchQueue.main) {\n            expDidFinishAnother?.fulfill()\n        }\n        wait(for: one, two) // wait for `one`, `two` and `another` (after `one` and `two`) to finish\n        PKAssertProcedureFinished(another)\n        XCTAssertLessThan(one.executedAt, another.executedAt)\n        XCTAssertLessThan(two.executedAt, another.executedAt)\n        XCTAssertLessThan(procedure.executedAt, another.executedAt)\n    }\n\n    func test__operation_added_to_array_using_then_via_closure() {\n        let one = TestProcedure()\n        let two = TestProcedure(delay: 1)\n        let another = TestProcedure()\n        let all = [one, two, procedure].then { another }\n        XCTAssertEqual(all.count, 4)\n        wait(for: one, two, procedure, another)\n        PKAssertProcedureFinished(another)\n        XCTAssertLessThan(one.executedAt, another.executedAt)\n        XCTAssertLessThan(two.executedAt, another.executedAt)\n        XCTAssertLessThan(procedure.executedAt, another.executedAt)\n    }\n\n    func test__operation_added_to_array_using_then_via_closure_throwing_error() {\n        let one = TestProcedure()\n        let two = TestProcedure(delay: 1)\n        do {\n            let _ = try [one, two, procedure].then { throw TestError() }\n        }\n        catch is TestError { }\n        catch { XCTFail(\"Caught unexpected error.\") }\n    }\n\n    func test__operation_added_to_array_using_then_via_closure_returning_nil() {\n        let one = TestProcedure()\n        let two = TestProcedure(delay: 1)\n        let all = [one, two, procedure].then { nil }\n        XCTAssertEqual(all.count, 3)\n    }\n}\n\nclass ProduceTests: ProcedureKitTestCase {\n\n    func test__procedure_produce_operation() {\n        let producedOperation = BlockProcedure { usleep(5000) }\n        producedOperation.name = \"ProducedOperation\"\n        let procedure = EventConcurrencyTrackingProcedure() { procedure in\n            try! procedure.produce(operation: producedOperation) // swiftlint:disable:this force_try\n            procedure.finish()\n        }\n        addCompletionBlockTo(procedure: producedOperation) // also wait for the producedOperation to finish\n        wait(for: procedure)\n        PKAssertProcedureFinished(producedOperation)\n        PKAssertProcedureFinished(procedure)\n        PKAssertProcedureNoConcurrentEvents(procedure)\n    }\n\n    func test__procedure_produce_operation_before_execute() {\n        let producedOperation = BlockProcedure { usleep(5000) }\n        producedOperation.name = \"ProducedOperation\"\n        let procedure = EventConcurrencyTrackingProcedure() { procedure in\n            procedure.finish()\n        }\n        procedure.addWillExecuteBlockObserver { procedure, pendingExecute in\n            try! procedure.produce(operation: producedOperation, before: pendingExecute) // swiftlint:disable:this force_try\n        }\n        addCompletionBlockTo(procedure: producedOperation) // also wait for the producedOperation to finish\n        wait(for: procedure)\n        PKAssertProcedureFinished(producedOperation)\n        PKAssertProcedureFinished(procedure)\n        PKAssertProcedureNoConcurrentEvents(procedure)\n    }\n\n    func test__procedure_produce_operation_before_execute_async() {\n        let didExecuteWillAddObserverForProducedOperation = Protector(false)\n        let procedureIsExecuting_InWillAddObserver = Protector(false)\n        let procedureIsFinished_InWillAddObserver = Protector(false)\n\n        let producedOperation = BlockProcedure { usleep(5000) }\n        producedOperation.name = \"ProducedOperation\"\n        let procedure = EventConcurrencyTrackingProcedure() { procedure in\n            procedure.finish()\n        }\n        procedure.addWillExecuteBlockObserver { procedure, pendingExecute in\n            DispatchQueue.global().asyncAfter(deadline: .now() + 0.5) {\n                // despite this being executed long after the willExecute observer has returned\n                // (and a delay), by passing the pendingExecute event to the produce function\n                // it should ensure that `procedure` does not execute until producing the\n                // operation succeeds (i.e. until all WillAdd observers have been fired and it's\n                // added to the queue)\n                try! procedure.produce(operation: producedOperation, before: pendingExecute) // swiftlint:disable:this force_try\n            }\n        }\n        procedure.addWillAddOperationBlockObserver { procedure, operation in\n            guard operation === producedOperation else { return }\n            didExecuteWillAddObserverForProducedOperation.overwrite(with: true)\n            procedureIsExecuting_InWillAddObserver.overwrite(with: procedure.isExecuting)\n            procedureIsFinished_InWillAddObserver.overwrite(with: procedure.isFinished)\n        }\n        addCompletionBlockTo(procedure: producedOperation) // also wait for the producedOperation to finish\n        wait(for: procedure)\n        PKAssertProcedureFinished(producedOperation)\n        PKAssertProcedureFinished(procedure)\n        XCTAssertTrue(didExecuteWillAddObserverForProducedOperation.access, \"procedure never executed its WillAddOperation observer for the produced operation\")\n        XCTAssertFalse(procedureIsExecuting_InWillAddObserver.access, \"procedure was executing when its WillAddOperation observer was fired for the produced operation\")\n        XCTAssertFalse(procedureIsFinished_InWillAddObserver.access, \"procedure was finished when its WillAddOperation observer was fired for the produced operation\")\n    }\n\n    func test__procedure_produce_operation_before_finish() {\n        let producedOperation = BlockProcedure { usleep(5000) }\n        producedOperation.name = \"ProducedOperation\"\n        let procedure = EventConcurrencyTrackingProcedure() { procedure in\n            procedure.finish()\n        }\n        procedure.addWillFinishBlockObserver { procedure, errors, pendingFinish in\n            try! procedure.produce(operation: producedOperation, before: pendingFinish) // swiftlint:disable:this force_try\n        }\n        addCompletionBlockTo(procedure: producedOperation) // also wait for the producedOperation to finish\n        wait(for: procedure)\n        PKAssertProcedureFinished(producedOperation)\n        PKAssertProcedureFinished(procedure)\n    }\n\n    func test__procedure_produce_operation_before_finish_async() {\n        let didExecuteWillAddObserverForProducedOperation = Protector(false)\n        let procedureIsExecuting_InWillAddObserver = Protector(false)\n        let procedureIsFinished_InWillAddObserver = Protector(false)\n\n        let producedOperation = BlockProcedure { usleep(5000) }\n        producedOperation.name = \"ProducedOperation\"\n        let procedure = EventConcurrencyTrackingProcedure() { procedure in\n            procedure.finish()\n        }\n        procedure.addWillFinishBlockObserver { procedure, errors, pendingFinish in\n            DispatchQueue.global().asyncAfter(deadline: .now() + 0.5) {\n                // despite this being executed long after the willFinish observer has returned\n                // (and a delay), by passing the pendingFinish event to the produce function\n                // it should ensure that `procedure` does not finish until producing the\n                // operation succeeds (i.e. until all WillAdd observers have been fired and it's\n                // added to the queue)\n                try! procedure.produce(operation: producedOperation, before: pendingFinish) // swiftlint:disable:this force_try\n            }\n        }\n        procedure.addWillAddOperationBlockObserver { procedure, operation in\n            guard operation === producedOperation else { return }\n            didExecuteWillAddObserverForProducedOperation.overwrite(with: true)\n            procedureIsExecuting_InWillAddObserver.overwrite(with: procedure.isExecuting)\n            procedureIsFinished_InWillAddObserver.overwrite(with: procedure.isFinished)\n        }\n        addCompletionBlockTo(procedure: producedOperation) // also wait for the producedOperation to finish\n        wait(for: procedure)\n        PKAssertProcedureFinished(producedOperation)\n        PKAssertProcedureFinished(procedure)\n        XCTAssertTrue(didExecuteWillAddObserverForProducedOperation.access, \"procedure never executed its WillAddOperation observer for the produced operation\")\n        XCTAssertFalse(procedureIsExecuting_InWillAddObserver.access, \"procedure was executing when its WillAddOperation observer was fired for the produced operation\")\n        XCTAssertFalse(procedureIsFinished_InWillAddObserver.access, \"procedure was finished when its WillAddOperation observer was fired for the produced operation\")\n    }\n}\n\nclass ObserverEventQueueTests: ProcedureKitTestCase {\n\n    func test__custom_observer_with_event_queue() {\n        let didFinishGroup = DispatchGroup()\n        didFinishGroup.enter()\n        let eventsNotOnSpecifiedQueue = Protector<[EventConcurrencyTrackingRegistrar.ProcedureEvent]>([])\n        let eventsOnSpecifiedQueue = Protector<[EventConcurrencyTrackingRegistrar.ProcedureEvent]>([])\n        let registrar = EventConcurrencyTrackingRegistrar()\n        let customEventQueue = EventQueue(label: \"run.kit.procedure.ProcedureKit.Testing.ObserverCustomEventQueue\")\n        let observer = ConcurrencyTrackingObserver(registrar: registrar, eventQueue: customEventQueue, callbackBlock: { procedure, event in\n            guard customEventQueue.isOnQueue else {\n                eventsNotOnSpecifiedQueue.append(event)//((procedure.operationName, event))\n                return\n            }\n            eventsOnSpecifiedQueue.append(event)//((procedure.operationName, event))\n        })\n        let procedure = EventConcurrencyTrackingProcedure(name: \"TestingProcedure\") { procedure in\n            procedure.finish()\n        }\n        procedure.addObserver(observer)\n        procedure.addDidFinishBlockObserver { _, _ in\n            didFinishGroup.leave()\n        }\n\n        let finishing = BlockProcedure { }\n        finishing.addDependency(procedure)\n\n        run(operation: procedure)\n        wait(for: finishing)\n\n        // Because Procedure signals isFinished KVO *prior* to calling DidFinish observers,\n        // the above wait() may return before the ConcurrencyTrackingObserver is called to\n        // record the DidFinish event.\n        // Thus, wait on a second observer added *after* the ConcurrencyTrackingObserver\n        // to ensure the event is captured by this test.\n        weak var expDidFinishObserverFired = expectation(description: \"DidFinishObserver was fired\")\n        didFinishGroup.notify(queue: DispatchQueue.main) {\n            expDidFinishObserverFired?.fulfill()\n        }\n        waitForExpectations(timeout: 2)\n\n        XCTAssertTrue(eventsNotOnSpecifiedQueue.access.isEmpty, \"Found events not on expected queue: \\(eventsNotOnSpecifiedQueue.access)\")\n\n        let expectedEventsOnQueue: [EventConcurrencyTrackingRegistrar.ProcedureEvent] = [.observer_didAttach, .observer_willExecute, .observer_didExecute, .observer_willFinish, .observer_didFinish]\n\n        XCTAssertEqual(eventsOnSpecifiedQueue.access, expectedEventsOnQueue)\n    }\n\n    func test__custom_observer_with_event_queue_same_as_self() {\n        let procedure = EventConcurrencyTrackingProcedure(name: \"TestingProcedure\") { procedure in\n            procedure.finish()\n        }\n\n        let registrar = EventConcurrencyTrackingRegistrar()\n        // NOTE: Don't do this. This is just for testing.\n        let observer = ConcurrencyTrackingObserver(registrar: registrar, eventQueue: procedure.eventQueue)\n        procedure.addObserver(observer)\n\n        let finishing = BlockProcedure { }\n        finishing.addDependency(procedure)\n\n        run(operation: procedure)\n        wait(for: finishing) // This test should not timeout.\n    }\n}\n\nclass MainQueueTests: XCTestCase {\n\n    func test__operation_queue_main_has_underlyingqueue_main() {\n        guard let underlyingQueue = OperationQueue.main.underlyingQueue else {\n            XCTFail(\"OperationQueue.main is missing any set underlyingQueue.\")\n            return\n        }\n        XCTAssertTrue(underlyingQueue.isMainDispatchQueue, \"OperationQueue.main.underlyingQueue does not seem to be the same as DispatchQueue.main\")\n    }\n\n    func test__procedure_queue_main_has_underlyingqueue_main() {\n        guard let underlyingQueue = ProcedureQueue.main.underlyingQueue else {\n            XCTFail(\"ProcedureQueue.main is missing any set underlyingQueue.\")\n            return\n        }\n        XCTAssertTrue(underlyingQueue.isMainDispatchQueue, \"ProcedureQueue.main.underlyingQueue does not seem to be the same as DispatchQueue.main\")\n    }\n}\n"
  },
  {
    "path": "Tests/ProcedureKitTests/ProfilerTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport TestingProcedureKit\n@testable import ProcedureKit\n\n\nclass TestableProfileReporter: ProcedureProfilerReporter {\n\n    let didProfileResultGroup = DispatchGroup()\n\n    init() {\n        didProfileResultGroup.enter()\n    }\n    deinit {\n        guard let _ = didProfileResult else {\n            // did not finish profiling before going out of scope\n            // missing matching leave for DispatchGroup.enter()\n            didProfileResultGroup.leave()\n            return\n        }\n    }\n\n    var didProfileResult: ProfileResult? {\n        get { return _didProfileResult.access }\n        set { _didProfileResult.overwrite(with: newValue) }\n    }\n\n    var _didProfileResult = Protector<ProfileResult?>(.none)\n\n    func finishedProfiling(withResult result: ProfileResult) {\n        didProfileResult = result\n        didProfileResultGroup.leave()\n    }\n}\n\nclass ProfilerTests: ProcedureKitTestCase {\n\n    var now: TimeInterval!\n    var reporter: TestableProfileReporter!\n    var profiler: ProcedureProfiler!\n\n    override func setUp() {\n        super.setUp()\n        now = CFAbsoluteTimeGetCurrent() as TimeInterval\n        reporter = TestableProfileReporter()\n        profiler = ProcedureProfiler(reporter)\n    }\n\n    override func tearDown() {\n        profiler = nil\n        reporter = nil\n        super.tearDown()\n    }\n\n    func waitForReporterAnd(for procedure: Procedure, withTimeout timeout: TimeInterval = 3, withExpectationDescription expectationDescription: String = #function) {\n        wait(for: procedure, andReporter: reporter, withTimeout: timeout, withExpectationDescription: expectationDescription)\n    }\n\n    func wait(for procedure: Procedure, andReporter reporter: TestableProfileReporter, withTimeout timeout: TimeInterval = 3, withExpectationDescription expectationDescription: String = #function) {\n\n        // Wait for the Procedure to finish\n        wait(for: procedure, withTimeout: timeout, withExpectationDescription: expectationDescription)\n\n        // - Profiling finishes via a DidFinish observer on the Procedure\n        // - The above wait may return prior to the DidFinish observer being called\n        // Thus, additionally wait for the TestableProfileReporter to be signaled\n        // with the ProfileResult.\n        weak var exp = expectation(description: \"Finished profiling for: \\(expectationDescription)\")\n        reporter.didProfileResultGroup.notify(queue: DispatchQueue.main) {\n            exp?.fulfill()\n        }\n        waitForExpectations(timeout: timeout)\n    }\n\n    func validateProfileResult(result: ProfileResult, after: TimeInterval) {\n        XCTAssertGreaterThanOrEqual(result.created, after)\n        XCTAssertGreaterThan(result.attached, 0)\n        XCTAssertGreaterThanOrEqual(result.started, result.attached)\n        if let cancelled = result.cancelled {\n            XCTAssertGreaterThanOrEqual(cancelled, result.attached)\n            XCTAssertGreaterThanOrEqual(result.finished ?? 0.0, cancelled)\n        }\n        else if let finished = result.finished {\n            XCTAssertGreaterThanOrEqual(finished, result.started)\n        }\n        else {\n            XCTFail(\"Profile result neither cancelled nor finished!\"); return\n        }\n    }\n\n    func test__profile_simple_operation_which_finishes() {\n        procedure.addObserver(profiler)\n\n        waitForReporterAnd(for: procedure)\n        guard let result = reporter.didProfileResult else {\n            XCTFail(\"Reporter did not receive profile result.\"); return\n        }\n\n        validateProfileResult(result: result, after: now)\n        PKAssertProcedureFinished(procedure)\n    }\n\n    func test__profile_simple_operation_which_cancels() {\n\n        procedure.addObserver(WillExecuteObserver { op, _ in\n            op.cancel()\n        })\n        procedure.addObserver(profiler)\n        waitForReporterAnd(for: procedure)\n\n        guard let result = reporter.didProfileResult else {\n            XCTFail(\"Reporter did not receive profile result.\"); return\n        }\n\n        validateProfileResult(result: result, after: now)\n        PKAssertProcedureCancelled(procedure)\n    }\n\n    func test__profile_operation__which_produces_child() {\n\n        let child = TestProcedure()\n        // Also wait for the produced child to complete\n        addCompletionBlockTo(procedure: child)\n\n        procedure = TestProcedure(produced: child)\n        procedure.addObserver(profiler)\n\n        // Because of the addCompletionBlockTo line above, wait for the procedure *and*\n        // the child it produces to complete\n        waitForReporterAnd(for: procedure)\n\n        guard let result = reporter.didProfileResult else {\n            XCTFail(\"Reporter did not receive profile result.\"); return\n        }\n\n        validateProfileResult(result: result, after: now)\n        PKAssertProcedureFinished(procedure)\n        XCTAssertEqual(result.children.count, 1)\n        if let childResult = result.children.first {\n            validateProfileResult(result: childResult, after: now)\n        }\n    }\n\n    func test__profile_group_operation() {\n        let group = GroupProcedure(operations: [ TestProcedure(), TestProcedure() ])\n        group.addObserver(profiler)\n\n        waitForReporterAnd(for: group)\n\n        guard let result = reporter.didProfileResult else {\n            XCTFail(\"Reporter did not receive profile result.\"); return\n        }\n\n        validateProfileResult(result: result, after: now)\n        PKAssertProcedureFinished(group)\n\n        XCTAssertEqual(result.children.count, 2)\n        for child in result.children {\n            validateProfileResult(result: child, after: now)\n        }\n    }\n}\n"
  },
  {
    "path": "Tests/ProcedureKitTests/ReachabilityTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport SystemConfiguration\n@testable import ProcedureKit\nimport TestingProcedureKit\n\nclass SCNetworkReachabilityFlagsTests: XCTestCase {\n\n    var flags: SCNetworkReachabilityFlags!\n\n    override func tearDown() {\n        flags = nil\n        super.tearDown()\n    }\n\n    func test__flags_is_reachable() {\n        flags = .reachable\n        XCTAssertTrue(flags.isReachable)\n    }\n\n    func test__flags_isConnectionRequired() {\n        flags = .connectionRequired\n        XCTAssertTrue(flags.isConnectionRequired)\n    }\n\n    func test__flags_isInterventionRequired() {\n        flags = .interventionRequired\n        XCTAssertTrue(flags.isInterventionRequired)\n    }\n\n    func test__flags_isConnectionOnTraffic() {\n        flags = .connectionOnTraffic\n        XCTAssertTrue(flags.isConnectionOnTraffic)\n    }\n\n    func test__flags_isConnectionOnDemand() {\n        flags = .connectionOnDemand\n        XCTAssertTrue(flags.isConnectionOnDemand)\n    }\n\n    func test__flags_isConnectionOnTrafficOrDemand_when_onTraffic() {\n        flags = .connectionOnTraffic\n        XCTAssertTrue(flags.isConnectionOnTrafficOrDemand)\n    }\n\n    func test__flags_isConnectionOnTrafficOrDemand_when_onDemand() {\n        flags = .connectionOnDemand\n        XCTAssertTrue(flags.isConnectionOnTrafficOrDemand)\n    }\n\n    func test__flags_isTransientConnection() {\n        flags = .transientConnection\n        XCTAssertTrue(flags.isTransientConnection)\n    }\n\n    func test__flags_isLocalAddress() {\n        flags = .isLocalAddress\n        XCTAssertTrue(flags.isALocalAddress)\n    }\n\n    func test__flags_isDirect() {\n        flags = .isDirect\n        XCTAssertTrue(flags.isDirectConnection)\n    }\n\n    func test__flags_isConnectionRequiredOrTransient_whenRequired() {\n        flags = .connectionRequired\n        XCTAssertTrue(flags.isConnectionRequiredOrTransient)\n    }\n\n    func test__flags_isConnectionRequiredOrTransient_whenTransient() {\n        flags = .transientConnection\n        XCTAssertTrue(flags.isConnectionRequiredOrTransient)\n    }\n\n    func test__flags_isOnWWAN() {\n        #if os(iOS)\n            flags = .isWWAN\n            XCTAssertTrue(flags.isOnWWAN)\n        #else\n            flags = .reachable\n            XCTAssertFalse(flags.isOnWWAN)\n        #endif\n    }\n\n    func test__flags_isReachableViaWifi_true_when_Reachable() {\n        flags = .reachable\n        XCTAssertTrue(flags.isReachableViaWiFi)\n    }\n\n    func test__flags_isReachableViaWiFi_false_when_Reachable_but_ConnectionRequired() {\n        flags = [ .reachable, .connectionRequired ]\n        XCTAssertFalse(flags.isReachableViaWiFi)\n    }\n\n    func test__flags_isReachableViaWWAN() {\n        #if os(iOS)\n            flags = [ .reachable, .isWWAN ]\n            XCTAssertTrue(flags.isReachableViaWWAN)\n        #else\n            flags = .reachable\n            XCTAssertTrue(flags.isReachableViaWWAN)\n        #endif\n    }\n}\n\nclass NetworkStatusTests: XCTestCase {\n    typealias Status = Reachability.NetworkStatus\n\n    var flags: SCNetworkReachabilityFlags!\n\n    override func tearDown() {\n        flags = nil\n        super.tearDown()\n    }\n\n    func test__equality() {\n        XCTAssertEqual(Status.reachable(.any), Status.reachable(.any))\n        XCTAssertEqual(Status.reachable(.wifi), Status.reachable(.wifi))\n        XCTAssertEqual(Status.reachable(.wwan), Status.reachable(.wwan))\n        XCTAssertEqual(Status.notReachable, Status.notReachable)\n        XCTAssertNotEqual(Status.reachable(.any), Status.reachable(.wifi))\n        XCTAssertNotEqual(Status.reachable(.wifi), Status.reachable(.wwan))\n        XCTAssertNotEqual(Status.reachable(.wwan), Status.reachable(.wifi))\n        XCTAssertNotEqual(Status.notReachable, Status.reachable(.any))\n    }\n\n    func test__init_flags__reachable_via_wifi() {\n        flags = [ .reachable ]\n        XCTAssertEqual(Status(flags: flags), Status.reachable(.wifi))\n    }\n\n    func test__init_flags__reachable_via_wwan() {\n        #if os(iOS)\n            flags = [ .reachable, .isWWAN ]\n            XCTAssertEqual(Reachability.NetworkStatus(flags: flags), Reachability.NetworkStatus.reachable(.wwan))\n        #endif\n    }\n\n    func test__init_flags__not_reachable() {\n        flags = [ .connectionRequired ]\n        XCTAssertEqual(Status(flags: flags), Status.notReachable)\n    }\n\n    func test__not_reachable_is_not_connected() {\n        let status: Status = .notReachable\n        XCTAssertFalse(status.isConnected(via: .any))\n    }\n\n    func test__reachable_via_wwan_is_not_connected_for_wifi() {\n        let status: Status = .reachable(.wwan)\n        XCTAssertFalse(status.isConnected(via: .wifi))\n    }\n\n    func test__reachable_via_wifi_is_connected_for_wwan() {\n        let status: Status = .reachable(.wifi)\n        XCTAssertTrue(status.isConnected(via: .wwan))\n    }\n}\n\nclass ReachabilityObserverTests: XCTestCase {\n\n    func test__init() {\n        var didRunBlock = false\n        let observer = Reachability.Observer(connectivity: .any) { didRunBlock = true }\n        observer.didConnectBlock()\n        XCTAssertTrue(didRunBlock)\n    }\n}\n\n\n"
  },
  {
    "path": "Tests/ProcedureKitTests/ReduceProcedureTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport TestingProcedureKit\n@testable import ProcedureKit\n\nclass NumbersProcedure: ResultProcedure<Array<Int>> {\n\n    init(error: Error? = nil) {\n        super.init {\n            if let error = error { throw error }\n            return [0, 1, 2, 3, 4, 5 , 6 , 7, 8, 9]\n        }\n    }\n}\n\nclass ReduceProcedureTests: ProcedureKitTestCase {\n\n    func test__requirement_is_reduced_to_result() {\n        let reduced = ReduceProcedure(source: [0, 1, 2, 3, 4, 5 , 6 , 7, 8, 9], initial: 0, nextPartialResult: +)\n        wait(for: reduced)\n        PKAssertProcedureFinished(reduced)\n        XCTAssertEqual(reduced.output.success ?? 0, 45)\n    }\n\n    func test__finishes_with_error_if_block_throws() {\n        let error = TestError()\n        let reduced = ReduceProcedure(source: [0, 1, 2, 3, 4, 5 , 6 , 7, 8, 9], initial: 0) { _, _ in throw error }\n        wait(for: reduced)\n        PKAssertProcedureFinishedWithError(reduced, error)\n    }\n\n    func test__reduce_dependency_which_finishes_without_errors() {\n        let numbers = NumbersProcedure()\n        let reduced = numbers.reduce(0, nextPartialResult: +)\n        wait(for: numbers, reduced)\n        PKAssertProcedureFinished(numbers)\n        PKAssertProcedureFinished(reduced)\n        XCTAssertEqual(reduced.output.success ?? 0, 45)\n    }\n\n    func test__reduce_dependency_which_finishes_with_error() {\n        let error = TestError()\n        let numbers = NumbersProcedure(error: error)\n        let reduced = numbers.reduce(0, nextPartialResult: +)\n        wait(for: numbers, reduced)\n        PKAssertProcedureFinishedWithError(numbers, error)\n        PKAssertProcedureCancelledWithError(reduced, ProcedureKitError.dependency(finishedWithError: error))\n    }\n}\n"
  },
  {
    "path": "Tests/ProcedureKitTests/RepeatProcedureTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport TestingProcedureKit\n@testable import ProcedureKit\n\nclass RepeatProcedureTests: RepeatTestCase {\n\n    func test__init_with_max_and_custom_iterator() {\n        repeatProcedure = RepeatProcedure(max: 2, iterator: createIterator())\n        wait(for: repeatProcedure)\n        PKAssertProcedureFinished(repeatProcedure)\n        XCTAssertEqual(repeatProcedure.count, 2)\n    }\n\n    func test__init_with_max_and_delay_iterator() {\n        repeatProcedure = RepeatProcedure(max: 2, delay: Delay.Iterator.immediate, iterator: AnyIterator { TestProcedure() })\n        wait(for: repeatProcedure)\n        PKAssertProcedureFinished(repeatProcedure)\n        XCTAssertEqual(repeatProcedure.count, 2)\n    }\n\n    func test__init_with_max_and_wait_strategy() {\n        repeatProcedure = RepeatProcedure(max: 2, wait: .constant(0.001), iterator: AnyIterator { TestProcedure() })\n        wait(for: repeatProcedure)\n        PKAssertProcedureFinished(repeatProcedure)\n        XCTAssertEqual(repeatProcedure.count, 2)\n    }\n\n    func test__init_with_max_and_body() {\n        let procedureExecutedCount = Protector<Int>(0)\n        let repeatProcedure = RepeatProcedure(max: 2) { BlockProcedure(block: { procedureExecutedCount.advance(by: 1) }) }\n        wait(for: repeatProcedure)\n        PKAssertProcedureFinished(repeatProcedure)\n        XCTAssertEqual(repeatProcedure.count, 2)\n        XCTAssertEqual(procedureExecutedCount.access, 2)\n    }\n\n    func test__init_with_no_max_and_delay_iterator() {\n        repeatProcedure = RepeatProcedure(delay: Delay.Iterator.immediate, iterator: createIterator(succeedsAfterCount: 2))\n        wait(for: repeatProcedure)\n        XCTAssertEqual(repeatProcedure.count, 2)\n        PKAssertProcedureFinishedWithError(repeatProcedure, expectedError)\n    }\n\n    func test__init_with_no_max_and_wait_strategy() {\n        repeatProcedure = RepeatProcedure(wait: .constant(0.001), iterator: createIterator(succeedsAfterCount: 2))\n        wait(for: repeatProcedure)\n        XCTAssertEqual(repeatProcedure.count, 2)\n        PKAssertProcedureFinishedWithError(repeatProcedure, expectedError)\n    }\n\n    func test__append_configure_block() {\n\n        repeatProcedure = RepeatProcedure() { TestProcedure() }\n\n        var didRunConfigureBlock1 = false\n        repeatProcedure.appendConfigureBlock { _ in\n            didRunConfigureBlock1 = true\n        }\n\n        var didRunConfigureBlock2 = false\n        repeatProcedure.appendConfigureBlock { _ in\n            didRunConfigureBlock2 = true\n        }\n\n        repeatProcedure.configure(TestProcedure())\n        XCTAssertTrue(didRunConfigureBlock1)\n        XCTAssertTrue(didRunConfigureBlock2)\n    }\n\n    func test__replace_configure_block() {\n        repeatProcedure = RepeatProcedure() { TestProcedure() }\n\n        repeatProcedure.appendConfigureBlock { _ in\n            XCTFail(\"Configure block should have been replaced.\")\n        }\n\n        var didRunConfigureBlock = false\n        repeatProcedure.replaceConfigureBlock { _ in\n            didRunConfigureBlock = true\n        }\n\n        repeatProcedure.configure(TestProcedure())\n        XCTAssertTrue(didRunConfigureBlock)\n    }\n\n    func test__payload_with_configure_block_replaces_configure() {\n        var didExecuteConfigureBlock = 0\n        repeatProcedure = RepeatProcedure(max: 3, iterator: AnyIterator { RepeatProcedurePayload(operation: TestProcedure()) { _ in\n                didExecuteConfigureBlock = didExecuteConfigureBlock + 1\n            }\n        })\n\n        wait(for: repeatProcedure)\n        PKAssertProcedureFinished(repeatProcedure)\n        XCTAssertEqual(repeatProcedure.count, 3)\n        XCTAssertEqual(didExecuteConfigureBlock, 2)\n    }\n\n    func test__with_input_procedure_payload() {\n\n        let outputProcedure = TestProcedure()\n        outputProcedure.output = .ready(.success(\"ProcedureKit\"))\n        repeatProcedure = RepeatProcedure(max: 3, iterator: createIterator())\n\n        var textOutput: [String] = []\n        repeatProcedure.addWillAddOperationBlockObserver { (_, operation) in\n            if let procedure = operation as? TestProcedure {\n                procedure.addDidFinishBlockObserver { (testProcedure, _) in\n                    if let output = testProcedure.output.value?.value {\n                        textOutput.append(output)\n                    }\n                }\n            }\n        }\n\n        repeatProcedure.injectResult(from: outputProcedure)\n\n        wait(for: repeatProcedure, outputProcedure)\n        PKAssertProcedureFinished(repeatProcedure)\n\n        XCTAssertEqual(textOutput, [\"Hello ProcedureKit\", \"Hello ProcedureKit\", \"Hello ProcedureKit\"])\n    }\n}\n\n@available(*, deprecated, message: \"Protocol is now deprecated\")\nclass RepeatableTestProcedure: TestProcedure, Repeatable {\n\n    let limit: Int\n\n    init(limit: Int = 5) {\n        self.limit = limit\n        super.init()\n    }\n\n    func shouldRepeat(count: Int) -> Bool {\n        return count < limit\n    }\n}\n\n@available(*, deprecated, message: \"Protocol is now deprecated\")\nclass RepeatableRepeatProcedureTests: ProcedureKitTestCase {\n\n    func test__init_with_repeatable_procedure() {\n        let repeatProcedure = RepeatProcedure { RepeatableTestProcedure() }\n        wait(for: repeatProcedure)\n        PKAssertProcedureFinished(repeatProcedure)\n        XCTAssertEqual(repeatProcedure.count, 5)\n    }\n\n    func test__init_with_max_repeatable_procedure() {\n        let repeatProcedure = RepeatProcedure(max: 4) { RepeatableTestProcedure() }\n        wait(for: repeatProcedure)\n        PKAssertProcedureFinished(repeatProcedure)\n        XCTAssertEqual(repeatProcedure.count, 4)\n    }\n}\n\nclass IteratorTests: XCTestCase {\n\n    func test__finite__limits_are_not_exceeeded() {\n\n        var iterator = FiniteIterator(AnyIterator(stride(from: 0, to: 10, by: 1).makeIterator()), limit: 2)\n\n        guard let _ = iterator.next(), let _ = iterator.next() else {\n            XCTFail(\"Should return values up to a limit.\"); return\n        }\n\n        if let _ = iterator.next() {\n            XCTFail(\"Should not return a value once the limit is reached.\")\n        }\n    }\n}\n\nclass WaitStrategyTestCase: XCTestCase {\n\n    var strategy: WaitStrategy!\n    var iterator: AnyIterator<TimeInterval>!\n\n    func test__constant() {\n        strategy = .constant(1.0)\n        iterator = strategy.iterator\n        XCTAssertEqual(iterator.next(), 1.0)\n        XCTAssertEqual(iterator.next(), 1.0)\n        XCTAssertEqual(iterator.next(), 1.0)\n        XCTAssertEqual(iterator.next(), 1.0)\n        XCTAssertEqual(iterator.next(), 1.0)\n    }\n\n    func test__incrementing() {\n        strategy = .incrementing(initial: 0, increment: 3)\n        iterator = strategy.iterator\n        XCTAssertEqual(iterator.next(), 0)\n        XCTAssertEqual(iterator.next(), 3)\n        XCTAssertEqual(iterator.next(), 6)\n        XCTAssertEqual(iterator.next(), 9)\n        XCTAssertEqual(iterator.next(), 12)\n        XCTAssertEqual(iterator.next(), 15)\n    }\n\n    func test__fibonacci() {\n        strategy = .fibonacci(period: 1, maximum: 30.0)\n        iterator = strategy.iterator\n        XCTAssertEqual(iterator.next(), 0)\n        XCTAssertEqual(iterator.next(), 1)\n        XCTAssertEqual(iterator.next(), 1)\n        XCTAssertEqual(iterator.next(), 2)\n        XCTAssertEqual(iterator.next(), 3)\n        XCTAssertEqual(iterator.next(), 5)\n        XCTAssertEqual(iterator.next(), 8)\n        XCTAssertEqual(iterator.next(), 13)\n        XCTAssertEqual(iterator.next(), 21)\n        XCTAssertEqual(iterator.next(), 30)\n    }\n\n    func test__exponential() {\n        strategy = .exponential(power: 2.0, period: 1.0, maximum: 20.0)\n        iterator = strategy.iterator\n        XCTAssertEqual(iterator.next(), 1)\n        XCTAssertEqual(iterator.next(), 2)\n        XCTAssertEqual(iterator.next(), 4)\n        XCTAssertEqual(iterator.next(), 8)\n        XCTAssertEqual(iterator.next(), 16)\n        XCTAssertEqual(iterator.next(), 20)\n    }\n}\n\nclass DelayIteratorTests: XCTestCase {\n    var iterator: AnyIterator<Delay>!\n\n    func test__constant() {\n        iterator = Delay.Iterator.constant(1.0)\n        XCTAssertEqual(iterator.next(), .by(1.0))\n        XCTAssertEqual(iterator.next(), .by(1.0))\n        XCTAssertEqual(iterator.next(), .by(1.0))\n        XCTAssertEqual(iterator.next(), .by(1.0))\n        XCTAssertEqual(iterator.next(), .by(1.0))\n    }\n\n    func test__incrementing() {\n        iterator = Delay.Iterator.incrementing(from: 0, by: 3)\n        XCTAssertEqual(iterator.next(), .by(0))\n        XCTAssertEqual(iterator.next(), .by(3))\n        XCTAssertEqual(iterator.next(), .by(6))\n        XCTAssertEqual(iterator.next(), .by(9))\n        XCTAssertEqual(iterator.next(), .by(12))\n        XCTAssertEqual(iterator.next(), .by(15))\n    }\n\n    func test__fibonacci() {\n        iterator = Delay.Iterator.fibonacci(withPeriod: 1, andMaximum: 30.0)\n        XCTAssertEqual(iterator.next(), .by(0))\n        XCTAssertEqual(iterator.next(), .by(1))\n        XCTAssertEqual(iterator.next(), .by(1))\n        XCTAssertEqual(iterator.next(), .by(2))\n        XCTAssertEqual(iterator.next(), .by(3))\n        XCTAssertEqual(iterator.next(), .by(5))\n        XCTAssertEqual(iterator.next(), .by(8))\n        XCTAssertEqual(iterator.next(), .by(13))\n        XCTAssertEqual(iterator.next(), .by(21))\n        XCTAssertEqual(iterator.next(), .by(30))\n    }\n\n    func test__exponential() {\n        iterator = Delay.Iterator.exponential(power: 2.0, withPeriod: 1, andMaximum: 20.0)\n        XCTAssertEqual(iterator.next(), .by(1))\n        XCTAssertEqual(iterator.next(), .by(2))\n        XCTAssertEqual(iterator.next(), .by(4))\n        XCTAssertEqual(iterator.next(), .by(8))\n        XCTAssertEqual(iterator.next(), .by(16))\n        XCTAssertEqual(iterator.next(), .by(20))\n    }\n}\n\nclass RandomnessTests: StressTestCase {\n\n    func test__random_wait_strategy() {\n        let wait: WaitStrategy = .random(minimum: 1.0, maximum: 2.0)\n        let iterator = wait.iterator\n        stress(level: .custom(1, 100_000)) { batch, iteration in\n            guard let interval = iterator.next() else { XCTFail(\"randomness never stops.\"); return }\n            XCTAssertGreaterThanOrEqual(interval, 1.0)\n            XCTAssertLessThanOrEqual(interval, 2.0)\n        }\n    }\n\n    func test__random_delay_iterator() {\n        let iterator = Delay.Iterator.random(withMinimum: 1.0, andMaximum: 2.0)\n        stress(level: .custom(1, 100_000)) { batch, iteration in\n            guard let delay = iterator.next() else { XCTFail(\"randomness never stops.\"); return }\n            XCTAssertGreaterThanOrEqual(delay, .by(1.0))\n            XCTAssertLessThanOrEqual(delay, .by(2.0))\n        }\n    }\n\n    func test__random_fail_iterator() {\n        var iterator = RandomFailIterator(AnyIterator { true }, probability: 0.2)\n        var numberOfSuccess = 0\n        stress(level: .custom(1, 100_000)) { batch, iteration in\n            if let _ = iterator.next() {\n                numberOfSuccess = numberOfSuccess + 1\n            }\n        }\n        let probabilityFailure = Double(100_000 - numberOfSuccess) / 100_000.0\n        #if swift(>=3.2)\n             XCTAssertEqual(probabilityFailure, iterator.probability, accuracy: 0.10)\n        #else\n            XCTAssertEqualWithAccuracy(probabilityFailure, iterator.probability, accuracy: 0.10)\n        #endif\n    }\n}\n\n"
  },
  {
    "path": "Tests/ProcedureKitTests/ResultInjectionTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport TestingProcedureKit\n@testable import ProcedureKit\n\nclass DataProcessing: Procedure, InputProcedure, OutputProcedure {\n    var input: Pending<String> = .pending\n    var output: Pending<ProcedureResult<Void>> = pendingVoidResult\n\n    override func execute() {\n        guard let output = input.value else {\n            finish(with: ProcedureKitError.requirementNotSatisfied())\n            return\n        }\n        log.info.message(output)\n        finish()\n    }\n}\n\nclass Printing: Procedure, InputProcedure, OutputProcedure {\n    var input: Pending<String> = .ready(\"Default Requirement\")\n    var output: Pending<ProcedureResult<Void>> = pendingVoidResult\n\n    override func execute() {\n        if let message = input.value {\n            log.info.message(message)\n        }\n        finish()\n    }\n}\n\nclass ResultInjectionTestCase: ProcedureKitTestCase {\n    var processing: DataProcessing!\n    var printing: Printing!\n\n    override func setUp() {\n        super.setUp()\n        processing = DataProcessing()\n        printing = Printing()\n    }\n}\n\nclass ResultInjectionTests: ResultInjectionTestCase {\n\n    func test__block_is_executed() {\n        var injectionBlockDidExecute = false\n        processing.inject(dependency: procedure) { processing, dependency, error in\n            injectionBlockDidExecute = true\n        }\n        wait(for: procedure, processing)\n        XCTAssertTrue(injectionBlockDidExecute)\n    }\n\n    func test__block_passes_through_errors() {\n        let expectedError = TestError()\n        var receivedError: Error?\n        procedure = TestProcedure(error: expectedError)\n        processing.inject(dependency: procedure) { processing, dependency, error in\n            receivedError = expectedError\n        }\n        wait(for: procedure, processing)\n        guard let error = receivedError as? TestError else {\n            XCTFail(\"Did not receive an error\"); return\n        }\n        XCTAssertEqual(expectedError, error)\n    }\n\n    func test__automatic_requirement_is_injected() {\n        processing.injectResult(from: procedure)\n        wait(for: processing, procedure)\n        PKAssertProcedureFinished(processing)\n    }\n\n    func test__receiver_cancels_with_error_if_dependency_errors() {\n        let expectedError = TestError()\n        procedure = TestProcedure(error: expectedError)\n        processing.injectResult(from: procedure)\n        wait(for: processing, procedure)\n        PKAssertProcedureCancelledWithError(processing, ProcedureKitError.dependency(finishedWithError: expectedError))\n    }\n\n    func test__receiver_cancels_with_errors_if_requirement_not_met() {\n        procedure.output = .pending\n        printing.injectResult(from: procedure)\n        wait(for: printing, procedure)\n        PKAssertProcedureCancelledWithError(printing, ProcedureKitError.requirementNotSatisfied())\n    }\n\n    func test__receiver_cancels_if_dependency_is_cancelled() {\n        processing.injectResult(from: procedure)\n        procedure.cancel()\n        wait(for: processing, procedure)\n        PKAssertProcedureCancelledWithError(processing, ProcedureKitError.dependenciesCancelled())\n    }\n\n    func test__automatic_unwrap_when_result_is_optional_requrement() {\n        let hello = ResultProcedure<String?> { \"Hello, World\" }\n        let print = Printing().injectResult(from: hello)\n        wait(for: print, hello)\n        PKAssertProcedureFinished(print)\n    }\n\n    func test__automatic_unwrap_when_result_is_nil_optional_requrement() {\n        let hello = ResultProcedure<String?> { nil }\n        let printer = Printing().injectResult(from: hello)\n        wait(for: printer, hello)\n        PKAssertProcedureCancelledWithError(printer, ProcedureKitError.requirementNotSatisfied())\n    }\n\n    func test__collection_flatMap() {\n        let hello = ResultProcedure { \"Hello\" }\n        let world = ResultProcedure { \"World\" }\n        let mapped = [world, hello].flatMap { $0.uppercased() }\n        wait(forAll: [hello, world, mapped])\n        PKAssertProcedureFinished(hello)\n        PKAssertProcedureFinished(world)\n        PKAssertProcedureFinished(mapped)\n        PKAssertProcedureOutput(mapped, [\"WORLD\", \"HELLO\"])\n    }\n\n    func test__collection_reduce() {\n        let hello = ResultProcedure { \"Hello\" }\n        let world = ResultProcedure { \"World\" }\n        let helloWorld = [hello, world].reduce(\"\") { accumulator, element in\n            guard !accumulator.isEmpty else { return element }\n            return \"\\(accumulator) \\(element)\"\n        }\n        wait(forAll: [hello, world, helloWorld])\n        PKAssertProcedureFinished(hello)\n        PKAssertProcedureFinished(world)\n        PKAssertProcedureFinished(helloWorld)\n        PKAssertProcedureOutput(helloWorld, \"Hello World\")\n    }\n\n    func test__collection_reduce_which_throws_finishes_with_error() {\n        let hello = ResultProcedure { \"Hello\" }\n        let world = ResultProcedure { \"World\" }\n        let error = TestError()\n        let helloWorld = [hello, world].reduce(\"\") { _, _ in throw error }\n        wait(forAll: [hello, world, helloWorld])\n        PKAssertProcedureFinished(hello)\n        PKAssertProcedureFinished(world)\n        PKAssertProcedureFinishedWithError(helloWorld, error)\n        XCTAssertNil(helloWorld.output.success)\n    }\n\n    func test__collection_gather() {\n        let hello = ResultProcedure { \"Hello\" }\n        let world = ResultProcedure { \"World\" }\n        let gathered = [hello, world].gathered()\n\n        wait(forAll: [hello, world, gathered])\n        PKAssertProcedureFinished(hello)\n        PKAssertProcedureFinished(world)\n        PKAssertProcedureFinished(gathered)\n        PKAssertProcedureOutput(gathered, [\"Hello\", \"World\"])\n    }\n\n    func test__input_binding() {\n        let hello = ResultProcedure { \"Hello\" }\n        let world = TransformProcedure<String, String> { \"\\($0) World\" }.injectResult(from: hello)\n        let dan = TransformProcedure<String, String> { \"\\($0) Dan\" }\n        world.bind(to: dan) // Binds the same input to another procedure\n        dan.addDependency(world) // note that bind does not setup any dependencies.\n\n        wait(for: hello, world, dan)\n        PKAssertProcedureFinished(hello)\n        PKAssertProcedureFinished(world)\n        PKAssertProcedureFinished(dan)\n        PKAssertProcedureOutput(dan, \"Hello Dan\")\n    }\n\n    func test__binding() {\n\n        class TestGroup: TestGroupProcedure, InputProcedure, OutputProcedure {\n            var input: Pending<String> = .pending\n            var output: Pending<ProcedureResult<String>> = .pending\n\n            init() {\n                let world = TransformProcedure<String, String> { \"\\($0) World\" }\n                let result = TransformProcedure<String, String> { \"\\($0), we are running on ProcedureKit\" }\n                    .injectResult(from: world)\n\n                super.init(operations: [world, result])\n\n                // Note that we do not need to worry about dependencies here\n                // because the child procedures are by definition depending on\n                // the group's dependency to have finished.\n                bind(to: world)\n                bind(from: result)\n            }\n        }\n\n        let hello = ResultProcedure { \"Hello\" }\n        let group = TestGroup().injectResult(from: hello)\n\n        wait(for: hello, group)\n        PKAssertProcedureFinished(hello)\n        PKAssertProcedureFinished(group)\n        PKAssertProcedureOutput(group, \"Hello World, we are running on ProcedureKit\")\n    }\n}\n\n\n"
  },
  {
    "path": "Tests/ProcedureKitTests/RetryProcedureTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport TestingProcedureKit\n@testable import ProcedureKit\n\nclass RetryProcedureTests: RetryTestCase {\n\n    func test__with_payload_iterator() {\n        retry = Retry(iterator: createPayloadIterator(succeedsAfterFailureCount: 2), retry: { $1 })\n        wait(for: retry)\n        PKAssertProcedureFinished(retry)\n        XCTAssertEqual(retry.count, 3)\n    }\n\n    func test__with_max_count() {\n        retry = Retry(max: 2, iterator: createPayloadIterator(succeedsAfterFailureCount: 4), retry: { $1 })\n        wait(for: retry)\n        XCTAssertEqual(retry.count, 2)\n        PKAssertProcedureFinishedWithError(retry, ProcedureKitError.conditionFailed())\n    }\n\n    func test__with_delay_and_operation_iterator() {\n        retry = Retry(delay: Delay.Iterator.fibonacci(withPeriod: 0.001), iterator: createOperationIterator(succeedsAfterFailureCount: 2), retry: { $1 })\n        wait(for: retry)\n        PKAssertProcedureFinished(retry)\n        XCTAssertEqual(retry.count, 3)\n    }\n\n    func test__with_wait_strategy_and_operation_iterator() {\n        retry = Retry(wait: .incrementing(initial: 0, increment: 0.001), iterator: createOperationIterator(succeedsAfterFailureCount: 2), retry: { $1 })\n        wait(for: retry)\n        PKAssertProcedureFinished(retry)\n        XCTAssertEqual(retry.count, 3)\n    }\n\n    func test__with_block_fails_after_max() {\n        retry = Retry(upto: 3) { TestProcedure(error: ProcedureKitError.unknown) }\n        wait(for: retry)\n        PKAssertProcedureFinishedWithError(retry, ProcedureKitError.unknown)\n        XCTAssertEqual(retry.count, 3)\n    }\n\n    func test__with_input_procedure_payload() {\n\n        let outputProcedure = TestProcedure()\n        outputProcedure.output = .ready(.success(\"ProcedureKit\"))\n        retry = Retry(iterator: createPayloadIterator(succeedsAfterFailureCount: 2), retry: { $1 })\n\n        var textOutput: [String] = []\n        retry.addWillAddOperationBlockObserver { (_, operation) in\n            if let procedure = operation as? TestProcedure {\n                procedure.addDidFinishBlockObserver { (testProcedure, error) in\n                    guard error == nil else { return }\n                    if let output = testProcedure.output.value?.value {\n                        textOutput.append(output)\n                    }\n                }\n            }\n        }\n\n        retry.injectResult(from: outputProcedure)\n\n        wait(for: retry, outputProcedure)\n        PKAssertProcedureFinished(retry)\n\n        // TODO: - Fix Swift access race in implicit closure\n        XCTAssertEqual(textOutput, [\"Hello ProcedureKit\"])\n    }\n\n    func test__retry_deinits_after_finished() {\n        // Catches reference cycles.\n\n        class RetryDeinitMonitor<T: Procedure>: RetryProcedure<T> {\n            var deinitBlock: (() -> Void)?\n            override public init<OperationIterator>(dispatchQueue: DispatchQueue? = nil, max: Int? = nil, wait: WaitStrategy, iterator base: OperationIterator, retry block: @escaping Handler) where OperationIterator: IteratorProtocol, OperationIterator.Element == T {\n                super.init(dispatchQueue: dispatchQueue, max: max, wait: wait, iterator: base, retry: block)\n            }\n            deinit {\n                deinitBlock?()\n            }\n        }\n\n        weak var didDeinitExpectation = expectation(description: \"RetryProcedure Did DeInit\")\n        DispatchQueue.default.async {\n            let queue = ProcedureQueue()\n            let retry = RetryDeinitMonitor<TestProcedure>(wait: .incrementing(initial: 0, increment: 0.001), iterator: self.createOperationIterator(succeedsAfterFailureCount: 2), retry: { $1 })\n            retry.deinitBlock = {\n                DispatchQueue.main.async {\n                    guard let didDeinitExpectation = didDeinitExpectation else { return }\n                    didDeinitExpectation.fulfill()\n                }\n            }\n            let semaphore = DispatchSemaphore(value: 0)\n            retry.addDidFinishBlockObserver { _, _ in\n                semaphore.signal()\n            }\n            queue.addOperation(retry)\n            semaphore.wait()\n        }\n\n        waitForExpectations(timeout: 3) { (error) in\n            if error != nil {\n                XCTFail(\"RetryProcedure did not deinit - something still has a reference. (Possible cycle.)\")\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Tests/ProcedureKitTests/SilentConditionTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport TestingProcedureKit\n@testable import ProcedureKit\n\nclass SilentConditionTests: ProcedureKitTestCase {\n\n    func test__silent_condition_composes_name_correctly() {\n        let silent = SilentCondition(FalseCondition())\n        XCTAssertEqual(silent.name, \"Silent<FalseCondition>\")\n    }\n\n    func test__silent_condition_removes_produced_dependencies_from_composed_condition() {\n        let dependency = TestProcedure()\n        let condition = TrueCondition()\n        condition.produceDependency(dependency)\n        let _ = SilentCondition(condition)\n        XCTAssertEqual(condition.producedDependencies.count, 0)\n    }\n}\n"
  },
  {
    "path": "Tests/ProcedureKitTests/TimeoutObserverTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport TestingProcedureKit\n@testable import ProcedureKit\n\nfinal class TimeoutObserverTests: ProcedureKitTestCase {\n\n    func test__timeout_observer() {\n        procedure = TestProcedure(delay: 0.5)\n        procedure.addObserver(TimeoutObserver(by: 0.1))\n        wait(for: procedure)\n        PKAssertProcedureCancelledWithError(procedure, ProcedureKitError.timedOut(with: .by(0.1)))\n    }\n\n    func test__timeout_observer_with_date() {\n        let timestamp = Date() + 0.1\n        procedure = TestProcedure(delay: 0.5)\n        procedure.addObserver(TimeoutObserver(until: timestamp))\n        wait(for: procedure)\n        PKAssertProcedureCancelledWithError(procedure, ProcedureKitError.timedOut(with: .until(timestamp)))\n    }\n\n    func test__timeout_observer_where_procedure_is_already_cancelled() {\n        procedure = TestProcedure(delay: 0.5)\n        procedure.addObserver(TimeoutObserver(until: Date() + 0.1))\n        procedure.cancel()\n        wait(for: procedure)\n        PKAssertProcedureCancelled(procedure)\n    }\n\n    func test__timeout_observer_where_procedure_is_already_finished() {\n        procedure = TestProcedure()\n        procedure.addObserver(TimeoutObserver(by: 0.5))\n        wait(for: procedure)\n        PKAssertProcedureFinished(procedure)\n    }\n\n    func test__timeout_observer_negative_interval() {\n        procedure = TestProcedure()\n        procedure.addObserver(TimeoutObserver(by: -0.5))\n        wait(for: procedure)\n        PKAssertProcedureFinished(procedure)\n    }\n\n    func test__multiple_timeout_observers_on_a_single_procedure() {\n        procedure = TestProcedure(delay: 0.5)\n        procedure.addObserver(TimeoutObserver(by: 0.1))\n        procedure.addObserver(TimeoutObserver(by: 0.1))\n        procedure.addObserver(TimeoutObserver(by: 0.2))\n        procedure.addObserver(TimeoutObserver(by: 3.0))\n        wait(for: procedure)\n        PKAssertProcedureCancelledWithError(procedure, ProcedureKitError.timedOut(with: .by(0.1)))\n    }\n\n    func test__add_single_timeout_observer_to_multiple_procedures() {\n        let procedure1 = TestProcedure(delay: 0.5)\n        let procedure2 = TestProcedure(delay: 0.5)\n        let procedure3 = TestProcedure(delay: 0)\n        let timeoutObserver = TimeoutObserver(by: 0.1)\n        procedure1.addObserver(timeoutObserver)\n        procedure2.addObserver(timeoutObserver)\n        procedure3.addObserver(timeoutObserver)\n        wait(for: procedure1, procedure2, procedure3)\n        PKAssertProcedureCancelledWithError(procedure1, ProcedureKitError.timedOut(with: .by(0.1)))\n        PKAssertProcedureCancelledWithError(procedure2, ProcedureKitError.timedOut(with: .by(0.1)))\n        PKAssertProcedureFinished(procedure3)\n    }\n}\n"
  },
  {
    "path": "Tests/ProcedureKitTests/TransformProcedureTests.swift",
    "content": "//\n//  ProcedureKit\n//\n//  Copyright © 2015-2018 ProcedureKit. All rights reserved.\n//\n\nimport XCTest\nimport TestingProcedureKit\n@testable import ProcedureKit\n\nclass TransformProcedureTests: ProcedureKitTestCase {\n\n    func test__requirement_is_transformed_to_result() {\n        let timesTwo = TransformProcedure<Int, Int> { return $0 * 2 }\n        timesTwo.input = .ready(2)\n        wait(for: timesTwo)\n        PKAssertProcedureFinished(timesTwo)\n        XCTAssertEqual(timesTwo.output.success ?? 0, 4)\n    }\n\n    func test__requirement_is_nil_finishes_with_error() {\n        let timesTwo = TransformProcedure<Int, Int> { return $0 * 2 }\n        // Note that input has not been set\n        wait(for: timesTwo)\n        PKAssertProcedureError(timesTwo, ProcedureKitError.requirementNotSatisfied())\n    }\n}\n\nclass AsyncTransformProcedureTests: ProcedureKitTestCase {\n\n    var dispatchQueue: DispatchQueue!\n\n    override func setUp() {\n        super.setUp()\n        dispatchQueue = DispatchQueue.initiated\n    }\n\n    override func tearDown() {\n        dispatchQueue = nil\n        super.tearDown()\n    }\n    \n    func test__requirement_is_transformed_to_result() {\n        let timesTwo = AsyncTransformProcedure<Int, Int> { input, finishWithResult in\n            self.dispatchQueue.async {\n                finishWithResult(.success(input * 2))\n            }\n        }\n        timesTwo.input = .ready(2)\n        wait(for: timesTwo)\n        PKAssertProcedureFinished(timesTwo)\n        XCTAssertEqual(timesTwo.output.success ?? 0, 4)\n    }\n\n    func test__requirement_is_nil_finishes_with_error() {\n        let timesTwo = AsyncTransformProcedure<Int, Int> { input, finishWithResult in\n            self.dispatchQueue.async {\n                finishWithResult(.success(input * 2))\n            }\n        }\n        wait(for: timesTwo)\n        PKAssertProcedureError(timesTwo, ProcedureKitError.requirementNotSatisfied())\n    }\n}\n"
  }
]