[
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: 'type: bug'\nassignees: ''\n\n---\n\n## Bug Report\nA clear and concise description of what the bug is.\n\n**To Reproduce**\nSteps to reproduce the behavior:\n1. Step one...\n\n**Expected behavior**\nA clear and concise description of what you expected to happen.\n\n## Platform Information\n - OS: [e.g. iOS 13.4, watchOS 6.2.1, tvOS 9.2.3, macOS 10.14.3, Catalyst 13.0]\n - Purchase Type: [e.g. consumable, non-consumable, auto-renewable subscription, non-renewing subscription, discount]\n - Environment: [e.g. sandbox, app review, production]\n - SwiftyStoreKit version: [e.g. 0.16]\n\n\n## Additional context\nAdd any other context about the problem here.\n\n**Potentially Related Issues**\n - Issue #___\n\n**Screenshots**\nIf applicable, add screenshots to help explain your problem.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: 'type: enhancement'\nassignees: ''\n\n---\n\n**Is your feature request related to a problem? Please describe.**\nA clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n\n**Describe the solution you'd like**\nA clear and concise description of what you want to happen.\n\n**Describe alternatives you've considered**\nA clear and concise description of any alternative solutions or features you've considered.\n\n**Additional context**\nAdd any other context or screenshots about the feature request here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/question.md",
    "content": "---\nname: Question\nabout: General questions about SwiftyStoreKit\ntitle: ''\nlabels: 'type: question'\nassignees: ''\n\n---\n\n## Question\nPlease explain your question in detail here.\n"
  },
  {
    "path": ".gitignore",
    "content": "# Xcode\n.DS_Store\nbuild/\n*.pbxuser\n!default.pbxuser\n*.mode1v3\n!default.mode1v3\n*.mode2v3\n!default.mode2v3\n*.perspectivev3\n!default.perspectivev3\n*.xcworkspace\n!default.xcworkspace\nxcuserdata\nprofile\n*.moved-aside\nDerivedData\n.idea/\nxcodebuild.log\n# Pods - for those of you who use CocoaPods\nPods\n# emacs\n*~\n# Swift Package Manager\n.build/\n# Carthage\nCarthage/Build\n"
  },
  {
    "path": ".swiftlint.yml",
    "content": "# included:\n#     - Sources\n\n# rule identifiers to exclude from running\ndisabled_rules:\n- line_length\n- identifier_name\n- trailing_whitespace\n\n# configurable rules can be customized from this configuration file\nline_length: 250\n\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: objective-c\nosx_image: xcode11.5\n\nbefore_install:\n  - gem install xcpretty\n# - rvm get stable\n\ninstall:\n  - ./scripts/install_swiftlint.sh\n  - bundle install --path vendor/bundle\n\nscript:\n  - swiftlint\n  - ./scripts/build.sh\n  - bundle exec danger --verbose\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\n\n* Make `ProductsInfoController`'s `retrieveProductsInfo` thread safe ([#405]https://github.com/bizz84/SwiftyStoreKit/pull/495), related issues: [#344](https://github.com/bizz84/SwiftyStoreKit/issues/344) and [#468](https://github.com/bizz84/SwiftyStoreKit/issues/468)\n\n## [0.15.0](https://github.com/bizz84/SwiftyStoreKit/releases/tag/0.15.0) Update project to Swift 5, Xcode 10.2\n\n* Update project to Swift 5 ([#457](https://github.com/bizz84/SwiftyStoreKit/pull/457)), related issue: [#456](https://github.com/bizz84/SwiftyStoreKit/issues/456)\n* Add basic SwiftPM manifest file ([#460](https://github.com/bizz84/SwiftyStoreKit/pull/460))\n\n## [0.14.2](https://github.com/bizz84/SwiftyStoreKit/releases/tag/0.14.2) Remove `canMakePayments` check on purchase method\n\n* Remove `canMakePayments` check on purchase method ([#434](https://github.com/bizz84/SwiftyStoreKit/pull/434))\n\n## [0.14.1](https://github.com/bizz84/SwiftyStoreKit/releases/tag/0.14.1) Add missing `else` condition in `SwiftyStoreKit.purchaseProduct`\n\n* Add missing `else` condition in `SwiftyStoreKit.purchaseProduct` ([#426](https://github.com/bizz84/SwiftyStoreKit/pull/426))\n\n## [0.14.0](https://github.com/bizz84/SwiftyStoreKit/releases/tag/0.14.0) Add `isInIntroOfferPeriod` property, update project to Swift 4.2, Xcode 10\n\n* Added new property `isInIntroOfferPeriod` to ReceiptItem ([#404](https://github.com/bizz84/SwiftyStoreKit/pull/404), [#409](https://github.com/bizz84/SwiftyStoreKit/pull/409))\n* Add Swift 4.2 Support ([#408](https://github.com/bizz84/SwiftyStoreKit/pull/408)), update project to Xcode 10 ([#410](https://github.com/bizz84/SwiftyStoreKit/pull/410))\n\n## [0.13.3](https://github.com/bizz84/SwiftyStoreKit/releases/tag/0.13.3) Fix macOS compile error on Xcode 10.0 beta (10L176w)\n\n* Fix macOS compile error on Xcode 10.0 beta (10L176w) ([#381](https://github.com/bizz84/SwiftyStoreKit/pull/381), see [#380](https://github.com/bizz84/SwiftyStoreKit/issues/380))\n\n## [0.13.2](https://github.com/bizz84/SwiftyStoreKit/releases/tag/0.13.2) Swift 4.1 / Xcode 9.3 Support\n\n* Swift 4.1 / Xcode 9.3 Support ([#360](https://github.com/bizz84/SwiftyStoreKit/pull/360))\n\n## [0.13.1](https://github.com/bizz84/SwiftyStoreKit/releases/tag/0.13.1) Add support Ask To Buy\n\n* Add a wrapper for `simulatesAskToBuyInSandbox` ([#349](https://github.com/bizz84/SwiftyStoreKit/pull/349))\n\n## [0.13.0](https://github.com/bizz84/SwiftyStoreKit/releases/tag/0.13.0) Add support for downloading content hosted with Apple\n\n* Add support for downloading content hosted with Apple ([#343](https://github.com/bizz84/SwiftyStoreKit/pull/343), related issue: [#128](https://github.com/bizz84/SwiftyStoreKit/issues/128))\n* Add table of contents to README ([#346](https://github.com/bizz84/SwiftyStoreKit/pull/346))\n\n## [0.12.1](https://github.com/bizz84/SwiftyStoreKit/releases/tag/0.12.1) Assert that `completeTransactions` was called when the app launches.\n\n* Assert that `completeTransactions()` was called when the app launches ([#337](https://github.com/bizz84/SwiftyStoreKit/pull/337), related issue: [#287](https://github.com/bizz84/SwiftyStoreKit/issues/287))\n\n## [0.12.0](https://github.com/bizz84/SwiftyStoreKit/releases/tag/0.12.0) Add `verifySubscriptions` method for subscription groups \n\n* Add `verifySubscriptions` method to check all subscriptions in a group at once ([#333](https://github.com/bizz84/SwiftyStoreKit/pull/333), related issue: [#194](https://github.com/bizz84/SwiftyStoreKit/issues/194))\n* Rename `verifySubscription(type:productId:inReceipt:validUntil:)` to `verifySubscription(ofType:productId:inReceipt:validUntil:)` ([#333](https://github.com/bizz84/SwiftyStoreKit/pull/333))\n* Add video tutorials section in README ([#328](https://github.com/bizz84/SwiftyStoreKit/pull/328), [#330](https://github.com/bizz84/SwiftyStoreKit/pull/330), see [#326](https://github.com/bizz84/SwiftyStoreKit/issues/326))\n* Update iOS Demo App ([#327](https://github.com/bizz84/SwiftyStoreKit/pull/327), see [#147](https://github.com/bizz84/SwiftyStoreKit/issues/147))\n\n## [0.11.3](https://github.com/bizz84/SwiftyStoreKit/releases/tag/0.11.3) `completeTransactions` finishes failed transactions if `atomically: false`\n\n* Add `originalTransaction` to `PurchaseDetails` ([#323](https://github.com/bizz84/SwiftyStoreKit/pull/323), fix for [#302](https://github.com/bizz84/SwiftyStoreKit/issues/302))\n* Bug fix: `completeTransactions` finishes failed transactions if `atomically: false` ([#322](https://github.com/bizz84/SwiftyStoreKit/pull/322), related issues: [#307](https://github.com/bizz84/SwiftyStoreKit/issues/307), [#288](https://github.com/bizz84/SwiftyStoreKit/issues/288))\n\n## [0.11.2](https://github.com/bizz84/SwiftyStoreKit/releases/tag/0.11.2) Remove `SKProduct.localizedIntroductoryPrice`\n\n* Remove `localizedIntroductoryPrice` ([#320](https://github.com/bizz84/SwiftyStoreKit/pull/320), see [#319](https://github.com/bizz84/SwiftyStoreKit/issues/319), [#318](https://github.com/bizz84/SwiftyStoreKit/pull/318), [#315](https://github.com/bizz84/SwiftyStoreKit/pull/315))\n\n## [0.11.1](https://github.com/bizz84/SwiftyStoreKit/releases/tag/0.11.1) Add `PaymentTransaction.transactionDate` and  `SKProduct.localizedIntroductoryPrice`\n\n* Add `transactionDate` to `PaymentTransaction` ([#316](https://github.com/bizz84/SwiftyStoreKit/pull/316), see [#312](https://github.com/bizz84/SwiftyStoreKit/issues/312)).\n* Add `localizedIntroductoryPrice` to `SKProduct` ([#318](https://github.com/bizz84/SwiftyStoreKit/pull/318)).\n\n## [0.11.0](https://github.com/bizz84/SwiftyStoreKit/releases/tag/0.11.0) Add `fetchReceipt` method + update `verifyReceipt` and `ReceiptValidator` protocol\n\n* Add `fetchReceipt` method. Update `verifyReceipt` to use it ([#278](https://github.com/bizz84/SwiftyStoreKit/pull/278), related issues: [#272](https://github.com/bizz84/SwiftyStoreKit/issues/272), [#223](https://github.com/bizz84/SwiftyStoreKit/issues/223)).\n* Update `fetchReceipt` and `ReceiptValidator` to use receipt as `Data` rather than `String`. This is consistent with `localReceiptData` ([#284](https://github.com/bizz84/SwiftyStoreKit/pull/284), see [#272](https://github.com/bizz84/SwiftyStoreKit/issues/272)).\n* Remove `password` from `ReceiptValidator` protocol as this is specific to `AppleReceiptValidator` ([#281](https://github.com/bizz84/SwiftyStoreKit/pull/281/), see [#263](https://github.com/bizz84/SwiftyStoreKit/issues/263)). **Note**: This is an API breaking change.\n* Unwrap `receipt[\"receipt\"]?[\"in_app\"]` in two steps (addresses casting problems) ([#283](https://github.com/bizz84/SwiftyStoreKit/pull/283), related issue [#256](https://github.com/bizz84/SwiftyStoreKit/issues/256)).\n\n\n## [0.10.8](https://github.com/bizz84/SwiftyStoreKit/releases/tag/0.10.8) Update to swiftlint 0.22.0\n\n* Update to swiftlint 0.22.0 ([#270](https://github.com/bizz84/SwiftyStoreKit/pull/270), fix for [#273](https://github.com/bizz84/SwiftyStoreKit/issues/273))\n\n## [0.10.7](https://github.com/bizz84/SwiftyStoreKit/releases/tag/0.10.7) Fix for concurrent `retrieveProductsInfo` calls\n\n* `ProductsInfoController`: Keep track of multiple completion blocks for the same request ([#259](https://github.com/bizz84/SwiftyStoreKit/pull/259), fix for [#250](https://github.com/bizz84/SwiftyStoreKit/issues/250))\n\n## [0.10.6](https://github.com/bizz84/SwiftyStoreKit/releases/tag/0.10.6) Add support for shouldAddStorePayment\n\n* Add support for the new `SKPaymentTransactionObserver.shouldAddStorePayment` method in iOS 11 ([#257](https://github.com/bizz84/SwiftyStoreKit/pull/257), related issue: [#240](https://github.com/bizz84/SwiftyStoreKit/issues/240))\n* Update swiftlint to version 0.21.0 ([#258](https://github.com/bizz84/SwiftyStoreKit/pull/258))\n\n## [0.10.5](https://github.com/bizz84/SwiftyStoreKit/releases/tag/0.10.5) Filter out transactions in purchasing state\n* Filter out all transactions with `state == .purchasing` early in purchase flows (related to [#169](https://github.com/bizz84/SwiftyStoreKit/issues/169), [#188](https://github.com/bizz84/SwiftyStoreKit/pull/188), [#179](https://github.com/bizz84/SwiftyStoreKit/issues/179))\n* Sample app: print localized description when a purchase fails with `.unknown` error\n\n## [0.10.4](https://github.com/bizz84/SwiftyStoreKit/releases/tag/0.10.4) Documentation and updates for Xcode 9\n\n* Update to Xcode 9 recommended project settings ([#247](https://github.com/bizz84/SwiftyStoreKit/pull/247))\n* Update build script iOS version to 10.3.1 ([#245](https://github.com/bizz84/SwiftyStoreKit/pull/245))\n* Update notes about Xcode 9, Swift 4 support to README\n\n## [0.10.3](https://github.com/bizz84/SwiftyStoreKit/releases/tag/0.10.3) Add `forceRefresh` option to `verifyReceipt`\n\n* Add `forceRefresh` option to `verifyReceipt` ([#224](https://github.com/bizz84/SwiftyStoreKit/pull/224), fix for [#223](https://github.com/bizz84/SwiftyStoreKit/issues/223))\n\n## [0.10.2](https://github.com/bizz84/SwiftyStoreKit/releases/tag/0.10.2) Remove SKProduct caching\n\n* Remove SKProduct caching ([#222](https://github.com/bizz84/SwiftyStoreKit/pull/222), related issue: [#212](https://github.com/bizz84/SwiftyStoreKit/issues/212))\n* Adds new purchase product method based on SKProduct\n\n## [0.10.1](https://github.com/bizz84/SwiftyStoreKit/releases/tag/0.10.1) Danger, xcpretty integration\n\n* Adds Danger for better Pull Request etiquette ([#215](https://github.com/bizz84/SwiftyStoreKit/pull/215)).\n* Adds xcpretty to improve build logs ([#217](https://github.com/bizz84/SwiftyStoreKit/pull/217))\n* Update SwiftLint to 0.18.1 ([#218](https://github.com/bizz84/SwiftyStoreKit/pull/218))\n\n## [0.10.0](https://github.com/bizz84/SwiftyStoreKit/releases/tag/0.10.0) `verifyReceipt` now automatically refreshes the receipt if needed\n\n#### API removed: `refreshReceipt`\n\nThis release simplifies the receipt verification flows by removing the `refreshReceipt` method from the public API.\n\nNow clients only need to call `verifyReceipt` and the receipt is refreshed internally if needed.\n\nAddressed in [#213](https://github.com/bizz84/SwiftyStoreKit/pull/213), related issue: [#42](https://github.com/bizz84/SwiftyStoreKit/issues/42).\n\nThe documentation in the README and various methods has also been considerably improved.\n\n## [0.9.3](https://github.com/bizz84/SwiftyStoreKit/releases/tag/0.9.3) Dispatch callbacks on main thread on macOS\n\nThis is a minor release to ensure callbacks are dispatched on the main thread on macOS.\n\nPR [#214](https://github.com/bizz84/SwiftyStoreKit/pull/214), fix for [#211](https://github.com/bizz84/SwiftyStoreKit/issues/211).\n\n## [0.9.2](https://github.com/bizz84/SwiftyStoreKit/releases/tag/0.9.2) Fix for failing receipt verification due to missing optional field\n\nThis is a critical fix for [#208](https://github.com/bizz84/SwiftyStoreKit/issues/208).\n\nIf you're using release 0.9.0, please update.\n\n## [0.9.1](https://github.com/bizz84/SwiftyStoreKit/releases/tag/0.9.1) Expose SKProduct in PurchaseDetails type returned by PurchaseResult\n\nThis is a minor release which includes a fix for [#185](https://github.com/bizz84/SwiftyStoreKit/issues/185) (addressed in [#206](https://github.com/bizz84/SwiftyStoreKit/pull/206)). Summary:\n\nWhen a purchase succeeds, it is desirable to get access to the purchased `SKProduct` in the completion block, so that it's possible to query the `price` and other properties.\n\nWith this change, this is now possible:\n\n```swift\nSwiftyStoreKit.purchaseProduct(\"productId\", atomically: true) { result in\n    if case .success(let purchase) = result {\n        // Deliver content from server, then:\n        if purchase.needsFinishTransaction {\n            SwiftyStoreKit.finishTransaction(purchase.transaction)\n        }\n        print(\"Purchased product with price: \\(purchase.product.price)\")\n    }\n}\n```\n\n## [0.9.0](https://github.com/bizz84/SwiftyStoreKit/releases/edit/0.9.0) Verify Subscription improvements + added quantity and originalTransaction to Payment\n\n**NOTE** This release introduces some API breaking changes (see [#202](https://github.com/bizz84/SwiftyStoreKit/pull/202)). Change-set:\n\n### [#198](https://github.com/bizz84/SwiftyStoreKit/pull/198): Subscription verification unit tests\n\n### [#199](https://github.com/bizz84/SwiftyStoreKit/pull/199) (fixes [#192](https://github.com/bizz84/SwiftyStoreKit/issues/192), [#190](https://github.com/bizz84/SwiftyStoreKit/issues/190) and [#65](https://github.com/bizz84/SwiftyStoreKit/issues/65)): Add `ReceiptItem` to `VerifyPurchaseResult`, `VerifySubscriptionResult`\n\nThis change introduces a new strong-typed `ReceiptItem` struct:\n\n```swift\npublic struct ReceiptItem {\n    // The product identifier of the item that was purchased. This value corresponds to the productIdentifier property of the SKPayment object stored in the transaction’s payment property.\n    public let productId: String\n    // The number of items purchased. This value corresponds to the quantity property of the SKPayment object stored in the transaction’s payment property.\n    public let quantity: Int\n    // The transaction identifier of the item that was purchased. This value corresponds to the transaction’s transactionIdentifier property.\n    public let transactionId: String\n    // For a transaction that restores a previous transaction, the transaction identifier of the original transaction. Otherwise, identical to the transaction identifier. This value corresponds to the original transaction’s transactionIdentifier property. All receipts in a chain of renewals for an auto-renewable subscription have the same value for this field.\n    public let originalTransactionId: String\n    // The date and time that the item was purchased. This value corresponds to the transaction’s transactionDate property.\n    public let purchaseDate: Date\n    // For a transaction that restores a previous transaction, the date of the original transaction. This value corresponds to the original transaction’s transactionDate property. In an auto-renewable subscription receipt, this indicates the beginning of the subscription period, even if the subscription has been renewed.\n    public let originalPurchaseDate: Date\n    // The primary key for identifying subscription purchases.\n    public let webOrderLineItemId: String\n    // The expiration date for the subscription, expressed as the number of milliseconds since January 1, 1970, 00:00:00 GMT. This key is only present for auto-renewable subscription receipts.\n    public let subscriptionExpirationDate: Date?\n    // For a transaction that was canceled by Apple customer support, the time and date of the cancellation. Treat a canceled receipt the same as if no purchase had ever been made.\n    public let cancellationDate: Date?\n\n    public let isTrialPeriod: Bool\n}\n```\n\nThis is parsed from the receipt and returned as part of the `verifySubscription` and `verifyPurchase` methods:\n\n```swift\n// Result for Consumable and NonConsumable\npublic enum VerifyPurchaseResult {\n    case purchased(item: ReceiptItem)\n    case notPurchased\n}\n\n// Verify subscription result\npublic enum VerifySubscriptionResult {\n    case purchased(expiryDate: Date, items: [ReceiptItem])\n    case expired(expiryDate: Date, items: [ReceiptItem])\n    case notPurchased\n}\n```\n\nNote that when one or more subscriptions are found for a given product id, they are returned as a `ReceiptItem` array ordered by `expiryDate`, with the first one being the newest.\n\nThis is useful to get all the valid date ranges for a given subscription.\n\n### [#202](https://github.com/bizz84/SwiftyStoreKit/pull/202) (fix for [#200](https://github.com/bizz84/SwiftyStoreKit/issues/200)): It's now possible to specify the quantity when making a purchase. Quantity is also accessible in the callback.\n\n#### This is an API breaking change. `Product` has been renamed to `Purchase`:\n\n```swift\npublic struct Purchase {\n    public let productId: String\n    public let quantity: Int\n    public let transaction: PaymentTransaction\n    public let needsFinishTransaction: Bool\n}\n```\n\n#### `PurchaseResult`\n\n```swift\npublic enum PurchaseResult {\n    //case success(product: Product) // old\n    case success(purchase: Purchase) // new\n    case error(error: SKError)\n}\n```\n\n#### `RestoreResults`\n\n```swift\npublic struct RestoreResults {\n    //public let restoredProducts: [Product] // old\n    //public let restoreFailedProducts: [(SKError, String?)] // old\n    public let restoredPurchases: [Purchase] // new\n    public let restoreFailedPurchases: [(SKError, String?)] // new\n}\n```\n\n### [#203](https://github.com/bizz84/SwiftyStoreKit/pull/203) (fix for [#193](https://github.com/bizz84/SwiftyStoreKit/issues/193)): Add `originalTransaction` from `SKPaymentTransaction.original` to `Payment` type\n\n\n\n## TODO: Older releases\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\ncontributors and maintainers pledge to making participation in our project and\nour community a harassment-free experience for everyone, regardless of age, body\nsize, disability, ethnicity, sex characteristics, gender identity and expression,\nlevel of experience, education, socio-economic status, nationality, personal\nappearance, race, religion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment\ninclude:\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\n 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\n address, without explicit permission\n* Other conduct which could reasonably be considered inappropriate in a\n professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable\nbehavior and are expected to take appropriate and fair corrective action in\nresponse to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or\nreject comments, commits, code, wiki edits, issues, and other contributions\nthat are not aligned to this Code of Conduct, or to ban temporarily or\npermanently any contributor for other behaviors that they deem inappropriate,\nthreatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces\nwhen an individual is representing the project or its community. Examples of\nrepresenting a project or community include using an official project e-mail\naddress, posting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event. Representation of a project may be\nfurther defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported by contacting the project team at hello@samspencer.art. All\ncomplaints will be reviewed and investigated and will result in a response that\nis deemed necessary and appropriate to the circumstances. The project team is\nobligated to maintain confidentiality with regard to the reporter of an incident.\nFurther details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good\nfaith may face temporary or permanent repercussions as determined by other\nmembers of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,\navailable at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html\n\n[homepage]: https://www.contributor-covenant.org\n\nFor answers to common questions about this code of conduct, see\nhttps://www.contributor-covenant.org/faq\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing to SwiftyStoreKit\n\n### All contributions to SwiftyStoreKit are welcome. 😎\n\nThis project is becoming widely adopted and its growth is now limited by the time the main maintainer can allocate.\n\nGoing forward, the aim is to **transfer some of the maintainance and development effort to the community**.\n\nIf you want to help developing SwiftyStoreKit, please look for issues marked with a blue **contributions welcome** label. See [this issue](https://github.com/bizz84/SwiftyStoreKit/issues/192) for an example.\n\nThe maintainer will use this label initially for simple tasks that are appropriate for beginners and first time contributors.\n\nAs the project and its community grows:\n\n* intermediate and advanced tasks will be opened up to contributors\n* most experienced contributors will be able to gain **admin** rights to review and merge pull requests\n\n**Note**: While the maintainer(s) try to regularly keep the project alive and healthy, issues and pull requests are not always reviewed in a timely manner. 🕰\n\n## Scope\n\nSwiftyStoreKit aims to be a lightweight wrapper on top of [StoreKit](https://developer.apple.com/reference/storekit).\n\nWhile SwiftyStoreKit offers access to the [local receipt data](https://developer.apple.com/reference/foundation/bundle/1407276-appstorereceipturl), it is a non-goal to add support for persisting IAP data locally. It is up to clients to do this with a storage solution of choice (i.e. NSUserDefaults, CoreData, Keychain).\n\n**Swift Version**: SwiftyStoreKit includes [Swift 2.3](https://github.com/bizz84/SwiftyStoreKit/tree/swift-2.3) and [Swift 2.2](https://github.com/bizz84/SwiftyStoreKit/tree/swift-2.2) branches. These legacy versions are no longer maintained and all active development happens on [master](https://github.com/bizz84/SwiftyStoreKit) and [develop](https://github.com/bizz84/SwiftyStoreKit/tree/develop), which support Swift 3.x and Swift 4.x.\n\n**Objective-C**: Currently, SwiftyStoreKit cannot be used in Objective-C projects. The main limitation is that most classes and types in the library are Swift-only. See [related issue](https://github.com/bizz84/SwiftyStoreKit/issues/123).\n\n## Pull requests\n\nThe project uses [gitflow](http://nvie.com/posts/a-successful-git-branching-model/) as a branching model.\n\nIn short:\n\n* All pull requests for **new features** and **bug fixes** should be made into the `develop` branch.\n* Pull requests for **hot fixes** can be done into both `master` and `develop`.\n* The maintainer(s) will merge `develop` into `master` and create a release tag as new features are added.\n* All releases [can be found here](https://github.com/bizz84/SwiftyStoreKit/releases).\n\n## Open Features / Enhancement Requests\n\nThese are intermediate / advanced tasks that will hopefully be implemented in the future:\n\n### Local Receipt validation\n\nSwiftyStoreKit offers a reference implementation for [receipt validation with Apple](https://github.com/bizz84/SwiftyStoreKit/blob/master/SwiftyStoreKit/AppleReceiptValidator.swift).\n\nThis could be extended by implementing local receipt validation as recommended by Apple. See [related issue](https://github.com/bizz84/SwiftyStoreKit/issues/101).\n\n### Support for content hosted by Apple for non-consumable products\n\nSee [related issue](https://github.com/bizz84/SwiftyStoreKit/issues/128).\n\n### Increase unit test coverage\n\nThe payment flows are unit tested fairly extensively. Additional unit test coverage is welcome:\n\n- [ ] Dependency injection for SwiftyStoreKit dependencies\n- [ ] Unit tests on main [SwiftyStoreKit class](https://github.com/bizz84/SwiftyStoreKit/blob/master/SwiftyStoreKit/SwiftyStoreKit.swift).\n- [ ] Unit tests for receipt verification code.\n\nSee [related issue](https://github.com/bizz84/SwiftyStoreKit/issues/38).\n\n\n## Issues\n\nIf SwiftyStoreKit doesn't work as you expect, please review [any open issues](https://github.com/bizz84/SwiftyStoreKit/issues) before opening a new one.\n\n"
  },
  {
    "path": "Dangerfile",
    "content": "# Ensure there is a summary for a pull request\nfail 'Please provide a summary in the Pull Request description' if github.pr_body.length < 5\n\n# Warn about develop branch\nwarn(\"Please target PRs to `develop` branch\") if github.branch_for_base != \"develop\"\n\n# Sometimes it's a README fix, or something like that - which isn't relevant for\n# including in a project's CHANGELOG for example\ndeclared_trivial = github.pr_title.include? \"#trivial\"\n\n# Make it more obvious that a PR is a work in progress and shouldn't be merged yet\nwarn(\"PR is classed as Work in Progress\") if github.pr_title.include? \"[WIP]\"\n\n# Warn no CHANGELOG\nwarn(\"No CHANGELOG changes made\") if git.lines_of_code > 50 && !git.modified_files.include?(\"CHANGELOG.md\") && !declared_trivial\n\n# Warn when there is a big PR\nwarn(\"Big PR\") if git.lines_of_code > 500\n\n## Let's check if there are any changes in the project folder\nhas_app_changes = !git.modified_files.grep(/SwiftyStoreKit/).empty?\n\n## Then, we should check if tests are updated\nhas_test_changes = !git.modified_files.grep(/SwiftyStoreKitTests/).empty?\n\n## Finally, let's combine them and put extra condition\n## for changed number of lines of code\nif has_app_changes && !has_test_changes && git.lines_of_code > 20\n  fail(\"Tests were not updated\", sticky: false)\nend\n"
  },
  {
    "path": "Gemfile",
    "content": "source 'https://rubygems.org'\n\ngem 'danger'\n"
  },
  {
    "path": "LICENSE.md",
    "content": "Copyright (c) 2015-2016 Andrea Bizzotto bizz84@gmail.com\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "Package.swift",
    "content": "// swift-tools-version:5.0\nimport PackageDescription\n\nlet package = Package(\n    name: \"SwiftyStoreKit\",\n    platforms: [.iOS(\"9.0\"), .macOS(\"10.10\"), .tvOS(\"9.0\"), .watchOS(\"6.2\")],\n    products: [\n        // Products define the executables and libraries produced by a package, and make them visible to other packages.\n        .library(\n            name: \"SwiftyStoreKit\",\n            targets: [\"SwiftyStoreKit\"])\n    ],\n    dependencies: [\n        // Dependencies declare other packages that this package depends on.\n        // .package(url: /* package url */, from: \"1.0.0\"),\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: \"SwiftyStoreKit\",\n            dependencies: []),\n        .testTarget(\n            name: \"SwiftyStoreKitTests\",\n            dependencies: [\"SwiftyStoreKit\"])\n    ]\n)\n"
  },
  {
    "path": "README.md",
    "content": "<img src=\"https://github.com/bizz84/SwiftyStoreKit/raw/master/SwiftyStoreKit-logo.png\" width=100%>\n\n[![License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat)](http://mit-license.org)\n[![Platform](http://img.shields.io/badge/platform-iOS%20%7C%20macOS%20%7C%20tvOS%20%7C%20watchOS-lightgrey.svg?style=flat)](https://developer.apple.com/resources/)\n[![Language](https://img.shields.io/badge/swift-5.0-orange.svg)](https://developer.apple.com/swift)\n[![Build](https://img.shields.io/travis/bizz84/SwiftyStoreKit.svg?style=flat)](https://travis-ci.org/bizz84/SwiftyStoreKit)\n[![Issues](https://img.shields.io/github/issues/bizz84/SwiftyStoreKit.svg?style=flat)](https://github.com/bizz84/SwiftyStoreKit/issues)\n[![Slack](https://img.shields.io/badge/Slack-Join-green.svg?style=flat)](https://join.slack.com/t/swiftystorekit/shared_invite/enQtODY3OTYxOTExMzE5LWVkNGY4MzcwY2VjNGM4MGU4NDFhMGE5YmUxMGM3ZTQ4NjVjNTRkNTJhNDAyMWZmY2M5OWE5MDE0ODc3OGJjMmM)\n\nSwiftyStoreKit is a lightweight In App Purchases framework for iOS, tvOS, watchOS, macOS, and Mac Catalyst.\n\n## Features\n- Super easy-to-use block-based API\n- Support for consumable and non-consumable in-app purchases\n- Support for free, auto-renewable and non-renewing subscriptions\n- Support for in-app purchases started in the App Store (iOS 11)\n- Support for subscription discounts and offers\n- Remote receipt verification\n- Verify purchases, subscriptions, subscription groups\n- Downloading content hosted with Apple\n- iOS, tvOS, watchOS, macOS, and Catalyst compatible\n\n## SwiftyStoreKit Alternatives\n\nDuring WWDC21, Apple introduced [StoreKit 2](https://developer.apple.com/videos/play/wwdc2021/10114/), a brand new Swift API for in-app purchases and auto-renewable subscriptions. \n\nWhile it would be highly desirable to support StoreKit 2 in this project, [little progress](https://github.com/bizz84/SwiftyStoreKit/issues/550) has been made over the last year and most issues [remain unanswered](https://github.com/bizz84/SwiftyStoreKit/issues).\n\nFortunately, there are some very good alternatives to SwiftyStoreKit, backed by real companies. By choosing their products, you'll make a safe choice and get much better support.\n\n### RevenueCat\n\n[RevenueCat](https://www.revenuecat.com/) is a great alternative to SwiftyStoreKit, offering great APIs, support, and much more at a very [reasonable price](https://www.revenuecat.com/pricing).\n\nIf you've been using SwiftyStoreKit and want to migrate to RevenueCat, this guide covers everything you need:\n\n- [SwiftyStoreKit Migration](https://docs.revenuecat.com/docs/swiftystorekit)\n\nOr if you're just getting started, consider skipping SwiftyStoreKit altogether and signing up for [RevenueCat](https://www.revenuecat.com/).\n\n### Glassfy\n\n[Glassfy](https://glassfy.io/) makes it easy to build, handle, and optimize in-app subscriptions. If you switch to Glassfy from SwiftyStoreKit, you'll get a 20% discount by using this [affiliate link](https://dashboard.glassfy.io/referral?code=SWIFTYSTOREKIT20).\n\n- Glassfy [pricing page](https://glassfy.io/pricing.html) - 20% off\n- Glassfy [migration guide](https://docs.glassfy.io/get-started/migrate-ssk) to support you with the migration\n\n> Note from the author: if you sign up with the link above, I will receive an affiliate commission from Glassfy, at no cost to yourself. I only recommend products that I personally know and believe will help you.\n\n### Apphud\n\n[Apphud](https://apphud.com/) is more than just making a purchase and validating receipts. Apphud is all-in-one infrastructure for your app growth. [Sign up for free](https://app.apphud.com/sign_up) and try it out.\n\nOr you can learn [how to migrate your app from SwiftyStoreKit to Apphud](https://docs.apphud.com/getting-started/migrate-from-swiftystorekit).\n\n### Adapty\n\nWith Adapty you can set up subscriptions in just an hour following these [simple steps](https://docs.adapty.io/docs/quickstart) and instantly launch in-app purchases with the [Paywall Builder](https://adapty.io/paywall-builder/). Adapty not only gives you the tools to embed purchases but also helps your customers grow.\nAnd the best part is that [it’s free for apps <$10k](https://adapty.io/pricing/).\n\n## Contributions Wanted\nSwiftyStoreKit makes it easy for an incredible number of developers to seemlessly integrate in-App Purchases. This project, however, is now **community-led**. We need help building out features and writing tests (see [issue #550](https://github.com/bizz84/SwiftyStoreKit/issues/550)).\n\n### Maintainers Wanted\nThe author is no longer maintaining this project actively. If you'd like to become a maintainer, [join the Slack workspace](https://join.slack.com/t/swiftystorekit/shared_invite/enQtODY3OTYxOTExMzE5LWVkNGY4MzcwY2VjNGM4MGU4NDFhMGE5YmUxMGM3ZTQ4NjVjNTRkNTJhNDAyMWZmY2M5OWE5MDE0ODc3OGJjMmM) and enter the [#maintainers](https://app.slack.com/client/TL2JYQ458/CLG62K26A/details/) channel.\nGoing forward, SwiftyStoreKit should be made for the community, by the community. \n\nMore info here: [The Future of SwiftyStoreKit: Maintainers Wanted](https://medium.com/@biz84/the-future-of-swiftystorekit-maintainers-needed-f60d01572c91).\n\n## Requirements\nIf you've shipped an app in the last five years, you're probably good to go. Some features (like discounts) are only available on new OS versions, but most features are available as far back as:\n\n| iOS | watchOS | tvOS | macOS | Mac Catalyst |\n| --- | ------- | ---- | ----- | ------------ |\n| 8.0 | 6.2     | 9.0  | 10.10 | 13.0         |\n\n## Installation\nThere are a number of ways to install SwiftyStoreKit for your project. Swift Package Manager, CocoaPods, and Carthage integrations are the preferred and recommended approaches.\n\nRegardless, make sure to import the project wherever you may use it:\n\n```swift\nimport SwiftyStoreKit\n```\n\n### Swift Package Manager\nThe [Swift Package Manager](https://swift.org/package-manager/) is a tool for automating the distribution of Swift code and is integrated into Xcode and the Swift compiler. **This is the recommended installation method.** Updates to SwiftyStoreKit will always be available immediately to projects with SPM. SPM is also integrated directly with Xcode.\n\nIf you are using Xcode 11 or later:\n 1. Click `File`\n 2. `Swift Packages`\n 3. `Add Package Dependency...`\n 4. Specify the git URL for SwiftyStoreKit.\n\n```swift\nhttps://github.com/bizz84/SwiftyStoreKit.git\n```\n\n### Carthage\nTo integrate SwiftyStoreKit into your Xcode project using [Carthage](https://github.com/Carthage/Carthage), specify it in your Cartfile:\n\n```ogdl\ngithub \"bizz84/SwiftyStoreKit\"\n```\n\n**NOTE**: Please ensure that you have the [latest](https://github.com/Carthage/Carthage/releases) Carthage installed.\n\n### CocoaPods\nSwiftyStoreKit can be installed as a [CocoaPod](https://cocoapods.org/) and builds as a Swift framework. To install, include this in your Podfile.\n\n```ruby\nuse_frameworks!\n\npod 'SwiftyStoreKit'\n```\n\n## Contributing\nGot issues / pull requests / want to contribute? [Read here](CONTRIBUTING.md).\n\n# Documentation\nFull documentation is available on the [SwiftyStoreKit Wiki](https://github.com/bizz84/SwiftyStoreKit/wiki). As SwiftyStoreKit (and Apple's StoreKit) gains features, platforms, and implementation approaches, new information will be added to the Wiki. Essential documentation is available here in the README and should be enough to get you up and running.\n\n## App startup\n\n### Complete Transactions\n\nApple recommends to register a transaction observer [as soon as the app starts](https://developer.apple.com/library/ios/technotes/tn2387/_index.html):\n> Adding your app's observer at launch ensures that it will persist during all launches of your app, thus allowing your app to receive all the payment queue notifications.\n\nSwiftyStoreKit supports this by calling `completeTransactions()` when the app starts:\n\n```swift\nfunc application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {\n\t// see notes below for the meaning of Atomic / Non-Atomic\n\tSwiftyStoreKit.completeTransactions(atomically: true) { purchases in\n\t    for purchase in purchases {\n\t        switch purchase.transaction.transactionState {\n\t        case .purchased, .restored:\n\t            if purchase.needsFinishTransaction {\n\t                // Deliver content from server, then:\n\t                SwiftyStoreKit.finishTransaction(purchase.transaction)\n\t            }\n\t            // Unlock content\n\t        case .failed, .purchasing, .deferred:\n\t            break // do nothing\n\t        }\n\t    }\n\t}\n    return true\n}\n```\n\nIf there are any pending transactions at this point, these will be reported by the completion block so that the app state and UI can be updated.\n\nIf there are no pending transactions, the completion block will **not** be called.\n\nNote that `completeTransactions()` **should only be called once** in your code, in `application(:didFinishLaunchingWithOptions:)`.\n\n## Purchases\n\n### Retrieve products info\n```swift\nSwiftyStoreKit.retrieveProductsInfo([\"com.musevisions.SwiftyStoreKit.Purchase1\"]) { result in\n    if let product = result.retrievedProducts.first {\n        let priceString = product.localizedPrice!\n        print(\"Product: \\(product.localizedDescription), price: \\(priceString)\")\n    }\n    else if let invalidProductId = result.invalidProductIDs.first {\n        print(\"Invalid product identifier: \\(invalidProductId)\")\n    }\n    else {\n        print(\"Error: \\(result.error)\")\n    }\n}\n```\n\n### Purchase a product (given a product id)\n\n* **Atomic**: to be used when the content is delivered immediately.\n\n```swift\nSwiftyStoreKit.purchaseProduct(\"com.musevisions.SwiftyStoreKit.Purchase1\", quantity: 1, atomically: true) { result in\n    switch result {\n    case .success(let purchase):\n        print(\"Purchase Success: \\(purchase.productId)\")\n    case .error(let error):\n        switch error.code {\n        case .unknown: print(\"Unknown error. Please contact support\")\n        case .clientInvalid: print(\"Not allowed to make the payment\")\n        case .paymentCancelled: break\n        case .paymentInvalid: print(\"The purchase identifier was invalid\")\n        case .paymentNotAllowed: print(\"The device is not allowed to make the payment\")\n        case .storeProductNotAvailable: print(\"The product is not available in the current storefront\")\n        case .cloudServicePermissionDenied: print(\"Access to cloud service information is not allowed\")\n        case .cloudServiceNetworkConnectionFailed: print(\"Could not connect to the network\")\n        case .cloudServiceRevoked: print(\"User has revoked permission to use this cloud service\")\n        default: print((error as NSError).localizedDescription)\n        }\n    }\n}\n```\n\n* **Non-Atomic**: to be used when the content is delivered by the server.\n\n```swift\nSwiftyStoreKit.purchaseProduct(\"com.musevisions.SwiftyStoreKit.Purchase1\", quantity: 1, atomically: false) { result in\n    switch result {\n    case .success(let product):\n        // fetch content from your server, then:\n        if product.needsFinishTransaction {\n            SwiftyStoreKit.finishTransaction(product.transaction)\n        }\n        print(\"Purchase Success: \\(product.productId)\")\n    case .error(let error):\n        switch error.code {\n        case .unknown: print(\"Unknown error. Please contact support\")\n        case .clientInvalid: print(\"Not allowed to make the payment\")\n        case .paymentCancelled: break\n        case .paymentInvalid: print(\"The purchase identifier was invalid\")\n        case .paymentNotAllowed: print(\"The device is not allowed to make the payment\")\n        case .storeProductNotAvailable: print(\"The product is not available in the current storefront\")\n        case .cloudServicePermissionDenied: print(\"Access to cloud service information is not allowed\")\n        case .cloudServiceNetworkConnectionFailed: print(\"Could not connect to the network\")\n        case .cloudServiceRevoked: print(\"User has revoked permission to use this cloud service\")\n        default: print((error as NSError).localizedDescription)\n        }\n    }\n}\n```\n\n### Additional Purchase Documentation\nThese additional topics are available on the Wiki:\n- [Purchase a product (given a SKProduct)](https://github.com/bizz84/SwiftyStoreKit/wiki/Purchasing#purchase-a-product-given-a-skproduct)\n- [Handle purchases started on the App Store (iOS 11)](https://github.com/bizz84/SwiftyStoreKit/wiki/App-Store-Purchases)\n\n### Restore Previous Purchases\n\nAccording to [Apple - Restoring Purchased Products](https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/StoreKitGuide/Chapters/Restoring.html#//apple_ref/doc/uid/TP40008267-CH8-SW9):\n\n> In most cases, all your app needs to do is refresh its receipt and deliver the products in its receipt. The refreshed receipt contains a record of the user’s purchases in this app, on this device or any other device.\n>\n> Restoring completed transactions creates a new transaction for every completed transaction the user made, essentially replaying history for your transaction queue observer.\n\nSee the **Receipt Verification** section below for how to restore previous purchases using the receipt.\n\nThis section shows how to restore completed transactions with the `restorePurchases` method instead. When successful, the method returns all non-consumable purchases, as well as all auto-renewable subscription purchases, **regardless of whether they are expired or not**.\n\n* **Atomic**: to be used when the content is delivered immediately.\n\n```swift\nSwiftyStoreKit.restorePurchases(atomically: true) { results in\n    if results.restoreFailedPurchases.count > 0 {\n        print(\"Restore Failed: \\(results.restoreFailedPurchases)\")\n    }\n    else if results.restoredPurchases.count > 0 {\n        print(\"Restore Success: \\(results.restoredPurchases)\")\n    }\n    else {\n        print(\"Nothing to Restore\")\n    }\n}\n```\n\n* **Non-Atomic**: to be used when the content is delivered by the server.\n\n```swift\nSwiftyStoreKit.restorePurchases(atomically: false) { results in\n    if results.restoreFailedPurchases.count > 0 {\n        print(\"Restore Failed: \\(results.restoreFailedPurchases)\")\n    }\n    else if results.restoredPurchases.count > 0 {\n        for purchase in results.restoredPurchases {\n            // fetch content from your server, then:\n            if purchase.needsFinishTransaction {\n                SwiftyStoreKit.finishTransaction(purchase.transaction)\n            }\n        }\n        print(\"Restore Success: \\(results.restoredPurchases)\")\n    }\n    else {\n        print(\"Nothing to Restore\")\n    }\n}\n```\n\n#### What does atomic / non-atomic mean?\nFor more information about atomic vs. non-atomic restorations, [view the Wiki page here](https://github.com/bizz84/SwiftyStoreKit/wiki/Restoring#what-does-atomic--non-atomic-mean).\n\n### Downloading content hosted with Apple\nMore information about downloading hosted content is [available on the Wiki](https://github.com/bizz84/SwiftyStoreKit/wiki/Downloading-Content).\n\nTo start downloads (this can be done in `purchaseProduct()`, `completeTransactions()` or `restorePurchases()`):\n\n```swift\nSwiftyStoreKit.purchaseProduct(\"com.musevisions.SwiftyStoreKit.Purchase1\", quantity: 1, atomically: false) { result in\n    switch result {\n    case .success(let product):\n        let downloads = purchase.transaction.downloads\n        if !downloads.isEmpty {\n            SwiftyStoreKit.start(downloads)\n        }\n    case .error(let error):\n        print(\"\\(error)\")\n    }\n}\n```\n\nTo check the updated downloads, setup a `updatedDownloadsHandler` block in your AppDelegate:\n\n```swift\nSwiftyStoreKit.updatedDownloadsHandler = { downloads in\n    // contentURL is not nil if downloadState == .finished\n    let contentURLs = downloads.flatMap { $0.contentURL }\n    if contentURLs.count == downloads.count {\n        // process all downloaded files, then finish the transaction\n        SwiftyStoreKit.finishTransaction(downloads[0].transaction)\n    }\n}\n```\n\nTo control the state of the downloads, SwiftyStoreKit offers `start()`, `pause()`, `resume()`, `cancel()` methods.\n\n## Receipt verification\n\nThis helper can be used to retrieve the (encrypted) local receipt data:\n\n```swift\nlet receiptData = SwiftyStoreKit.localReceiptData\nlet receiptString = receiptData.base64EncodedString(options: [])\n// do your receipt validation here\n```\n\nHowever, the receipt file may be missing or outdated. Use this method to get the updated receipt:\n\n```swift\nSwiftyStoreKit.fetchReceipt(forceRefresh: true) { result in\n    switch result {\n    case .success(let receiptData):\n        let encryptedReceipt = receiptData.base64EncodedString(options: [])\n        print(\"Fetch receipt success:\\n\\(encryptedReceipt)\")\n    case .error(let error):\n        print(\"Fetch receipt failed: \\(error)\")\n    }\n}\n```\n\nUse this method to (optionally) refresh the receipt and perform validation in one step.\n\n```swift\nlet appleValidator = AppleReceiptValidator(service: .production, sharedSecret: \"your-shared-secret\")\nSwiftyStoreKit.verifyReceipt(using: appleValidator, forceRefresh: false) { result in\n    switch result {\n    case .success(let receipt):\n        print(\"Verify receipt success: \\(receipt)\")\n    case .error(let error):\n        print(\"Verify receipt failed: \\(error)\")\n    }\n}\n```\n\nAdditional details about receipt verification are [available on the wiki](https://github.com/bizz84/SwiftyStoreKit/wiki/Verify-Receipt).\n\n## Verifying purchases and subscriptions\nOnce you have retrieved the receipt using the `verifyReceipt` method, you can verify your purchases and subscriptions by product identifier.\n\n### Verify Purchase\n\n```swift\nlet appleValidator = AppleReceiptValidator(service: .production, sharedSecret: \"your-shared-secret\")\nSwiftyStoreKit.verifyReceipt(using: appleValidator) { result in\n    switch result {\n    case .success(let receipt):\n        let productId = \"com.musevisions.SwiftyStoreKit.Purchase1\"\n        // Verify the purchase of Consumable or NonConsumable\n        let purchaseResult = SwiftyStoreKit.verifyPurchase(\n            productId: productId,\n            inReceipt: receipt)\n            \n        switch purchaseResult {\n        case .purchased(let receiptItem):\n            print(\"\\(productId) is purchased: \\(receiptItem)\")\n        case .notPurchased:\n            print(\"The user has never purchased \\(productId)\")\n        }\n    case .error(let error):\n        print(\"Receipt verification failed: \\(error)\")\n    }\n}\n```\n\n### Verify Subscription\nThis can be used to check if a subscription was previously purchased, and whether it is still active or if it's expired.\n\nFrom [Apple - Working with Subscriptions](https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/StoreKitGuide/Chapters/Subscriptions.html#//apple_ref/doc/uid/TP40008267-CH7-SW6):\n\n> Keep a record of the date that each piece of content is published. Read the Original Purchase Date and Subscription Expiration Date field from each receipt entry to determine the start and end dates of the subscription.\n\nWhen one or more subscriptions are found for a given product id, they are returned as a `ReceiptItem` array ordered by `expiryDate`, with the first one being the newest.\n\n```swift\nlet appleValidator = AppleReceiptValidator(service: .production, sharedSecret: \"your-shared-secret\")\nSwiftyStoreKit.verifyReceipt(using: appleValidator) { result in\n    switch result {\n    case .success(let receipt):\n        let productId = \"com.musevisions.SwiftyStoreKit.Subscription\"\n        // Verify the purchase of a Subscription\n        let purchaseResult = SwiftyStoreKit.verifySubscription(\n            ofType: .autoRenewable, // or .nonRenewing (see below)\n            productId: productId,\n            inReceipt: receipt)\n            \n        switch purchaseResult {\n        case .purchased(let expiryDate, let items):\n            print(\"\\(productId) is valid until \\(expiryDate)\\n\\(items)\\n\")\n        case .expired(let expiryDate, let items):\n            print(\"\\(productId) is expired since \\(expiryDate)\\n\\(items)\\n\")\n        case .notPurchased:\n            print(\"The user has never purchased \\(productId)\")\n        }\n\n    case .error(let error):\n        print(\"Receipt verification failed: \\(error)\")\n    }\n}\n```\n\nFurther documentation on verifying subscriptions is [available on the wiki](https://github.com/bizz84/SwiftyStoreKit/wiki/Verify-Subscription).\n\n### Subscription Groups\n\nFrom [Apple Docs - Offering Subscriptions](https://developer.apple.com/app-store/subscriptions/):\n\n> A subscription group is a set of in-app purchases that you can create to provide users with a range of content offerings, service levels, or durations to best meet their needs. Users can only buy one subscription within a subscription group at a time. If users would want to buy more that one type of subscription — for example, to subscribe to more than one channel in a streaming app — you can put these in-app purchases in different subscription groups.\n\nYou can verify all subscriptions within the same group with the `verifySubscriptions` method. [Learn more on the wiki](https://github.com/bizz84/SwiftyStoreKit/wiki/Subscription-Groups).\n\n\n## Notes\nThe framework provides a simple block based API with robust error handling on top of the existing StoreKit framework. It does **NOT** persist in app purchases data locally. It is up to clients to do this with a storage solution of choice (i.e. NSUserDefaults, CoreData, Keychain).\n\n## Change Log\nSee the [Releases Page](https://github.com/bizz84/SwiftyStoreKit/releases).\n\n## Sample Code\nThe project includes demo apps [for iOS](https://github.com/bizz84/SwiftyStoreKit/blob/master/SwiftyStoreKit-iOS-Demo/ViewController.swift) [and macOS](https://github.com/bizz84/SwiftyStoreKit/blob/master/SwiftyStoreKit-macOS-Demo/ViewController.swift) showing how to use SwiftyStoreKit.\nNote that the pre-registered in app purchases in the demo apps are for illustration purposes only and may not work as iTunes Connect may invalidate them.\n\n## Essential Reading\n* [Apple - WWDC16, Session 702: Using Store Kit for In-app Purchases with Swift 3](https://developer.apple.com/videos/play/wwdc2016/702/)\n* [Apple - TN2387: In-App Purchase Best Practices](https://developer.apple.com/library/content/technotes/tn2387/_index.html)\n* [Apple - TN2413: In-App Purchase FAQ](https://developer.apple.com/library/content/technotes/tn2413/_index.html) (also see [Cannot connect to iTunes Store](https://developer.apple.com/library/content/technotes/tn2413/_index.html#//apple_ref/doc/uid/DTS40016228-CH1-ERROR_MESSAGES-CANNOT_CONNECT_TO_ITUNES_STORE))\n* [Apple - TN2259: Adding In-App Purchase to Your Applications](https://developer.apple.com/library/content/technotes/tn2259/_index.html)\n* [iTunes Connect Developer Help - Workflow for configuring in-app purchases](https://help.apple.com/itunes-connect/developer/#/devb57be10e7)\n* [Apple - About Receipt Validation](https://developer.apple.com/library/content/releasenotes/General/ValidateAppStoreReceipt/Introduction.html)\n* [Apple - Receipt Validation Programming Guide](https://developer.apple.com/library/content/releasenotes/General/ValidateAppStoreReceipt/Chapters/ReceiptFields.html#//apple_ref/doc/uid/TP40010573-CH106-SW1)\n* [Apple - Validating Receipts Locally](https://developer.apple.com/library/content/releasenotes/General/ValidateAppStoreReceipt/Chapters/ValidateLocally.html)\n* [Apple - Working with Subscriptions](https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/StoreKitGuide/Chapters/Subscriptions.html#//apple_ref/doc/uid/TP40008267-CH7-SW6)\n* [Apple - Offering Subscriptions](https://developer.apple.com/app-store/subscriptions/)\n* [Apple - Restoring Purchased Products](https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/StoreKitGuide/Chapters/Restoring.html#//apple_ref/doc/uid/TP40008267-CH8-SW9)\n* [Apple - Testing In-App Purchase Products](https://developer.apple.com/library/content/documentation/LanguagesUtilities/Conceptual/iTunesConnectInAppPurchase_Guide/Chapters/TestingInAppPurchases.html): includes info on duration of subscriptions in sandbox mode\n* [objc.io - Receipt Validation](https://www.objc.io/issues/17-security/receipt-validation/)\n\nI have also written about building SwiftyStoreKit on Medium:\n\n* [How I got 1000 ⭐️ on my GitHub Project](https://medium.com/ios-os-x-development/how-i-got-1000-%EF%B8%8F-on-my-github-project-654d3d394ca6#.1idp27olf)\n* [Maintaining a Growing Open Source Project](https://medium.com/@biz84/maintaining-a-growing-open-source-project-1d385ca84c5#.4cv2g7tdc)\n\n### Troubleshooting \n* [Apple TN 2413 - Why are my product identifiers being returned in the invalidProductIdentifiers array?](https://developer.apple.com/library/content/technotes/tn2413/_index.html#//apple_ref/doc/uid/DTS40016228-CH1-TROUBLESHOOTING-WHY_ARE_MY_PRODUCT_IDENTIFIERS_BEING_RETURNED_IN_THE_INVALIDPRODUCTIDENTIFIERS_ARRAY_)\n* [Invalid Product IDs](http://troybrant.net/blog/2010/01/invalid-product-ids/): Checklist of common mistakes\n* [Testing Auto-Renewable Subscriptions on iOS](http://davidbarnard.com/post/164337147440/testing-auto-renewable-subscriptions-on-ios)\n* [Apple forums - iOS 11 beta sandbox - cannot connect to App Store](https://forums.developer.apple.com/message/261428#261428)\n\n## Video Tutorials\n\n#### Jared Davidson: In App Purchases! (Swift 3 in Xcode : Swifty Store Kit)\n\n<a href=\"https://www.youtube.com/watch?v=dwPFtwDJ7tcb\"><img src=\"https://raw.githubusercontent.com/bizz84/SwiftyStoreKit/master/Screenshots/VideoTutorial-JaredDavidson.jpg\" width=\"50%\" /></a>\n\n#### [@rebeloper](https://github.com/rebeloper): Ultimate In-app Purchases Guide\n\n<a href=\"https://www.youtube.com/watch?v=MP-U5gQylHc\"><img src=\"https://user-images.githubusercontent.com/2488011/65576278-55cccc80-df7a-11e9-8db5-244e2afa3e46.png\" width=\"50%\" /></a>\n\n## Written Tutorials\n\n* [In App Purchase (IAP) made simple with SwiftyStoreKit](https://levelup.gitconnected.com/beginner-ios-dev-in-app-purchase-iap-made-simple-with-swiftystorekit-3add60e9065d)\n\n## Credits\nMany thanks to [phimage](https://github.com/phimage) for adding macOS support and receipt verification.\n\n## Apps using SwiftyStoreKit\n\nIt would be great to showcase apps using SwiftyStoreKit here. Pull requests welcome :)\n\n* [Every Plant, Ever](https://itunes.apple.com/us/app/every-plant-ever/id1433967019) - The sticker pack of every plant, ever.\n* [Countdown](https://countdowns.download/ssk) - Countdown the days until your next vacation, deadline, or event\n* [MDacne](https://itunes.apple.com/app/id1044050208) - Acne analysis and treatment\n* [Pixel Picker](https://itunes.apple.com/app/id930804327) - Image Color Picker\n* [KType](https://itunes.apple.com/app/id1037000234) - Space shooter game\n* [iPic](https://itunes.apple.com/app/id1101244278) - Automatically upload images and save Markdown links\n* [iHosts](https://itunes.apple.com/app/id1102004240) - Perfect for editing /etc/hosts\n* [Arise](http://www.abnehm-app.de/) - Calorie counter\n* [Truth Truth Lie](https://itunes.apple.com/app/id1130832864) - iMessage game, featured by Apple\n* [Tactus Music Player](https://itunes.apple.com/app/id557446352) - Alternative music player app\n* [Drops](https://itunes.apple.com/app/id939540371) - Language learning app\n* [Fresh Snow](https://itunes.apple.com/app/id1063000470) - Colorado Ski Report\n* [Zmeu Grand Canyon](http://grandcanyon.zmeu.guide/) - Interactive hiking map & planner\n* [OB Monitor](https://itunes.apple.com/app/id1073398446) - The app for Texas Longhorns athletics fans\n* [Talk Dim Sum](https://itunes.apple.com/us/app/talk-dim-sum/id953929066) - Your dim sum companion\n* [Sluggard](https://itunes.apple.com/app/id1160131071) - Perform simple exercises to reduce the risks of sedentary lifestyle\n* [Debts iOS](https://debts.ivanvorobei.by/ios) & [Debts macOS](https://debts.ivanvorobei.by/macos) - Track amounts owed\n* [Botcher](https://itunes.apple.com/us/app/id1522337788) - Good for finding something to do\n* [Hashr](https://apps.apple.com/app/id1166499829) - Generate unique password hashes based on website and master password\n* [QRFi](https://apps.apple.com/app/id1535761355) - Create stylish QR Codes for WiFi\n\nA full list of apps is published [on AppSight](https://www.appsight.io/sdk/574154).\n"
  },
  {
    "path": "Sources/SwiftyStoreKit/AppleReceiptValidator.swift",
    "content": "//\n//  InAppReceipt.swift\n//  SwiftyStoreKit\n//\n//  Created by phimage on 22/12/15.\n// Copyright (c) 2015 Andrea Bizzotto (bizz84@gmail.com)\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\nimport Foundation\n\n// https://developer.apple.com/library/ios/releasenotes/General/ValidateAppStoreReceipt/Chapters/ValidateRemotely.html\n\npublic class AppleReceiptValidator: ReceiptValidator {\n\n\tpublic enum VerifyReceiptURLType: String {\n\t\tcase production = \"https://buy.itunes.apple.com/verifyReceipt\"\n\t\tcase sandbox = \"https://sandbox.itunes.apple.com/verifyReceipt\"\n\t}\n\n    /// You should always verify your receipt first with the `production` service\n    /// Note: will auto change to `.sandbox` and validate again if received a 21007 status code from Apple\n    public var service: VerifyReceiptURLType\n\n    private let sharedSecret: String?\n\n    /**\n     * Reference Apple Receipt Validator\n     *  - Parameter service: Either .production or .sandbox\n     *  - Parameter sharedSecret: Only used for receipts that contain auto-renewable subscriptions. Your app’s shared secret (a hexadecimal string).\n     */\n    public init(service: VerifyReceiptURLType = .production, sharedSecret: String? = nil) {\n\t\tself.service = service\n        self.sharedSecret = sharedSecret\n\t}\n\n\tpublic func validate(receiptData: Data, completion: @escaping (VerifyReceiptResult) -> Void) {\n\n\t\tlet storeURL = URL(string: service.rawValue)! // safe (until no more)\n\t\tlet storeRequest = NSMutableURLRequest(url: storeURL)\n\t\tstoreRequest.httpMethod = \"POST\"\n\n        let receipt = receiptData.base64EncodedString(options: [])\n\t\tlet requestContents: NSMutableDictionary = [ \"receipt-data\": receipt ]\n\t\t// password if defined\n\t\tif let password = sharedSecret {\n\t\t\trequestContents.setValue(password, forKey: \"password\")\n\t\t}\n\n\t\t// Encore request body\n\t\tdo {\n\t\t\tstoreRequest.httpBody = try JSONSerialization.data(withJSONObject: requestContents, options: [])\n\t\t} catch let e {\n\t\t\tcompletion(.error(error: .requestBodyEncodeError(error: e)))\n\t\t\treturn\n\t\t}\n\n\t\t// Remote task\n\t\tlet task = URLSession.shared.dataTask(with: storeRequest as URLRequest) { data, _, error -> Void in\n\n\t\t\t// there is an error\n\t\t\tif let networkError = error {\n\t\t\t\tcompletion(.error(error: .networkError(error: networkError)))\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// there is no data\n\t\t\tguard let safeData = data else {\n\t\t\t\tcompletion(.error(error: .noRemoteData))\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// cannot decode data\n\t\t\tguard let receiptInfo = try? JSONSerialization.jsonObject(with: safeData, options: .mutableLeaves) as? ReceiptInfo ?? [:] else {\n\t\t\t\tlet jsonStr = String(data: safeData, encoding: String.Encoding.utf8)\n\t\t\t\tcompletion(.error(error: .jsonDecodeError(string: jsonStr)))\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// get status from info\n\t\t\tif let status = receiptInfo[\"status\"] as? Int {\n\t\t\t\t/*\n\t\t\t\t* http://stackoverflow.com/questions/16187231/how-do-i-know-if-an-in-app-purchase-receipt-comes-from-the-sandbox\n\t\t\t\t* How do I verify my receipt (iOS)?\n\t\t\t\t* Always verify your receipt first with the production URL; proceed to verify\n\t\t\t\t* with the sandbox URL if you receive a 21007 status code. Following this\n\t\t\t\t* approach ensures that you do not have to switch between URLs while your\n\t\t\t\t* application is being tested or reviewed in the sandbox or is live in the\n\t\t\t\t* App Store.\n\n\t\t\t\t* Note: The 21007 status code indicates that this receipt is a sandbox receipt,\n\t\t\t\t* but it was sent to the production service for verification.\n\t\t\t\t*/\n\t\t\t\tlet receiptStatus = ReceiptStatus(rawValue: status) ?? ReceiptStatus.unknown\n\t\t\t\tif case .testReceipt = receiptStatus {\n                    self.service = .sandbox\n                    self.validate(receiptData: receiptData, completion: completion)\n\t\t\t\t} else {\n\t\t\t\t\tif receiptStatus.isValid {\n\t\t\t\t\t\tcompletion(.success(receipt: receiptInfo))\n\t\t\t\t\t} else {\n\t\t\t\t\t\tcompletion(.error(error: .receiptInvalid(receipt: receiptInfo, status: receiptStatus)))\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tcompletion(.error(error: .receiptInvalid(receipt: receiptInfo, status: ReceiptStatus.none)))\n\t\t\t}\n\t\t}\n\t\ttask.resume()\n\t}\n}\n"
  },
  {
    "path": "Sources/SwiftyStoreKit/CompleteTransactionsController.swift",
    "content": "//\n// CompleteTransactionsController.swift\n// SwiftyStoreKit\n//\n// Copyright (c) 2017 Andrea Bizzotto (bizz84@gmail.com)\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\nimport Foundation\nimport StoreKit\n\nstruct CompleteTransactions {\n    let atomically: Bool\n    let callback: ([Purchase]) -> Void\n\n    init(atomically: Bool, callback: @escaping ([Purchase]) -> Void) {\n        self.atomically = atomically\n        self.callback = callback\n    }\n}\n\nclass CompleteTransactionsController: TransactionController {\n\n    var completeTransactions: CompleteTransactions?\n\n    func processTransactions(_ transactions: [SKPaymentTransaction], on paymentQueue: PaymentQueue) -> [SKPaymentTransaction] {\n\n        guard let completeTransactions = completeTransactions else {\n            print(\"SwiftyStoreKit.completeTransactions() should be called once when the app launches.\")\n            return transactions\n        }\n\n        var unhandledTransactions: [SKPaymentTransaction] = []\n        var purchases: [Purchase] = []\n\n        for transaction in transactions {\n\n            let transactionState = transaction.transactionState\n\n            if transactionState != .purchasing {\n\n                let willFinishTransaction = completeTransactions.atomically || transactionState == .failed\n                let purchase = Purchase(productId: transaction.payment.productIdentifier, quantity: transaction.payment.quantity, transaction: transaction, originalTransaction: transaction.original, needsFinishTransaction: !willFinishTransaction)\n\n                purchases.append(purchase)\n\n                if willFinishTransaction {\n                    print(\"Finishing transaction for payment \\\"\\(transaction.payment.productIdentifier)\\\" with state: \\(transactionState.debugDescription)\")\n                    paymentQueue.finishTransaction(transaction)\n                }\n            } else {\n                unhandledTransactions.append(transaction)\n            }\n        }\n        if purchases.count > 0 {\n            completeTransactions.callback(purchases)\n        }\n\n        return unhandledTransactions\n    }\n}\n"
  },
  {
    "path": "Sources/SwiftyStoreKit/InAppProductQueryRequest.swift",
    "content": "//\n// InAppPurchaseProductRequest.swift\n// SwiftyStoreKit\n//\n// Copyright (c) 2015 Andrea Bizzotto (bizz84@gmail.com)\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\nimport StoreKit\n\ntypealias InAppProductRequestCallback = (RetrieveResults) -> Void\n\npublic protocol InAppRequest: AnyObject {\n    func start()\n    func cancel()\n}\n\nprotocol InAppProductRequest: InAppRequest {\n    var hasCompleted: Bool { get }\n    var cachedResults: RetrieveResults? { get }\n}\n\nclass InAppProductQueryRequest: NSObject, InAppProductRequest, SKProductsRequestDelegate {\n\n    private let callback: InAppProductRequestCallback\n    private let request: SKProductsRequest\n\n    private(set) var cachedResults: RetrieveResults?\n\n    var hasCompleted: Bool { cachedResults != nil }\n\n    deinit {\n        request.delegate = nil\n    }\n    init(productIds: Set<String>, callback: @escaping InAppProductRequestCallback) {\n\n        self.callback = callback\n        request = SKProductsRequest(productIdentifiers: productIds)\n        super.init()\n        request.delegate = self\n    }\n\n    func start() {\n        request.start()\n    }\n\n    func cancel() {\n        request.cancel()\n    }\n\n    // MARK: SKProductsRequestDelegate\n    func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {\n\n        let retrievedProducts = Set<SKProduct>(response.products)\n        let invalidProductIDs = Set<String>(response.invalidProductIdentifiers)\n        let results = RetrieveResults(\n            retrievedProducts: retrievedProducts,\n            invalidProductIDs: invalidProductIDs, error: nil\n        )\n        self.cachedResults = results\n        performCallback(results)\n    }\n\n    func requestDidFinish(_ request: SKRequest) {\n\n    }\n\n    func request(_ request: SKRequest, didFailWithError error: Error) {\n        performCallback(RetrieveResults(retrievedProducts: Set<SKProduct>(), invalidProductIDs: Set<String>(), error: error))\n    }\n    \n    private func performCallback(_ results: RetrieveResults) {\n        DispatchQueue.main.async {\n            self.callback(results)\n        }\n    }\n}\n"
  },
  {
    "path": "Sources/SwiftyStoreKit/InAppReceipt.swift",
    "content": "//\n//  InAppReceipt.swift\n//  SwiftyStoreKit\n//\n//  Created by phimage on 22/12/15.\n// Copyright (c) 2015 Andrea Bizzotto (bizz84@gmail.com)\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\nimport Foundation\n\nextension Date {\n\n    init?(millisecondsSince1970: String) {\n        guard let millisecondsNumber = Double(millisecondsSince1970) else {\n            return nil\n        }\n        self = Date(timeIntervalSince1970: millisecondsNumber / 1000)\n    }\n}\n\nextension ReceiptItem {\n\n    public init?(receiptInfo: ReceiptInfo) {\n        guard\n            let productId = receiptInfo[\"product_id\"] as? String,\n            let quantityString = receiptInfo[\"quantity\"] as? String,\n            let quantity = Int(quantityString),\n            let transactionId = receiptInfo[\"transaction_id\"] as? String,\n            let originalTransactionId = receiptInfo[\"original_transaction_id\"] as? String,\n            let purchaseDate = ReceiptItem.parseDate(from: receiptInfo, key: \"purchase_date_ms\"),\n            let originalPurchaseDate = ReceiptItem.parseDate(from: receiptInfo, key: \"original_purchase_date_ms\")\n            else {\n                print(\"could not parse receipt item: \\(receiptInfo). Skipping...\")\n                return nil\n        }\n        self.productId = productId\n        self.quantity = quantity\n        self.transactionId = transactionId\n        self.originalTransactionId = originalTransactionId\n        self.purchaseDate = purchaseDate\n        self.originalPurchaseDate = originalPurchaseDate\n        self.webOrderLineItemId = receiptInfo[\"web_order_line_item_id\"] as? String\n        self.subscriptionExpirationDate = ReceiptItem.parseDate(from: receiptInfo, key: \"expires_date_ms\")\n        self.cancellationDate = ReceiptItem.parseDate(from: receiptInfo, key: \"cancellation_date_ms\")\n        if let isTrialPeriod = receiptInfo[\"is_trial_period\"] as? String {\n            self.isTrialPeriod = Bool(isTrialPeriod) ?? false\n        } else {\n            self.isTrialPeriod = false\n        }\n        if let isInIntroOfferPeriod = receiptInfo[\"is_in_intro_offer_period\"] as? String {\n            self.isInIntroOfferPeriod = Bool(isInIntroOfferPeriod) ?? false\n        } else {\n            self.isInIntroOfferPeriod = false\n        }\n        self.isUpgraded = receiptInfo[\"is_upgraded\"] as? Bool ?? false\n    }\n\n    private static func parseDate(from receiptInfo: ReceiptInfo, key: String) -> Date? {\n\n        guard\n            let requestDateString = receiptInfo[key] as? String,\n            let requestDateMs = Double(requestDateString) else {\n                return nil\n        }\n        return Date(timeIntervalSince1970: requestDateMs / 1000)\n    }\n}\n\n// MARK: - receipt mangement\ninternal class InAppReceipt {\n\n    /**\n     *  Verify the purchase of a Consumable or NonConsumable product in a receipt\n     *  - Parameter productId: the product id of the purchase to verify\n     *  - Parameter inReceipt: the receipt to use for looking up the purchase\n     *  - return: either notPurchased or purchased\n     */\n    class func verifyPurchase(\n        productId: String,\n        inReceipt receipt: ReceiptInfo\n    ) -> VerifyPurchaseResult {\n\n        // Get receipts info for the product\n        let receipts = getInAppReceipts(receipt: receipt)\n        let filteredReceiptsInfo = filterReceiptsInfo(receipts: receipts, withProductIds: [productId])\n        let nonCancelledReceiptsInfo = filteredReceiptsInfo.filter { receipt in receipt[\"cancellation_date\"] == nil }\n\n        #if swift(>=4.1)\n            let receiptItems = nonCancelledReceiptsInfo.compactMap { ReceiptItem(receiptInfo: $0) }\n        #else\n            let receiptItems = nonCancelledReceiptsInfo.flatMap { ReceiptItem(receiptInfo: $0) }\n        #endif\n        \n        // Verify that at least one receipt has the right product id\n        if let firstItem = receiptItems.first {\n            return .purchased(item: firstItem)\n        }\n        return .notPurchased\n    }\n\n    /**\n     *  Verify the validity of a set of subscriptions in a receipt.\n     *\n     *  This method extracts all transactions matching the given productIds and sorts them by date in descending order. It then compares the first transaction expiry date against the receipt date, to determine its validity.\n     *  - Note: You can use this method to check the validity of (mutually exclusive) subscriptions in a subscription group.\n     *  - Remark: The type parameter determines how the expiration dates are calculated for all subscriptions. Make sure all productIds match the specified subscription type to avoid incorrect results.\n     *  - Parameter type: .autoRenewable or .nonRenewing.\n     *  - Parameter productIds: The product ids of the subscriptions to verify.\n     *  - Parameter receipt: The receipt to use for looking up the subscriptions\n     *  - Parameter validUntil: Date to check against the expiry date of the subscriptions. This is only used if a date is not found in the receipt.\n     *  - return: Either .notPurchased or .purchased / .expired with the expiry date found in the receipt.\n     */\n    class func verifySubscriptions(\n        ofType type: SubscriptionType,\n        productIds: Set<String>,\n        inReceipt receipt: ReceiptInfo,\n        validUntil date: Date = Date()\n    ) -> VerifySubscriptionResult {\n\n        // The values of the latest_receipt and latest_receipt_info keys are useful when checking whether an auto-renewable subscription is currently active. By providing any transaction receipt for the subscription and checking these values, you can get information about the currently-active subscription period. If the receipt being validated is for the latest renewal, the value for latest_receipt is the same as receipt-data (in the request) and the value for latest_receipt_info is the same as receipt.\n        let (receipts, duration) = getReceiptsAndDuration(for: type, inReceipt: receipt)\n        let receiptsInfo = filterReceiptsInfo(receipts: receipts, withProductIds: productIds)\n        let nonCancelledReceiptsInfo = receiptsInfo.filter { receipt in receipt[\"cancellation_date\"] == nil }\n        if nonCancelledReceiptsInfo.count == 0 {\n            return .notPurchased\n        }\n\n        let receiptDate = getReceiptRequestDate(inReceipt: receipt) ?? date\n\n        #if swift(>=4.1)\n            let receiptItems = nonCancelledReceiptsInfo.compactMap { ReceiptItem(receiptInfo: $0) }\n        #else\n            let receiptItems = nonCancelledReceiptsInfo.flatMap { ReceiptItem(receiptInfo: $0) }\n        #endif\n\n        if nonCancelledReceiptsInfo.count > receiptItems.count {\n            print(\"receipt has \\(nonCancelledReceiptsInfo.count) items, but only \\(receiptItems.count) were parsed\")\n        }\n\n        let sortedExpiryDatesAndItems = expiryDatesAndItems(receiptItems: receiptItems, duration: duration).sorted { a, b in\n            return a.0 > b.0\n        }\n\n        guard let firstExpiryDateItemPair = sortedExpiryDatesAndItems.first else {\n            return .notPurchased\n        }\n\n        let sortedReceiptItems = sortedExpiryDatesAndItems.map { $0.1 }\n        if firstExpiryDateItemPair.0 > receiptDate {\n            return .purchased(expiryDate: firstExpiryDateItemPair.0, items: sortedReceiptItems)\n        } else {\n            return .expired(expiryDate: firstExpiryDateItemPair.0, items: sortedReceiptItems)\n        }\n    }\n    \n    /**\n     *  Get the distinct product identifiers from receipt.\n     *\n     *  This Method extracts all product identifiers. (Including cancelled ones).\n     *  - Note: You can use this method to get all unique product identifiers from receipt.\n     *  - Parameter type: .autoRenewable or .nonRenewing.\n     *  - Parameter receipt: The receipt to use for looking up the product identifiers.\n     *  - return: Either Set<String> or nil.\n     */\n    class func getDistinctPurchaseIds(\n        ofType type: SubscriptionType,\n        inReceipt receipt: ReceiptInfo\n    ) -> Set<String>? {\n        \n        // Get receipts array from receipt\n        guard let receipts = getReceipts(for: type, inReceipt: receipt) else {\n            return nil\n        }\n        \n        #if swift(>=4.1)\n            let receiptIds = receipts.compactMap { ReceiptItem(receiptInfo: $0)?.productId }\n        #else\n            let receiptIds = receipts.flatMap { ReceiptItem(receiptInfo: $0)?.productId }\n        #endif\n        \n        if receiptIds.isEmpty {\n            return nil\n        }\n        \n        return Set(receiptIds)\n    }\n\n    private class func expiryDatesAndItems(receiptItems: [ReceiptItem], duration: TimeInterval?) -> [(Date, ReceiptItem)] {\n\n        if let duration = duration {\n            return receiptItems.map {\n                let expirationDate = Date(timeIntervalSince1970: $0.originalPurchaseDate.timeIntervalSince1970 + duration)\n                return (expirationDate, $0)\n            }\n        } else {\n            #if swift(>=4.1)\n                return receiptItems.compactMap {\n                    if let expirationDate = $0.subscriptionExpirationDate {\n                        return (expirationDate, $0)\n                    }\n                    return nil\n                }\n            #else\n                return receiptItems.flatMap {\n                    if let expirationDate = $0.subscriptionExpirationDate {\n                        return (expirationDate, $0)\n                    }\n                    return nil\n                }\n            #endif\n        }\n    }\n    \n    private class func getReceipts(for subscriptionType: SubscriptionType, inReceipt receipt: ReceiptInfo) -> [ReceiptInfo]? {\n        switch subscriptionType {\n        case .autoRenewable:\n            return receipt[\"latest_receipt_info\"] as? [ReceiptInfo]\n        case .nonRenewing:\n            return getInAppReceipts(receipt: receipt)\n        }\n    }\n\n    private class func getReceiptsAndDuration(for subscriptionType: SubscriptionType, inReceipt receipt: ReceiptInfo) -> ([ReceiptInfo]?, TimeInterval?) {\n        switch subscriptionType {\n        case .autoRenewable:\n            return (receipt[\"latest_receipt_info\"] as? [ReceiptInfo], nil)\n        case .nonRenewing(let duration):\n            return (getInAppReceipts(receipt: receipt), duration)\n        }\n    }\n\n    private class func getReceiptRequestDate(inReceipt receipt: ReceiptInfo) -> Date? {\n\n        guard let receiptInfo = receipt[\"receipt\"] as? ReceiptInfo,\n            let requestDateString = receiptInfo[\"request_date_ms\"] as? String else {\n            return nil\n        }\n        return Date(millisecondsSince1970: requestDateString)\n    }\n    \n    private class func getInAppReceipts(receipt: ReceiptInfo) -> [ReceiptInfo]? {\n        \n        let appReceipt = receipt[\"receipt\"] as? ReceiptInfo\n        return appReceipt?[\"in_app\"] as? [ReceiptInfo]\n    }\n\n    /**\n     *  Get all the receipts info for a specific product\n     *  - Parameter receipts: the receipts array to grab info from\n     *  - Parameter productId: the product id\n     */\n    private class func filterReceiptsInfo(receipts: [ReceiptInfo]?, withProductIds productIds: Set<String>) -> [ReceiptInfo] {\n\n        guard let receipts = receipts else {\n            return []\n        }\n\n        // Filter receipts with matching product ids\n        let receiptsMatchingProductIds = receipts\n            .filter { (receipt) -> Bool in\n                if let productId = receipt[\"product_id\"] as? String {\n                    return productIds.contains(productId)\n                }\n                return false\n            }\n\n        return receiptsMatchingProductIds\n    }\n}\n"
  },
  {
    "path": "Sources/SwiftyStoreKit/InAppReceiptRefreshRequest.swift",
    "content": "//\n//  InAppReceiptRefreshRequest.swift\n//  SwiftyStoreKit\n//\n//  Created by phimage on 23/12/15.\n// Copyright (c) 2015 Andrea Bizzotto (bizz84@gmail.com)\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\nimport StoreKit\nimport Foundation\n\nclass InAppReceiptRefreshRequest: NSObject, SKRequestDelegate, InAppRequest {\n\n    enum ResultType {\n        case success\n        case error(e: Error)\n    }\n\n    typealias RequestCallback = (ResultType) -> Void\n    typealias ReceiptRefresh = (_ receiptProperties: [String: Any]?, _ callback: @escaping RequestCallback) -> InAppReceiptRefreshRequest\n\n    class func refresh(_ receiptProperties: [String: Any]? = nil, callback: @escaping RequestCallback) -> InAppReceiptRefreshRequest {\n        let request = InAppReceiptRefreshRequest(receiptProperties: receiptProperties, callback: callback)\n        request.start()\n        return request\n    }\n\n    let refreshReceiptRequest: SKReceiptRefreshRequest\n    let callback: RequestCallback\n\n    deinit {\n        refreshReceiptRequest.delegate = nil\n    }\n\n    init(receiptProperties: [String: Any]? = nil, callback: @escaping RequestCallback) {\n        self.callback = callback\n        self.refreshReceiptRequest = SKReceiptRefreshRequest(receiptProperties: receiptProperties)\n        super.init()\n        self.refreshReceiptRequest.delegate = self\n    }\n\n    func start() {\n        self.refreshReceiptRequest.start()\n    }\n\n    func cancel() {\n        self.refreshReceiptRequest.cancel()\n    }\n    \n    func requestDidFinish(_ request: SKRequest) {\n        /*if let resoreRequest = request as? SKReceiptRefreshRequest {\n         let receiptProperties = resoreRequest.receiptProperties ?? [:]\n         for (k, v) in receiptProperties {\n         print(\"\\(k): \\(v)\")\n         }\n         }*/\n        performCallback(.success)\n    }\n    func request(_ request: SKRequest, didFailWithError error: Error) {\n        // XXX could here check domain and error code to return typed exception\n        performCallback(.error(e: error))\n    }\n    private func performCallback(_ result: ResultType) {\n        DispatchQueue.main.async {\n            self.callback(result)\n        }\n    }\n}\n"
  },
  {
    "path": "Sources/SwiftyStoreKit/InAppReceiptVerificator.swift",
    "content": "//\n//  InAppReceiptVerificator.swift\n//  SwiftyStoreKit\n//\n//  Created by Andrea Bizzotto on 16/05/2017.\n// Copyright (c) 2017 Andrea Bizzotto (bizz84@gmail.com)\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\nimport Foundation\n\nclass InAppReceiptVerificator: NSObject {\n\n    let appStoreReceiptURL: URL?\n    init(appStoreReceiptURL: URL? = Bundle.main.appStoreReceiptURL) {\n        self.appStoreReceiptURL = appStoreReceiptURL\n    }\n\n    var appStoreReceiptData: Data? {\n        guard let receiptDataURL = appStoreReceiptURL,\n            let data = try? Data(contentsOf: receiptDataURL) else {\n            return nil\n        }\n        return data\n    }\n\n    private var receiptRefreshRequest: InAppReceiptRefreshRequest?\n\n    /**\n     *  Verify application receipt.\n     *  - Parameter validator: Validator to check the encrypted receipt and return the receipt in readable format\n     *  - Parameter forceRefresh: If true, refreshes the receipt even if one already exists.\n     *  - Parameter refresh: closure to perform receipt refresh (this is made explicit for testability)\n     *  - Parameter completion: handler for result\n     */\n    @discardableResult\n    public func verifyReceipt(using validator: ReceiptValidator,\n                              forceRefresh: Bool,\n                              refresh: InAppReceiptRefreshRequest.ReceiptRefresh = InAppReceiptRefreshRequest.refresh,\n                              completion: @escaping (VerifyReceiptResult) -> Void) -> InAppRequest? {\n        \n        return fetchReceipt(forceRefresh: forceRefresh, refresh: refresh) { result in\n            switch result {\n            case .success(let receiptData):\n                self.verify(receiptData: receiptData, using: validator, completion: completion)\n            case .error(let error):\n                completion(.error(error: error))\n            }\n        }\n    }\n    \n    /**\n     *  Fetch application receipt. This method does two things:\n     *  * If the receipt is missing, refresh it\n     *  * If the receipt is available or is refreshed, validate it\n     *  - Parameter forceRefresh: If true, refreshes the receipt even if one already exists.\n     *  - Parameter refresh: closure to perform receipt refresh (this is made explicit for testability)\n     *  - Parameter completion: handler for result\n     */\n    @discardableResult\n    public func fetchReceipt(forceRefresh: Bool,\n                             refresh: InAppReceiptRefreshRequest.ReceiptRefresh = InAppReceiptRefreshRequest.refresh,\n                             completion: @escaping (FetchReceiptResult) -> Void) -> InAppRequest? {\n\n        if let receiptData = appStoreReceiptData, forceRefresh == false {\n            completion(.success(receiptData: receiptData))\n            return nil\n        } else {\n            \n            receiptRefreshRequest = refresh(nil) { result in\n                \n                self.receiptRefreshRequest = nil\n                \n                switch result {\n                case .success:\n                    if let receiptData = self.appStoreReceiptData {\n                        completion(.success(receiptData: receiptData))\n                    } else {\n                        completion(.error(error: .noReceiptData))\n                    }\n                case .error(let e):\n                    completion(.error(error: .networkError(error: e)))\n                }\n            }\n            return receiptRefreshRequest\n        }\n    }\n    \n    /**\n     *  - Parameter receiptData: encrypted receipt data\n     *  - Parameter validator: Validator to check the encrypted receipt and return the receipt in readable format\n     *  - Parameter completion: handler for result\n     */\n    private func verify(receiptData: Data, using validator: ReceiptValidator, completion: @escaping (VerifyReceiptResult) -> Void) {\n     \n        validator.validate(receiptData: receiptData) { result in\n            \n            DispatchQueue.main.async {\n                completion(result)\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Sources/SwiftyStoreKit/OS.swift",
    "content": "//\n//  OS.swift\n//  SwiftyStoreKit\n//\n//  Copyright (c) 2020 Andrea Bizzotto (bizz84@gmail.com)\n//\n//  Permission is hereby granted, free of charge, to any person obtaining a copy\n//  of this software and associated documentation files (the \"Software\"), to deal\n//  in the Software without restriction, including without limitation the rights\n//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n//  copies of the Software, and to permit persons to whom the Software is\n//  furnished to do so, subject to the following conditions:\n//\n//  The above copyright notice and this permission notice shall be included in\n//  all copies or substantial portions of the Software.\n//\n//  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n//  THE SOFTWARE.\n\nimport StoreKit\n\n// MARK: - Missing SKMutablePayment init with product on macOS\n#if os(OSX)\n    extension SKMutablePayment {\n        convenience init(product: SKProduct) {\n            self.init()\n            self.productIdentifier = product.productIdentifier\n        }\n    }\n#endif\n\n// MARK: - Missing SKError on watchOS\n#if os(watchOS) && swift(<5.3)\npublic struct SKError: Error {\n    \n    public typealias Code = SKErrorCode\n    \n    let _nsError: NSError\n\n    init(_nsError: NSError) {\n        self._nsError = _nsError\n    }\n    \n    public var code: Code {\n        return Code(rawValue: _nsError.code) ?? .unknown\n    }\n    \n    static var unknown: Code = .unknown\n    static var paymentInvalid: Code = .paymentInvalid\n}\n#endif\n"
  },
  {
    "path": "Sources/SwiftyStoreKit/PaymentQueueController.swift",
    "content": "//\n// PaymentQueueController.swift\n// SwiftyStoreKit\n//\n// Copyright (c) 2017 Andrea Bizzotto (bizz84@gmail.com)\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\nimport Foundation\nimport StoreKit\n\nprotocol TransactionController {\n    \n    /// Process the supplied transactions on a given queue.\n    /// - parameter transactions: transactions to process\n    /// - parameter paymentQueue: payment queue for finishing transactions\n    /// - returns: array of unhandled transactions\n    func processTransactions(_ transactions: [SKPaymentTransaction], on paymentQueue: PaymentQueue) -> [SKPaymentTransaction]\n    \n}\n\npublic enum TransactionResult {\n    case purchased(purchase: PurchaseDetails)\n    case restored(purchase: Purchase)\n    case deferred(purchase: PurchaseDetails)\n    case failed(error: SKError)\n}\n\npublic protocol PaymentQueue: AnyObject {\n    \n    func add(_ observer: SKPaymentTransactionObserver)\n    func remove(_ observer: SKPaymentTransactionObserver)\n    \n    func add(_ payment: SKPayment)\n    \n    func start(_ downloads: [SKDownload])\n    func pause(_ downloads: [SKDownload])\n    func resume(_ downloads: [SKDownload])\n    func cancel(_ downloads: [SKDownload])\n    \n    func restoreCompletedTransactions(withApplicationUsername username: String?)\n    \n    func finishTransaction(_ transaction: SKPaymentTransaction)\n}\n\nextension SKPaymentQueue: PaymentQueue {\n    \n    #if os(watchOS) && swift(<5.3)\n    public func resume(_ downloads: [SKDownload]) {\n        resumeDownloads(downloads)\n    }\n    #endif\n    \n}\n\nextension SKPaymentTransaction {\n    \n    open override var debugDescription: String {\n        let transactionId = transactionIdentifier ?? \"null\"\n        return \"productId: \\(payment.productIdentifier), transactionId: \\(transactionId), state: \\(transactionState), date: \\(String(describing: transactionDate))\"\n    }\n    \n}\n\nextension SKPaymentTransactionState: CustomDebugStringConvertible {\n    \n    public var debugDescription: String {\n        switch self {\n        case .purchasing: return \"purchasing\"\n        case .purchased: return \"purchased\"\n        case .failed: return \"failed\"\n        case .restored: return \"restored\"\n        case .deferred: return \"deferred\"\n        @unknown default: return \"default\"\n        }\n    }\n}\n\nstruct EntitlementRevocation {\n    let callback: ([String]) -> Void\n    \n    init(callback: @escaping ([String]) -> Void) {\n        self.callback = callback\n    }\n}\n\nclass PaymentQueueController: NSObject, SKPaymentTransactionObserver {\n    \n    private let paymentsController: PaymentsController\n    private let restorePurchasesController: RestorePurchasesController\n    private let completeTransactionsController: CompleteTransactionsController\n    unowned let paymentQueue: PaymentQueue\n    private var entitlementRevocation: EntitlementRevocation?\n    \n    deinit {\n        paymentQueue.remove(self)\n    }\n    \n    init(paymentQueue: PaymentQueue = SKPaymentQueue.default(),\n         paymentsController: PaymentsController = PaymentsController(),\n         restorePurchasesController: RestorePurchasesController = RestorePurchasesController(),\n         completeTransactionsController: CompleteTransactionsController = CompleteTransactionsController()) {\n        \n        self.paymentQueue = paymentQueue\n        self.paymentsController = paymentsController\n        self.restorePurchasesController = restorePurchasesController\n        self.completeTransactionsController = completeTransactionsController\n        super.init()\n        paymentQueue.add(self)\n    }\n    \n    private func assertCompleteTransactionsWasCalled() {\n        \n        let message = \"SwiftyStoreKit.completeTransactions() must be called when the app launches.\"\n        assert(completeTransactionsController.completeTransactions != nil, message)\n    }\n    \n    func startPayment(_ payment: Payment) {\n        assertCompleteTransactionsWasCalled()\n        \n        let skPayment = SKMutablePayment(product: payment.product)\n        skPayment.applicationUsername = payment.applicationUsername\n        skPayment.quantity = payment.quantity\n        \n        if #available(iOS 12.2, tvOS 12.2, OSX 10.14.4, watchOS 6.2, *) {\n            if let discount = payment.paymentDiscount?.discount as? SKPaymentDiscount {\n                skPayment.paymentDiscount = discount\n            }\n        }\n        \n        #if os(iOS) || os(tvOS) || os(watchOS)\n        if #available(iOS 8.3, watchOS 6.2, *) {\n            skPayment.simulatesAskToBuyInSandbox = payment.simulatesAskToBuyInSandbox\n        }\n        #endif\n        \n        paymentQueue.add(skPayment)\n        \n        paymentsController.append(payment)\n    }\n    \n    func onEntitlementRevocation(_ revocation: EntitlementRevocation) {\n        guard entitlementRevocation == nil else {\n            print(\"SwiftyStoreKit.onEntitlementRevocation() should only be called once when the app launches. Ignoring this call\")\n            return\n        }\n        \n        self.entitlementRevocation = revocation\n    }\n    \n    func restorePurchases(_ restorePurchases: RestorePurchases) {\n        assertCompleteTransactionsWasCalled()\n        \n        if restorePurchasesController.restorePurchases != nil {\n            return\n        }\n        \n        paymentQueue.restoreCompletedTransactions(withApplicationUsername: restorePurchases.applicationUsername)\n        \n        restorePurchasesController.restorePurchases = restorePurchases\n    }\n    \n    func completeTransactions(_ completeTransactions: CompleteTransactions) {\n        guard completeTransactionsController.completeTransactions == nil else {\n            print(\"SwiftyStoreKit.completeTransactions() should only be called once when the app launches. Ignoring this call\")\n            return\n        }\n        \n        completeTransactionsController.completeTransactions = completeTransactions\n    }\n    \n    func finishTransaction(_ transaction: PaymentTransaction) {\n        guard let skTransaction = transaction as? SKPaymentTransaction else {\n            print(\"Object is not a SKPaymentTransaction: \\(transaction)\")\n            return\n        }\n        paymentQueue.finishTransaction(skTransaction)\n    }\n    \n    func start(_ downloads: [SKDownload]) {\n        paymentQueue.start(downloads)\n    }\n    \n    func pause(_ downloads: [SKDownload]) {\n        paymentQueue.pause(downloads)\n    }\n    \n    func resume(_ downloads: [SKDownload]) {\n        paymentQueue.resume(downloads)\n    }\n    \n    func cancel(_ downloads: [SKDownload]) {\n        paymentQueue.cancel(downloads)\n    }\n    \n    var shouldAddStorePaymentHandler: ShouldAddStorePaymentHandler?\n    var updatedDownloadsHandler: UpdatedDownloadsHandler?\n    \n    \n    // MARK: - SKPaymentTransactionObserver\n    \n    func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {\n        /*\n         * Some notes about how requests are processed by SKPaymentQueue:\n         *\n         * SKPaymentQueue is used to queue payments or restore purchases requests.\n         * Payments are processed serially and in-order and require user interaction.\n         * Restore purchases requests don't require user interaction and can jump ahead of the queue.\n         * SKPaymentQueue rejects multiple restore purchases calls.\n         * Having one payment queue observer for each request causes extra processing\n         * Failed transactions only ever belong to queued payment requests.\n         * restoreCompletedTransactionsFailedWithError is always called when a restore purchases request fails.\n         * paymentQueueRestoreCompletedTransactionsFinished is always called following 0 or more update transactions when a restore purchases request succeeds.\n         * A complete transactions handler is required to catch any transactions that are updated when the app is not running.\n         * Registering a complete transactions handler when the app launches ensures that any pending transactions can be cleared.\n         * If a complete transactions handler is missing, pending transactions can be mis-attributed to any new incoming payments or restore purchases.\n         *\n         * The order in which transaction updates are processed is:\n         * 1. payments (transactionState: .purchased and .failed for matching product identifiers)\n         * 2. restore purchases (transactionState: .restored, or restoreCompletedTransactionsFailedWithError, or paymentQueueRestoreCompletedTransactionsFinished)\n         * 3. complete transactions (transactionState: .purchased, .failed, .restored, .deferred)\n         * Any transactions where state == .purchasing are ignored.\n         */\n        var unhandledTransactions = transactions.filter { $0.transactionState != .purchasing }\n        \n        if unhandledTransactions.count > 0 {\n            \n            unhandledTransactions = paymentsController.processTransactions(transactions, on: paymentQueue)\n            \n            unhandledTransactions = restorePurchasesController.processTransactions(unhandledTransactions, on: paymentQueue)\n            \n            unhandledTransactions = completeTransactionsController.processTransactions(unhandledTransactions, on: paymentQueue)\n            \n            if unhandledTransactions.count > 0 {\n                let strings = unhandledTransactions.map { $0.debugDescription }.joined(separator: \"\\n\")\n                print(\"unhandledTransactions:\\n\\(strings)\")\n            }\n        }\n    }\n    \n    func paymentQueue(_ queue: SKPaymentQueue, didRevokeEntitlementsForProductIdentifiers productIdentifiers: [String]) {\n        self.entitlementRevocation?.callback(productIdentifiers)\n    }\n    \n    func paymentQueue(_ queue: SKPaymentQueue, removedTransactions transactions: [SKPaymentTransaction]) {\n        \n    }\n    \n    func paymentQueue(_ queue: SKPaymentQueue, restoreCompletedTransactionsFailedWithError error: Error) {\n        restorePurchasesController.restoreCompletedTransactionsFailed(withError: error)\n    }\n    \n    func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) {\n        restorePurchasesController.restoreCompletedTransactionsFinished()\n    }\n    \n    func paymentQueue(_ queue: SKPaymentQueue, updatedDownloads downloads: [SKDownload]) {\n        updatedDownloadsHandler?(downloads)\n    }\n    \n    #if !os(watchOS)\n    func paymentQueue(_ queue: SKPaymentQueue, shouldAddStorePayment payment: SKPayment, for product: SKProduct) -> Bool {\n        return shouldAddStorePaymentHandler?(payment, product) ?? false\n    }\n    #endif\n}\n"
  },
  {
    "path": "Sources/SwiftyStoreKit/PaymentsController.swift",
    "content": "//\n// PaymentsController.swift\n// SwiftyStoreKit\n//\n// Copyright (c) 2017 Andrea Bizzotto (bizz84@gmail.com)\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\nimport Foundation\nimport StoreKit\n\nstruct Payment: Hashable {\n    let product: SKProduct\n    \n    let paymentDiscount: PaymentDiscount?\n    let quantity: Int\n    let atomically: Bool\n    let applicationUsername: String\n    let simulatesAskToBuyInSandbox: Bool\n    let callback: (TransactionResult) -> Void\n\n    func hash(into hasher: inout Hasher) {\n        hasher.combine(product)\n        hasher.combine(quantity)\n        hasher.combine(atomically)\n        hasher.combine(applicationUsername)\n        hasher.combine(simulatesAskToBuyInSandbox)\n    }\n    \n    static func == (lhs: Payment, rhs: Payment) -> Bool {\n        return lhs.product.productIdentifier == rhs.product.productIdentifier\n    }\n}\n\npublic struct PaymentDiscount {\n    let discount: AnyObject?\n    \n    @available(iOS 12.2, tvOS 12.2, OSX 10.14.4, watchOS 6.2, macCatalyst 13.0, *)\n    public init(discount: SKPaymentDiscount) {\n        self.discount = discount\n    }\n    \n    private init() {\n        self.discount = nil\n    }\n}\n\nclass PaymentsController: TransactionController {\n\n    private var payments: [Payment] = []\n\n    private func findPaymentIndex(withProductIdentifier identifier: String) -> Int? {\n        for payment in payments where payment.product.productIdentifier == identifier {\n            return payments.firstIndex(of: payment)\n        }\n        return nil\n    }\n\n    func hasPayment(_ payment: Payment) -> Bool {\n        return findPaymentIndex(withProductIdentifier: payment.product.productIdentifier) != nil\n    }\n\n    func append(_ payment: Payment) {\n        payments.append(payment)\n    }\n\n    func processTransaction(_ transaction: SKPaymentTransaction, on paymentQueue: PaymentQueue) -> Bool {\n\n        let transactionProductIdentifier = transaction.payment.productIdentifier\n\n        guard let paymentIndex = findPaymentIndex(withProductIdentifier: transactionProductIdentifier) else {\n\n            return false\n        }\n        let payment = payments[paymentIndex]\n\n        let transactionState = transaction.transactionState\n\n        if transactionState == .purchased {\n            let purchase = PurchaseDetails(productId: transactionProductIdentifier, quantity: transaction.payment.quantity, product: payment.product, transaction: transaction, originalTransaction: transaction.original, needsFinishTransaction: !payment.atomically)\n            \n            payment.callback(.purchased(purchase: purchase))\n\n            if payment.atomically {\n                paymentQueue.finishTransaction(transaction)\n            }\n            payments.remove(at: paymentIndex)\n            return true\n        }\n\n        if transactionState == .restored {\n            print(\"Unexpected restored transaction for payment \\(transactionProductIdentifier)\")\n\n            let purchase = PurchaseDetails(productId: transactionProductIdentifier, quantity: transaction.payment.quantity, product: payment.product, transaction: transaction, originalTransaction: transaction.original, needsFinishTransaction: !payment.atomically)\n\n            payment.callback(.purchased(purchase: purchase))\n\n            if payment.atomically {\n                paymentQueue.finishTransaction(transaction)\n            }\n            payments.remove(at: paymentIndex)\n            return true\n        }\n\n        if transactionState == .failed {\n\n            payment.callback(.failed(error: transactionError(for: transaction.error as NSError?)))\n\n            paymentQueue.finishTransaction(transaction)\n            payments.remove(at: paymentIndex)\n            return true\n        }\n\n        if transactionState == .deferred {\n            let purchase = PurchaseDetails(productId: transactionProductIdentifier, quantity: transaction.payment.quantity, product: payment.product, transaction: transaction, originalTransaction: transaction.original, needsFinishTransaction: !payment.atomically)\n\n            payment.callback(.deferred(purchase: purchase))\n\n            payments.remove(at: paymentIndex)\n            return true\n        }\n\n        return false\n    }\n\n    func transactionError(for error: NSError?) -> SKError {\n        let message = \"Unknown error\"\n        let altError = NSError(domain: SKErrorDomain, code: SKError.unknown.rawValue, userInfo: [ NSLocalizedDescriptionKey: message ])\n        let nsError = error ?? altError\n        return SKError(_nsError: nsError)\n    }\n\n    func processTransactions(_ transactions: [SKPaymentTransaction], on paymentQueue: PaymentQueue) -> [SKPaymentTransaction] {\n\n        return transactions.filter { !processTransaction($0, on: paymentQueue) }\n    }\n}\n"
  },
  {
    "path": "Sources/SwiftyStoreKit/Platforms/Info-iOS.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>FMWK</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>$(CURRENT_PROJECT_VERSION)</string>\n\t<key>NSPrincipalClass</key>\n\t<string></string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Sources/SwiftyStoreKit/Platforms/Info-macOS.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>FMWK</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>$(CURRENT_PROJECT_VERSION)</string>\n\t<key>NSHumanReadableCopyright</key>\n\t<string>Copyright © 2015 musevisions. All rights reserved.</string>\n\t<key>NSPrincipalClass</key>\n\t<string></string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Sources/SwiftyStoreKit/Platforms/Info-tvOS.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>FMWK</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>$(CURRENT_PROJECT_VERSION)</string>\n\t<key>NSPrincipalClass</key>\n\t<string></string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Sources/SwiftyStoreKit/Platforms/Info-watchOS.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>FMWK</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>$(CURRENT_PROJECT_VERSION)</string>\n\t<key>NSPrincipalClass</key>\n\t<string></string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Sources/SwiftyStoreKit/Platforms/SwiftyStoreKit-iOS.h",
    "content": "//\n// SwiftyStoreKit-iOS.h\n// SwiftyStoreKit\n//\n// Copyright (c) 2015 Andrea Bizzotto (bizz84@gmail.com)\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\n#import <UIKit/UIKit.h>\n\n//! Project version number for SwiftyStoreKit.\nFOUNDATION_EXPORT double SwiftyStoreKitVersionNumber;\n\n//! Project version string for SwiftyStoreKit.\nFOUNDATION_EXPORT const unsigned char SwiftyStoreKitVersionString[];\n\n// In this header, you should import all the public headers of your framework using statements like #import <SwiftyStoreKit/PublicHeader.h>\n\n\n"
  },
  {
    "path": "Sources/SwiftyStoreKit/Platforms/SwiftyStoreKit-macOS.h",
    "content": "//\n//  SwiftyStoreKit-macOS.h\n//  SwiftyStoreKit\n//\n//  Created by phimage on 19/12/15.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\n#import <Cocoa/Cocoa.h>\n\n//! Project version number for SwiftyStoreKit.\nFOUNDATION_EXPORT double SwiftyStoreKitVersionNumber;\n\n//! Project version string for SwiftyStoreKit.\nFOUNDATION_EXPORT const unsigned char SwiftyStoreKitVersionString[];\n\n// In this header, you should import all the public headers of your framework using statements like #import <SwiftyStoreKit/PublicHeader.h>\n\n\n"
  },
  {
    "path": "Sources/SwiftyStoreKit/Platforms/SwiftyStoreKit-tvOS.h",
    "content": "//\n//  SwiftyStoreKit-tvOS.h\n//  SwiftyStoreKit\n//\n//  Created by Florian Weich on 26.05.16.\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\n#import <UIKit/UIKit.h>\n\n//! Project version number for SwiftyStoreKit.\nFOUNDATION_EXPORT double SwiftyStoreKitVersionNumber;\n\n//! Project version string for SwiftyStoreKit.\nFOUNDATION_EXPORT const unsigned char SwiftyStoreKitVersionString[];\n\n// In this header, you should import all the public headers of your framework using statements like #import <SwiftyStoreKit/PublicHeader.h>\n\n\n"
  },
  {
    "path": "Sources/SwiftyStoreKit/Platforms/SwiftyStoreKit-watchOS.h",
    "content": "//\n//  SwiftyStoreKit-watchOS.h\n//  SwiftyStoreKit\n//\n//  Created by Sam Spencer on 5/29/20.\n//  Copyright © 2020 Sam Spencer. All rights reserved.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\n#import <UIKit/UIKit.h>\n#import <WatchKit/WatchKit.h>\n#import <StoreKit/StoreKit.h>\n\n//! Project version number for SwiftyStoreKit.\nFOUNDATION_EXPORT double SwiftyStoreKitVersionNumber;\n\n//! Project version string for SwiftyStoreKit.\nFOUNDATION_EXPORT const unsigned char SwiftyStoreKitVersionString[];\n\n// In this header, you should import all the public headers of your framework using statements like #import <SwiftyStoreKit/PublicHeader.h>\n\n\n"
  },
  {
    "path": "Sources/SwiftyStoreKit/ProductsInfoController.swift",
    "content": "//\n// ProductsInfoController.swift\n// SwiftyStoreKit\n//\n// Copyright (c) 2015 Andrea Bizzotto (bizz84@gmail.com)\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\nimport Foundation\nimport StoreKit\n\nprotocol InAppProductRequestBuilder: AnyObject {\n    func request(productIds: Set<String>, callback: @escaping InAppProductRequestCallback) -> InAppProductRequest\n}\n\nclass InAppProductQueryRequestBuilder: InAppProductRequestBuilder {\n    \n    func request(productIds: Set<String>, callback: @escaping InAppProductRequestCallback) -> InAppProductRequest {\n        return InAppProductQueryRequest(productIds: productIds, callback: callback)\n    }\n}\n\nclass ProductsInfoController: NSObject {\n\n    struct InAppProductQuery {\n        let request: InAppProductRequest\n        var completionHandlers: [InAppProductRequestCallback]\n    }\n    \n    let inAppProductRequestBuilder: InAppProductRequestBuilder\n    init(inAppProductRequestBuilder: InAppProductRequestBuilder = InAppProductQueryRequestBuilder()) {\n        self.inAppProductRequestBuilder = inAppProductRequestBuilder\n    }\n    \n    // As we can have multiple inflight requests, we store them in a dictionary by product ids\n    private var inflightRequests: [Set<String>: InAppProductQuery] = [:]\n\n    @discardableResult\n    func retrieveProductsInfo(_ productIds: Set<String>, completion: @escaping (RetrieveResults) -> Void) -> InAppProductRequest {\n\n        if inflightRequests[productIds] == nil {\n            let request = inAppProductRequestBuilder.request(productIds: productIds) { results in\n                \n                if let query = self.inflightRequests[productIds] {\n                    for completion in query.completionHandlers {\n                        completion(results)\n                    }\n                    self.inflightRequests[productIds] = nil\n                } else {\n                    // should not get here, but if it does it seems reasonable to call the outer completion block\n                    completion(results)\n                }\n            }\n            inflightRequests[productIds] = InAppProductQuery(request: request, completionHandlers: [completion])\n            request.start()\n\n            return request\n\n        } else {\n            \n            inflightRequests[productIds]!.completionHandlers.append(completion)\n\n            let query = inflightRequests[productIds]!\n\n            if query.request.hasCompleted {\n                query.completionHandlers.forEach {\n                    $0(query.request.cachedResults!)\n                }\n            }\n\n            return inflightRequests[productIds]!.request\n        }\n    }\n}\n"
  },
  {
    "path": "Sources/SwiftyStoreKit/RestorePurchasesController.swift",
    "content": "//\n// RestorePurchasesController.swift\n// SwiftyStoreKit\n//\n// Copyright (c) 2017 Andrea Bizzotto (bizz84@gmail.com)\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\nimport Foundation\nimport StoreKit\n\nstruct RestorePurchases {\n    let atomically: Bool\n    let applicationUsername: String?\n    let callback: ([TransactionResult]) -> Void\n\n    init(atomically: Bool, applicationUsername: String? = nil, callback: @escaping ([TransactionResult]) -> Void) {\n        self.atomically = atomically\n        self.applicationUsername = applicationUsername\n        self.callback = callback\n    }\n}\n\nclass RestorePurchasesController: TransactionController {\n\n    public var restorePurchases: RestorePurchases?\n\n    private var restoredPurchases: [TransactionResult] = []\n\n    func processTransaction(_ transaction: SKPaymentTransaction, atomically: Bool, on paymentQueue: PaymentQueue) -> Purchase? {\n\n        let transactionState = transaction.transactionState\n\n        if transactionState == .restored {\n\n            let transactionProductIdentifier = transaction.payment.productIdentifier\n            \n            let purchase = Purchase(productId: transactionProductIdentifier, quantity: transaction.payment.quantity, transaction: transaction, originalTransaction: transaction.original, needsFinishTransaction: !atomically)\n            if atomically {\n                paymentQueue.finishTransaction(transaction)\n            }\n            return purchase\n        }\n        return nil\n    }\n\n    func processTransactions(_ transactions: [SKPaymentTransaction], on paymentQueue: PaymentQueue) -> [SKPaymentTransaction] {\n\n        guard let restorePurchases = restorePurchases else {\n            return transactions\n        }\n\n        var unhandledTransactions: [SKPaymentTransaction] = []\n        for transaction in transactions {\n            if let restoredPurchase = processTransaction(transaction, atomically: restorePurchases.atomically, on: paymentQueue) {\n                restoredPurchases.append(.restored(purchase: restoredPurchase))\n            } else {\n                unhandledTransactions.append(transaction)\n            }\n        }\n\n        return unhandledTransactions\n    }\n\n    func restoreCompletedTransactionsFailed(withError error: Error) {\n\n        guard let restorePurchases = restorePurchases else {\n            print(\"Callback already called. Returning\")\n            return\n        }\n        restoredPurchases.append(.failed(error: SKError(_nsError: error as NSError)))\n        restorePurchases.callback(restoredPurchases)\n\n        // Reset state after error received\n        restoredPurchases = []\n        self.restorePurchases = nil\n\n    }\n\n    func restoreCompletedTransactionsFinished() {\n\n        guard let restorePurchases = restorePurchases else {\n            print(\"Callback already called. Returning\")\n            return\n        }\n        restorePurchases.callback(restoredPurchases)\n\n        // Reset state after error transactions finished\n        restoredPurchases = []\n        self.restorePurchases = nil\n    }\n}\n"
  },
  {
    "path": "Sources/SwiftyStoreKit/SKProduct+LocalizedPrice.swift",
    "content": "//\n// SKProduct+LocalizedPrice.swift\n// SwiftyStoreKit\n//\n// Created by Andrea Bizzotto on 19/10/2016.\n// Copyright (c) 2015 Andrea Bizzotto (bizz84@gmail.com)\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\nimport StoreKit\n\npublic extension SKProduct {\n\n    var localizedPrice: String? {\n        return priceFormatter(locale: priceLocale).string(from: price)\n    }\n    \n    private func priceFormatter(locale: Locale) -> NumberFormatter {\n        let formatter = NumberFormatter()\n        formatter.locale = locale\n        formatter.numberStyle = .currency\n        return formatter\n    }\n    \n    @available(iOSApplicationExtension 11.2, iOS 11.2, OSX 10.13.2, tvOS 11.2, watchOS 6.2, macCatalyst 13.0, *)\n    var localizedSubscriptionPeriod: String {\n        guard let subscriptionPeriod = self.subscriptionPeriod else { return \"\" }\n        \n        let dateComponents: DateComponents\n        \n        switch subscriptionPeriod.unit {\n        case .day: dateComponents = DateComponents(day: subscriptionPeriod.numberOfUnits)\n        case .week: dateComponents = DateComponents(weekOfMonth: subscriptionPeriod.numberOfUnits)\n        case .month: dateComponents = DateComponents(month: subscriptionPeriod.numberOfUnits)\n        case .year: dateComponents = DateComponents(year: subscriptionPeriod.numberOfUnits)\n        @unknown default: \n            print(\"WARNING: SwiftyStoreKit localizedSubscriptionPeriod does not handle all SKProduct.PeriodUnit cases.\")\n            // Default to month units in the unlikely event a different unit type is added to a future OS version\n            dateComponents = DateComponents(month: subscriptionPeriod.numberOfUnits) \n        }\n\n        return DateComponentsFormatter.localizedString(from: dateComponents, unitsStyle: .short) ?? \"\"\n    }\n    \n}\n"
  },
  {
    "path": "Sources/SwiftyStoreKit/SKProductDiscount+LocalizedPrice.swift",
    "content": "//\n//  SKProductDiscount+LocalizedPrice.swift\n//  SwiftyStoreKit\n//\n//  Created by Sam Spencer on 5/29/20.\n//  Copyright © 2020 Sam Spencer. All rights reserved.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\nimport StoreKit\n\n@available(iOSApplicationExtension 11.2, iOS 11.2, OSX 10.13.2, tvOS 11.2, watchOS 4.2, macCatalyst 13.0, *)\npublic extension SKProductDiscount {\n    \n    /// The formatted discount price of the product using the local currency.\n    var localizedPrice: String? {\n        return priceFormatter(locale: priceLocale).string(from: price)\n    }\n    \n    private func priceFormatter(locale: Locale) -> NumberFormatter {\n        let formatter = NumberFormatter()\n        formatter.locale = locale\n        formatter.numberStyle = .currency\n        return formatter\n    }\n    \n    /// The formatted, localized period / date for the product discount.\n    /// - note: The subscription period for the discount is independent of the product's regular subscription period, and does not have to match in units or duration.\n    var localizedSubscriptionPeriod: String {\n        let dateComponents: DateComponents\n        \n        switch subscriptionPeriod.unit {\n        case .day: dateComponents = DateComponents(day: subscriptionPeriod.numberOfUnits)\n        case .week: dateComponents = DateComponents(weekOfMonth: subscriptionPeriod.numberOfUnits)\n        case .month: dateComponents = DateComponents(month: subscriptionPeriod.numberOfUnits)\n        case .year: dateComponents = DateComponents(year: subscriptionPeriod.numberOfUnits)\n        @unknown default: \n            print(\"WARNING: SwiftyStoreKit localizedSubscriptionPeriod does not handle all SKProduct.PeriodUnit cases.\")\n            // Default to month units in the unlikely event a different unit type is added to a future OS version\n            dateComponents = DateComponents(month: subscriptionPeriod.numberOfUnits) \n        }\n        \n        return DateComponentsFormatter.localizedString(from: dateComponents, unitsStyle: .full) ?? \"\"\n    }\n    \n}\n"
  },
  {
    "path": "Sources/SwiftyStoreKit/SwiftyStoreKit+Types.swift",
    "content": "//\n// SwiftyStoreKit+Types.swift\n// SwiftyStoreKit\n//\n// Copyright (c) 2015 Andrea Bizzotto (bizz84@gmail.com)\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\nimport StoreKit\n\n// MARK: Purchases\n\n/// The Purchased protocol allows different purchase flows to be handled by common code in simple cases\n/// \n/// For example you could route through to\n///\n///     func didPurchase<P:Purchased>(item:P) { ... }\n///\n/// for example\n///  - SwiftyStoreKit.completeTransactions (in .purchased and .restored cases)\n///  - SwiftyStoreKit.restorePurchases (for results.restoredPurchases)\n///  - SwiftyStoreKit.purchaseProducd (in .success case)\npublic protocol Purchased {\n    var productId: String { get }\n    var quantity: Int { get }\n    var originalPurchaseDate: Date { get }\n}\n\nextension Purchase: Purchased {\n    public var originalPurchaseDate: Date {\n        guard let date = originalTransaction?.transactionDate ?? transaction.transactionDate else {\n            fatalError(\"there should always be a transaction date, so this should not happen...\")\n        }\n        return  date\n    }\n}\n\nextension PurchaseDetails: Purchased {\n    public var originalPurchaseDate: Date {\n        guard let date = originalTransaction?.transactionDate ?? transaction.transactionDate else {\n            fatalError(\"there should always be a transaction date, so this should not happen...\")\n        }\n        return  date\n    }\n}\n\n// Restored product\npublic struct Purchase {\n    public let productId: String\n    public let quantity: Int\n    public let transaction: PaymentTransaction\n    public let originalTransaction: PaymentTransaction?\n    public let needsFinishTransaction: Bool\n    \n    public init(productId: String, quantity: Int, transaction: PaymentTransaction, originalTransaction: PaymentTransaction?, needsFinishTransaction: Bool) {\n        self.productId = productId\n        self.quantity = quantity\n        self.transaction = transaction\n        self.originalTransaction = originalTransaction\n        self.needsFinishTransaction = needsFinishTransaction\n    }\n}\n\n/// Purchased product\npublic struct PurchaseDetails {\n    public let productId: String\n    public let quantity: Int\n    public let product: SKProduct\n    public let transaction: PaymentTransaction\n    public let originalTransaction: PaymentTransaction?\n    public let needsFinishTransaction: Bool\n    \n    public init(productId: String, quantity: Int, product: SKProduct, transaction: PaymentTransaction, originalTransaction: PaymentTransaction?, needsFinishTransaction: Bool) {\n        self.productId = productId\n        self.quantity = quantity\n        self.product = product\n        self.transaction = transaction\n        self.originalTransaction = originalTransaction\n        self.needsFinishTransaction = needsFinishTransaction\n    }\n}\n\n/// Conform to this protocol to provide custom receipt validator\npublic protocol ReceiptValidator {\n\tfunc validate(receiptData: Data, completion: @escaping (VerifyReceiptResult) -> Void)\n}\n\n/// Payment transaction\npublic protocol PaymentTransaction {\n    var transactionDate: Date? { get }\n    var transactionState: SKPaymentTransactionState { get }\n    var transactionIdentifier: String? { get }\n    var downloads: [SKDownload] { get }\n}\n\n/// Add PaymentTransaction conformance to SKPaymentTransaction\nextension SKPaymentTransaction: PaymentTransaction { }\n\n/// Products information\npublic struct RetrieveResults {\n    public let retrievedProducts: Set<SKProduct>\n    public let invalidProductIDs: Set<String>\n    public let error: Error?\n    \n    public init(retrievedProducts: Set<SKProduct>, invalidProductIDs: Set<String>, error: Error?) {\n        self.retrievedProducts = retrievedProducts\n        self.invalidProductIDs = invalidProductIDs\n        self.error = error\n    }\n}\n\n/// Purchase result\npublic enum PurchaseResult {\n    case success(purchase: PurchaseDetails)\n    case deferred(purchase: PurchaseDetails)\n    case error(error: SKError)\n}\n\n/// Restore purchase results\npublic struct RestoreResults {\n    public let restoredPurchases: [Purchase]\n    public let restoreFailedPurchases: [(SKError, String?)]\n    \n    public init(restoredPurchases: [Purchase], restoreFailedPurchases: [(SKError, String?)]) {\n        self.restoredPurchases = restoredPurchases\n        self.restoreFailedPurchases = restoreFailedPurchases\n    }\n}\n\npublic typealias ShouldAddStorePaymentHandler = (_ payment: SKPayment, _ product: SKProduct) -> Bool\npublic typealias UpdatedDownloadsHandler = (_ downloads: [SKDownload]) -> Void\n\n// MARK: Receipt verification\n\n/// Info for receipt returned by server\npublic typealias ReceiptInfo = [String: AnyObject]\n\n/// Fetch receipt result\npublic enum FetchReceiptResult {\n    case success(receiptData: Data)\n    case error(error: ReceiptError)\n}\n\n/// Verify receipt result\npublic enum VerifyReceiptResult {\n    case success(receipt: ReceiptInfo)\n    case error(error: ReceiptError)\n}\n\n/// Result for Consumable and NonConsumable\npublic enum VerifyPurchaseResult {\n    case purchased(item: ReceiptItem)\n    case notPurchased\n}\n\n/// Verify subscription result\npublic enum VerifySubscriptionResult {\n    case purchased(expiryDate: Date, items: [ReceiptItem])\n    case expired(expiryDate: Date, items: [ReceiptItem])\n    case notPurchased\n}\n\npublic enum SubscriptionType: Hashable {\n    case autoRenewable\n    case nonRenewing(validDuration: TimeInterval)\n}\n\npublic struct ReceiptItem: Purchased, Codable {\n    \n    /// The product identifier of the item that was purchased. This value corresponds to the `productIdentifier` property of the `SKPayment` object stored in the transaction’s payment property.\n    public var productId: String\n    \n    /// The number of items purchased. This value corresponds to the `quantity` property of the `SKPayment` object stored in the transaction’s payment property.\n    public var quantity: Int\n    \n    /// The transaction identifier of the item that was purchased. This value corresponds to the transaction’s `transactionIdentifier` property.\n    public var transactionId: String\n    \n    /// For a transaction that restores a previous transaction, the transaction identifier of the original transaction. \n    /// \n    /// Otherwise, identical to the transaction identifier. This value corresponds to the original transaction’s `transactionIdentifier` property. All receipts in a chain of renewals for an auto-renewable subscription have the same value for this field.\n    public var originalTransactionId: String\n    \n    /// The date and time that the item was purchased. This value corresponds to the transaction’s `transactionDate` property.\n    public var purchaseDate: Date\n    \n    /// For a transaction that restores a previous transaction, the date of the original transaction. This value corresponds to the original transaction’s `transactionDate` property. In an auto-renewable subscription receipt, this indicates the beginning of the subscription period, even if the subscription has been renewed.\n    public var originalPurchaseDate: Date\n    \n    /// The primary key for identifying subscription purchases.\n    public var webOrderLineItemId: String?\n    \n    /// The expiration date for the subscription, expressed as the number of milliseconds since January 1, 1970, 00:00:00 GMT. This key is **only** present for **auto-renewable** subscription receipts.\n    public var subscriptionExpirationDate: Date?\n    \n    /// For a transaction that was canceled by Apple customer support, the time and date of the cancellation. \n    /// \n    /// Treat a canceled receipt the same as if no purchase had ever been made.\n    public var cancellationDate: Date?\n    \n    /// Indicates whether or not the subscription item is currently within a given trial period.\n    public var isTrialPeriod: Bool\n    \n    /// Indicates whether or not the subscription item is currently within an intro offer period.\n    public var isInIntroOfferPeriod: Bool\n    \n    /// An indicator that a subscription has been canceled due to an upgrade. This field is only present for upgrade transactions.\n    public var isUpgraded: Bool\n    \n    public init(productId: String, quantity: Int, transactionId: String, originalTransactionId: String, purchaseDate: Date, originalPurchaseDate: Date, webOrderLineItemId: String?, subscriptionExpirationDate: Date?, cancellationDate: Date?, isTrialPeriod: Bool, isInIntroOfferPeriod: Bool, isUpgraded: Bool) {\n        self.productId = productId\n        self.quantity = quantity\n        self.transactionId = transactionId\n        self.originalTransactionId = originalTransactionId\n        self.purchaseDate = purchaseDate\n        self.originalPurchaseDate = originalPurchaseDate\n        self.webOrderLineItemId = webOrderLineItemId\n        self.subscriptionExpirationDate = subscriptionExpirationDate\n        self.cancellationDate = cancellationDate\n        self.isTrialPeriod = isTrialPeriod\n        self.isInIntroOfferPeriod = isInIntroOfferPeriod\n        self.isUpgraded = isUpgraded\n    }\n}\n\n/// Error when managing receipt\npublic enum ReceiptError: Swift.Error {\n    /// No receipt data\n    case noReceiptData\n    /// No data received\n    case noRemoteData\n    /// Error when encoding HTTP body into JSON\n    case requestBodyEncodeError(error: Swift.Error)\n    /// Error when proceeding request\n    case networkError(error: Swift.Error)\n    /// Error when decoding response\n    case jsonDecodeError(string: String?)\n    /// Receive invalid - bad status returned\n    case receiptInvalid(receipt: ReceiptInfo, status: ReceiptStatus)\n}\n\n/// Status code returned by remote server\n/// \n/// See Table 2-1  Status codes\npublic enum ReceiptStatus: Int {\n    /// Not decodable status\n    case unknown = -2\n    /// No status returned\n    case none = -1\n    /// valid statua\n    case valid = 0\n    /// The App Store could not read the JSON object you provided.\n    case jsonNotReadable = 21000\n    /// The data in the receipt-data property was malformed or missing.\n    case malformedOrMissingData = 21002\n    /// The receipt could not be authenticated.\n    case receiptCouldNotBeAuthenticated = 21003\n    /// The shared secret you provided does not match the shared secret on file for your account.\n    case secretNotMatching = 21004\n    /// The receipt server is not currently available.\n    case receiptServerUnavailable = 21005\n    /// This receipt is valid but the subscription has expired. When this status code is returned to your server, the receipt data is also decoded and returned as part of the response.\n    case subscriptionExpired = 21006\n    ///  This receipt is from the test environment, but it was sent to the production environment for verification. Send it to the test environment instead.\n    case testReceipt = 21007\n    /// This receipt is from the production environment, but it was sent to the test environment for verification. Send it to the production environment instead.\n    case productionEnvironment = 21008\n\n    var isValid: Bool { return self == .valid}\n}\n\n// Receipt field as defined in : https://developer.apple.com/library/ios/releasenotes/General/ValidateAppStoreReceipt/Chapters/ReceiptFields.html#//apple_ref/doc/uid/TP40010573-CH106-SW1\npublic enum ReceiptInfoField: String {\n    /// Bundle Identifier. This corresponds to the value of CFBundleIdentifier in the Info.plist file.\n    case bundle_id\n    /// The app’s version number.This corresponds to the value of CFBundleVersion (in iOS) or CFBundleShortVersionString (in OS X) in the Info.plist.\n    case application_version\n    /// The version of the app that was originally purchased. This corresponds to the value of CFBundleVersion (in iOS) or CFBundleShortVersionString (in OS X) in the Info.plist file when the purchase was originally made.\n    case original_application_version\n    /// The date when the app receipt was created.\n    case creation_date\n    /// The date that the app receipt expires. This key is present only for apps purchased through the Volume Purchase Program.\n    case expiration_date\n\n    /// The receipt for an in-app purchase.\n    case in_app\n\n    public enum InApp: String {\n        /// The number of items purchased. This value corresponds to the quantity property of the SKPayment object stored in the transaction’s payment property.\n        case quantity\n        /// The product identifier of the item that was purchased. This value corresponds to the productIdentifier property of the SKPayment object stored in the transaction’s payment property.\n        case product_id\n        /// The transaction identifier of the item that was purchased. This value corresponds to the transaction’s transactionIdentifier property.\n        case transaction_id\n        /// For a transaction that restores a previous transaction, the transaction identifier of the original transaction. Otherwise, identical to the transaction identifier. This value corresponds to the original transaction’s transactionIdentifier property. All receipts in a chain of renewals for an auto-renewable subscription have the same value for this field.\n        case original_transaction_id\n        /// The date and time that the item was purchased. This value corresponds to the transaction’s transactionDate property.\n        case purchase_date\n        /// For a transaction that restores a previous transaction, the date of the original transaction. This value corresponds to the original transaction’s transactionDate property. In an auto-renewable subscription receipt, this indicates the beginning of the subscription period, even if the subscription has been renewed.\n        case original_purchase_date\n        /// The expiration date for the subscription, expressed as the number of milliseconds since January 1, 1970, 00:00:00 GMT. This key is only present for auto-renewable subscription receipts.\n        case expires_date\n        /// For a transaction that was canceled by Apple customer support, the time and date of the cancellation. Treat a canceled receipt the same as if no purchase had ever been made.\n        case cancellation_date\n        #if os(iOS) || os(tvOS)\n        /// A string that the App Store uses to uniquely identify the application that created the transaction. If your server supports multiple applications, you can use this value to differentiate between them. Apps are assigned an identifier only in the production environment, so this key is not present for receipts created in the test environment. This field is not present for Mac apps. See also Bundle Identifier.\n        case app_item_id\n        #endif\n        /// An arbitrary number that uniquely identifies a revision of your application. This key is not present for receipts created in the test environment.\n        case version_external_identifier\n        /// The primary key for identifying subscription purchases.\n        case web_order_line_item_id\n    }\n}\n\n#if os(OSX)\n    public enum ReceiptExitCode: Int32 {\n        /// If validation fails in OS X, call exit with a status of 173. This exit status notifies the system that your application has determined that its receipt is invalid. At this point, the system attempts to obtain a valid receipt and may prompt for the user’s iTunes credentials\n        case notValid = 173\n    }\n#endif\n"
  },
  {
    "path": "Sources/SwiftyStoreKit/SwiftyStoreKit.swift",
    "content": "//\n// SwiftyStoreKit.swift\n// SwiftyStoreKit\n//\n// Copyright (c) 2015 Andrea Bizzotto (bizz84@gmail.com)\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\nimport StoreKit\n\npublic class SwiftyStoreKit {\n    \n    private let productsInfoController: ProductsInfoController\n    \n    fileprivate let paymentQueueController: PaymentQueueController\n    \n    fileprivate let receiptVerificator: InAppReceiptVerificator\n    \n    init(productsInfoController: ProductsInfoController = ProductsInfoController(),\n         paymentQueueController: PaymentQueueController = PaymentQueueController(paymentQueue: SKPaymentQueue.default()),\n         receiptVerificator: InAppReceiptVerificator = InAppReceiptVerificator()) {\n        \n        self.productsInfoController = productsInfoController\n        self.paymentQueueController = paymentQueueController\n        self.receiptVerificator = receiptVerificator\n    }\n    \n    // MARK: private methods\n    fileprivate func retrieveProductsInfo(_ productIds: Set<String>, completion: @escaping (RetrieveResults) -> Void) -> InAppProductRequest {\n        return productsInfoController.retrieveProductsInfo(productIds, completion: completion)\n    }\n    \n    fileprivate func purchaseProduct(_ productId: String, quantity: Int = 1, atomically: Bool = true, applicationUsername: String = \"\", simulatesAskToBuyInSandbox: Bool = false, completion: @escaping ( PurchaseResult) -> Void) -> InAppProductRequest {\n        \n        return retrieveProductsInfo(Set([productId])) { result -> Void in\n            if let product = result.retrievedProducts.first {\n                self.purchase(product: product, quantity: quantity, atomically: atomically, applicationUsername: applicationUsername, simulatesAskToBuyInSandbox: simulatesAskToBuyInSandbox, completion: completion)\n            } else if let error = result.error {\n                completion(.error(error: SKError(_nsError: error as NSError)))\n            } else if let invalidProductId = result.invalidProductIDs.first {\n                let userInfo = [ NSLocalizedDescriptionKey: \"Invalid product id: \\(invalidProductId)\" ]\n                let error = NSError(domain: SKErrorDomain, code: SKError.paymentInvalid.rawValue, userInfo: userInfo)\n                completion(.error(error: SKError(_nsError: error)))\n            } else {\n                let error = NSError(domain: SKErrorDomain, code: SKError.unknown.rawValue, userInfo: nil)\n                completion(.error(error: SKError(_nsError: error)))\n            }\n        }\n    }\n    \n    fileprivate func purchase(product: SKProduct, quantity: Int, atomically: Bool, applicationUsername: String = \"\", simulatesAskToBuyInSandbox: Bool = false, paymentDiscount: PaymentDiscount? = nil, completion: @escaping (PurchaseResult) -> Void) {\n        paymentQueueController.startPayment(Payment(product: product, paymentDiscount: paymentDiscount, quantity: quantity, atomically: atomically, applicationUsername: applicationUsername, simulatesAskToBuyInSandbox: simulatesAskToBuyInSandbox) { result in\n            \n            completion(self.processPurchaseResult(result))\n        })\n    }\n    \n    fileprivate func restorePurchases(atomically: Bool = true, applicationUsername: String = \"\", completion: @escaping (RestoreResults) -> Void) {\n        \n        paymentQueueController.restorePurchases(RestorePurchases(atomically: atomically, applicationUsername: applicationUsername) { results in\n            \n            let results = self.processRestoreResults(results)\n            completion(results)\n        })\n    }\n    \n    fileprivate func completeTransactions(atomically: Bool = true, completion: @escaping ([Purchase]) -> Void) {\n        \n        paymentQueueController.completeTransactions(CompleteTransactions(atomically: atomically, callback: completion))\n    }\n\n    fileprivate func onEntitlementRevocation(completion: @escaping ([String]) -> Void) {\n\n        paymentQueueController.onEntitlementRevocation(EntitlementRevocation(callback: completion))\n    }\n    \n    fileprivate func finishTransaction(_ transaction: PaymentTransaction) {\n        \n        paymentQueueController.finishTransaction(transaction)\n    }\n    \n    private func processPurchaseResult(_ result: TransactionResult) -> PurchaseResult {\n        switch result {\n        case .purchased(let purchase):\n            return .success(purchase: purchase)\n        case .deferred(let purchase):\n            return .deferred(purchase: purchase)\n        case .failed(let error):\n            return .error(error: error)\n        case .restored(let purchase):\n            return .error(error: storeInternalError(description: \"Cannot restore product \\(purchase.productId) from purchase path\"))\n        }\n    }\n    \n    private func processRestoreResults(_ results: [TransactionResult]) -> RestoreResults {\n        var restoredPurchases: [Purchase] = []\n        var restoreFailedPurchases: [(SKError, String?)] = []\n        for result in results {\n            switch result {\n            case .purchased(let purchase):\n                let error = storeInternalError(description: \"Cannot purchase product \\(purchase.productId) from restore purchases path\")\n                restoreFailedPurchases.append((error, purchase.productId))\n            case .deferred(let purchase):\n                let error = storeInternalError(description: \"Cannot purchase product \\(purchase.productId) from restore purchases path\")\n                restoreFailedPurchases.append((error, purchase.productId))\n            case .failed(let error):\n                restoreFailedPurchases.append((error, nil))\n            case .restored(let purchase):\n                restoredPurchases.append(purchase)\n            }\n        }\n        return RestoreResults(restoredPurchases: restoredPurchases, restoreFailedPurchases: restoreFailedPurchases)\n    }\n    \n    private func storeInternalError(code: SKError.Code = SKError.unknown, description: String = \"\") -> SKError {\n        let error = NSError(domain: SKErrorDomain, code: code.rawValue, userInfo: [ NSLocalizedDescriptionKey: description ])\n        return SKError(_nsError: error)\n    }\n}\n\nextension SwiftyStoreKit {\n    \n    // MARK: Singleton\n    fileprivate static let sharedInstance = SwiftyStoreKit()\n    \n    // MARK: Public methods - Purchases\n    \n    /// Check if the current device can make payments.\n    /// - returns: `false` if this device is not able or allowed to make payments\n    public class var canMakePayments: Bool {\n        return SKPaymentQueue.canMakePayments()\n    }\n    \n    /// Retrieve products information\n    /// - Parameter productIds: The set of product identifiers to retrieve corresponding products for\n    /// - Parameter completion: handler for result\n    /// - returns: A cancellable `InAppRequest` object \n    @discardableResult\n    public class func retrieveProductsInfo(_ productIds: Set<String>, completion: @escaping (RetrieveResults) -> Void) -> InAppRequest {\n        return sharedInstance.retrieveProductsInfo(productIds, completion: completion)\n    }\n    \n    /// Purchase a product\n    ///  - Parameter productId: productId as specified in App Store Connect\n    ///  - Parameter quantity: quantity of the product to be purchased\n    ///  - Parameter atomically: whether the product is purchased atomically (e.g. `finishTransaction` is called immediately)\n    ///  - Parameter applicationUsername: an opaque identifier for the user’s account on your system\n    ///  - Parameter completion: handler for result\n    ///  - returns: A cancellable `InAppRequest` object   \n    @discardableResult\n    public class func purchaseProduct(_ productId: String, quantity: Int = 1, atomically: Bool = true, applicationUsername: String = \"\", simulatesAskToBuyInSandbox: Bool = false, completion: @escaping (PurchaseResult) -> Void) -> InAppRequest {\n        \n        return sharedInstance.purchaseProduct(productId, quantity: quantity, atomically: atomically, applicationUsername: applicationUsername, simulatesAskToBuyInSandbox: simulatesAskToBuyInSandbox, completion: completion)\n    }\n    \n    /// Purchase a product\n    ///  - Parameter product: product to be purchased\n    ///  - Parameter quantity: quantity of the product to be purchased\n    ///  - Parameter atomically: whether the product is purchased atomically (e.g. `finishTransaction` is called immediately)\n    ///  - Parameter applicationUsername: an opaque identifier for the user’s account on your system\n    ///  - Parameter product: optional discount to be applied. Must be of `SKProductPayment` type\n    ///  - Parameter completion: handler for result\n    public class func purchaseProduct(_ product: SKProduct, quantity: Int = 1, atomically: Bool = true, applicationUsername: String = \"\", simulatesAskToBuyInSandbox: Bool = false, paymentDiscount: PaymentDiscount? = nil, completion: @escaping ( PurchaseResult) -> Void) {\n        \n        sharedInstance.purchase(product: product, quantity: quantity, atomically: atomically, applicationUsername: applicationUsername, simulatesAskToBuyInSandbox: simulatesAskToBuyInSandbox, paymentDiscount: paymentDiscount, completion: completion)\n    }\n    \n    /// Restore purchases\n    ///  - Parameter atomically: whether the product is purchased atomically (e.g. `finishTransaction` is called immediately)\n    ///  - Parameter applicationUsername: an opaque identifier for the user’s account on your system\n    ///  - Parameter completion: handler for result\n    public class func restorePurchases(atomically: Bool = true, applicationUsername: String = \"\", completion: @escaping (RestoreResults) -> Void) {\n        \n        sharedInstance.restorePurchases(atomically: atomically, applicationUsername: applicationUsername, completion: completion)\n    }\n    \n    /// Complete transactions\n    ///  - Parameter atomically: whether the product is purchased atomically (e.g. `finishTransaction` is called immediately)\n    ///  - Parameter completion: handler for result\n    public class func completeTransactions(atomically: Bool = true, completion: @escaping ([Purchase]) -> Void) {\n        \n        sharedInstance.completeTransactions(atomically: atomically, completion: completion)\n    }\n\n    /// Entitlement revocation notification\n    ///   - Parameter completion: handler for result (list of product identifiers revoked)\n    @available(iOS 14, tvOS 14, OSX 11, watchOS 7, macCatalyst 14, *)\n    public class func onEntitlementRevocation(completion: @escaping ([String]) -> Void) {\n\n        sharedInstance.onEntitlementRevocation(completion: completion)\n    }\n    \n    /// Finish a transaction\n    /// \n    /// Once the content has been delivered, call this method to finish a transaction that was performed non-atomically\n    /// - Parameter transaction: transaction to finish\n    public class func finishTransaction(_ transaction: PaymentTransaction) {\n        \n        sharedInstance.finishTransaction(transaction)\n    }\n    \n    /// Register a handler for `SKPaymentQueue.shouldAddStorePayment` delegate method.\n    /// - requires: iOS 11.0+\n    public static var shouldAddStorePaymentHandler: ShouldAddStorePaymentHandler? {\n        didSet {\n            sharedInstance.paymentQueueController.shouldAddStorePaymentHandler = shouldAddStorePaymentHandler\n        }\n    }\n    \n    /// Register a handler for `paymentQueue(_:updatedDownloads:)`\n    /// - seealso: `paymentQueue(_:updatedDownloads:)`\n    public static var updatedDownloadsHandler: UpdatedDownloadsHandler? {\n        didSet {\n            sharedInstance.paymentQueueController.updatedDownloadsHandler = updatedDownloadsHandler\n        }\n    }\n    \n    public class func start(_ downloads: [SKDownload]) {\n        sharedInstance.paymentQueueController.start(downloads)\n    }\n    public class func pause(_ downloads: [SKDownload]) {\n        sharedInstance.paymentQueueController.pause(downloads)\n    }\n    public class func resume(_ downloads: [SKDownload]) {\n        sharedInstance.paymentQueueController.resume(downloads)\n    }\n    public class func cancel(_ downloads: [SKDownload]) {\n        sharedInstance.paymentQueueController.cancel(downloads)\n    }\n}\n\nextension SwiftyStoreKit {\n    \n    // MARK: Public methods - Receipt verification\n    \n    /// Return receipt data from the application bundle. This is read from `Bundle.main.appStoreReceiptURL`.\n    public static var localReceiptData: Data? {\n        return sharedInstance.receiptVerificator.appStoreReceiptData\n    }\n    \n    /// Verify application receipt\n    /// - Parameter validator: receipt validator to use\n    /// - Parameter forceRefresh: If `true`, refreshes the receipt even if one already exists.\n    /// - Parameter completion: handler for result\n    /// - returns: A cancellable `InAppRequest` object \n    @discardableResult\n    public class func verifyReceipt(using validator: ReceiptValidator, forceRefresh: Bool = false, completion: @escaping (VerifyReceiptResult) -> Void) -> InAppRequest? {\n        \n        return sharedInstance.receiptVerificator.verifyReceipt(using: validator, forceRefresh: forceRefresh, completion: completion)\n    }\n    \n    /// Fetch application receipt\n    /// - Parameter forceRefresh: If true, refreshes the receipt even if one already exists.\n    /// - Parameter completion: handler for result\n    /// - returns: A cancellable `InAppRequest` object \n    @discardableResult\n    public class func fetchReceipt(forceRefresh: Bool, completion: @escaping (FetchReceiptResult) -> Void) -> InAppRequest? {\n        \n        return sharedInstance.receiptVerificator.fetchReceipt(forceRefresh: forceRefresh, completion: completion)\n    }\n    \n    ///  Verify the purchase of a Consumable or NonConsumable product in a receipt\n    ///  - Parameter productId: the product id of the purchase to verify\n    ///  - Parameter inReceipt: the receipt to use for looking up the purchase\n    ///  - returns: A `VerifyPurchaseResult`, which may be either `notPurchased` or `purchased`.\n    public class func verifyPurchase(productId: String, inReceipt receipt: ReceiptInfo) -> VerifyPurchaseResult {\n        \n        return InAppReceipt.verifyPurchase(productId: productId, inReceipt: receipt)\n    }\n    \n    /**\n     *  Verify the validity of a subscription (auto-renewable, free or non-renewing) in a receipt.\n     *\n     *  This method extracts all transactions matching the given productId and sorts them by date in descending order. It then compares the first transaction expiry date against the receipt date to determine its validity.\n     *  - Parameter type: `.autoRenewable` or `.nonRenewing`.\n     *  - Parameter productId: The product id of the subscription to verify.\n     *  - Parameter receipt: The receipt to use for looking up the subscription.\n     *  - Parameter validUntil: Date to check against the expiry date of the subscription. This is only used if a date is not found in the receipt.\n     *  - returns: Either `.notPurchased` or `.purchased` / `.expired` with the expiry date found in the receipt.\n     */\n    public class func verifySubscription(ofType type: SubscriptionType, productId: String, inReceipt receipt: ReceiptInfo, validUntil date: Date = Date()) -> VerifySubscriptionResult {\n        \n        return InAppReceipt.verifySubscriptions(ofType: type, productIds: [productId], inReceipt: receipt, validUntil: date)\n    }\n    \n    /**\n     *  Verify the validity of a set of subscriptions in a receipt.\n     *\n     *  This method extracts all transactions matching the given productIds and sorts them by date in descending order. It then compares the first transaction expiry date against the receipt date, to determine its validity.\n     *  - Note: You can use this method to check the validity of (mutually exclusive) subscriptions in a subscription group.\n     *  - Remark: The type parameter determines how the expiration dates are calculated for all subscriptions. Make sure all productIds match the specified subscription type to avoid incorrect results.\n     *  - Parameter type: `.autoRenewable` or `.nonRenewing`.\n     *  - Parameter productIds: The product IDs of the subscriptions to verify.\n     *  - Parameter receipt: The receipt to use for looking up the subscriptions\n     *  - Parameter validUntil: Date to check against the expiry date of the subscriptions. This is only used if a date is not found in the receipt.\n     *  - returns: Either `.notPurchased` or `.purchased` / `.expired` with the expiry date found in the receipt.\n     */\n    public class func verifySubscriptions(ofType type: SubscriptionType = .autoRenewable, productIds: Set<String>, inReceipt receipt: ReceiptInfo, validUntil date: Date = Date()) -> VerifySubscriptionResult {\n        \n        return InAppReceipt.verifySubscriptions(ofType: type, productIds: productIds, inReceipt: receipt, validUntil: date)\n    }\n    \n    ///  Get the distinct product identifiers from receipt.\n    ///\n    /// This Method extracts all product identifiers. (Including cancelled ones).\n    /// - Note: You can use this method to get all unique product identifiers from receipt.\n    /// - Parameter type: `.autoRenewable` or `.nonRenewing`.\n    /// - Parameter receipt: The receipt to use for looking up product identifiers.\n    /// - returns: Either `Set<String>` or `nil`.\n    public class func getDistinctPurchaseIds(ofType type: SubscriptionType = .autoRenewable, inReceipt receipt: ReceiptInfo) -> Set<String>? {\n        \n        return InAppReceipt.getDistinctPurchaseIds(ofType: type, inReceipt: receipt)\n    }\n}\n"
  },
  {
    "path": "SwiftyStoreKit-iOS-Demo/AppDelegate.swift",
    "content": "//\n//  AppDelegate.swift\n//  SwiftyStoreKit\n//\n//  Created by Andrea Bizzotto on 03/09/2015.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\nimport UIKit\nimport SwiftyStoreKit\n\n@UIApplicationMain\nclass AppDelegate: UIResponder, UIApplicationDelegate {\n\n    var window: UIWindow?\n\n    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {\n\n        setupIAP()\n\n        return true\n    }\n\n    func setupIAP() {\n\n        SwiftyStoreKit.completeTransactions(atomically: true) { purchases in\n\n            for purchase in purchases {\n                switch purchase.transaction.transactionState {\n                case .purchased, .restored:\n                    let downloads = purchase.transaction.downloads\n                    if !downloads.isEmpty {\n                        SwiftyStoreKit.start(downloads)\n                    } else if purchase.needsFinishTransaction {\n                        // Deliver content from server, then:\n                        SwiftyStoreKit.finishTransaction(purchase.transaction)\n                    }\n                    print(\"\\(purchase.transaction.transactionState.debugDescription): \\(purchase.productId)\")\n                case .failed, .purchasing, .deferred:\n                    break // do nothing\n                @unknown default:\n                    break // do nothing\n                }\n            }\n        }\n        \n        SwiftyStoreKit.updatedDownloadsHandler = { downloads in\n\n            // contentURL is not nil if downloadState == .finished\n            let contentURLs = downloads.compactMap { $0.contentURL }\n            if contentURLs.count == downloads.count {\n                print(\"Saving: \\(contentURLs)\")\n                SwiftyStoreKit.finishTransaction(downloads[0].transaction)\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "SwiftyStoreKit-iOS-Demo/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"3x\"\n    },\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      \"idiom\" : \"ios-marketing\",\n      \"size\" : \"1024x1024\",\n      \"scale\" : \"1x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "SwiftyStoreKit-iOS-Demo/Assets.xcassets/Background.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"Background.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "SwiftyStoreKit-iOS-Demo/Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "SwiftyStoreKit-iOS-Demo/Base.lproj/LaunchScreen.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"11542\" systemVersion=\"16A270f\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" useTraitCollections=\"YES\" colorMatched=\"YES\" initialViewController=\"01J-lp-oVM\">\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=\"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": "SwiftyStoreKit-iOS-Demo/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=\"13771\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" colorMatched=\"YES\" initialViewController=\"BYZ-38-t0r\">\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=\"13772\"/>\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=\"SwiftyStoreKit_iOSDemo\" 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                            <imageView userInteractionEnabled=\"NO\" contentMode=\"scaleAspectFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"Background\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"JDz-7n-4vD\" userLabel=\"Background\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                            </imageView>\n                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"R2x-3P-rjx\" userLabel=\"Opaque\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                                <color key=\"backgroundColor\" red=\"0.0\" green=\"0.0\" blue=\"0.0\" alpha=\"0.29999999999999999\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                            </view>\n                            <scrollView clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"scaleToFill\" showsHorizontalScrollIndicator=\"NO\" showsVerticalScrollIndicator=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"hrH-XV-mE8\">\n                                <rect key=\"frame\" x=\"20\" y=\"20\" width=\"335\" height=\"627\"/>\n                                <subviews>\n                                    <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"SwiftyStoreKit\" textAlignment=\"center\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"FTs-3H-z8C\">\n                                        <rect key=\"frame\" x=\"87\" y=\"20\" width=\"159.5\" height=\"31.5\"/>\n                                        <fontDescription key=\"fontDescription\" style=\"UICTFontTextStyleTitle1\"/>\n                                        <color key=\"textColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                        <nil key=\"highlightedColor\"/>\n                                    </label>\n                                    <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Lightweight In App Purchases framework for iOS 8.0+\" textAlignment=\"center\" lineBreakMode=\"tailTruncation\" numberOfLines=\"0\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"gg1-bw-Mzz\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"66.5\" width=\"335\" height=\"16\"/>\n                                        <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"13\"/>\n                                        <color key=\"textColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                        <nil key=\"highlightedColor\"/>\n                                    </label>\n                                    <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Available purchases:\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"s8k-6i-mKn\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"102.5\" width=\"335\" height=\"21\"/>\n                                        <fontDescription key=\"fontDescription\" type=\"system\" weight=\"medium\" pointSize=\"17\"/>\n                                        <color key=\"textColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                        <nil key=\"highlightedColor\"/>\n                                    </label>\n                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"FII-Z2-VOo\" userLabel=\"Purchases Holder\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"133.5\" width=\"335\" height=\"373\"/>\n                                        <subviews>\n                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"C8u-2D-Dst\" userLabel=\"Non Consumable\">\n                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"335\" height=\"85\"/>\n                                                <subviews>\n                                                    <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"non consumable\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"uz9-cT-1WH\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"10\" width=\"126.5\" height=\"21\"/>\n                                                        <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                                                        <color key=\"textColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                                        <nil key=\"highlightedColor\"/>\n                                                    </label>\n                                                    <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"miS-cF-iGP\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"41\" width=\"111.5\" height=\"44\"/>\n                                                        <constraints>\n                                                            <constraint firstAttribute=\"height\" constant=\"44\" id=\"dYp-jU-vFF\"/>\n                                                        </constraints>\n                                                        <fontDescription key=\"fontDescription\" type=\"boldSystem\" pointSize=\"20\"/>\n                                                        <state key=\"normal\" title=\"Get Info\">\n                                                            <color key=\"titleColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                                        </state>\n                                                        <connections>\n                                                            <action selector=\"nonConsumableGetInfo\" destination=\"BYZ-38-t0r\" eventType=\"touchUpInside\" id=\"cNs-X3-9a0\"/>\n                                                        </connections>\n                                                    </button>\n                                                    <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"bVC-6b-q8f\">\n                                                        <rect key=\"frame\" x=\"223\" y=\"41\" width=\"112\" height=\"44\"/>\n                                                        <fontDescription key=\"fontDescription\" type=\"boldSystem\" pointSize=\"20\"/>\n                                                        <state key=\"normal\" title=\"Verify\">\n                                                            <color key=\"titleColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                                        </state>\n                                                        <connections>\n                                                            <action selector=\"nonConsumableVerifyPurchase\" destination=\"BYZ-38-t0r\" eventType=\"touchUpInside\" id=\"qK5-bQ-i2y\"/>\n                                                        </connections>\n                                                    </button>\n                                                    <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"DnE-MP-9Li\">\n                                                        <rect key=\"frame\" x=\"111.5\" y=\"41\" width=\"111.5\" height=\"44\"/>\n                                                        <fontDescription key=\"fontDescription\" type=\"boldSystem\" pointSize=\"20\"/>\n                                                        <state key=\"normal\" title=\"Purchase\">\n                                                            <color key=\"titleColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                                        </state>\n                                                        <connections>\n                                                            <action selector=\"nonConsumablePurchase\" destination=\"BYZ-38-t0r\" eventType=\"touchUpInside\" id=\"kql-d9-lgd\"/>\n                                                        </connections>\n                                                    </button>\n                                                    <switch opaque=\"NO\" contentMode=\"scaleToFill\" horizontalHuggingPriority=\"750\" verticalHuggingPriority=\"750\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" on=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"4Ha-LL-b2D\">\n                                                        <rect key=\"frame\" x=\"286\" y=\"5\" width=\"51\" height=\"31\"/>\n                                                    </switch>\n                                                    <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"atomic\" textAlignment=\"right\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"evJ-JG-n3W\">\n                                                        <rect key=\"frame\" x=\"226\" y=\"10\" width=\"52\" height=\"21\"/>\n                                                        <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                                                        <color key=\"textColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                                        <nil key=\"highlightedColor\"/>\n                                                    </label>\n                                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"II1-8z-X4b\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"84.5\" width=\"335\" height=\"0.5\"/>\n                                                        <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                                                        <constraints>\n                                                            <constraint firstAttribute=\"height\" constant=\"0.5\" id=\"nkJ-Fz-Bbq\"/>\n                                                        </constraints>\n                                                    </view>\n                                                </subviews>\n                                                <color key=\"backgroundColor\" red=\"0.0\" green=\"0.0\" blue=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                                <constraints>\n                                                    <constraint firstItem=\"DnE-MP-9Li\" firstAttribute=\"leading\" secondItem=\"miS-cF-iGP\" secondAttribute=\"trailing\" id=\"03Y-Zf-Crd\"/>\n                                                    <constraint firstAttribute=\"bottom\" secondItem=\"II1-8z-X4b\" secondAttribute=\"bottom\" id=\"4ek-ka-AAK\"/>\n                                                    <constraint firstItem=\"DnE-MP-9Li\" firstAttribute=\"width\" secondItem=\"bVC-6b-q8f\" secondAttribute=\"width\" id=\"5VM-4u-G3r\"/>\n                                                    <constraint firstAttribute=\"bottom\" secondItem=\"miS-cF-iGP\" secondAttribute=\"bottom\" id=\"84f-wu-LTK\"/>\n                                                    <constraint firstAttribute=\"trailing\" secondItem=\"bVC-6b-q8f\" secondAttribute=\"trailing\" id=\"FlO-j4-7Iu\"/>\n                                                    <constraint firstItem=\"bVC-6b-q8f\" firstAttribute=\"height\" secondItem=\"miS-cF-iGP\" secondAttribute=\"height\" id=\"GFq-56-rxW\"/>\n                                                    <constraint firstAttribute=\"trailing\" secondItem=\"II1-8z-X4b\" secondAttribute=\"trailing\" id=\"GZS-9h-uRG\"/>\n                                                    <constraint firstAttribute=\"trailing\" secondItem=\"4Ha-LL-b2D\" secondAttribute=\"trailing\" id=\"IB1-ME-I7f\"/>\n                                                    <constraint firstItem=\"uz9-cT-1WH\" firstAttribute=\"leading\" secondItem=\"C8u-2D-Dst\" secondAttribute=\"leading\" id=\"OVw-1f-UyK\"/>\n                                                    <constraint firstItem=\"bVC-6b-q8f\" firstAttribute=\"leading\" secondItem=\"DnE-MP-9Li\" secondAttribute=\"trailing\" id=\"PJQ-eg-Wx0\"/>\n                                                    <constraint firstAttribute=\"bottom\" secondItem=\"DnE-MP-9Li\" secondAttribute=\"bottom\" id=\"QGA-GC-0fc\"/>\n                                                    <constraint firstItem=\"miS-cF-iGP\" firstAttribute=\"top\" secondItem=\"uz9-cT-1WH\" secondAttribute=\"bottom\" constant=\"10\" id=\"R0o-N7-VRC\"/>\n                                                    <constraint firstAttribute=\"bottom\" secondItem=\"bVC-6b-q8f\" secondAttribute=\"bottom\" id=\"SFg-6m-fav\"/>\n                                                    <constraint firstItem=\"DnE-MP-9Li\" firstAttribute=\"height\" secondItem=\"miS-cF-iGP\" secondAttribute=\"height\" id=\"Sqj-CN-OmN\"/>\n                                                    <constraint firstItem=\"4Ha-LL-b2D\" firstAttribute=\"top\" secondItem=\"C8u-2D-Dst\" secondAttribute=\"top\" constant=\"5\" id=\"WNp-Qz-jZt\"/>\n                                                    <constraint firstItem=\"miS-cF-iGP\" firstAttribute=\"width\" secondItem=\"DnE-MP-9Li\" secondAttribute=\"width\" id=\"ZQN-Ih-dD1\"/>\n                                                    <constraint firstItem=\"II1-8z-X4b\" firstAttribute=\"leading\" secondItem=\"C8u-2D-Dst\" secondAttribute=\"leading\" id=\"gnE-TP-5Zl\"/>\n                                                    <constraint firstItem=\"evJ-JG-n3W\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"C8u-2D-Dst\" secondAttribute=\"leading\" constant=\"20\" symbolic=\"YES\" id=\"gvx-6f-EwM\"/>\n                                                    <constraint firstItem=\"uz9-cT-1WH\" firstAttribute=\"centerY\" secondItem=\"4Ha-LL-b2D\" secondAttribute=\"centerY\" id=\"hyD-Fo-Htp\"/>\n                                                    <constraint firstItem=\"4Ha-LL-b2D\" firstAttribute=\"leading\" secondItem=\"evJ-JG-n3W\" secondAttribute=\"trailing\" constant=\"8\" id=\"iGI-nt-CTg\"/>\n                                                    <constraint firstItem=\"miS-cF-iGP\" firstAttribute=\"leading\" secondItem=\"C8u-2D-Dst\" secondAttribute=\"leading\" id=\"jgB-bB-JUl\"/>\n                                                    <constraint firstItem=\"evJ-JG-n3W\" firstAttribute=\"centerY\" secondItem=\"4Ha-LL-b2D\" secondAttribute=\"centerY\" id=\"vXA-l0-mkR\"/>\n                                                    <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"uz9-cT-1WH\" secondAttribute=\"trailing\" constant=\"20\" symbolic=\"YES\" id=\"zUo-kR-4p4\"/>\n                                                </constraints>\n                                                <userDefinedRuntimeAttributes>\n                                                    <userDefinedRuntimeAttribute type=\"number\" keyPath=\"layer.borderWidth\">\n                                                        <integer key=\"value\" value=\"1\"/>\n                                                    </userDefinedRuntimeAttribute>\n                                                    <userDefinedRuntimeAttribute type=\"color\" keyPath=\"layer.borderColor\">\n                                                        <color key=\"value\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"calibratedRGB\"/>\n                                                    </userDefinedRuntimeAttribute>\n                                                </userDefinedRuntimeAttributes>\n                                            </view>\n                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"wOH-TN-d5B\" userLabel=\"Consumable\">\n                                                <rect key=\"frame\" x=\"0.0\" y=\"85\" width=\"335\" height=\"85\"/>\n                                                <subviews>\n                                                    <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"consumable\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"y0A-ka-mxL\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"10\" width=\"93.5\" height=\"21\"/>\n                                                        <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                                                        <color key=\"textColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                                        <nil key=\"highlightedColor\"/>\n                                                    </label>\n                                                    <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Bfi-CH-Fhw\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"41\" width=\"111.5\" height=\"44\"/>\n                                                        <constraints>\n                                                            <constraint firstAttribute=\"height\" constant=\"44\" id=\"DNz-gk-Fux\"/>\n                                                        </constraints>\n                                                        <fontDescription key=\"fontDescription\" type=\"boldSystem\" pointSize=\"20\"/>\n                                                        <state key=\"normal\" title=\"Get Info\">\n                                                            <color key=\"titleColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                                        </state>\n                                                        <connections>\n                                                            <action selector=\"consumableGetInfo\" destination=\"BYZ-38-t0r\" eventType=\"touchUpInside\" id=\"yBZ-bc-CJj\"/>\n                                                        </connections>\n                                                    </button>\n                                                    <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"SkZ-Nb-HJh\">\n                                                        <rect key=\"frame\" x=\"223\" y=\"41\" width=\"112\" height=\"44\"/>\n                                                        <fontDescription key=\"fontDescription\" type=\"boldSystem\" pointSize=\"20\"/>\n                                                        <state key=\"normal\" title=\"Verify\">\n                                                            <color key=\"titleColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                                        </state>\n                                                        <connections>\n                                                            <action selector=\"consumableVerifyPurchase\" destination=\"BYZ-38-t0r\" eventType=\"touchUpInside\" id=\"HLP-8R-y2t\"/>\n                                                        </connections>\n                                                    </button>\n                                                    <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Ikz-VC-5Ce\">\n                                                        <rect key=\"frame\" x=\"111.5\" y=\"41\" width=\"111.5\" height=\"44\"/>\n                                                        <fontDescription key=\"fontDescription\" type=\"boldSystem\" pointSize=\"20\"/>\n                                                        <state key=\"normal\" title=\"Purchase\">\n                                                            <color key=\"titleColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                                        </state>\n                                                        <connections>\n                                                            <action selector=\"consumablePurchase\" destination=\"BYZ-38-t0r\" eventType=\"touchUpInside\" id=\"znp-KQ-hUm\"/>\n                                                        </connections>\n                                                    </button>\n                                                    <switch opaque=\"NO\" contentMode=\"scaleToFill\" horizontalHuggingPriority=\"750\" verticalHuggingPriority=\"750\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" on=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"LFG-nF-AB9\">\n                                                        <rect key=\"frame\" x=\"286\" y=\"5\" width=\"51\" height=\"31\"/>\n                                                    </switch>\n                                                    <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"atomic\" textAlignment=\"right\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Rjg-Bu-Y2k\">\n                                                        <rect key=\"frame\" x=\"226\" y=\"10\" width=\"52\" height=\"21\"/>\n                                                        <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                                                        <color key=\"textColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                                        <nil key=\"highlightedColor\"/>\n                                                    </label>\n                                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"IAU-iH-Kwf\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"84.5\" width=\"335\" height=\"0.5\"/>\n                                                        <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                                                        <constraints>\n                                                            <constraint firstAttribute=\"height\" constant=\"0.5\" id=\"P3v-hu-b4A\"/>\n                                                        </constraints>\n                                                    </view>\n                                                </subviews>\n                                                <color key=\"backgroundColor\" red=\"0.0\" green=\"0.0\" blue=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                                <constraints>\n                                                    <constraint firstItem=\"y0A-ka-mxL\" firstAttribute=\"centerY\" secondItem=\"LFG-nF-AB9\" secondAttribute=\"centerY\" id=\"0CJ-MZ-SHt\"/>\n                                                    <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"y0A-ka-mxL\" secondAttribute=\"trailing\" constant=\"20\" symbolic=\"YES\" id=\"3RZ-NK-yHq\"/>\n                                                    <constraint firstItem=\"Ikz-VC-5Ce\" firstAttribute=\"width\" secondItem=\"SkZ-Nb-HJh\" secondAttribute=\"width\" id=\"EuT-aZ-Xd7\"/>\n                                                    <constraint firstAttribute=\"bottom\" secondItem=\"Bfi-CH-Fhw\" secondAttribute=\"bottom\" id=\"GSM-mj-3oD\"/>\n                                                    <constraint firstAttribute=\"trailing\" secondItem=\"LFG-nF-AB9\" secondAttribute=\"trailing\" id=\"Gn1-RW-iBd\"/>\n                                                    <constraint firstAttribute=\"bottom\" secondItem=\"Ikz-VC-5Ce\" secondAttribute=\"bottom\" id=\"Hq5-f9-UIq\"/>\n                                                    <constraint firstItem=\"Rjg-Bu-Y2k\" firstAttribute=\"centerY\" secondItem=\"LFG-nF-AB9\" secondAttribute=\"centerY\" id=\"Jtb-SI-EVy\"/>\n                                                    <constraint firstItem=\"Bfi-CH-Fhw\" firstAttribute=\"width\" secondItem=\"Ikz-VC-5Ce\" secondAttribute=\"width\" id=\"LZc-lK-97Z\"/>\n                                                    <constraint firstAttribute=\"bottom\" secondItem=\"SkZ-Nb-HJh\" secondAttribute=\"bottom\" id=\"RxE-NR-DBH\"/>\n                                                    <constraint firstItem=\"Ikz-VC-5Ce\" firstAttribute=\"height\" secondItem=\"Bfi-CH-Fhw\" secondAttribute=\"height\" id=\"Ryc-vh-KE9\"/>\n                                                    <constraint firstItem=\"Bfi-CH-Fhw\" firstAttribute=\"leading\" secondItem=\"wOH-TN-d5B\" secondAttribute=\"leading\" id=\"Srh-80-wgk\"/>\n                                                    <constraint firstItem=\"SkZ-Nb-HJh\" firstAttribute=\"height\" secondItem=\"Bfi-CH-Fhw\" secondAttribute=\"height\" id=\"Sw4-Wc-uw4\"/>\n                                                    <constraint firstItem=\"Bfi-CH-Fhw\" firstAttribute=\"top\" secondItem=\"y0A-ka-mxL\" secondAttribute=\"bottom\" constant=\"10\" id=\"UtD-Xc-JtR\"/>\n                                                    <constraint firstItem=\"Ikz-VC-5Ce\" firstAttribute=\"leading\" secondItem=\"Bfi-CH-Fhw\" secondAttribute=\"trailing\" id=\"Z2l-ec-1PE\"/>\n                                                    <constraint firstItem=\"Rjg-Bu-Y2k\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"wOH-TN-d5B\" secondAttribute=\"leading\" constant=\"20\" symbolic=\"YES\" id=\"e3g-MX-2M3\"/>\n                                                    <constraint firstAttribute=\"bottom\" secondItem=\"IAU-iH-Kwf\" secondAttribute=\"bottom\" id=\"jb0-cd-uhd\"/>\n                                                    <constraint firstAttribute=\"trailing\" secondItem=\"SkZ-Nb-HJh\" secondAttribute=\"trailing\" id=\"jp6-K7-eSd\"/>\n                                                    <constraint firstItem=\"SkZ-Nb-HJh\" firstAttribute=\"leading\" secondItem=\"Ikz-VC-5Ce\" secondAttribute=\"trailing\" id=\"kbI-hv-xhS\"/>\n                                                    <constraint firstItem=\"LFG-nF-AB9\" firstAttribute=\"top\" secondItem=\"wOH-TN-d5B\" secondAttribute=\"top\" constant=\"5\" id=\"oNw-Pa-0I8\"/>\n                                                    <constraint firstAttribute=\"trailing\" secondItem=\"IAU-iH-Kwf\" secondAttribute=\"trailing\" id=\"t1e-04-Qda\"/>\n                                                    <constraint firstItem=\"LFG-nF-AB9\" firstAttribute=\"leading\" secondItem=\"Rjg-Bu-Y2k\" secondAttribute=\"trailing\" constant=\"8\" id=\"ujT-Nh-rPd\"/>\n                                                    <constraint firstItem=\"y0A-ka-mxL\" firstAttribute=\"leading\" secondItem=\"wOH-TN-d5B\" secondAttribute=\"leading\" id=\"z1Q-aB-b6s\"/>\n                                                    <constraint firstItem=\"IAU-iH-Kwf\" firstAttribute=\"leading\" secondItem=\"wOH-TN-d5B\" secondAttribute=\"leading\" id=\"zsW-LW-4is\"/>\n                                                </constraints>\n                                            </view>\n                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"v1J-op-cSJ\" userLabel=\"Non Renewing\">\n                                                <rect key=\"frame\" x=\"0.0\" y=\"170\" width=\"335\" height=\"85\"/>\n                                                <subviews>\n                                                    <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"non renewing\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"5G0-vy-9K1\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"10\" width=\"104\" height=\"21\"/>\n                                                        <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                                                        <color key=\"textColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                                        <nil key=\"highlightedColor\"/>\n                                                    </label>\n                                                    <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Qsk-qr-ODg\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"41\" width=\"111.5\" height=\"44\"/>\n                                                        <constraints>\n                                                            <constraint firstAttribute=\"height\" constant=\"44\" id=\"rfG-CU-gJt\"/>\n                                                        </constraints>\n                                                        <fontDescription key=\"fontDescription\" type=\"boldSystem\" pointSize=\"20\"/>\n                                                        <state key=\"normal\" title=\"Get Info\">\n                                                            <color key=\"titleColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                                        </state>\n                                                        <connections>\n                                                            <action selector=\"nonRenewingGetInfo\" destination=\"BYZ-38-t0r\" eventType=\"touchUpInside\" id=\"AHq-cE-Tqq\"/>\n                                                        </connections>\n                                                    </button>\n                                                    <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ON5-Nn-RAE\">\n                                                        <rect key=\"frame\" x=\"223\" y=\"41\" width=\"112\" height=\"44\"/>\n                                                        <fontDescription key=\"fontDescription\" type=\"boldSystem\" pointSize=\"20\"/>\n                                                        <state key=\"normal\" title=\"Verify\">\n                                                            <color key=\"titleColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                                        </state>\n                                                        <connections>\n                                                            <action selector=\"nonRenewingVerifyPurchase\" destination=\"BYZ-38-t0r\" eventType=\"touchUpInside\" id=\"660-9I-cgZ\"/>\n                                                        </connections>\n                                                    </button>\n                                                    <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"sHg-e5-nXp\">\n                                                        <rect key=\"frame\" x=\"111.5\" y=\"41\" width=\"111.5\" height=\"44\"/>\n                                                        <fontDescription key=\"fontDescription\" type=\"boldSystem\" pointSize=\"20\"/>\n                                                        <state key=\"normal\" title=\"Purchase\">\n                                                            <color key=\"titleColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                                        </state>\n                                                        <connections>\n                                                            <action selector=\"nonRenewingPurchase\" destination=\"BYZ-38-t0r\" eventType=\"touchUpInside\" id=\"En3-8Z-NjV\"/>\n                                                        </connections>\n                                                    </button>\n                                                    <switch opaque=\"NO\" contentMode=\"scaleToFill\" horizontalHuggingPriority=\"750\" verticalHuggingPriority=\"750\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" on=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"0wG-zO-KFz\">\n                                                        <rect key=\"frame\" x=\"286\" y=\"5\" width=\"51\" height=\"31\"/>\n                                                    </switch>\n                                                    <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"atomic\" textAlignment=\"right\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"yg2-nB-s6N\">\n                                                        <rect key=\"frame\" x=\"226\" y=\"10\" width=\"52\" height=\"21\"/>\n                                                        <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                                                        <color key=\"textColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                                        <nil key=\"highlightedColor\"/>\n                                                    </label>\n                                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"lJD-qS-D0e\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"84.5\" width=\"335\" height=\"0.5\"/>\n                                                        <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                                                        <constraints>\n                                                            <constraint firstAttribute=\"height\" constant=\"0.5\" id=\"JIO-o0-Q6l\"/>\n                                                        </constraints>\n                                                    </view>\n                                                </subviews>\n                                                <color key=\"backgroundColor\" red=\"0.0\" green=\"0.0\" blue=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                                <constraints>\n                                                    <constraint firstItem=\"sHg-e5-nXp\" firstAttribute=\"leading\" secondItem=\"Qsk-qr-ODg\" secondAttribute=\"trailing\" id=\"0mI-Nd-QdR\"/>\n                                                    <constraint firstItem=\"ON5-Nn-RAE\" firstAttribute=\"height\" secondItem=\"Qsk-qr-ODg\" secondAttribute=\"height\" id=\"1up-fi-dPo\"/>\n                                                    <constraint firstItem=\"sHg-e5-nXp\" firstAttribute=\"width\" secondItem=\"ON5-Nn-RAE\" secondAttribute=\"width\" id=\"2NQ-TS-cR6\"/>\n                                                    <constraint firstItem=\"Qsk-qr-ODg\" firstAttribute=\"leading\" secondItem=\"v1J-op-cSJ\" secondAttribute=\"leading\" id=\"3Ag-F7-Jkv\"/>\n                                                    <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"5G0-vy-9K1\" secondAttribute=\"trailing\" constant=\"20\" symbolic=\"YES\" id=\"3Hm-aR-aTA\"/>\n                                                    <constraint firstAttribute=\"trailing\" secondItem=\"0wG-zO-KFz\" secondAttribute=\"trailing\" id=\"4LA-f2-dba\"/>\n                                                    <constraint firstAttribute=\"trailing\" secondItem=\"ON5-Nn-RAE\" secondAttribute=\"trailing\" id=\"6AD-qZ-3Xd\"/>\n                                                    <constraint firstItem=\"yg2-nB-s6N\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"v1J-op-cSJ\" secondAttribute=\"leading\" constant=\"20\" symbolic=\"YES\" id=\"84e-bg-IgJ\"/>\n                                                    <constraint firstItem=\"5G0-vy-9K1\" firstAttribute=\"leading\" secondItem=\"v1J-op-cSJ\" secondAttribute=\"leading\" id=\"8h6-Bb-N2b\"/>\n                                                    <constraint firstItem=\"yg2-nB-s6N\" firstAttribute=\"centerY\" secondItem=\"0wG-zO-KFz\" secondAttribute=\"centerY\" id=\"G7T-aV-BPt\"/>\n                                                    <constraint firstItem=\"0wG-zO-KFz\" firstAttribute=\"leading\" secondItem=\"yg2-nB-s6N\" secondAttribute=\"trailing\" constant=\"8\" id=\"MHb-pj-A8u\"/>\n                                                    <constraint firstItem=\"Qsk-qr-ODg\" firstAttribute=\"top\" secondItem=\"5G0-vy-9K1\" secondAttribute=\"bottom\" constant=\"10\" id=\"ORf-1n-tvl\"/>\n                                                    <constraint firstAttribute=\"trailing\" secondItem=\"lJD-qS-D0e\" secondAttribute=\"trailing\" id=\"PAZ-cf-6PO\"/>\n                                                    <constraint firstItem=\"Qsk-qr-ODg\" firstAttribute=\"width\" secondItem=\"sHg-e5-nXp\" secondAttribute=\"width\" id=\"Su9-dE-xio\"/>\n                                                    <constraint firstAttribute=\"bottom\" secondItem=\"sHg-e5-nXp\" secondAttribute=\"bottom\" id=\"WEr-9z-fpz\"/>\n                                                    <constraint firstItem=\"5G0-vy-9K1\" firstAttribute=\"centerY\" secondItem=\"0wG-zO-KFz\" secondAttribute=\"centerY\" id=\"Xct-Os-4i5\"/>\n                                                    <constraint firstItem=\"ON5-Nn-RAE\" firstAttribute=\"leading\" secondItem=\"sHg-e5-nXp\" secondAttribute=\"trailing\" id=\"Zyo-Nf-Tup\"/>\n                                                    <constraint firstItem=\"0wG-zO-KFz\" firstAttribute=\"top\" secondItem=\"v1J-op-cSJ\" secondAttribute=\"top\" constant=\"5\" id=\"cq6-tQ-UZ2\"/>\n                                                    <constraint firstAttribute=\"bottom\" secondItem=\"ON5-Nn-RAE\" secondAttribute=\"bottom\" id=\"kYt-GF-jzL\"/>\n                                                    <constraint firstAttribute=\"bottom\" secondItem=\"lJD-qS-D0e\" secondAttribute=\"bottom\" id=\"m66-al-h0I\"/>\n                                                    <constraint firstItem=\"sHg-e5-nXp\" firstAttribute=\"height\" secondItem=\"Qsk-qr-ODg\" secondAttribute=\"height\" id=\"tGW-Eq-fDv\"/>\n                                                    <constraint firstItem=\"lJD-qS-D0e\" firstAttribute=\"leading\" secondItem=\"v1J-op-cSJ\" secondAttribute=\"leading\" id=\"uhH-qI-ta4\"/>\n                                                    <constraint firstAttribute=\"bottom\" secondItem=\"Qsk-qr-ODg\" secondAttribute=\"bottom\" id=\"wiH-C3-ebm\"/>\n                                                </constraints>\n                                            </view>\n                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"A6G-Y9-4Xc\" userLabel=\"Auto Renewable\">\n                                                <rect key=\"frame\" x=\"0.0\" y=\"255\" width=\"335\" height=\"118\"/>\n                                                <subviews>\n                                                    <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"auto renewable\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"g1v-Yu-UQg\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"10\" width=\"117.5\" height=\"21\"/>\n                                                        <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                                                        <color key=\"textColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                                        <nil key=\"highlightedColor\"/>\n                                                    </label>\n                                                    <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Ckv-3X-zfV\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"41\" width=\"111.5\" height=\"44\"/>\n                                                        <constraints>\n                                                            <constraint firstAttribute=\"height\" constant=\"44\" id=\"ryx-Zk-QQW\"/>\n                                                        </constraints>\n                                                        <fontDescription key=\"fontDescription\" type=\"boldSystem\" pointSize=\"20\"/>\n                                                        <state key=\"normal\" title=\"Get Info\">\n                                                            <color key=\"titleColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                                        </state>\n                                                        <connections>\n                                                            <action selector=\"autoRenewableGetInfo\" destination=\"BYZ-38-t0r\" eventType=\"touchUpInside\" id=\"BYd-fm-ySR\"/>\n                                                        </connections>\n                                                    </button>\n                                                    <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"bWL-ZF-hDb\">\n                                                        <rect key=\"frame\" x=\"223\" y=\"41\" width=\"112\" height=\"44\"/>\n                                                        <fontDescription key=\"fontDescription\" type=\"boldSystem\" pointSize=\"20\"/>\n                                                        <state key=\"normal\" title=\"Verify\">\n                                                            <color key=\"titleColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                                        </state>\n                                                        <connections>\n                                                            <action selector=\"autoRenewableVerifyPurchase\" destination=\"BYZ-38-t0r\" eventType=\"touchUpInside\" id=\"piu-eN-GTz\"/>\n                                                        </connections>\n                                                    </button>\n                                                    <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"0AB-wg-Qch\">\n                                                        <rect key=\"frame\" x=\"111.5\" y=\"41\" width=\"111.5\" height=\"44\"/>\n                                                        <fontDescription key=\"fontDescription\" type=\"boldSystem\" pointSize=\"20\"/>\n                                                        <state key=\"normal\" title=\"Purchase\">\n                                                            <color key=\"titleColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                                        </state>\n                                                        <connections>\n                                                            <action selector=\"autoRenewablePurchase\" destination=\"BYZ-38-t0r\" eventType=\"touchUpInside\" id=\"lSx-jS-8W9\"/>\n                                                        </connections>\n                                                    </button>\n                                                    <switch opaque=\"NO\" contentMode=\"scaleToFill\" horizontalHuggingPriority=\"750\" verticalHuggingPriority=\"750\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" on=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"kJm-Ez-ODL\">\n                                                        <rect key=\"frame\" x=\"286\" y=\"5\" width=\"51\" height=\"31\"/>\n                                                    </switch>\n                                                    <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"atomic\" textAlignment=\"right\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"bV3-kp-plm\">\n                                                        <rect key=\"frame\" x=\"226\" y=\"10\" width=\"52\" height=\"21\"/>\n                                                        <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                                                        <color key=\"textColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                                        <nil key=\"highlightedColor\"/>\n                                                    </label>\n                                                    <segmentedControl opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"left\" contentVerticalAlignment=\"top\" segmentControlStyle=\"plain\" selectedSegmentIndex=\"0\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"wJ0-th-Tca\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"90\" width=\"335\" height=\"29\"/>\n                                                        <segments>\n                                                            <segment title=\"Weekly\"/>\n                                                            <segment title=\"Monthly\"/>\n                                                            <segment title=\"Yearly\"/>\n                                                        </segments>\n                                                        <color key=\"tintColor\" white=\"1\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                                                    </segmentedControl>\n                                                </subviews>\n                                                <color key=\"backgroundColor\" red=\"0.0\" green=\"0.0\" blue=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                                <constraints>\n                                                    <constraint firstItem=\"bV3-kp-plm\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"A6G-Y9-4Xc\" secondAttribute=\"leading\" constant=\"20\" symbolic=\"YES\" id=\"6J6-oA-3Dx\"/>\n                                                    <constraint firstItem=\"bV3-kp-plm\" firstAttribute=\"centerY\" secondItem=\"kJm-Ez-ODL\" secondAttribute=\"centerY\" id=\"6nA-bL-ODJ\"/>\n                                                    <constraint firstAttribute=\"bottom\" secondItem=\"wJ0-th-Tca\" secondAttribute=\"bottom\" id=\"7ha-Hg-sYo\"/>\n                                                    <constraint firstItem=\"bWL-ZF-hDb\" firstAttribute=\"top\" secondItem=\"Ckv-3X-zfV\" secondAttribute=\"top\" id=\"8vk-bQ-Pg1\"/>\n                                                    <constraint firstItem=\"bWL-ZF-hDb\" firstAttribute=\"leading\" secondItem=\"0AB-wg-Qch\" secondAttribute=\"trailing\" id=\"Dg4-zT-hC5\"/>\n                                                    <constraint firstItem=\"Ckv-3X-zfV\" firstAttribute=\"top\" secondItem=\"g1v-Yu-UQg\" secondAttribute=\"bottom\" constant=\"10\" id=\"H5H-nW-6cL\"/>\n                                                    <constraint firstItem=\"g1v-Yu-UQg\" firstAttribute=\"centerY\" secondItem=\"kJm-Ez-ODL\" secondAttribute=\"centerY\" id=\"LSk-oj-2bI\"/>\n                                                    <constraint firstItem=\"wJ0-th-Tca\" firstAttribute=\"top\" secondItem=\"Ckv-3X-zfV\" secondAttribute=\"bottom\" constant=\"5\" id=\"QeQ-wR-BMr\"/>\n                                                    <constraint firstItem=\"0AB-wg-Qch\" firstAttribute=\"height\" secondItem=\"Ckv-3X-zfV\" secondAttribute=\"height\" id=\"TC1-ma-sYy\"/>\n                                                    <constraint firstItem=\"wJ0-th-Tca\" firstAttribute=\"leading\" secondItem=\"A6G-Y9-4Xc\" secondAttribute=\"leading\" id=\"Zlm-c2-4a5\"/>\n                                                    <constraint firstItem=\"g1v-Yu-UQg\" firstAttribute=\"leading\" secondItem=\"A6G-Y9-4Xc\" secondAttribute=\"leading\" id=\"bXU-ty-CCw\"/>\n                                                    <constraint firstItem=\"kJm-Ez-ODL\" firstAttribute=\"top\" secondItem=\"A6G-Y9-4Xc\" secondAttribute=\"top\" constant=\"5\" id=\"gJV-sw-SHd\"/>\n                                                    <constraint firstItem=\"Ckv-3X-zfV\" firstAttribute=\"width\" secondItem=\"0AB-wg-Qch\" secondAttribute=\"width\" id=\"mbX-Bf-E0f\"/>\n                                                    <constraint firstItem=\"kJm-Ez-ODL\" firstAttribute=\"leading\" secondItem=\"bV3-kp-plm\" secondAttribute=\"trailing\" constant=\"8\" id=\"nzX-S8-JzC\"/>\n                                                    <constraint firstAttribute=\"trailing\" secondItem=\"kJm-Ez-ODL\" secondAttribute=\"trailing\" id=\"p1V-he-hai\"/>\n                                                    <constraint firstItem=\"bWL-ZF-hDb\" firstAttribute=\"height\" secondItem=\"Ckv-3X-zfV\" secondAttribute=\"height\" id=\"p3w-vj-lPQ\"/>\n                                                    <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"g1v-Yu-UQg\" secondAttribute=\"trailing\" constant=\"20\" symbolic=\"YES\" id=\"rg2-Ls-Wl9\"/>\n                                                    <constraint firstAttribute=\"trailing\" secondItem=\"wJ0-th-Tca\" secondAttribute=\"trailing\" id=\"s36-23-oCH\"/>\n                                                    <constraint firstItem=\"Ckv-3X-zfV\" firstAttribute=\"leading\" secondItem=\"A6G-Y9-4Xc\" secondAttribute=\"leading\" id=\"vYH-is-gBa\"/>\n                                                    <constraint firstItem=\"0AB-wg-Qch\" firstAttribute=\"width\" secondItem=\"bWL-ZF-hDb\" secondAttribute=\"width\" id=\"woZ-KV-JQr\"/>\n                                                    <constraint firstItem=\"0AB-wg-Qch\" firstAttribute=\"top\" secondItem=\"Ckv-3X-zfV\" secondAttribute=\"top\" id=\"yrv-7r-W7g\"/>\n                                                    <constraint firstAttribute=\"trailing\" secondItem=\"bWL-ZF-hDb\" secondAttribute=\"trailing\" id=\"z6z-cC-YAh\"/>\n                                                    <constraint firstItem=\"0AB-wg-Qch\" firstAttribute=\"leading\" secondItem=\"Ckv-3X-zfV\" secondAttribute=\"trailing\" id=\"zcG-Eq-ePR\"/>\n                                                </constraints>\n                                            </view>\n                                        </subviews>\n                                        <color key=\"backgroundColor\" red=\"0.0\" green=\"0.0\" blue=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                        <constraints>\n                                            <constraint firstItem=\"wOH-TN-d5B\" firstAttribute=\"leading\" secondItem=\"FII-Z2-VOo\" secondAttribute=\"leading\" id=\"1Pv-fp-OsN\"/>\n                                            <constraint firstAttribute=\"bottom\" secondItem=\"A6G-Y9-4Xc\" secondAttribute=\"bottom\" id=\"8ig-CB-zMe\"/>\n                                            <constraint firstItem=\"A6G-Y9-4Xc\" firstAttribute=\"leading\" secondItem=\"FII-Z2-VOo\" secondAttribute=\"leading\" id=\"DKS-P0-Z3C\"/>\n                                            <constraint firstItem=\"v1J-op-cSJ\" firstAttribute=\"leading\" secondItem=\"FII-Z2-VOo\" secondAttribute=\"leading\" id=\"EF3-J3-UdJ\"/>\n                                            <constraint firstItem=\"wOH-TN-d5B\" firstAttribute=\"top\" secondItem=\"C8u-2D-Dst\" secondAttribute=\"bottom\" id=\"Hry-ka-1DG\"/>\n                                            <constraint firstItem=\"C8u-2D-Dst\" firstAttribute=\"leading\" secondItem=\"FII-Z2-VOo\" secondAttribute=\"leading\" id=\"JaE-gD-I5U\"/>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"v1J-op-cSJ\" secondAttribute=\"trailing\" id=\"Pdg-Gw-ydH\"/>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"wOH-TN-d5B\" secondAttribute=\"trailing\" id=\"ST1-Qb-jhR\"/>\n                                            <constraint firstItem=\"A6G-Y9-4Xc\" firstAttribute=\"top\" secondItem=\"v1J-op-cSJ\" secondAttribute=\"bottom\" id=\"TEW-Xv-tph\"/>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"A6G-Y9-4Xc\" secondAttribute=\"trailing\" id=\"bTe-na-Maa\"/>\n                                            <constraint firstItem=\"C8u-2D-Dst\" firstAttribute=\"top\" secondItem=\"FII-Z2-VOo\" secondAttribute=\"top\" id=\"j0O-gu-GTO\"/>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"C8u-2D-Dst\" secondAttribute=\"trailing\" id=\"rQz-If-7Am\"/>\n                                            <constraint firstItem=\"v1J-op-cSJ\" firstAttribute=\"top\" secondItem=\"wOH-TN-d5B\" secondAttribute=\"bottom\" id=\"x0O-O8-f4H\"/>\n                                        </constraints>\n                                    </view>\n                                    <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"CG8-Ue-vcg\">\n                                        <rect key=\"frame\" x=\"79\" y=\"526.5\" width=\"177\" height=\"36\"/>\n                                        <fontDescription key=\"fontDescription\" type=\"boldSystem\" pointSize=\"20\"/>\n                                        <state key=\"normal\" title=\"Restore Purchases\">\n                                            <color key=\"titleColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                        </state>\n                                        <connections>\n                                            <action selector=\"restorePurchases\" destination=\"BYZ-38-t0r\" eventType=\"touchUpInside\" id=\"ulP-6V-3dz\"/>\n                                        </connections>\n                                    </button>\n                                    <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Hpv-ED-Dlg\">\n                                        <rect key=\"frame\" x=\"101\" y=\"572.5\" width=\"132\" height=\"36\"/>\n                                        <fontDescription key=\"fontDescription\" type=\"boldSystem\" pointSize=\"20\"/>\n                                        <state key=\"normal\" title=\"Verify Receipt\">\n                                            <color key=\"titleColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                        </state>\n                                        <connections>\n                                            <action selector=\"verifyReceipt\" destination=\"BYZ-38-t0r\" eventType=\"touchUpInside\" id=\"61I-gF-E2O\"/>\n                                        </connections>\n                                    </button>\n                                </subviews>\n                                <constraints>\n                                    <constraint firstItem=\"gg1-bw-Mzz\" firstAttribute=\"top\" secondItem=\"FTs-3H-z8C\" secondAttribute=\"bottom\" constant=\"15\" id=\"2gQ-e6-vP5\"/>\n                                    <constraint firstItem=\"FTs-3H-z8C\" firstAttribute=\"centerX\" secondItem=\"hrH-XV-mE8\" secondAttribute=\"centerX\" id=\"85H-Sv-3SK\"/>\n                                    <constraint firstItem=\"CG8-Ue-vcg\" firstAttribute=\"centerX\" secondItem=\"hrH-XV-mE8\" secondAttribute=\"centerX\" id=\"9Pq-4d-eYZ\"/>\n                                    <constraint firstItem=\"FTs-3H-z8C\" firstAttribute=\"top\" secondItem=\"hrH-XV-mE8\" secondAttribute=\"top\" constant=\"20\" id=\"DoR-dQ-GaM\"/>\n                                    <constraint firstItem=\"s8k-6i-mKn\" firstAttribute=\"leading\" secondItem=\"hrH-XV-mE8\" secondAttribute=\"leading\" id=\"HPZ-tB-ylq\"/>\n                                    <constraint firstItem=\"Hpv-ED-Dlg\" firstAttribute=\"centerX\" secondItem=\"hrH-XV-mE8\" secondAttribute=\"centerX\" id=\"Ijk-Uk-OZd\"/>\n                                    <constraint firstAttribute=\"trailing\" secondItem=\"FII-Z2-VOo\" secondAttribute=\"trailing\" id=\"Nbt-3g-tVY\"/>\n                                    <constraint firstItem=\"FII-Z2-VOo\" firstAttribute=\"top\" secondItem=\"s8k-6i-mKn\" secondAttribute=\"bottom\" constant=\"10\" id=\"QQo-06-tLV\"/>\n                                    <constraint firstAttribute=\"bottom\" secondItem=\"Hpv-ED-Dlg\" secondAttribute=\"bottom\" id=\"Ri2-IQ-4Cs\"/>\n                                    <constraint firstAttribute=\"trailing\" secondItem=\"s8k-6i-mKn\" secondAttribute=\"trailing\" id=\"Sig-bU-iuB\"/>\n                                    <constraint firstItem=\"gg1-bw-Mzz\" firstAttribute=\"leading\" secondItem=\"hrH-XV-mE8\" secondAttribute=\"leading\" id=\"UC7-wz-7Vo\"/>\n                                    <constraint firstItem=\"FII-Z2-VOo\" firstAttribute=\"leading\" secondItem=\"hrH-XV-mE8\" secondAttribute=\"leading\" id=\"ZkK-Vp-8BU\"/>\n                                    <constraint firstAttribute=\"trailing\" secondItem=\"gg1-bw-Mzz\" secondAttribute=\"trailing\" id=\"hJy-65-wXa\"/>\n                                    <constraint firstItem=\"Hpv-ED-Dlg\" firstAttribute=\"top\" secondItem=\"CG8-Ue-vcg\" secondAttribute=\"bottom\" constant=\"10\" id=\"hf6-qf-CGe\"/>\n                                    <constraint firstItem=\"s8k-6i-mKn\" firstAttribute=\"top\" secondItem=\"gg1-bw-Mzz\" secondAttribute=\"bottom\" constant=\"20\" id=\"uJT-iN-Llv\"/>\n                                    <constraint firstItem=\"CG8-Ue-vcg\" firstAttribute=\"top\" secondItem=\"FII-Z2-VOo\" secondAttribute=\"bottom\" constant=\"20\" id=\"z27-o8-vQT\"/>\n                                </constraints>\n                            </scrollView>\n                        </subviews>\n                        <color key=\"backgroundColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                        <constraints>\n                            <constraint firstItem=\"wfy-db-euE\" firstAttribute=\"top\" secondItem=\"hrH-XV-mE8\" secondAttribute=\"bottom\" constant=\"20\" id=\"Adu-9x-zbm\"/>\n                            <constraint firstAttribute=\"trailing\" secondItem=\"JDz-7n-4vD\" secondAttribute=\"trailing\" id=\"GBV-Mt-YQc\"/>\n                            <constraint firstItem=\"JDz-7n-4vD\" firstAttribute=\"top\" secondItem=\"8bC-Xf-vdC\" secondAttribute=\"top\" id=\"GlE-OZ-BQY\"/>\n                            <constraint firstItem=\"wfy-db-euE\" firstAttribute=\"top\" secondItem=\"R2x-3P-rjx\" secondAttribute=\"bottom\" id=\"JpO-AG-cGD\"/>\n                            <constraint firstAttribute=\"trailing\" secondItem=\"hrH-XV-mE8\" secondAttribute=\"trailing\" constant=\"20\" id=\"Ojq-cY-dzO\"/>\n                            <constraint firstAttribute=\"trailing\" secondItem=\"R2x-3P-rjx\" secondAttribute=\"trailing\" id=\"Pyv-8m-m9C\"/>\n                            <constraint firstItem=\"R2x-3P-rjx\" firstAttribute=\"leading\" secondItem=\"8bC-Xf-vdC\" secondAttribute=\"leading\" id=\"U9f-il-AMN\"/>\n                            <constraint firstItem=\"wfy-db-euE\" firstAttribute=\"top\" secondItem=\"JDz-7n-4vD\" secondAttribute=\"bottom\" id=\"Uxb-Hz-CCC\"/>\n                            <constraint firstItem=\"hrH-XV-mE8\" firstAttribute=\"top\" secondItem=\"y3c-jy-aDJ\" secondAttribute=\"bottom\" id=\"WSw-Pf-Ei7\"/>\n                            <constraint firstItem=\"hrH-XV-mE8\" firstAttribute=\"leading\" secondItem=\"8bC-Xf-vdC\" secondAttribute=\"leading\" constant=\"20\" id=\"bEn-LM-sAf\"/>\n                            <constraint firstItem=\"JDz-7n-4vD\" firstAttribute=\"leading\" secondItem=\"8bC-Xf-vdC\" secondAttribute=\"leading\" id=\"eKg-Cq-0M3\"/>\n                            <constraint firstItem=\"R2x-3P-rjx\" firstAttribute=\"top\" secondItem=\"8bC-Xf-vdC\" secondAttribute=\"top\" id=\"gD0-3o-Ni3\"/>\n                            <constraint firstItem=\"FII-Z2-VOo\" firstAttribute=\"width\" secondItem=\"8bC-Xf-vdC\" secondAttribute=\"width\" constant=\"-40\" id=\"tX0-sI-uZq\"/>\n                        </constraints>\n                    </view>\n                    <connections>\n                        <outlet property=\"autoRenewableAtomicSwitch\" destination=\"kJm-Ez-ODL\" id=\"D2B-pC-N1Q\"/>\n                        <outlet property=\"autoRenewableSubscriptionSegmentedControl\" destination=\"wJ0-th-Tca\" id=\"Zhd-0w-UUw\"/>\n                        <outlet property=\"consumableAtomicSwitch\" destination=\"LFG-nF-AB9\" id=\"t5b-Xz-Veo\"/>\n                        <outlet property=\"nonConsumableAtomicSwitch\" destination=\"4Ha-LL-b2D\" id=\"EIo-LC-STW\"/>\n                        <outlet property=\"nonRenewingAtomicSwitch\" destination=\"0wG-zO-KFz\" id=\"VKS-xs-ZzT\"/>\n                    </connections>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"dkx-z0-nzr\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"308\" y=\"373.76311844077964\"/>\n        </scene>\n    </scenes>\n    <resources>\n        <image name=\"Background\" width=\"375\" height=\"667\"/>\n    </resources>\n</document>\n"
  },
  {
    "path": "SwiftyStoreKit-iOS-Demo/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>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</array>\n\t<key>UIViewControllerBasedStatusBarAppearance</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "SwiftyStoreKit-iOS-Demo/NetworkActivityIndicatorManager.swift",
    "content": "//\n//  NetworkActivityIndicatorManager.swift\n//  SwiftyStoreKit\n//\n//  Created by Andrea Bizzotto on 28/09/2015.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\nimport UIKit\n\nclass NetworkActivityIndicatorManager: NSObject {\n\n    private static var loadingCount = 0\n\n    class func networkOperationStarted() {\n\n        #if os(iOS)\n        if loadingCount == 0 {\n            UIApplication.shared.isNetworkActivityIndicatorVisible = true\n        }\n        loadingCount += 1\n        #endif\n    }\n\n    class func networkOperationFinished() {\n        #if os(iOS)\n        if loadingCount > 0 {\n            loadingCount -= 1\n        }\n        if loadingCount == 0 {\n            UIApplication.shared.isNetworkActivityIndicatorVisible = false\n        }\n        #endif\n    }\n}\n"
  },
  {
    "path": "SwiftyStoreKit-iOS-Demo/ViewController.swift",
    "content": "//\n//  ViewController.swift\n//  SwiftyStoreKit\n//\n//  Created by Andrea Bizzotto on 03/09/2015.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\nimport UIKit\nimport StoreKit\nimport SwiftyStoreKit\n\nenum RegisteredPurchase: String {\n\n    case purchase1\n    case purchase2\n    case nonConsumablePurchase\n    case consumablePurchase\n    case nonRenewingPurchase\n    case autoRenewableWeekly\n    case autoRenewableMonthly\n    case autoRenewableYearly\n}\n\nclass ViewController: UIViewController {\n\n    let appBundleId = \"com.musevisions.iOS.SwiftyStoreKit\"\n    \n#if os(iOS)\n    // UISwitch is unavailable on tvOS\n    @IBOutlet var nonConsumableAtomicSwitch: UISwitch!\n    @IBOutlet var consumableAtomicSwitch: UISwitch!\n    @IBOutlet var nonRenewingAtomicSwitch: UISwitch!\n    @IBOutlet var autoRenewableAtomicSwitch: UISwitch!\n    var nonConsumableIsAtomic: Bool { return nonConsumableAtomicSwitch.isOn }\n    var consumableIsAtomic: Bool { return consumableAtomicSwitch.isOn }\n    var nonRenewingIsAtomic: Bool { return nonRenewingAtomicSwitch.isOn }\n    var autoRenewableIsAtomic: Bool { return autoRenewableAtomicSwitch.isOn }\n#else\n    let nonConsumableIsAtomic = true\n    let consumableIsAtomic = true\n    let nonRenewingIsAtomic = true\n    let autoRenewableIsAtomic = true\n#endif\n    // MARK: non consumable\n    @IBAction func nonConsumableGetInfo() {\n        getInfo(.nonConsumablePurchase)\n    }\n    @IBAction func nonConsumablePurchase() {\n        purchase(.nonConsumablePurchase, atomically: nonConsumableIsAtomic)\n    }\n    @IBAction func nonConsumableVerifyPurchase() {\n        verifyPurchase(.nonConsumablePurchase)\n    }\n    \n    // MARK: consumable\n    @IBAction func consumableGetInfo() {\n        getInfo(.consumablePurchase)\n    }\n    @IBAction func consumablePurchase() {\n        purchase(.consumablePurchase, atomically: consumableIsAtomic)\n    }\n    @IBAction func consumableVerifyPurchase() {\n        verifyPurchase(.consumablePurchase)\n    }\n\n    // MARK: non renewing\n    @IBAction func nonRenewingGetInfo() {\n        getInfo(.nonRenewingPurchase)\n    }\n    @IBAction func nonRenewingPurchase() {\n        purchase(.nonRenewingPurchase, atomically: nonRenewingIsAtomic)\n    }\n    @IBAction func nonRenewingVerifyPurchase() {\n        verifyPurchase(.nonRenewingPurchase)\n    }\n\n    // MARK: auto renewable\n#if os(iOS)\n    @IBOutlet var autoRenewableSubscriptionSegmentedControl: UISegmentedControl!\n    \n    var autoRenewableSubscription: RegisteredPurchase {\n        switch autoRenewableSubscriptionSegmentedControl.selectedSegmentIndex {\n        case 0: return .autoRenewableWeekly\n        case 1: return .autoRenewableMonthly\n        case 2: return .autoRenewableYearly\n        default: return .autoRenewableWeekly\n        }\n    }\n#else\n    let autoRenewableSubscription = RegisteredPurchase.autoRenewableWeekly\n#endif\n    @IBAction func autoRenewableGetInfo() {\n        getInfo(autoRenewableSubscription)\n    }\n    @IBAction func autoRenewablePurchase() {\n        purchase(autoRenewableSubscription, atomically: autoRenewableIsAtomic)\n    }\n    @IBAction func autoRenewableVerifyPurchase() {\n        verifySubscriptions([.autoRenewableWeekly, .autoRenewableMonthly, .autoRenewableYearly])\n    }\n\n    func getInfo(_ purchase: RegisteredPurchase) {\n\n        NetworkActivityIndicatorManager.networkOperationStarted()\n        SwiftyStoreKit.retrieveProductsInfo([appBundleId + \".\" + purchase.rawValue]) { result in\n            NetworkActivityIndicatorManager.networkOperationFinished()\n\n            self.showAlert(self.alertForProductRetrievalInfo(result))\n        }\n    }\n\n    func purchase(_ purchase: RegisteredPurchase, atomically: Bool) {\n\n        NetworkActivityIndicatorManager.networkOperationStarted()\n        SwiftyStoreKit.purchaseProduct(appBundleId + \".\" + purchase.rawValue, atomically: atomically) { result in\n            NetworkActivityIndicatorManager.networkOperationFinished()\n\n            if case .success(let purchase) = result {\n                let downloads = purchase.transaction.downloads\n                if !downloads.isEmpty {\n                    SwiftyStoreKit.start(downloads)\n                }\n                // Deliver content from server, then:\n                if purchase.needsFinishTransaction {\n                    SwiftyStoreKit.finishTransaction(purchase.transaction)\n                }\n            }\n            if let alert = self.alertForPurchaseResult(result) {\n                self.showAlert(alert)\n            }\n        }\n    }\n\n    @IBAction func restorePurchases() {\n\n        NetworkActivityIndicatorManager.networkOperationStarted()\n        SwiftyStoreKit.restorePurchases(atomically: true) { results in\n            NetworkActivityIndicatorManager.networkOperationFinished()\n\n            for purchase in results.restoredPurchases {\n                let downloads = purchase.transaction.downloads\n                if !downloads.isEmpty {\n                    SwiftyStoreKit.start(downloads)\n                } else if purchase.needsFinishTransaction {\n                    // Deliver content from server, then:\n                    SwiftyStoreKit.finishTransaction(purchase.transaction)\n                }\n            }\n            self.showAlert(self.alertForRestorePurchases(results))\n        }\n    }\n\n    @IBAction func verifyReceipt() {\n\n        NetworkActivityIndicatorManager.networkOperationStarted()\n        verifyReceipt { result in\n            NetworkActivityIndicatorManager.networkOperationFinished()\n            self.showAlert(self.alertForVerifyReceipt(result))\n        }\n    }\n    \n    func verifyReceipt(completion: @escaping (VerifyReceiptResult) -> Void) {\n        \n        let appleValidator = AppleReceiptValidator(service: .production, sharedSecret: \"your-shared-secret\")\n        SwiftyStoreKit.verifyReceipt(using: appleValidator, completion: completion)\n    }\n    \n    func verifyPurchase(_ purchase: RegisteredPurchase) {\n\n        NetworkActivityIndicatorManager.networkOperationStarted()\n        verifyReceipt { result in\n            NetworkActivityIndicatorManager.networkOperationFinished()\n\n            switch result {\n            case .success(let receipt):\n\n                let productId = self.appBundleId + \".\" + purchase.rawValue\n\n                switch purchase {\n                case .autoRenewableWeekly, .autoRenewableMonthly, .autoRenewableYearly:\n                    let purchaseResult = SwiftyStoreKit.verifySubscription(\n                        ofType: .autoRenewable,\n                        productId: productId,\n                        inReceipt: receipt)\n                    self.showAlert(self.alertForVerifySubscriptions(purchaseResult, productIds: [productId]))\n                case .nonRenewingPurchase:\n                    let purchaseResult = SwiftyStoreKit.verifySubscription(\n                        ofType: .nonRenewing(validDuration: 60),\n                        productId: productId,\n                        inReceipt: receipt)\n                    self.showAlert(self.alertForVerifySubscriptions(purchaseResult, productIds: [productId]))\n                default:\n                    let purchaseResult = SwiftyStoreKit.verifyPurchase(\n                        productId: productId,\n                        inReceipt: receipt)\n                    self.showAlert(self.alertForVerifyPurchase(purchaseResult, productId: productId))\n                }\n\n            case .error:\n                self.showAlert(self.alertForVerifyReceipt(result))\n            }\n        }\n    }\n    \n    func verifySubscriptions(_ purchases: Set<RegisteredPurchase>) {\n        \n        NetworkActivityIndicatorManager.networkOperationStarted()\n        verifyReceipt { result in\n            NetworkActivityIndicatorManager.networkOperationFinished()\n            \n            switch result {\n            case .success(let receipt):\n                let productIds = Set(purchases.map { self.appBundleId + \".\" + $0.rawValue })\n                let purchaseResult = SwiftyStoreKit.verifySubscriptions(productIds: productIds, inReceipt: receipt)\n                self.showAlert(self.alertForVerifySubscriptions(purchaseResult, productIds: productIds))\n            case .error:\n                self.showAlert(self.alertForVerifyReceipt(result))\n            }\n        }\n    }\n\n#if os(iOS)\n    override var preferredStatusBarStyle: UIStatusBarStyle {\n        return .lightContent\n    }\n#endif\n}\n\n// MARK: User facing alerts\nextension ViewController {\n\n    func alertWithTitle(_ title: String, message: String) -> UIAlertController {\n\n        let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)\n        alert.addAction(UIAlertAction(title: \"OK\", style: .cancel, handler: nil))\n        return alert\n    }\n\n    func showAlert(_ alert: UIAlertController) {\n        guard self.presentedViewController != nil else {\n            self.present(alert, animated: true, completion: nil)\n            return\n        }\n    }\n\n    func alertForProductRetrievalInfo(_ result: RetrieveResults) -> UIAlertController {\n\n        if let product = result.retrievedProducts.first {\n            let priceString = product.localizedPrice!\n            return alertWithTitle(product.localizedTitle, message: \"\\(product.localizedDescription) - \\(priceString)\")\n        } else if let invalidProductId = result.invalidProductIDs.first {\n            return alertWithTitle(\"Could not retrieve product info\", message: \"Invalid product identifier: \\(invalidProductId)\")\n        } else {\n            let errorString = result.error?.localizedDescription ?? \"Unknown error. Please contact support\"\n            return alertWithTitle(\"Could not retrieve product info\", message: errorString)\n        }\n    }\n\n    // swiftlint:disable cyclomatic_complexity\n    func alertForPurchaseResult(_ result: PurchaseResult) -> UIAlertController? {\n        switch result {\n        case .success(let purchase):\n            print(\"Purchase Success: \\(purchase.productId)\")\n            return nil\n        case .error(let error):\n            print(\"Purchase Failed: \\(error)\")\n            switch error.code {\n            case .unknown: return alertWithTitle(\"Purchase failed\", message: error.localizedDescription)\n            case .clientInvalid: // client is not allowed to issue the request, etc.\n                return alertWithTitle(\"Purchase failed\", message: \"Not allowed to make the payment\")\n            case .paymentCancelled: // user cancelled the request, etc.\n                return nil\n            case .paymentInvalid: // purchase identifier was invalid, etc.\n                return alertWithTitle(\"Purchase failed\", message: \"The purchase identifier was invalid\")\n            case .paymentNotAllowed: // this device is not allowed to make the payment\n                return alertWithTitle(\"Purchase failed\", message: \"The device is not allowed to make the payment\")\n            case .storeProductNotAvailable: // Product is not available in the current storefront\n                return alertWithTitle(\"Purchase failed\", message: \"The product is not available in the current storefront\")\n            case .cloudServicePermissionDenied: // user has not allowed access to cloud service information\n                return alertWithTitle(\"Purchase failed\", message: \"Access to cloud service information is not allowed\")\n            case .cloudServiceNetworkConnectionFailed: // the device could not connect to the nework\n                return alertWithTitle(\"Purchase failed\", message: \"Could not connect to the network\")\n            case .cloudServiceRevoked: // user has revoked permission to use this cloud service\n                return alertWithTitle(\"Purchase failed\", message: \"Cloud service was revoked\")\n            default:\n                return alertWithTitle(\"Purchase failed\", message: (error as NSError).localizedDescription)\n            }\n        }\n    }\n\n    func alertForRestorePurchases(_ results: RestoreResults) -> UIAlertController {\n\n        if results.restoreFailedPurchases.count > 0 {\n            print(\"Restore Failed: \\(results.restoreFailedPurchases)\")\n            return alertWithTitle(\"Restore failed\", message: \"Unknown error. Please contact support\")\n        } else if results.restoredPurchases.count > 0 {\n            print(\"Restore Success: \\(results.restoredPurchases)\")\n            return alertWithTitle(\"Purchases Restored\", message: \"All purchases have been restored\")\n        } else {\n            print(\"Nothing to Restore\")\n            return alertWithTitle(\"Nothing to restore\", message: \"No previous purchases were found\")\n        }\n    }\n\n    func alertForVerifyReceipt(_ result: VerifyReceiptResult) -> UIAlertController {\n\n        switch result {\n        case .success(let receipt):\n            print(\"Verify receipt Success: \\(receipt)\")\n            return alertWithTitle(\"Receipt verified\", message: \"Receipt verified remotely\")\n        case .error(let error):\n            print(\"Verify receipt Failed: \\(error)\")\n            switch error {\n            case .noReceiptData:\n                return alertWithTitle(\"Receipt verification\", message: \"No receipt data. Try again.\")\n            case .networkError(let error):\n                return alertWithTitle(\"Receipt verification\", message: \"Network error while verifying receipt: \\(error)\")\n            default:\n                return alertWithTitle(\"Receipt verification\", message: \"Receipt verification failed: \\(error)\")\n            }\n        }\n    }\n\n    func alertForVerifySubscriptions(_ result: VerifySubscriptionResult, productIds: Set<String>) -> UIAlertController {\n\n        switch result {\n        case .purchased(let expiryDate, let items):\n            print(\"\\(productIds) is valid until \\(expiryDate)\\n\\(items)\\n\")\n            return alertWithTitle(\"Product is purchased\", message: \"Product is valid until \\(expiryDate)\")\n        case .expired(let expiryDate, let items):\n            print(\"\\(productIds) is expired since \\(expiryDate)\\n\\(items)\\n\")\n            return alertWithTitle(\"Product expired\", message: \"Product is expired since \\(expiryDate)\")\n        case .notPurchased:\n            print(\"\\(productIds) has never been purchased\")\n            return alertWithTitle(\"Not purchased\", message: \"This product has never been purchased\")\n        }\n    }\n\n    func alertForVerifyPurchase(_ result: VerifyPurchaseResult, productId: String) -> UIAlertController {\n\n        switch result {\n        case .purchased:\n            print(\"\\(productId) is purchased\")\n            return alertWithTitle(\"Product is purchased\", message: \"Product will not expire\")\n        case .notPurchased:\n            print(\"\\(productId) has never been purchased\")\n            return alertWithTitle(\"Not purchased\", message: \"This product has never been purchased\")\n        }\n    }\n}\n"
  },
  {
    "path": "SwiftyStoreKit-macOS-Demo/AppDelegate.swift",
    "content": "//\n//  AppDelegate.swift\n//  SwiftStoreOSXDemo\n//\n//  Created by phimage on 22/12/15.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\nimport Cocoa\nimport SwiftyStoreKit\n\n@NSApplicationMain\nclass AppDelegate: NSObject, NSApplicationDelegate {\n\n    func applicationDidFinishLaunching(_ aNotification: Notification) {\n\n        completeIAPTransactions()\n    }\n\n    func completeIAPTransactions() {\n\n        SwiftyStoreKit.completeTransactions(atomically: true) { purchases in\n\n            for purchase in purchases {\n                switch purchase.transaction.transactionState {\n                case .purchased, .restored:\n                    if purchase.needsFinishTransaction {\n                        // Deliver content from server, then:\n                        SwiftyStoreKit.finishTransaction(purchase.transaction)\n                    }\n                    print(\"\\(purchase.transaction.transactionState.debugDescription): \\(purchase.productId)\")\n                case .failed, .purchasing, .deferred:\n                    break // do nothing\n                @unknown default:\n                  break // do nothing\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "SwiftyStoreKit-macOS-Demo/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": "SwiftyStoreKit-macOS-Demo/Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "SwiftyStoreKit-macOS-Demo/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=\"10117\" systemVersion=\"15E65\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" initialViewController=\"B8D-0N-5wS\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"10117\"/>\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=\"SwiftStoreOSXDemo\" id=\"1Xt-HY-uBw\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"SwiftStoreOSXDemo\" systemMenu=\"apple\" id=\"uQy-DD-JDr\">\n                                    <items>\n                                        <menuItem title=\"About SwiftStoreOSXDemo\" 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 SwiftStoreOSXDemo\" 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 SwiftStoreOSXDemo\" 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\" id=\"KaW-ft-85H\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\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                                    </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=\"SwiftStoreOSXDemo 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\" customModule=\"SwiftyStoreOSXDemo\" 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=\"SwiftyStoreKit\" 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\" customModule=\"SwiftyStoreOSXDemo\" customModuleProvider=\"target\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" id=\"m2S-Jp-Qdl\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"480\" height=\"305\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                        <subviews>\n                            <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"4ix-eb-y5G\">\n                                <rect key=\"frame\" x=\"163\" y=\"73\" width=\"154\" height=\"32\"/>\n                                <buttonCell key=\"cell\" type=\"push\" title=\"Restore Purchases\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"mmO-hG-Xyq\">\n                                    <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <connections>\n                                        <action selector=\"restorePurchases:\" target=\"XfG-lQ-9wD\" id=\"fOG-v6-bQI\"/>\n                                    </connections>\n                                </buttonCell>\n                            </button>\n                            <customView misplaced=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"aBh-sv-MN6\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"121\" width=\"480\" height=\"139\"/>\n                                <subviews>\n                                    <splitView focusRingType=\"none\" misplaced=\"YES\" dividerStyle=\"thin\" vertical=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"dZR-88-4H6\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"-37\" width=\"480\" height=\"176\"/>\n                                        <subviews>\n                                            <customView misplaced=\"YES\" id=\"rDg-4M-vFs\">\n                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"254\" height=\"176\"/>\n                                                <autoresizingMask key=\"autoresizingMask\"/>\n                                                <subviews>\n                                                    <button verticalHuggingPriority=\"750\" misplaced=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ypp-fu-oEb\">\n                                                        <rect key=\"frame\" x=\"83\" y=\"103\" width=\"89\" height=\"32\"/>\n                                                        <buttonCell key=\"cell\" type=\"push\" title=\"Get Info\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"vSi-fu-wrI\">\n                                                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                                            <font key=\"font\" metaFont=\"system\"/>\n                                                        </buttonCell>\n                                                        <connections>\n                                                            <action selector=\"getInfo1:\" target=\"XfG-lQ-9wD\" id=\"PTC-RY-Aom\"/>\n                                                        </connections>\n                                                    </button>\n                                                    <textField horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" misplaced=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"23w-eX-lGC\">\n                                                        <rect key=\"frame\" x=\"105\" y=\"139\" width=\"44\" height=\"17\"/>\n                                                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"5 days\" id=\"U2h-U7-cdn\">\n                                                            <font key=\"font\" metaFont=\"system\"/>\n                                                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                        </textFieldCell>\n                                                    </textField>\n                                                    <button verticalHuggingPriority=\"750\" misplaced=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Hez-z0-TRG\">\n                                                        <rect key=\"frame\" x=\"79\" y=\"70\" width=\"97\" height=\"32\"/>\n                                                        <buttonCell key=\"cell\" type=\"push\" title=\"Purchase\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"5bl-kX-gwW\">\n                                                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                                            <font key=\"font\" metaFont=\"system\"/>\n                                                        </buttonCell>\n                                                        <connections>\n                                                            <action selector=\"purchase1:\" target=\"XfG-lQ-9wD\" id=\"vds-cI-c90\"/>\n                                                        </connections>\n                                                    </button>\n                                                    <button verticalHuggingPriority=\"750\" misplaced=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"mmd-5V-ZlT\">\n                                                        <rect key=\"frame\" x=\"59\" y=\"37\" width=\"136\" height=\"32\"/>\n                                                        <buttonCell key=\"cell\" type=\"push\" title=\"Verify Purchase\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"7F7-3v-kkM\">\n                                                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                                            <font key=\"font\" metaFont=\"system\"/>\n                                                        </buttonCell>\n                                                        <connections>\n                                                            <action selector=\"verifyPurchase1:\" target=\"XfG-lQ-9wD\" id=\"38W-SD-m1J\"/>\n                                                        </connections>\n                                                    </button>\n                                                </subviews>\n                                                <constraints>\n                                                    <constraint firstItem=\"ypp-fu-oEb\" firstAttribute=\"top\" secondItem=\"23w-eX-lGC\" secondAttribute=\"bottom\" constant=\"8\" id=\"HsY-yu-fTe\"/>\n                                                    <constraint firstItem=\"Hez-z0-TRG\" firstAttribute=\"top\" secondItem=\"ypp-fu-oEb\" secondAttribute=\"bottom\" constant=\"12\" id=\"LrL-rs-Cvu\"/>\n                                                    <constraint firstItem=\"mmd-5V-ZlT\" firstAttribute=\"centerX\" secondItem=\"Hez-z0-TRG\" secondAttribute=\"centerX\" id=\"MP8-pj-dj9\"/>\n                                                    <constraint firstItem=\"Hez-z0-TRG\" firstAttribute=\"centerX\" secondItem=\"rDg-4M-vFs\" secondAttribute=\"centerX\" id=\"Txa-bs-hn6\"/>\n                                                    <constraint firstItem=\"mmd-5V-ZlT\" firstAttribute=\"top\" secondItem=\"Hez-z0-TRG\" secondAttribute=\"bottom\" constant=\"12\" id=\"VtJ-vO-b5h\"/>\n                                                    <constraint firstItem=\"23w-eX-lGC\" firstAttribute=\"top\" secondItem=\"rDg-4M-vFs\" secondAttribute=\"top\" constant=\"20\" id=\"dv9-p8-n6y\"/>\n                                                    <constraint firstItem=\"23w-eX-lGC\" firstAttribute=\"centerX\" secondItem=\"rDg-4M-vFs\" secondAttribute=\"centerX\" id=\"h4c-nW-umA\"/>\n                                                    <constraint firstItem=\"ypp-fu-oEb\" firstAttribute=\"centerX\" secondItem=\"rDg-4M-vFs\" secondAttribute=\"centerX\" id=\"jeS-t3-Km1\"/>\n                                                </constraints>\n                                            </customView>\n                                            <customView misplaced=\"YES\" id=\"ecz-ZL-FwI\">\n                                                <rect key=\"frame\" x=\"255\" y=\"0.0\" width=\"225\" height=\"176\"/>\n                                                <autoresizingMask key=\"autoresizingMask\"/>\n                                                <subviews>\n                                                    <textField horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" misplaced=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"gj2-Z2-1qo\">\n                                                        <rect key=\"frame\" x=\"88\" y=\"139\" width=\"50\" height=\"17\"/>\n                                                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"10 days\" id=\"XkC-cw-jpP\">\n                                                            <font key=\"font\" metaFont=\"system\"/>\n                                                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                            <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                        </textFieldCell>\n                                                    </textField>\n                                                    <button verticalHuggingPriority=\"750\" misplaced=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"32D-7s-IOR\">\n                                                        <rect key=\"frame\" x=\"68\" y=\"103\" width=\"89\" height=\"32\"/>\n                                                        <buttonCell key=\"cell\" type=\"push\" title=\"Get Info\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"F8O-DF-BZX\">\n                                                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                                            <font key=\"font\" metaFont=\"system\"/>\n                                                        </buttonCell>\n                                                        <connections>\n                                                            <action selector=\"getInfo2:\" target=\"XfG-lQ-9wD\" id=\"u4g-Qb-RyE\"/>\n                                                        </connections>\n                                                    </button>\n                                                    <button verticalHuggingPriority=\"750\" misplaced=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"GkW-aD-XKc\">\n                                                        <rect key=\"frame\" x=\"64\" y=\"70\" width=\"97\" height=\"32\"/>\n                                                        <buttonCell key=\"cell\" type=\"push\" title=\"Purchase\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"TDW-1n-a4d\">\n                                                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                                            <font key=\"font\" metaFont=\"system\"/>\n                                                        </buttonCell>\n                                                        <connections>\n                                                            <action selector=\"purchase2:\" target=\"XfG-lQ-9wD\" id=\"wP2-Fe-Uee\"/>\n                                                        </connections>\n                                                    </button>\n                                                    <button verticalHuggingPriority=\"750\" misplaced=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"eaU-oc-e9m\">\n                                                        <rect key=\"frame\" x=\"44\" y=\"37\" width=\"136\" height=\"32\"/>\n                                                        <buttonCell key=\"cell\" type=\"push\" title=\"Verify Purchase\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"e9S-YC-oMc\">\n                                                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                                            <font key=\"font\" metaFont=\"system\"/>\n                                                        </buttonCell>\n                                                        <connections>\n                                                            <action selector=\"verifyPurchase2:\" target=\"XfG-lQ-9wD\" id=\"i3P-qj-mFY\"/>\n                                                        </connections>\n                                                    </button>\n                                                </subviews>\n                                                <constraints>\n                                                    <constraint firstItem=\"32D-7s-IOR\" firstAttribute=\"top\" secondItem=\"gj2-Z2-1qo\" secondAttribute=\"bottom\" constant=\"8\" id=\"7nw-8P-EZz\"/>\n                                                    <constraint firstItem=\"GkW-aD-XKc\" firstAttribute=\"top\" secondItem=\"32D-7s-IOR\" secondAttribute=\"bottom\" constant=\"12\" id=\"9ht-Vg-3pn\"/>\n                                                    <constraint firstItem=\"GkW-aD-XKc\" firstAttribute=\"centerX\" secondItem=\"ecz-ZL-FwI\" secondAttribute=\"centerX\" id=\"FOu-2O-PY7\"/>\n                                                    <constraint firstItem=\"32D-7s-IOR\" firstAttribute=\"centerX\" secondItem=\"ecz-ZL-FwI\" secondAttribute=\"centerX\" id=\"FyQ-66-nvQ\"/>\n                                                    <constraint firstItem=\"eaU-oc-e9m\" firstAttribute=\"centerX\" secondItem=\"GkW-aD-XKc\" secondAttribute=\"centerX\" id=\"I5Z-mc-plm\"/>\n                                                    <constraint firstItem=\"gj2-Z2-1qo\" firstAttribute=\"top\" secondItem=\"ecz-ZL-FwI\" secondAttribute=\"top\" constant=\"20\" id=\"MKZ-lm-5CM\"/>\n                                                    <constraint firstItem=\"eaU-oc-e9m\" firstAttribute=\"top\" secondItem=\"GkW-aD-XKc\" secondAttribute=\"bottom\" constant=\"12\" id=\"PhS-uW-Y9r\"/>\n                                                    <constraint firstItem=\"gj2-Z2-1qo\" firstAttribute=\"centerX\" secondItem=\"ecz-ZL-FwI\" secondAttribute=\"centerX\" id=\"wOt-5L-Iq5\"/>\n                                                </constraints>\n                                            </customView>\n                                        </subviews>\n                                        <holdingPriorities>\n                                            <real value=\"250\"/>\n                                            <real value=\"250\"/>\n                                        </holdingPriorities>\n                                    </splitView>\n                                </subviews>\n                                <constraints>\n                                    <constraint firstAttribute=\"bottom\" secondItem=\"dZR-88-4H6\" secondAttribute=\"bottom\" id=\"6pF-6i-TGr\"/>\n                                    <constraint firstAttribute=\"trailing\" secondItem=\"dZR-88-4H6\" secondAttribute=\"trailing\" id=\"Bv3-M1-jOE\"/>\n                                    <constraint firstItem=\"dZR-88-4H6\" firstAttribute=\"leading\" secondItem=\"aBh-sv-MN6\" secondAttribute=\"leading\" id=\"YDo-PG-kGg\"/>\n                                    <constraint firstItem=\"dZR-88-4H6\" firstAttribute=\"top\" secondItem=\"aBh-sv-MN6\" secondAttribute=\"top\" id=\"b1e-Gp-3Al\"/>\n                                </constraints>\n                            </customView>\n                            <textField verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"fQC-8G-INF\">\n                                <rect key=\"frame\" x=\"176\" y=\"268\" width=\"128\" height=\"17\"/>\n                                <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" title=\"Available purchases:\" id=\"Ntg-PD-43y\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                            <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Yzl-nj-7ol\">\n                                <rect key=\"frame\" x=\"178\" y=\"40\" width=\"125\" height=\"32\"/>\n                                <buttonCell key=\"cell\" type=\"push\" title=\"Verify Receipt\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"6bY-Fv-W6P\">\n                                    <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                </buttonCell>\n                                <connections>\n                                    <action selector=\"verifyReceipt:\" target=\"XfG-lQ-9wD\" id=\"uf9-Pe-MRz\"/>\n                                </connections>\n                            </button>\n                        </subviews>\n                        <constraints>\n                            <constraint firstItem=\"Yzl-nj-7ol\" firstAttribute=\"top\" secondItem=\"4ix-eb-y5G\" secondAttribute=\"bottom\" constant=\"12\" id=\"B88-P1-tBj\"/>\n                            <constraint firstAttribute=\"trailing\" secondItem=\"aBh-sv-MN6\" secondAttribute=\"trailing\" id=\"F8t-R2-cad\"/>\n                            <constraint firstItem=\"fQC-8G-INF\" firstAttribute=\"centerX\" secondItem=\"m2S-Jp-Qdl\" secondAttribute=\"centerX\" id=\"RDD-02-SB0\"/>\n                            <constraint firstItem=\"4ix-eb-y5G\" firstAttribute=\"top\" secondItem=\"aBh-sv-MN6\" secondAttribute=\"bottom\" constant=\"8\" id=\"b6U-zT-POc\"/>\n                            <constraint firstItem=\"Yzl-nj-7ol\" firstAttribute=\"centerX\" secondItem=\"m2S-Jp-Qdl\" secondAttribute=\"centerX\" id=\"dQi-Vh-Bwb\"/>\n                            <constraint firstItem=\"aBh-sv-MN6\" firstAttribute=\"leading\" secondItem=\"m2S-Jp-Qdl\" secondAttribute=\"leading\" id=\"enN-Hg-kUA\"/>\n                            <constraint firstItem=\"fQC-8G-INF\" firstAttribute=\"top\" secondItem=\"m2S-Jp-Qdl\" secondAttribute=\"top\" constant=\"20\" id=\"kMt-Ye-T67\"/>\n                            <constraint firstAttribute=\"bottom\" secondItem=\"Yzl-nj-7ol\" secondAttribute=\"bottom\" constant=\"47\" id=\"oJS-dD-6Gz\"/>\n                            <constraint firstItem=\"aBh-sv-MN6\" firstAttribute=\"top\" secondItem=\"fQC-8G-INF\" secondAttribute=\"bottom\" constant=\"8\" id=\"rz5-by-FYa\"/>\n                            <constraint firstItem=\"4ix-eb-y5G\" firstAttribute=\"centerX\" secondItem=\"m2S-Jp-Qdl\" secondAttribute=\"centerX\" id=\"vs9-D1-ALb\"/>\n                        </constraints>\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=\"672.5\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "SwiftyStoreKit-macOS-Demo/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>CFBundleSignature</key>\n\t<string>????</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 © 2015 musevisions. 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": "SwiftyStoreKit-macOS-Demo/ViewController.swift",
    "content": "//\n//  ViewController.swift\n//  SwiftStoreOSXDemo\n//\n//  Created by phimage on 22/12/15.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\nimport Cocoa\nimport StoreKit\nimport SwiftyStoreKit\n\nenum RegisteredPurchase: String {\n\n    case purchase1\n    case purchase2\n    case nonConsumablePurchase\n    case consumablePurchase\n    case autoRenewablePurchase\n    case nonRenewingPurchase\n\n}\n\nclass ViewController: NSViewController {\n\n    let appBundleId = \"com.musevisions.MacOS.SwiftyStoreKitDemo\"\n\n    let purchase1Suffix = RegisteredPurchase.purchase1\n    let purchase2Suffix = RegisteredPurchase.autoRenewablePurchase\n\n    // MARK: actions\n    @IBAction func getInfo1(_ sender: Any?) {\n        getInfo(purchase1Suffix)\n    }\n    @IBAction func purchase1(_ sender: Any?) {\n        purchase(purchase1Suffix)\n    }\n    @IBAction func verifyPurchase1(_ sender: Any?) {\n        verifyPurchase(purchase1Suffix)\n    }\n\n    @IBAction func getInfo2(_ sender: Any?) {\n        getInfo(purchase2Suffix)\n    }\n    @IBAction func purchase2(_ sender: Any?) {\n        purchase(purchase2Suffix)\n    }\n    @IBAction func verifyPurchase2(_ sender: Any?) {\n        verifyPurchase(purchase2Suffix)\n    }\n\n    func getInfo(_ purchase: RegisteredPurchase) {\n\n        SwiftyStoreKit.retrieveProductsInfo([appBundleId + \".\" + purchase.rawValue]) { result in\n\n            self.showAlert(self.alertForProductRetrievalInfo(result))\n        }\n    }\n\n    func purchase(_ purchase: RegisteredPurchase) {\n\n        SwiftyStoreKit.purchaseProduct(appBundleId + \".\" + purchase.rawValue, atomically: true) { result in\n\n            if case .success(let purchase) = result {\n                // Deliver content from server, then:\n                if purchase.needsFinishTransaction {\n                    SwiftyStoreKit.finishTransaction(purchase.transaction)\n                }\n            }\n\n            if let errorAlert = self.alertForPurchaseResult(result) {\n                self.showAlert(errorAlert)\n            }\n        }\n    }\n\n    @IBAction func restorePurchases(_ sender: Any?) {\n\n        SwiftyStoreKit.restorePurchases(atomically: true) { results in\n\n            for purchase in results.restoredPurchases where purchase.needsFinishTransaction {\n                // Deliver content from server, then:\n                SwiftyStoreKit.finishTransaction(purchase.transaction)\n            }\n\n            self.showAlert(self.alertForRestorePurchases(results))\n        }\n    }\n\n    @IBAction func verifyReceipt(_ sender: Any?) {\n\n        verifyReceipt(completion: { result in\n            self.showAlert(self.alertForVerifyReceipt(result))\n        })\n    }\n    \n    func verifyReceipt(completion: @escaping (VerifyReceiptResult) -> Void) {\n        \n        let appleValidator = AppleReceiptValidator(service: .production, sharedSecret: \"your-shared-secret\")\n        SwiftyStoreKit.verifyReceipt(using: appleValidator, completion: completion)\n    }\n\n    func verifyPurchase(_ purchase: RegisteredPurchase) {\n\n        verifyReceipt { result in\n\n            switch result {\n            case .success(let receipt):\n\n                let productId = self.appBundleId + \".\" + purchase.rawValue\n\n                switch purchase {\n                case .autoRenewablePurchase:\n                    let purchaseResult = SwiftyStoreKit.verifySubscription(\n                        ofType: .autoRenewable,\n                        productId: productId,\n                        inReceipt: receipt)\n                    self.showAlert(self.alertForVerifySubscription(purchaseResult))\n                case .nonRenewingPurchase:\n                    let purchaseResult = SwiftyStoreKit.verifySubscription(\n                        ofType: .nonRenewing(validDuration: 60),\n                        productId: productId,\n                        inReceipt: receipt)\n                    self.showAlert(self.alertForVerifySubscription(purchaseResult))\n                default:\n                    let purchaseResult = SwiftyStoreKit.verifyPurchase(\n                        productId: productId,\n                        inReceipt: receipt)\n                    self.showAlert(self.alertForVerifyPurchase(purchaseResult))\n                }\n\n            case .error:\n                self.showAlert(self.alertForVerifyReceipt(result))\n            }\n        }\n    }\n}\n\n// MARK: User facing alerts\nextension ViewController {\n\n    func alertWithTitle(_ title: String, message: String) -> NSAlert {\n\n        let alert: NSAlert = NSAlert()\n        alert.messageText = title\n        alert.informativeText = message\n        alert.alertStyle = .informational\n        return alert\n    }\n    func showAlert(_ alert: NSAlert, handler: ((NSApplication.ModalResponse) -> Void)? = nil) {\n\n        if let window = NSApplication.shared.keyWindow {\n            alert.beginSheetModal(for: window) { (response: NSApplication.ModalResponse) in\n                handler?(response)\n            }\n        } else {\n            let response = alert.runModal()\n            handler?(response)\n        }\n    }\n\n    func alertForProductRetrievalInfo(_ result: RetrieveResults) -> NSAlert {\n\n        if let product = result.retrievedProducts.first {\n            let priceString = product.localizedPrice!\n            return alertWithTitle(product.localizedTitle, message: \"\\(product.localizedDescription) - \\(priceString)\")\n        } else if let invalidProductId = result.invalidProductIDs.first {\n            return alertWithTitle(\"Could not retrieve product info\", message: \"Invalid product identifier: \\(invalidProductId)\")\n        } else {\n            let errorString = result.error?.localizedDescription ?? \"Unknown error. Please contact support\"\n            return alertWithTitle(\"Could not retrieve product info\", message: errorString)\n        }\n    }\n\n    func alertForPurchaseResult(_ result: PurchaseResult) -> NSAlert? {\n        switch result {\n        case .success(let purchase):\n            print(\"Purchase Success: \\(purchase.productId)\")\n            return alertWithTitle(\"Thank You\", message: \"Purchase completed\")\n        case .error(let error):\n            print(\"Purchase Failed: \\(error)\")\n            switch error.code {\n            case .unknown: return alertWithTitle(\"Purchase failed\", message: error.localizedDescription)\n            case .clientInvalid: // client is not allowed to issue the request, etc.\n                return alertWithTitle(\"Purchase failed\", message: \"Not allowed to make the payment\")\n            case .paymentCancelled: // user cancelled the request, etc.\n                return nil\n            case .paymentInvalid: // purchase identifier was invalid, etc.\n                return alertWithTitle(\"Purchase failed\", message: \"The purchase identifier was invalid\")\n            case .paymentNotAllowed: // this device is not allowed to make the payment\n                return alertWithTitle(\"Purchase failed\", message: \"The device is not allowed to make the payment\")\n            default:\n                return alertWithTitle(\"Purchase failed\", message: (error as NSError).localizedDescription)\n            }\n        }\n    }\n\n    func alertForRestorePurchases(_ results: RestoreResults) -> NSAlert {\n\n        if results.restoreFailedPurchases.count > 0 {\n            print(\"Restore Failed: \\(results.restoreFailedPurchases)\")\n            return alertWithTitle(\"Restore failed\", message: \"Unknown error. Please contact support\")\n        } else if results.restoredPurchases.count > 0 {\n            print(\"Restore Success: \\(results.restoredPurchases)\")\n            return alertWithTitle(\"Purchases Restored\", message: \"All purchases have been restored\")\n        } else {\n            print(\"Nothing to Restore\")\n            return alertWithTitle(\"Nothing to restore\", message: \"No previous purchases were found\")\n        }\n    }\n\n    func alertForVerifyReceipt(_ result: VerifyReceiptResult) -> NSAlert {\n\n        switch result {\n        case .success(let receipt):\n            print(\"Verify receipt Success: \\(receipt)\")\n            return self.alertWithTitle(\"Receipt verified\", message: \"Receipt verified remotely\")\n        case .error(let error):\n            print(\"Verify receipt Failed: \\(error)\")\n            switch error {\n            case .noReceiptData:\n                return alertWithTitle(\"Receipt verification\", message: \"No receipt data. Try again.\")\n            case .networkError(let error):\n                return alertWithTitle(\"Receipt verification\", message: \"Network error while verifying receipt: \\(error)\")\n            default:\n                return alertWithTitle(\"Receipt verification\", message: \"Receipt verification failed: \\(error)\")\n            }\n        }\n    }\n\n    func alertForVerifySubscription(_ result: VerifySubscriptionResult) -> NSAlert {\n\n        switch result {\n        case .purchased(let expiryDate):\n            print(\"Product is valid until \\(expiryDate)\")\n            return alertWithTitle(\"Product is purchased\", message: \"Product is valid until \\(expiryDate)\")\n        case .expired(let expiryDate):\n            print(\"Product is expired since \\(expiryDate)\")\n            return alertWithTitle(\"Product expired\", message: \"Product is expired since \\(expiryDate)\")\n        case .notPurchased:\n            print(\"This product has never been purchased\")\n            return alertWithTitle(\"Not purchased\", message: \"This product has never been purchased\")\n        }\n    }\n\n    func alertForVerifyPurchase(_ result: VerifyPurchaseResult) -> NSAlert {\n\n        switch result {\n        case .purchased:\n            print(\"Product is purchased\")\n            return alertWithTitle(\"Product is purchased\", message: \"Product will not expire\")\n        case .notPurchased:\n            print(\"This product has never been purchased\")\n            return alertWithTitle(\"Not purchased\", message: \"This product has never been purchased\")\n        }\n    }\n}\n"
  },
  {
    "path": "SwiftyStoreKit-tvOS-Demo/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Content.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"tv\",\n      \"scale\" : \"1x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "SwiftyStoreKit-tvOS-Demo/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Contents.json",
    "content": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "SwiftyStoreKit-tvOS-Demo/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Contents.json",
    "content": "{\n  \"layers\" : [\n    {\n      \"filename\" : \"Front.imagestacklayer\"\n    },\n    {\n      \"filename\" : \"Middle.imagestacklayer\"\n    },\n    {\n      \"filename\" : \"Back.imagestacklayer\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}\n"
  },
  {
    "path": "SwiftyStoreKit-tvOS-Demo/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Content.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"tv\",\n      \"scale\" : \"1x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "SwiftyStoreKit-tvOS-Demo/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Contents.json",
    "content": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "SwiftyStoreKit-tvOS-Demo/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"tv\",\n      \"scale\" : \"1x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "SwiftyStoreKit-tvOS-Demo/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Contents.json",
    "content": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "SwiftyStoreKit-tvOS-Demo/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Content.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"tv\",\n      \"scale\" : \"1x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "SwiftyStoreKit-tvOS-Demo/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Contents.json",
    "content": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "SwiftyStoreKit-tvOS-Demo/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Contents.json",
    "content": "{\n  \"layers\" : [\n    {\n      \"filename\" : \"Front.imagestacklayer\"\n    },\n    {\n      \"filename\" : \"Middle.imagestacklayer\"\n    },\n    {\n      \"filename\" : \"Back.imagestacklayer\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}\n"
  },
  {
    "path": "SwiftyStoreKit-tvOS-Demo/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Content.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"tv\",\n      \"scale\" : \"1x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "SwiftyStoreKit-tvOS-Demo/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Contents.json",
    "content": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "SwiftyStoreKit-tvOS-Demo/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"tv\",\n      \"scale\" : \"1x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "SwiftyStoreKit-tvOS-Demo/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Contents.json",
    "content": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "SwiftyStoreKit-tvOS-Demo/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json",
    "content": "{\n  \"assets\" : [\n    {\n      \"size\" : \"1280x768\",\n      \"idiom\" : \"tv\",\n      \"filename\" : \"App Icon - Large.imagestack\",\n      \"role\" : \"primary-app-icon\"\n    },\n    {\n      \"size\" : \"400x240\",\n      \"idiom\" : \"tv\",\n      \"filename\" : \"App Icon - Small.imagestack\",\n      \"role\" : \"primary-app-icon\"\n    },\n    {\n      \"size\" : \"2320x720\",\n      \"idiom\" : \"tv\",\n      \"filename\" : \"Top Shelf Image Wide.imageset\",\n      \"role\" : \"top-shelf-image-wide\"\n    },\n    {\n      \"size\" : \"1920x720\",\n      \"idiom\" : \"tv\",\n      \"filename\" : \"Top Shelf Image.imageset\",\n      \"role\" : \"top-shelf-image\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}\n"
  },
  {
    "path": "SwiftyStoreKit-tvOS-Demo/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"tv\",\n      \"scale\" : \"1x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "SwiftyStoreKit-tvOS-Demo/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"tv\",\n      \"scale\" : \"1x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "SwiftyStoreKit-tvOS-Demo/Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "SwiftyStoreKit-tvOS-Demo/Assets.xcassets/LaunchImage.launchimage/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"orientation\" : \"landscape\",\n      \"idiom\" : \"tv\",\n      \"extent\" : \"full-screen\",\n      \"minimum-system-version\" : \"9.0\",\n      \"scale\" : \"1x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "SwiftyStoreKit-tvOS-Demo/Base.lproj/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder.AppleTV.Storyboard\" version=\"3.0\" toolsVersion=\"13771\" targetRuntime=\"AppleTV\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" colorMatched=\"YES\" initialViewController=\"BYZ-38-t0r\">\n    <device id=\"appleTV\" orientation=\"landscape\">\n        <adaptation id=\"light\"/>\n    </device>\n    <dependencies>\n        <deployment identifier=\"tvOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"13772\"/>\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=\"SwiftyStoreKit_tvOSDemo\" 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=\"1920\" height=\"1080\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <button opaque=\"NO\" contentMode=\"scaleToFill\" fixedFrame=\"YES\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"0V2-Mg-12F\">\n                                <rect key=\"frame\" x=\"876\" y=\"106\" width=\"170\" height=\"86\"/>\n                                <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                                <inset key=\"contentEdgeInsets\" minX=\"40\" minY=\"20\" maxX=\"40\" maxY=\"20\"/>\n                                <state key=\"normal\" title=\"info 1\"/>\n                                <connections>\n                                    <action selector=\"nonConsumableGetInfo\" destination=\"BYZ-38-t0r\" eventType=\"primaryActionTriggered\" id=\"KQL-dt-eTv\"/>\n                                </connections>\n                            </button>\n                            <button opaque=\"NO\" contentMode=\"scaleToFill\" fixedFrame=\"YES\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Fad-e7-Q2a\">\n                                <rect key=\"frame\" x=\"873\" y=\"227\" width=\"176\" height=\"86\"/>\n                                <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                                <inset key=\"contentEdgeInsets\" minX=\"40\" minY=\"20\" maxX=\"40\" maxY=\"20\"/>\n                                <state key=\"normal\" title=\"info 2\"/>\n                                <connections>\n                                    <action selector=\"autoRenewableGetInfo\" destination=\"BYZ-38-t0r\" eventType=\"primaryActionTriggered\" id=\"Xf3-53-eEI\"/>\n                                </connections>\n                            </button>\n                            <button opaque=\"NO\" contentMode=\"scaleToFill\" fixedFrame=\"YES\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"lOy-18-mr9\">\n                                <rect key=\"frame\" x=\"828\" y=\"337\" width=\"266\" height=\"86\"/>\n                                <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                                <inset key=\"contentEdgeInsets\" minX=\"40\" minY=\"20\" maxX=\"40\" maxY=\"20\"/>\n                                <state key=\"normal\" title=\"purchase 1\"/>\n                                <connections>\n                                    <action selector=\"nonConsumablePurchase\" destination=\"BYZ-38-t0r\" eventType=\"primaryActionTriggered\" id=\"8j3-oq-8F4\"/>\n                                </connections>\n                            </button>\n                            <button opaque=\"NO\" contentMode=\"scaleToFill\" fixedFrame=\"YES\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"VG3-26-V8F\">\n                                <rect key=\"frame\" x=\"825\" y=\"447\" width=\"271\" height=\"86\"/>\n                                <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                                <inset key=\"contentEdgeInsets\" minX=\"40\" minY=\"20\" maxX=\"40\" maxY=\"20\"/>\n                                <state key=\"normal\" title=\"purchase 2\"/>\n                                <connections>\n                                    <action selector=\"autoRenewablePurchase\" destination=\"BYZ-38-t0r\" eventType=\"primaryActionTriggered\" id=\"qSE-zE-v41\"/>\n                                </connections>\n                            </button>\n                            <button opaque=\"NO\" contentMode=\"scaleToFill\" fixedFrame=\"YES\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"984-qT-rjk\">\n                                <rect key=\"frame\" x=\"860\" y=\"557\" width=\"202\" height=\"86\"/>\n                                <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                                <inset key=\"contentEdgeInsets\" minX=\"40\" minY=\"20\" maxX=\"40\" maxY=\"20\"/>\n                                <state key=\"normal\" title=\"restore\"/>\n                                <connections>\n                                    <action selector=\"restorePurchases\" destination=\"BYZ-38-t0r\" eventType=\"primaryActionTriggered\" id=\"Ce8-Mj-esn\"/>\n                                </connections>\n                            </button>\n                            <button opaque=\"NO\" contentMode=\"scaleToFill\" fixedFrame=\"YES\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"TE5-kT-3nP\">\n                                <rect key=\"frame\" x=\"864\" y=\"667\" width=\"193\" height=\"86\"/>\n                                <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                                <inset key=\"contentEdgeInsets\" minX=\"40\" minY=\"20\" maxX=\"40\" maxY=\"20\"/>\n                                <state key=\"normal\" title=\"verify1\"/>\n                                <connections>\n                                    <action selector=\"nonConsumableVerifyPurchase\" destination=\"BYZ-38-t0r\" eventType=\"primaryActionTriggered\" id=\"VkV-9u-PqD\"/>\n                                </connections>\n                            </button>\n                            <button opaque=\"NO\" contentMode=\"scaleToFill\" fixedFrame=\"YES\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"iYp-Z0-czh\">\n                                <rect key=\"frame\" x=\"862\" y=\"777\" width=\"198\" height=\"86\"/>\n                                <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                                <inset key=\"contentEdgeInsets\" minX=\"40\" minY=\"20\" maxX=\"40\" maxY=\"20\"/>\n                                <state key=\"normal\" title=\"verify2\"/>\n                                <connections>\n                                    <action selector=\"autoRenewableVerifyPurchase\" destination=\"BYZ-38-t0r\" eventType=\"primaryActionTriggered\" id=\"kqM-Mg-BKc\"/>\n                                </connections>\n                            </button>\n                            <button opaque=\"NO\" contentMode=\"scaleToFill\" fixedFrame=\"YES\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"hdi-nV-Cky\">\n                                <rect key=\"frame\" x=\"860\" y=\"887\" width=\"200\" height=\"86\"/>\n                                <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                                <inset key=\"contentEdgeInsets\" minX=\"40\" minY=\"20\" maxX=\"40\" maxY=\"20\"/>\n                                <state key=\"normal\" title=\"receipt\"/>\n                                <connections>\n                                    <action selector=\"verifyReceipt\" destination=\"BYZ-38-t0r\" eventType=\"primaryActionTriggered\" id=\"N3M-ke-Dgy\"/>\n                                </connections>\n                            </button>\n                        </subviews>\n                        <color key=\"backgroundColor\" red=\"0.0\" green=\"0.0\" blue=\"0.84593750000000001\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"dkx-z0-nzr\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "SwiftyStoreKit-tvOS-Demo/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>UIMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>UIRequiredDeviceCapabilities</key>\n\t<array>\n\t\t<string>arm64</string>\n\t</array>\n\t<key>UIUserInterfaceStyle</key>\n\t<string>Automatic</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "SwiftyStoreKit.podspec",
    "content": "Pod::Spec.new do |s|\n  s.name         = 'SwiftyStoreKit'\n  s.version      = '0.16.4'\n  s.summary      = 'Lightweight In App Purchases Swift framework for iOS, tvOS, watchOS, macOS and Mac Catalyst.'\n  s.license      = 'MIT'\n  s.homepage     = 'https://github.com/bizz84/SwiftyStoreKit'\n  s.author       = { 'Andrea Bizzotto' => 'bizz84@gmail.com' }\n  s.ios.deployment_target = '9.0'\n  s.osx.deployment_target = '10.10'\n  s.tvos.deployment_target = '9.0'\n  s.watchos.deployment_target = '6.2'\n  s.swift_version = '5.0'\n  s.source       = { :git => \"https://github.com/bizz84/SwiftyStoreKit.git\", :tag => s.version }\n  s.source_files = 'Sources/SwiftyStoreKit/*.{swift}'\n  s.screenshots  = [\"https://github.com/bizz84/SwiftyStoreKit/raw/master/Screenshots/Preview.jpg\"]\n  s.requires_arc = true\nend\n"
  },
  {
    "path": "SwiftyStoreKit.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\t2F2B8B3024A64CC100CEF088 /* SKProductDiscount+LocalizedPrice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2124A64CC000CEF088 /* SKProductDiscount+LocalizedPrice.swift */; };\n\t\t2F2B8B3124A64CC100CEF088 /* SKProductDiscount+LocalizedPrice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2124A64CC000CEF088 /* SKProductDiscount+LocalizedPrice.swift */; };\n\t\t2F2B8B3224A64CC100CEF088 /* SKProductDiscount+LocalizedPrice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2124A64CC000CEF088 /* SKProductDiscount+LocalizedPrice.swift */; };\n\t\t2F2B8B3324A64CC100CEF088 /* SKProductDiscount+LocalizedPrice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2124A64CC000CEF088 /* SKProductDiscount+LocalizedPrice.swift */; };\n\t\t2F2B8B3424A64CC100CEF088 /* AppleReceiptValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2224A64CC000CEF088 /* AppleReceiptValidator.swift */; };\n\t\t2F2B8B3524A64CC100CEF088 /* AppleReceiptValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2224A64CC000CEF088 /* AppleReceiptValidator.swift */; };\n\t\t2F2B8B3624A64CC100CEF088 /* AppleReceiptValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2224A64CC000CEF088 /* AppleReceiptValidator.swift */; };\n\t\t2F2B8B3724A64CC100CEF088 /* AppleReceiptValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2224A64CC000CEF088 /* AppleReceiptValidator.swift */; };\n\t\t2F2B8B3824A64CC100CEF088 /* InAppProductQueryRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2324A64CC000CEF088 /* InAppProductQueryRequest.swift */; };\n\t\t2F2B8B3924A64CC100CEF088 /* InAppProductQueryRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2324A64CC000CEF088 /* InAppProductQueryRequest.swift */; };\n\t\t2F2B8B3A24A64CC100CEF088 /* InAppProductQueryRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2324A64CC000CEF088 /* InAppProductQueryRequest.swift */; };\n\t\t2F2B8B3B24A64CC100CEF088 /* InAppProductQueryRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2324A64CC000CEF088 /* InAppProductQueryRequest.swift */; };\n\t\t2F2B8B3C24A64CC100CEF088 /* InAppReceipt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2424A64CC000CEF088 /* InAppReceipt.swift */; };\n\t\t2F2B8B3D24A64CC100CEF088 /* InAppReceipt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2424A64CC000CEF088 /* InAppReceipt.swift */; };\n\t\t2F2B8B3E24A64CC100CEF088 /* InAppReceipt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2424A64CC000CEF088 /* InAppReceipt.swift */; };\n\t\t2F2B8B3F24A64CC100CEF088 /* InAppReceipt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2424A64CC000CEF088 /* InAppReceipt.swift */; };\n\t\t2F2B8B4024A64CC100CEF088 /* SwiftyStoreKit+Types.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2524A64CC000CEF088 /* SwiftyStoreKit+Types.swift */; };\n\t\t2F2B8B4124A64CC100CEF088 /* SwiftyStoreKit+Types.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2524A64CC000CEF088 /* SwiftyStoreKit+Types.swift */; };\n\t\t2F2B8B4224A64CC100CEF088 /* SwiftyStoreKit+Types.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2524A64CC000CEF088 /* SwiftyStoreKit+Types.swift */; };\n\t\t2F2B8B4324A64CC100CEF088 /* SwiftyStoreKit+Types.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2524A64CC000CEF088 /* SwiftyStoreKit+Types.swift */; };\n\t\t2F2B8B4424A64CC100CEF088 /* CompleteTransactionsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2624A64CC000CEF088 /* CompleteTransactionsController.swift */; };\n\t\t2F2B8B4524A64CC100CEF088 /* CompleteTransactionsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2624A64CC000CEF088 /* CompleteTransactionsController.swift */; };\n\t\t2F2B8B4624A64CC100CEF088 /* CompleteTransactionsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2624A64CC000CEF088 /* CompleteTransactionsController.swift */; };\n\t\t2F2B8B4724A64CC100CEF088 /* CompleteTransactionsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2624A64CC000CEF088 /* CompleteTransactionsController.swift */; };\n\t\t2F2B8B4824A64CC100CEF088 /* PaymentQueueController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2724A64CC000CEF088 /* PaymentQueueController.swift */; };\n\t\t2F2B8B4924A64CC100CEF088 /* PaymentQueueController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2724A64CC000CEF088 /* PaymentQueueController.swift */; };\n\t\t2F2B8B4A24A64CC100CEF088 /* PaymentQueueController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2724A64CC000CEF088 /* PaymentQueueController.swift */; };\n\t\t2F2B8B4B24A64CC100CEF088 /* PaymentQueueController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2724A64CC000CEF088 /* PaymentQueueController.swift */; };\n\t\t2F2B8B4C24A64CC100CEF088 /* InAppReceiptRefreshRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2824A64CC000CEF088 /* InAppReceiptRefreshRequest.swift */; };\n\t\t2F2B8B4D24A64CC100CEF088 /* InAppReceiptRefreshRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2824A64CC000CEF088 /* InAppReceiptRefreshRequest.swift */; };\n\t\t2F2B8B4E24A64CC100CEF088 /* InAppReceiptRefreshRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2824A64CC000CEF088 /* InAppReceiptRefreshRequest.swift */; };\n\t\t2F2B8B4F24A64CC100CEF088 /* InAppReceiptRefreshRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2824A64CC000CEF088 /* InAppReceiptRefreshRequest.swift */; };\n\t\t2F2B8B5024A64CC100CEF088 /* InAppReceiptVerificator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2924A64CC100CEF088 /* InAppReceiptVerificator.swift */; };\n\t\t2F2B8B5124A64CC100CEF088 /* InAppReceiptVerificator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2924A64CC100CEF088 /* InAppReceiptVerificator.swift */; };\n\t\t2F2B8B5224A64CC100CEF088 /* InAppReceiptVerificator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2924A64CC100CEF088 /* InAppReceiptVerificator.swift */; };\n\t\t2F2B8B5324A64CC100CEF088 /* InAppReceiptVerificator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2924A64CC100CEF088 /* InAppReceiptVerificator.swift */; };\n\t\t2F2B8B5424A64CC100CEF088 /* SKProduct+LocalizedPrice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2A24A64CC100CEF088 /* SKProduct+LocalizedPrice.swift */; };\n\t\t2F2B8B5524A64CC100CEF088 /* SKProduct+LocalizedPrice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2A24A64CC100CEF088 /* SKProduct+LocalizedPrice.swift */; };\n\t\t2F2B8B5624A64CC100CEF088 /* SKProduct+LocalizedPrice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2A24A64CC100CEF088 /* SKProduct+LocalizedPrice.swift */; };\n\t\t2F2B8B5724A64CC100CEF088 /* SKProduct+LocalizedPrice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2A24A64CC100CEF088 /* SKProduct+LocalizedPrice.swift */; };\n\t\t2F2B8B5824A64CC100CEF088 /* ProductsInfoController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2B24A64CC100CEF088 /* ProductsInfoController.swift */; };\n\t\t2F2B8B5924A64CC100CEF088 /* ProductsInfoController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2B24A64CC100CEF088 /* ProductsInfoController.swift */; };\n\t\t2F2B8B5A24A64CC100CEF088 /* ProductsInfoController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2B24A64CC100CEF088 /* ProductsInfoController.swift */; };\n\t\t2F2B8B5B24A64CC100CEF088 /* ProductsInfoController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2B24A64CC100CEF088 /* ProductsInfoController.swift */; };\n\t\t2F2B8B5C24A64CC100CEF088 /* OS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2C24A64CC100CEF088 /* OS.swift */; };\n\t\t2F2B8B5D24A64CC100CEF088 /* OS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2C24A64CC100CEF088 /* OS.swift */; };\n\t\t2F2B8B5E24A64CC100CEF088 /* OS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2C24A64CC100CEF088 /* OS.swift */; };\n\t\t2F2B8B5F24A64CC100CEF088 /* OS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2C24A64CC100CEF088 /* OS.swift */; };\n\t\t2F2B8B6024A64CC100CEF088 /* PaymentsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2D24A64CC100CEF088 /* PaymentsController.swift */; };\n\t\t2F2B8B6124A64CC100CEF088 /* PaymentsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2D24A64CC100CEF088 /* PaymentsController.swift */; };\n\t\t2F2B8B6224A64CC100CEF088 /* PaymentsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2D24A64CC100CEF088 /* PaymentsController.swift */; };\n\t\t2F2B8B6324A64CC100CEF088 /* PaymentsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2D24A64CC100CEF088 /* PaymentsController.swift */; };\n\t\t2F2B8B6424A64CC100CEF088 /* SwiftyStoreKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2E24A64CC100CEF088 /* SwiftyStoreKit.swift */; };\n\t\t2F2B8B6524A64CC100CEF088 /* SwiftyStoreKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2E24A64CC100CEF088 /* SwiftyStoreKit.swift */; };\n\t\t2F2B8B6624A64CC100CEF088 /* SwiftyStoreKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2E24A64CC100CEF088 /* SwiftyStoreKit.swift */; };\n\t\t2F2B8B6724A64CC100CEF088 /* SwiftyStoreKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2E24A64CC100CEF088 /* SwiftyStoreKit.swift */; };\n\t\t2F2B8B6824A64CC100CEF088 /* RestorePurchasesController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2F24A64CC100CEF088 /* RestorePurchasesController.swift */; };\n\t\t2F2B8B6924A64CC100CEF088 /* RestorePurchasesController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2F24A64CC100CEF088 /* RestorePurchasesController.swift */; };\n\t\t2F2B8B6A24A64CC100CEF088 /* RestorePurchasesController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2F24A64CC100CEF088 /* RestorePurchasesController.swift */; };\n\t\t2F2B8B6B24A64CC100CEF088 /* RestorePurchasesController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B2F24A64CC100CEF088 /* RestorePurchasesController.swift */; };\n\t\t2F2B8B7424A64CD700CEF088 /* SwiftyStoreKit-watchOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F2B8B6C24A64CD700CEF088 /* SwiftyStoreKit-watchOS.h */; };\n\t\t2F2B8B7524A64CD700CEF088 /* SwiftyStoreKit-watchOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F2B8B6C24A64CD700CEF088 /* SwiftyStoreKit-watchOS.h */; };\n\t\t2F2B8B7624A64CD700CEF088 /* SwiftyStoreKit-watchOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F2B8B6C24A64CD700CEF088 /* SwiftyStoreKit-watchOS.h */; };\n\t\t2F2B8B7724A64CD700CEF088 /* SwiftyStoreKit-watchOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F2B8B6C24A64CD700CEF088 /* SwiftyStoreKit-watchOS.h */; };\n\t\t2F2B8B8424A64CD700CEF088 /* SwiftyStoreKit-tvOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F2B8B7024A64CD700CEF088 /* SwiftyStoreKit-tvOS.h */; };\n\t\t2F2B8B8524A64CD700CEF088 /* SwiftyStoreKit-tvOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F2B8B7024A64CD700CEF088 /* SwiftyStoreKit-tvOS.h */; };\n\t\t2F2B8B8624A64CD700CEF088 /* SwiftyStoreKit-tvOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F2B8B7024A64CD700CEF088 /* SwiftyStoreKit-tvOS.h */; };\n\t\t2F2B8B8724A64CD700CEF088 /* SwiftyStoreKit-tvOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F2B8B7024A64CD700CEF088 /* SwiftyStoreKit-tvOS.h */; };\n\t\t2F2B8B8824A64CD700CEF088 /* SwiftyStoreKit-iOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F2B8B7124A64CD700CEF088 /* SwiftyStoreKit-iOS.h */; };\n\t\t2F2B8B8924A64CD700CEF088 /* SwiftyStoreKit-iOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F2B8B7124A64CD700CEF088 /* SwiftyStoreKit-iOS.h */; };\n\t\t2F2B8B8A24A64CD700CEF088 /* SwiftyStoreKit-iOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F2B8B7124A64CD700CEF088 /* SwiftyStoreKit-iOS.h */; };\n\t\t2F2B8B8B24A64CD700CEF088 /* SwiftyStoreKit-iOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F2B8B7124A64CD700CEF088 /* SwiftyStoreKit-iOS.h */; };\n\t\t2F2B8B8C24A64CD700CEF088 /* SwiftyStoreKit-macOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F2B8B7224A64CD700CEF088 /* SwiftyStoreKit-macOS.h */; };\n\t\t2F2B8B8D24A64CD700CEF088 /* SwiftyStoreKit-macOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F2B8B7224A64CD700CEF088 /* SwiftyStoreKit-macOS.h */; };\n\t\t2F2B8B8E24A64CD700CEF088 /* SwiftyStoreKit-macOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F2B8B7224A64CD700CEF088 /* SwiftyStoreKit-macOS.h */; };\n\t\t2F2B8B8F24A64CD700CEF088 /* SwiftyStoreKit-macOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F2B8B7224A64CD700CEF088 /* SwiftyStoreKit-macOS.h */; };\n\t\t2F2B8BA024A64DE600CEF088 /* PaymentQueueControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B9424A64DE600CEF088 /* PaymentQueueControllerTests.swift */; };\n\t\t2F2B8BA124A64DE600CEF088 /* PaymentTransactionObserverFake.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B9524A64DE600CEF088 /* PaymentTransactionObserverFake.swift */; };\n\t\t2F2B8BA224A64DE600CEF088 /* ProductsInfoControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B9624A64DE600CEF088 /* ProductsInfoControllerTests.swift */; };\n\t\t2F2B8BA324A64DE600CEF088 /* TestPaymentTransaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B9724A64DE600CEF088 /* TestPaymentTransaction.swift */; };\n\t\t2F2B8BA424A64DE600CEF088 /* TestProduct.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B9824A64DE600CEF088 /* TestProduct.swift */; };\n\t\t2F2B8BA524A64DE600CEF088 /* RestorePurchasesControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B9924A64DE600CEF088 /* RestorePurchasesControllerTests.swift */; };\n\t\t2F2B8BA624A64DE600CEF088 /* CompleteTransactionsControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B9A24A64DE600CEF088 /* CompleteTransactionsControllerTests.swift */; };\n\t\t2F2B8BA724A64DE600CEF088 /* InAppReceiptVerificatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B9B24A64DE600CEF088 /* InAppReceiptVerificatorTests.swift */; };\n\t\t2F2B8BA824A64DE600CEF088 /* InAppReceiptTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B9C24A64DE600CEF088 /* InAppReceiptTests.swift */; };\n\t\t2F2B8BA924A64DE600CEF088 /* PaymentsControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B9D24A64DE600CEF088 /* PaymentsControllerTests.swift */; };\n\t\t2F2B8BAB24A64DE600CEF088 /* PaymentQueueSpy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2B8B9F24A64DE600CEF088 /* PaymentQueueSpy.swift */; };\n\t\t654287F61E79F5A000F61800 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 654287F41E79F5A000F61800 /* Main.storyboard */; };\n\t\t654287F81E79F5A000F61800 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 654287F71E79F5A000F61800 /* Assets.xcassets */; };\n\t\t654287FD1E79F75000F61800 /* SwiftyStoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 54C0D52C1CF7404500F90BCE /* SwiftyStoreKit.framework */; };\n\t\t654287FE1E79F75000F61800 /* SwiftyStoreKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 54C0D52C1CF7404500F90BCE /* SwiftyStoreKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };\n\t\t654288021E7B34E500F61800 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F7DF701DCD4DF000835D30 /* ViewController.swift */; };\n\t\t654288061E7B3A8800F61800 /* NetworkActivityIndicatorManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F7DF6F1DCD4DF000835D30 /* NetworkActivityIndicatorManager.swift */; };\n\t\t654288071E7B3E1500F61800 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F7DF681DCD4DF000835D30 /* AppDelegate.swift */; };\n\t\t658A08431E2EC5120074A98F /* SwiftyStoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6502F62D1B985C40004E342D /* SwiftyStoreKit.framework */; };\n\t\t65F7DF711DCD4DF000835D30 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F7DF681DCD4DF000835D30 /* AppDelegate.swift */; };\n\t\t65F7DF721DCD4DF000835D30 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 65F7DF691DCD4DF000835D30 /* Assets.xcassets */; };\n\t\t65F7DF731DCD4DF000835D30 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 65F7DF6A1DCD4DF000835D30 /* LaunchScreen.storyboard */; };\n\t\t65F7DF741DCD4DF000835D30 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 65F7DF6C1DCD4DF000835D30 /* Main.storyboard */; };\n\t\t65F7DF761DCD4DF000835D30 /* NetworkActivityIndicatorManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F7DF6F1DCD4DF000835D30 /* NetworkActivityIndicatorManager.swift */; };\n\t\t65F7DF771DCD4DF000835D30 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F7DF701DCD4DF000835D30 /* ViewController.swift */; };\n\t\t65F7DF841DCD4FC500835D30 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F7DF7E1DCD4FC500835D30 /* AppDelegate.swift */; };\n\t\t65F7DF851DCD4FC500835D30 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 65F7DF7F1DCD4FC500835D30 /* Assets.xcassets */; };\n\t\t65F7DF861DCD4FC500835D30 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 65F7DF801DCD4FC500835D30 /* Main.storyboard */; };\n\t\t65F7DF881DCD4FC500835D30 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F7DF831DCD4FC500835D30 /* ViewController.swift */; };\n\t\t65F7DF8E1DCD524300835D30 /* SwiftyStoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6502F62D1B985C40004E342D /* SwiftyStoreKit.framework */; };\n\t\t65F7DF8F1DCD524300835D30 /* SwiftyStoreKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 6502F62D1B985C40004E342D /* SwiftyStoreKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };\n\t\tC4FD3A101C2954CD0035CFF3 /* SwiftyStoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C4D74BBB1C24CEC90071AD3E /* SwiftyStoreKit.framework */; };\n\t\tC4FD3A111C2954CD0035CFF3 /* SwiftyStoreKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = C4D74BBB1C24CEC90071AD3E /* SwiftyStoreKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };\n/* End PBXBuildFile section */\n\n/* Begin PBXContainerItemProxy section */\n\t\t654287FF1E79F75000F61800 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 6502F5F61B985833004E342D /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 54C0D52B1CF7404500F90BCE;\n\t\t\tremoteInfo = SwiftyStoreKit_tvOS;\n\t\t};\n\t\t658A08441E2EC5120074A98F /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 6502F5F61B985833004E342D /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 6502F62C1B985C40004E342D;\n\t\t\tremoteInfo = SwiftyStoreKit_iOS;\n\t\t};\n\t\t658A084D1E2EC83F0074A98F /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 6502F5F61B985833004E342D /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 6502F5FD1B985833004E342D;\n\t\t\tremoteInfo = SwiftyStoreKit_iOSDemo;\n\t\t};\n\t\t65F7DF901DCD524300835D30 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 6502F5F61B985833004E342D /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 6502F62C1B985C40004E342D;\n\t\t\tremoteInfo = SwiftyStoreKit_iOS;\n\t\t};\n\t\tC4FD3A121C2954CD0035CFF3 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 6502F5F61B985833004E342D /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = C4D74BBA1C24CEC90071AD3E;\n\t\t\tremoteInfo = SwiftyStoreKitOSX;\n\t\t};\n/* End PBXContainerItemProxy section */\n\n/* Begin PBXCopyFilesBuildPhase section */\n\t\t654288011E79F75100F61800 /* Embed Frameworks */ = {\n\t\t\tisa = PBXCopyFilesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tdstPath = \"\";\n\t\t\tdstSubfolderSpec = 10;\n\t\t\tfiles = (\n\t\t\t\t654287FE1E79F75000F61800 /* SwiftyStoreKit.framework in Embed Frameworks */,\n\t\t\t);\n\t\t\tname = \"Embed Frameworks\";\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t65F7DF921DCD524300835D30 /* Embed Frameworks */ = {\n\t\t\tisa = PBXCopyFilesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tdstPath = \"\";\n\t\t\tdstSubfolderSpec = 10;\n\t\t\tfiles = (\n\t\t\t\t65F7DF8F1DCD524300835D30 /* SwiftyStoreKit.framework in Embed Frameworks */,\n\t\t\t);\n\t\t\tname = \"Embed Frameworks\";\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tC4FD3A141C2954CD0035CFF3 /* Embed Frameworks */ = {\n\t\t\tisa = PBXCopyFilesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tdstPath = \"\";\n\t\t\tdstSubfolderSpec = 10;\n\t\t\tfiles = (\n\t\t\t\tC4FD3A111C2954CD0035CFF3 /* SwiftyStoreKit.framework in Embed Frameworks */,\n\t\t\t);\n\t\t\tname = \"Embed Frameworks\";\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXCopyFilesBuildPhase section */\n\n/* Begin PBXFileReference section */\n\t\t2F2B8B2124A64CC000CEF088 /* SKProductDiscount+LocalizedPrice.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = \"SKProductDiscount+LocalizedPrice.swift\"; path = \"Sources/SwiftyStoreKit/SKProductDiscount+LocalizedPrice.swift\"; sourceTree = SOURCE_ROOT; };\n\t\t2F2B8B2224A64CC000CEF088 /* AppleReceiptValidator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AppleReceiptValidator.swift; path = Sources/SwiftyStoreKit/AppleReceiptValidator.swift; sourceTree = SOURCE_ROOT; };\n\t\t2F2B8B2324A64CC000CEF088 /* InAppProductQueryRequest.swift */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.swift; name = InAppProductQueryRequest.swift; path = Sources/SwiftyStoreKit/InAppProductQueryRequest.swift; sourceTree = SOURCE_ROOT; };\n\t\t2F2B8B2424A64CC000CEF088 /* InAppReceipt.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = InAppReceipt.swift; path = Sources/SwiftyStoreKit/InAppReceipt.swift; sourceTree = SOURCE_ROOT; };\n\t\t2F2B8B2524A64CC000CEF088 /* SwiftyStoreKit+Types.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = \"SwiftyStoreKit+Types.swift\"; path = \"Sources/SwiftyStoreKit/SwiftyStoreKit+Types.swift\"; sourceTree = SOURCE_ROOT; };\n\t\t2F2B8B2624A64CC000CEF088 /* CompleteTransactionsController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CompleteTransactionsController.swift; path = Sources/SwiftyStoreKit/CompleteTransactionsController.swift; sourceTree = SOURCE_ROOT; };\n\t\t2F2B8B2724A64CC000CEF088 /* PaymentQueueController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PaymentQueueController.swift; path = Sources/SwiftyStoreKit/PaymentQueueController.swift; sourceTree = SOURCE_ROOT; };\n\t\t2F2B8B2824A64CC000CEF088 /* InAppReceiptRefreshRequest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = InAppReceiptRefreshRequest.swift; path = Sources/SwiftyStoreKit/InAppReceiptRefreshRequest.swift; sourceTree = SOURCE_ROOT; };\n\t\t2F2B8B2924A64CC100CEF088 /* InAppReceiptVerificator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = InAppReceiptVerificator.swift; path = Sources/SwiftyStoreKit/InAppReceiptVerificator.swift; sourceTree = SOURCE_ROOT; };\n\t\t2F2B8B2A24A64CC100CEF088 /* SKProduct+LocalizedPrice.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = \"SKProduct+LocalizedPrice.swift\"; path = \"Sources/SwiftyStoreKit/SKProduct+LocalizedPrice.swift\"; sourceTree = SOURCE_ROOT; };\n\t\t2F2B8B2B24A64CC100CEF088 /* ProductsInfoController.swift */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.swift; name = ProductsInfoController.swift; path = Sources/SwiftyStoreKit/ProductsInfoController.swift; sourceTree = SOURCE_ROOT; };\n\t\t2F2B8B2C24A64CC100CEF088 /* OS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OS.swift; path = Sources/SwiftyStoreKit/OS.swift; sourceTree = SOURCE_ROOT; };\n\t\t2F2B8B2D24A64CC100CEF088 /* PaymentsController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PaymentsController.swift; path = Sources/SwiftyStoreKit/PaymentsController.swift; sourceTree = SOURCE_ROOT; };\n\t\t2F2B8B2E24A64CC100CEF088 /* SwiftyStoreKit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SwiftyStoreKit.swift; path = Sources/SwiftyStoreKit/SwiftyStoreKit.swift; sourceTree = SOURCE_ROOT; };\n\t\t2F2B8B2F24A64CC100CEF088 /* RestorePurchasesController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RestorePurchasesController.swift; path = Sources/SwiftyStoreKit/RestorePurchasesController.swift; sourceTree = SOURCE_ROOT; };\n\t\t2F2B8B6C24A64CD700CEF088 /* SwiftyStoreKit-watchOS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = \"SwiftyStoreKit-watchOS.h\"; path = \"Sources/SwiftyStoreKit/Platforms/SwiftyStoreKit-watchOS.h\"; sourceTree = SOURCE_ROOT; };\n\t\t2F2B8B6D24A64CD700CEF088 /* Info-macOS.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; name = \"Info-macOS.plist\"; path = \"Sources/SwiftyStoreKit/Platforms/Info-macOS.plist\"; sourceTree = SOURCE_ROOT; };\n\t\t2F2B8B6E24A64CD700CEF088 /* Info-watchOS.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; name = \"Info-watchOS.plist\"; path = \"Sources/SwiftyStoreKit/Platforms/Info-watchOS.plist\"; sourceTree = SOURCE_ROOT; };\n\t\t2F2B8B6F24A64CD700CEF088 /* Info-iOS.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; name = \"Info-iOS.plist\"; path = \"Sources/SwiftyStoreKit/Platforms/Info-iOS.plist\"; sourceTree = SOURCE_ROOT; };\n\t\t2F2B8B7024A64CD700CEF088 /* SwiftyStoreKit-tvOS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = \"SwiftyStoreKit-tvOS.h\"; path = \"Sources/SwiftyStoreKit/Platforms/SwiftyStoreKit-tvOS.h\"; sourceTree = SOURCE_ROOT; };\n\t\t2F2B8B7124A64CD700CEF088 /* SwiftyStoreKit-iOS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = \"SwiftyStoreKit-iOS.h\"; path = \"Sources/SwiftyStoreKit/Platforms/SwiftyStoreKit-iOS.h\"; sourceTree = SOURCE_ROOT; };\n\t\t2F2B8B7224A64CD700CEF088 /* SwiftyStoreKit-macOS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = \"SwiftyStoreKit-macOS.h\"; path = \"Sources/SwiftyStoreKit/Platforms/SwiftyStoreKit-macOS.h\"; sourceTree = SOURCE_ROOT; };\n\t\t2F2B8B7324A64CD700CEF088 /* Info-tvOS.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; name = \"Info-tvOS.plist\"; path = \"Sources/SwiftyStoreKit/Platforms/Info-tvOS.plist\"; sourceTree = SOURCE_ROOT; };\n\t\t2F2B8B9424A64DE600CEF088 /* PaymentQueueControllerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PaymentQueueControllerTests.swift; path = Tests/SwiftyStoreKitTests/PaymentQueueControllerTests.swift; sourceTree = SOURCE_ROOT; };\n\t\t2F2B8B9524A64DE600CEF088 /* PaymentTransactionObserverFake.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PaymentTransactionObserverFake.swift; path = Tests/SwiftyStoreKitTests/PaymentTransactionObserverFake.swift; sourceTree = SOURCE_ROOT; };\n\t\t2F2B8B9624A64DE600CEF088 /* ProductsInfoControllerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ProductsInfoControllerTests.swift; path = Tests/SwiftyStoreKitTests/ProductsInfoControllerTests.swift; sourceTree = SOURCE_ROOT; };\n\t\t2F2B8B9724A64DE600CEF088 /* TestPaymentTransaction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TestPaymentTransaction.swift; path = Tests/SwiftyStoreKitTests/TestPaymentTransaction.swift; sourceTree = SOURCE_ROOT; };\n\t\t2F2B8B9824A64DE600CEF088 /* TestProduct.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TestProduct.swift; path = Tests/SwiftyStoreKitTests/TestProduct.swift; sourceTree = SOURCE_ROOT; };\n\t\t2F2B8B9924A64DE600CEF088 /* RestorePurchasesControllerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RestorePurchasesControllerTests.swift; path = Tests/SwiftyStoreKitTests/RestorePurchasesControllerTests.swift; sourceTree = SOURCE_ROOT; };\n\t\t2F2B8B9A24A64DE600CEF088 /* CompleteTransactionsControllerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CompleteTransactionsControllerTests.swift; path = Tests/SwiftyStoreKitTests/CompleteTransactionsControllerTests.swift; sourceTree = SOURCE_ROOT; };\n\t\t2F2B8B9B24A64DE600CEF088 /* InAppReceiptVerificatorTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = InAppReceiptVerificatorTests.swift; path = Tests/SwiftyStoreKitTests/InAppReceiptVerificatorTests.swift; sourceTree = SOURCE_ROOT; };\n\t\t2F2B8B9C24A64DE600CEF088 /* InAppReceiptTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = InAppReceiptTests.swift; path = Tests/SwiftyStoreKitTests/InAppReceiptTests.swift; sourceTree = SOURCE_ROOT; };\n\t\t2F2B8B9D24A64DE600CEF088 /* PaymentsControllerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PaymentsControllerTests.swift; path = Tests/SwiftyStoreKitTests/PaymentsControllerTests.swift; sourceTree = SOURCE_ROOT; };\n\t\t2F2B8B9E24A64DE600CEF088 /* Info-Tests.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = \"Info-Tests.plist\"; path = \"Tests/SwiftyStoreKitTests/Info-Tests.plist\"; sourceTree = SOURCE_ROOT; };\n\t\t2F2B8B9F24A64DE600CEF088 /* PaymentQueueSpy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PaymentQueueSpy.swift; path = Tests/SwiftyStoreKitTests/PaymentQueueSpy.swift; sourceTree = SOURCE_ROOT; };\n\t\t54C0D52C1CF7404500F90BCE /* SwiftyStoreKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftyStoreKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t6502F5FE1B985833004E342D /* SwiftyStoreKit_iOSDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwiftyStoreKit_iOSDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t6502F62D1B985C40004E342D /* SwiftyStoreKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftyStoreKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t654287EE1E79F5A000F61800 /* SwiftyStoreKit_tvOSDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwiftyStoreKit_tvOSDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t654287F51E79F5A000F61800 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = \"<group>\"; };\n\t\t654287F71E79F5A000F61800 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\t654287F91E79F5A000F61800 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t658A083E1E2EC5120074A98F /* SwiftyStoreKitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftyStoreKitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t65F7DF681DCD4DF000835D30 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = \"<group>\"; };\n\t\t65F7DF691DCD4DF000835D30 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\t65F7DF6B1DCD4DF000835D30 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = \"<group>\"; };\n\t\t65F7DF6D1DCD4DF000835D30 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = \"<group>\"; };\n\t\t65F7DF6E1DCD4DF000835D30 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t65F7DF6F1DCD4DF000835D30 /* NetworkActivityIndicatorManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkActivityIndicatorManager.swift; sourceTree = \"<group>\"; };\n\t\t65F7DF701DCD4DF000835D30 /* ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = \"<group>\"; };\n\t\t65F7DF7E1DCD4FC500835D30 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = \"<group>\"; };\n\t\t65F7DF7F1DCD4FC500835D30 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\t65F7DF811DCD4FC500835D30 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = \"<group>\"; };\n\t\t65F7DF821DCD4FC500835D30 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t65F7DF831DCD4FC500835D30 /* ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = \"<group>\"; };\n\t\tA61BF4DD2481F4970017D9BC /* SwiftyStoreKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftyStoreKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tC4D74BBB1C24CEC90071AD3E /* SwiftyStoreKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftyStoreKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tC4FD3A011C2954C10035CFF3 /* SwiftyStoreKit_macOSDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwiftyStoreKit_macOSDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t54C0D5281CF7404500F90BCE /* 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\t6502F5FB1B985833004E342D /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t65F7DF8E1DCD524300835D30 /* SwiftyStoreKit.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t6502F6291B985C40004E342D /* 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\t654287EB1E79F5A000F61800 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t654287FD1E79F75000F61800 /* SwiftyStoreKit.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t658A083B1E2EC5120074A98F /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t658A08431E2EC5120074A98F /* SwiftyStoreKit.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tA61BF4D52481F4970017D9BC /* 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\tC4D74BB71C24CEC90071AD3E /* 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\tC4FD39FE1C2954C10035CFF3 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tC4FD3A101C2954CD0035CFF3 /* SwiftyStoreKit.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\t6502F5F51B985833004E342D = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t6502F6001B985833004E342D /* SwiftyStoreKit */,\n\t\t\t\t65F7DF671DCD4DF000835D30 /* SwiftyStoreKit-iOS-Demo */,\n\t\t\t\t65F7DF7D1DCD4FC500835D30 /* SwiftyStoreKit-macOS-Demo */,\n\t\t\t\t654287EF1E79F5A000F61800 /* SwiftyStoreKit-tvOS-Demo */,\n\t\t\t\t658A083F1E2EC5120074A98F /* SwiftyStoreKitTests */,\n\t\t\t\t6502F5FF1B985833004E342D /* Products */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t6502F5FF1B985833004E342D /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t6502F5FE1B985833004E342D /* SwiftyStoreKit_iOSDemo.app */,\n\t\t\t\t6502F62D1B985C40004E342D /* SwiftyStoreKit.framework */,\n\t\t\t\tC4D74BBB1C24CEC90071AD3E /* SwiftyStoreKit.framework */,\n\t\t\t\tC4FD3A011C2954C10035CFF3 /* SwiftyStoreKit_macOSDemo.app */,\n\t\t\t\t54C0D52C1CF7404500F90BCE /* SwiftyStoreKit.framework */,\n\t\t\t\t658A083E1E2EC5120074A98F /* SwiftyStoreKitTests.xctest */,\n\t\t\t\t654287EE1E79F5A000F61800 /* SwiftyStoreKit_tvOSDemo.app */,\n\t\t\t\tA61BF4DD2481F4970017D9BC /* SwiftyStoreKit.framework */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t6502F6001B985833004E342D /* SwiftyStoreKit */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2F2B8B2224A64CC000CEF088 /* AppleReceiptValidator.swift */,\n\t\t\t\t2F2B8B2624A64CC000CEF088 /* CompleteTransactionsController.swift */,\n\t\t\t\t2F2B8B2324A64CC000CEF088 /* InAppProductQueryRequest.swift */,\n\t\t\t\t2F2B8B2424A64CC000CEF088 /* InAppReceipt.swift */,\n\t\t\t\t2F2B8B2824A64CC000CEF088 /* InAppReceiptRefreshRequest.swift */,\n\t\t\t\t2F2B8B2924A64CC100CEF088 /* InAppReceiptVerificator.swift */,\n\t\t\t\t2F2B8B2C24A64CC100CEF088 /* OS.swift */,\n\t\t\t\t2F2B8B2724A64CC000CEF088 /* PaymentQueueController.swift */,\n\t\t\t\t2F2B8B2D24A64CC100CEF088 /* PaymentsController.swift */,\n\t\t\t\t2F2B8B2B24A64CC100CEF088 /* ProductsInfoController.swift */,\n\t\t\t\t2F2B8B2F24A64CC100CEF088 /* RestorePurchasesController.swift */,\n\t\t\t\t2F2B8B2A24A64CC100CEF088 /* SKProduct+LocalizedPrice.swift */,\n\t\t\t\t2F2B8B2124A64CC000CEF088 /* SKProductDiscount+LocalizedPrice.swift */,\n\t\t\t\t2F2B8B2E24A64CC100CEF088 /* SwiftyStoreKit.swift */,\n\t\t\t\t2F2B8B2524A64CC000CEF088 /* SwiftyStoreKit+Types.swift */,\n\t\t\t\t65F7DF931DCD536100835D30 /* Platforms */,\n\t\t\t);\n\t\t\tpath = SwiftyStoreKit;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t654287EF1E79F5A000F61800 /* SwiftyStoreKit-tvOS-Demo */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t654287F41E79F5A000F61800 /* Main.storyboard */,\n\t\t\t\t654287F71E79F5A000F61800 /* Assets.xcassets */,\n\t\t\t\t654287F91E79F5A000F61800 /* Info.plist */,\n\t\t\t);\n\t\t\tpath = \"SwiftyStoreKit-tvOS-Demo\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t658A083F1E2EC5120074A98F /* SwiftyStoreKitTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2F2B8B9A24A64DE600CEF088 /* CompleteTransactionsControllerTests.swift */,\n\t\t\t\t2F2B8B9C24A64DE600CEF088 /* InAppReceiptTests.swift */,\n\t\t\t\t2F2B8B9B24A64DE600CEF088 /* InAppReceiptVerificatorTests.swift */,\n\t\t\t\t2F2B8B9E24A64DE600CEF088 /* Info-Tests.plist */,\n\t\t\t\t2F2B8B9424A64DE600CEF088 /* PaymentQueueControllerTests.swift */,\n\t\t\t\t2F2B8B9F24A64DE600CEF088 /* PaymentQueueSpy.swift */,\n\t\t\t\t2F2B8B9D24A64DE600CEF088 /* PaymentsControllerTests.swift */,\n\t\t\t\t2F2B8B9524A64DE600CEF088 /* PaymentTransactionObserverFake.swift */,\n\t\t\t\t2F2B8B9624A64DE600CEF088 /* ProductsInfoControllerTests.swift */,\n\t\t\t\t2F2B8B9924A64DE600CEF088 /* RestorePurchasesControllerTests.swift */,\n\t\t\t\t2F2B8B9724A64DE600CEF088 /* TestPaymentTransaction.swift */,\n\t\t\t\t2F2B8B9824A64DE600CEF088 /* TestProduct.swift */,\n\t\t\t);\n\t\t\tpath = SwiftyStoreKitTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t65F7DF671DCD4DF000835D30 /* SwiftyStoreKit-iOS-Demo */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t65F7DF681DCD4DF000835D30 /* AppDelegate.swift */,\n\t\t\t\t65F7DF691DCD4DF000835D30 /* Assets.xcassets */,\n\t\t\t\t65F7DF6A1DCD4DF000835D30 /* LaunchScreen.storyboard */,\n\t\t\t\t65F7DF6C1DCD4DF000835D30 /* Main.storyboard */,\n\t\t\t\t65F7DF6E1DCD4DF000835D30 /* Info.plist */,\n\t\t\t\t65F7DF6F1DCD4DF000835D30 /* NetworkActivityIndicatorManager.swift */,\n\t\t\t\t65F7DF701DCD4DF000835D30 /* ViewController.swift */,\n\t\t\t);\n\t\t\tpath = \"SwiftyStoreKit-iOS-Demo\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t65F7DF7D1DCD4FC500835D30 /* SwiftyStoreKit-macOS-Demo */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t65F7DF7E1DCD4FC500835D30 /* AppDelegate.swift */,\n\t\t\t\t65F7DF7F1DCD4FC500835D30 /* Assets.xcassets */,\n\t\t\t\t65F7DF801DCD4FC500835D30 /* Main.storyboard */,\n\t\t\t\t65F7DF821DCD4FC500835D30 /* Info.plist */,\n\t\t\t\t65F7DF831DCD4FC500835D30 /* ViewController.swift */,\n\t\t\t);\n\t\t\tpath = \"SwiftyStoreKit-macOS-Demo\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t65F7DF931DCD536100835D30 /* Platforms */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t2F2B8B6F24A64CD700CEF088 /* Info-iOS.plist */,\n\t\t\t\t2F2B8B6D24A64CD700CEF088 /* Info-macOS.plist */,\n\t\t\t\t2F2B8B7324A64CD700CEF088 /* Info-tvOS.plist */,\n\t\t\t\t2F2B8B6E24A64CD700CEF088 /* Info-watchOS.plist */,\n\t\t\t\t2F2B8B7124A64CD700CEF088 /* SwiftyStoreKit-iOS.h */,\n\t\t\t\t2F2B8B7224A64CD700CEF088 /* SwiftyStoreKit-macOS.h */,\n\t\t\t\t2F2B8B7024A64CD700CEF088 /* SwiftyStoreKit-tvOS.h */,\n\t\t\t\t2F2B8B6C24A64CD700CEF088 /* SwiftyStoreKit-watchOS.h */,\n\t\t\t);\n\t\t\tpath = Platforms;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXHeadersBuildPhase section */\n\t\t54C0D5291CF7404500F90BCE /* Headers */ = {\n\t\t\tisa = PBXHeadersBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2F2B8B8A24A64CD700CEF088 /* SwiftyStoreKit-iOS.h in Headers */,\n\t\t\t\t2F2B8B7624A64CD700CEF088 /* SwiftyStoreKit-watchOS.h in Headers */,\n\t\t\t\t2F2B8B8624A64CD700CEF088 /* SwiftyStoreKit-tvOS.h in Headers */,\n\t\t\t\t2F2B8B8E24A64CD700CEF088 /* SwiftyStoreKit-macOS.h in Headers */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t6502F62A1B985C40004E342D /* Headers */ = {\n\t\t\tisa = PBXHeadersBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2F2B8B8824A64CD700CEF088 /* SwiftyStoreKit-iOS.h in Headers */,\n\t\t\t\t2F2B8B7424A64CD700CEF088 /* SwiftyStoreKit-watchOS.h in Headers */,\n\t\t\t\t2F2B8B8424A64CD700CEF088 /* SwiftyStoreKit-tvOS.h in Headers */,\n\t\t\t\t2F2B8B8C24A64CD700CEF088 /* SwiftyStoreKit-macOS.h in Headers */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tA61BF4D62481F4970017D9BC /* Headers */ = {\n\t\t\tisa = PBXHeadersBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2F2B8B8B24A64CD700CEF088 /* SwiftyStoreKit-iOS.h in Headers */,\n\t\t\t\t2F2B8B7724A64CD700CEF088 /* SwiftyStoreKit-watchOS.h in Headers */,\n\t\t\t\t2F2B8B8724A64CD700CEF088 /* SwiftyStoreKit-tvOS.h in Headers */,\n\t\t\t\t2F2B8B8F24A64CD700CEF088 /* SwiftyStoreKit-macOS.h in Headers */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tC4D74BB81C24CEC90071AD3E /* Headers */ = {\n\t\t\tisa = PBXHeadersBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2F2B8B8924A64CD700CEF088 /* SwiftyStoreKit-iOS.h in Headers */,\n\t\t\t\t2F2B8B7524A64CD700CEF088 /* SwiftyStoreKit-watchOS.h in Headers */,\n\t\t\t\t2F2B8B8524A64CD700CEF088 /* SwiftyStoreKit-tvOS.h in Headers */,\n\t\t\t\t2F2B8B8D24A64CD700CEF088 /* SwiftyStoreKit-macOS.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\t54C0D52B1CF7404500F90BCE /* SwiftyStoreKit_tvOS */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 54C0D5331CF7404500F90BCE /* Build configuration list for PBXNativeTarget \"SwiftyStoreKit_tvOS\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t54C0D5271CF7404500F90BCE /* Sources */,\n\t\t\t\t54C0D5281CF7404500F90BCE /* Frameworks */,\n\t\t\t\t54C0D5291CF7404500F90BCE /* Headers */,\n\t\t\t\t54C0D52A1CF7404500F90BCE /* 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 = SwiftyStoreKit_tvOS;\n\t\t\tproductName = SwiftyStoreKitTV;\n\t\t\tproductReference = 54C0D52C1CF7404500F90BCE /* SwiftyStoreKit.framework */;\n\t\t\tproductType = \"com.apple.product-type.framework\";\n\t\t};\n\t\t6502F5FD1B985833004E342D /* SwiftyStoreKit_iOSDemo */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 6502F6101B985833004E342D /* Build configuration list for PBXNativeTarget \"SwiftyStoreKit_iOSDemo\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t6502F5FA1B985833004E342D /* Sources */,\n\t\t\t\t6502F5FB1B985833004E342D /* Frameworks */,\n\t\t\t\t6502F5FC1B985833004E342D /* Resources */,\n\t\t\t\t65F7DF921DCD524300835D30 /* Embed Frameworks */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\t65F7DF911DCD524300835D30 /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = SwiftyStoreKit_iOSDemo;\n\t\t\tproductName = SwiftyStoreKit;\n\t\t\tproductReference = 6502F5FE1B985833004E342D /* SwiftyStoreKit_iOSDemo.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n\t\t6502F62C1B985C40004E342D /* SwiftyStoreKit_iOS */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 6502F6361B985C40004E342D /* Build configuration list for PBXNativeTarget \"SwiftyStoreKit_iOS\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t6502F6281B985C40004E342D /* Sources */,\n\t\t\t\t6502F6291B985C40004E342D /* Frameworks */,\n\t\t\t\t6502F62A1B985C40004E342D /* Headers */,\n\t\t\t\t6502F62B1B985C40004E342D /* Resources */,\n\t\t\t\tC4B298351E5C25E5007C87C2 /* swiftlint */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = SwiftyStoreKit_iOS;\n\t\t\tproductName = SwiftyStoreKit;\n\t\t\tproductReference = 6502F62D1B985C40004E342D /* SwiftyStoreKit.framework */;\n\t\t\tproductType = \"com.apple.product-type.framework\";\n\t\t};\n\t\t654287ED1E79F5A000F61800 /* SwiftyStoreKit_tvOSDemo */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 654287FC1E79F5A000F61800 /* Build configuration list for PBXNativeTarget \"SwiftyStoreKit_tvOSDemo\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t654287EA1E79F5A000F61800 /* Sources */,\n\t\t\t\t654287EB1E79F5A000F61800 /* Frameworks */,\n\t\t\t\t654287EC1E79F5A000F61800 /* Resources */,\n\t\t\t\t654288011E79F75100F61800 /* Embed Frameworks */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\t654288001E79F75000F61800 /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = SwiftyStoreKit_tvOSDemo;\n\t\t\tproductName = \"SwiftyStoreKit-tvOS-Demo\";\n\t\t\tproductReference = 654287EE1E79F5A000F61800 /* SwiftyStoreKit_tvOSDemo.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n\t\t658A083D1E2EC5120074A98F /* SwiftyStoreKitTests */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 658A08461E2EC5120074A98F /* Build configuration list for PBXNativeTarget \"SwiftyStoreKitTests\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t658A083A1E2EC5120074A98F /* Sources */,\n\t\t\t\t658A083B1E2EC5120074A98F /* Frameworks */,\n\t\t\t\t658A083C1E2EC5120074A98F /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\t658A08451E2EC5120074A98F /* PBXTargetDependency */,\n\t\t\t\t658A084E1E2EC83F0074A98F /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = SwiftyStoreKitTests;\n\t\t\tproductName = SwiftyStoreKitTests;\n\t\t\tproductReference = 658A083E1E2EC5120074A98F /* SwiftyStoreKitTests.xctest */;\n\t\t\tproductType = \"com.apple.product-type.bundle.unit-test\";\n\t\t};\n\t\tA61BF4C42481F4970017D9BC /* SwiftyStoreKit_watchOS */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = A61BF4DA2481F4970017D9BC /* Build configuration list for PBXNativeTarget \"SwiftyStoreKit_watchOS\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tA61BF4C52481F4970017D9BC /* Sources */,\n\t\t\t\tA61BF4D62481F4970017D9BC /* Headers */,\n\t\t\t\tA61BF4D52481F4970017D9BC /* Frameworks */,\n\t\t\t\tA61BF4D82481F4970017D9BC /* Resources */,\n\t\t\t\tA61BF4D92481F4970017D9BC /* swiftlint */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = SwiftyStoreKit_watchOS;\n\t\t\tproductName = SwiftyStoreKit;\n\t\t\tproductReference = A61BF4DD2481F4970017D9BC /* SwiftyStoreKit.framework */;\n\t\t\tproductType = \"com.apple.product-type.framework\";\n\t\t};\n\t\tC4D74BBA1C24CEC90071AD3E /* SwiftyStoreKit_macOS */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = C4D74BC21C24CECA0071AD3E /* Build configuration list for PBXNativeTarget \"SwiftyStoreKit_macOS\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tC4D74BB61C24CEC90071AD3E /* Sources */,\n\t\t\t\tC4D74BB71C24CEC90071AD3E /* Frameworks */,\n\t\t\t\tC4D74BB81C24CEC90071AD3E /* Headers */,\n\t\t\t\tC4D74BB91C24CEC90071AD3E /* Resources */,\n\t\t\t\tC4B298341E5C25DD007C87C2 /* swiftlint */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = SwiftyStoreKit_macOS;\n\t\t\tproductName = SwiftyStoreKitOSX;\n\t\t\tproductReference = C4D74BBB1C24CEC90071AD3E /* SwiftyStoreKit.framework */;\n\t\t\tproductType = \"com.apple.product-type.framework\";\n\t\t};\n\t\tC4FD3A001C2954C10035CFF3 /* SwiftyStoreKit_macOSDemo */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = C4FD3A0D1C2954C10035CFF3 /* Build configuration list for PBXNativeTarget \"SwiftyStoreKit_macOSDemo\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tC4FD39FD1C2954C10035CFF3 /* Sources */,\n\t\t\t\tC4FD39FE1C2954C10035CFF3 /* Frameworks */,\n\t\t\t\tC4FD39FF1C2954C10035CFF3 /* Resources */,\n\t\t\t\tC4FD3A141C2954CD0035CFF3 /* Embed Frameworks */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\tC4FD3A131C2954CD0035CFF3 /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = SwiftyStoreKit_macOSDemo;\n\t\t\tproductName = SwiftyStoreOSXDemo;\n\t\t\tproductReference = C4FD3A011C2954C10035CFF3 /* SwiftyStoreKit_macOSDemo.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t6502F5F61B985833004E342D /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastSwiftUpdateCheck = 0820;\n\t\t\t\tLastUpgradeCheck = 1160;\n\t\t\t\tORGANIZATIONNAME = musevisions;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t54C0D52B1CF7404500F90BCE = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 7.3.1;\n\t\t\t\t\t\tDevelopmentTeam = M54ZVB688G;\n\t\t\t\t\t\tLastSwiftMigration = 1150;\n\t\t\t\t\t};\n\t\t\t\t\t6502F5FD1B985833004E342D = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 7.0;\n\t\t\t\t\t\tLastSwiftMigration = 0800;\n\t\t\t\t\t\tProvisioningStyle = Automatic;\n\t\t\t\t\t};\n\t\t\t\t\t6502F62C1B985C40004E342D = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 7.0;\n\t\t\t\t\t\tLastSwiftMigration = 1150;\n\t\t\t\t\t};\n\t\t\t\t\t654287ED1E79F5A000F61800 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 8.2.1;\n\t\t\t\t\t\tProvisioningStyle = Automatic;\n\t\t\t\t\t};\n\t\t\t\t\t658A083D1E2EC5120074A98F = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 8.2.1;\n\t\t\t\t\t\tLastSwiftMigration = 1150;\n\t\t\t\t\t\tProvisioningStyle = Automatic;\n\t\t\t\t\t\tTestTargetID = 6502F5FD1B985833004E342D;\n\t\t\t\t\t};\n\t\t\t\t\tA61BF4C42481F4970017D9BC = {\n\t\t\t\t\t\tLastSwiftMigration = 1150;\n\t\t\t\t\t};\n\t\t\t\t\tC4D74BBA1C24CEC90071AD3E = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 7.2;\n\t\t\t\t\t\tLastSwiftMigration = 1150;\n\t\t\t\t\t};\n\t\t\t\t\tC4FD3A001C2954C10035CFF3 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 7.2;\n\t\t\t\t\t\tLastSwiftMigration = 0800;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 6502F5F91B985833004E342D /* Build configuration list for PBXProject \"SwiftyStoreKit\" */;\n\t\t\tcompatibilityVersion = \"Xcode 3.2\";\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 = 6502F5F51B985833004E342D;\n\t\t\tproductRefGroup = 6502F5FF1B985833004E342D /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t6502F62C1B985C40004E342D /* SwiftyStoreKit_iOS */,\n\t\t\t\tC4D74BBA1C24CEC90071AD3E /* SwiftyStoreKit_macOS */,\n\t\t\t\t54C0D52B1CF7404500F90BCE /* SwiftyStoreKit_tvOS */,\n\t\t\t\tA61BF4C42481F4970017D9BC /* SwiftyStoreKit_watchOS */,\n\t\t\t\t6502F5FD1B985833004E342D /* SwiftyStoreKit_iOSDemo */,\n\t\t\t\tC4FD3A001C2954C10035CFF3 /* SwiftyStoreKit_macOSDemo */,\n\t\t\t\t654287ED1E79F5A000F61800 /* SwiftyStoreKit_tvOSDemo */,\n\t\t\t\t658A083D1E2EC5120074A98F /* SwiftyStoreKitTests */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t54C0D52A1CF7404500F90BCE /* 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\t6502F5FC1B985833004E342D /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t65F7DF721DCD4DF000835D30 /* Assets.xcassets in Resources */,\n\t\t\t\t65F7DF741DCD4DF000835D30 /* Main.storyboard in Resources */,\n\t\t\t\t65F7DF731DCD4DF000835D30 /* LaunchScreen.storyboard in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t6502F62B1B985C40004E342D /* 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\t654287EC1E79F5A000F61800 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t654287F81E79F5A000F61800 /* Assets.xcassets in Resources */,\n\t\t\t\t654287F61E79F5A000F61800 /* Main.storyboard in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t658A083C1E2EC5120074A98F /* 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\tA61BF4D82481F4970017D9BC /* 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\tC4D74BB91C24CEC90071AD3E /* 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\tC4FD39FF1C2954C10035CFF3 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t65F7DF851DCD4FC500835D30 /* Assets.xcassets in Resources */,\n\t\t\t\t65F7DF861DCD4FC500835D30 /* Main.storyboard in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXShellScriptBuildPhase section */\n\t\tA61BF4D92481F4970017D9BC /* swiftlint */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t);\n\t\t\tname = swiftlint;\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"if which swiftlint >/dev/null; then\\nswiftlint\\nelse\\necho \\\"SwiftLint does not exist, download from https://github.com/realm/SwiftLint\\\"\\nfi\\n\";\n\t\t};\n\t\tC4B298341E5C25DD007C87C2 /* swiftlint */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t);\n\t\t\tname = swiftlint;\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"if which swiftlint >/dev/null; then\\nswiftlint\\nelse\\necho \\\"SwiftLint does not exist, download from https://github.com/realm/SwiftLint\\\"\\nfi\";\n\t\t};\n\t\tC4B298351E5C25E5007C87C2 /* swiftlint */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t);\n\t\t\tname = swiftlint;\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"if which swiftlint >/dev/null; then\\nswiftlint\\nelse\\necho \\\"SwiftLint does not exist, download from https://github.com/realm/SwiftLint\\\"\\nfi\";\n\t\t};\n/* End PBXShellScriptBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t54C0D5271CF7404500F90BCE /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2F2B8B3A24A64CC100CEF088 /* InAppProductQueryRequest.swift in Sources */,\n\t\t\t\t2F2B8B6224A64CC100CEF088 /* PaymentsController.swift in Sources */,\n\t\t\t\t2F2B8B5624A64CC100CEF088 /* SKProduct+LocalizedPrice.swift in Sources */,\n\t\t\t\t2F2B8B3E24A64CC100CEF088 /* InAppReceipt.swift in Sources */,\n\t\t\t\t2F2B8B3624A64CC100CEF088 /* AppleReceiptValidator.swift in Sources */,\n\t\t\t\t2F2B8B6A24A64CC100CEF088 /* RestorePurchasesController.swift in Sources */,\n\t\t\t\t2F2B8B4624A64CC100CEF088 /* CompleteTransactionsController.swift in Sources */,\n\t\t\t\t2F2B8B5E24A64CC100CEF088 /* OS.swift in Sources */,\n\t\t\t\t2F2B8B5224A64CC100CEF088 /* InAppReceiptVerificator.swift in Sources */,\n\t\t\t\t2F2B8B6624A64CC100CEF088 /* SwiftyStoreKit.swift in Sources */,\n\t\t\t\t2F2B8B4A24A64CC100CEF088 /* PaymentQueueController.swift in Sources */,\n\t\t\t\t2F2B8B4224A64CC100CEF088 /* SwiftyStoreKit+Types.swift in Sources */,\n\t\t\t\t2F2B8B4E24A64CC100CEF088 /* InAppReceiptRefreshRequest.swift in Sources */,\n\t\t\t\t2F2B8B3224A64CC100CEF088 /* SKProductDiscount+LocalizedPrice.swift in Sources */,\n\t\t\t\t2F2B8B5A24A64CC100CEF088 /* ProductsInfoController.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t6502F5FA1B985833004E342D /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t65F7DF771DCD4DF000835D30 /* ViewController.swift in Sources */,\n\t\t\t\t65F7DF711DCD4DF000835D30 /* AppDelegate.swift in Sources */,\n\t\t\t\t65F7DF761DCD4DF000835D30 /* NetworkActivityIndicatorManager.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t6502F6281B985C40004E342D /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2F2B8B3824A64CC100CEF088 /* InAppProductQueryRequest.swift in Sources */,\n\t\t\t\t2F2B8B6024A64CC100CEF088 /* PaymentsController.swift in Sources */,\n\t\t\t\t2F2B8B5424A64CC100CEF088 /* SKProduct+LocalizedPrice.swift in Sources */,\n\t\t\t\t2F2B8B3C24A64CC100CEF088 /* InAppReceipt.swift in Sources */,\n\t\t\t\t2F2B8B3424A64CC100CEF088 /* AppleReceiptValidator.swift in Sources */,\n\t\t\t\t2F2B8B6824A64CC100CEF088 /* RestorePurchasesController.swift in Sources */,\n\t\t\t\t2F2B8B4424A64CC100CEF088 /* CompleteTransactionsController.swift in Sources */,\n\t\t\t\t2F2B8B5C24A64CC100CEF088 /* OS.swift in Sources */,\n\t\t\t\t2F2B8B5024A64CC100CEF088 /* InAppReceiptVerificator.swift in Sources */,\n\t\t\t\t2F2B8B6424A64CC100CEF088 /* SwiftyStoreKit.swift in Sources */,\n\t\t\t\t2F2B8B4824A64CC100CEF088 /* PaymentQueueController.swift in Sources */,\n\t\t\t\t2F2B8B4024A64CC100CEF088 /* SwiftyStoreKit+Types.swift in Sources */,\n\t\t\t\t2F2B8B4C24A64CC100CEF088 /* InAppReceiptRefreshRequest.swift in Sources */,\n\t\t\t\t2F2B8B3024A64CC100CEF088 /* SKProductDiscount+LocalizedPrice.swift in Sources */,\n\t\t\t\t2F2B8B5824A64CC100CEF088 /* ProductsInfoController.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t654287EA1E79F5A000F61800 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t654288071E7B3E1500F61800 /* AppDelegate.swift in Sources */,\n\t\t\t\t654288021E7B34E500F61800 /* ViewController.swift in Sources */,\n\t\t\t\t654288061E7B3A8800F61800 /* NetworkActivityIndicatorManager.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t658A083A1E2EC5120074A98F /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2F2B8BA924A64DE600CEF088 /* PaymentsControllerTests.swift in Sources */,\n\t\t\t\t2F2B8BA224A64DE600CEF088 /* ProductsInfoControllerTests.swift in Sources */,\n\t\t\t\t2F2B8BA524A64DE600CEF088 /* RestorePurchasesControllerTests.swift in Sources */,\n\t\t\t\t2F2B8BA724A64DE600CEF088 /* InAppReceiptVerificatorTests.swift in Sources */,\n\t\t\t\t2F2B8BA124A64DE600CEF088 /* PaymentTransactionObserverFake.swift in Sources */,\n\t\t\t\t2F2B8BAB24A64DE600CEF088 /* PaymentQueueSpy.swift in Sources */,\n\t\t\t\t2F2B8BA624A64DE600CEF088 /* CompleteTransactionsControllerTests.swift in Sources */,\n\t\t\t\t2F2B8BA024A64DE600CEF088 /* PaymentQueueControllerTests.swift in Sources */,\n\t\t\t\t2F2B8BA324A64DE600CEF088 /* TestPaymentTransaction.swift in Sources */,\n\t\t\t\t2F2B8BA424A64DE600CEF088 /* TestProduct.swift in Sources */,\n\t\t\t\t2F2B8BA824A64DE600CEF088 /* InAppReceiptTests.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tA61BF4C52481F4970017D9BC /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2F2B8B3B24A64CC100CEF088 /* InAppProductQueryRequest.swift in Sources */,\n\t\t\t\t2F2B8B6324A64CC100CEF088 /* PaymentsController.swift in Sources */,\n\t\t\t\t2F2B8B5724A64CC100CEF088 /* SKProduct+LocalizedPrice.swift in Sources */,\n\t\t\t\t2F2B8B3F24A64CC100CEF088 /* InAppReceipt.swift in Sources */,\n\t\t\t\t2F2B8B3724A64CC100CEF088 /* AppleReceiptValidator.swift in Sources */,\n\t\t\t\t2F2B8B6B24A64CC100CEF088 /* RestorePurchasesController.swift in Sources */,\n\t\t\t\t2F2B8B4724A64CC100CEF088 /* CompleteTransactionsController.swift in Sources */,\n\t\t\t\t2F2B8B5F24A64CC100CEF088 /* OS.swift in Sources */,\n\t\t\t\t2F2B8B5324A64CC100CEF088 /* InAppReceiptVerificator.swift in Sources */,\n\t\t\t\t2F2B8B6724A64CC100CEF088 /* SwiftyStoreKit.swift in Sources */,\n\t\t\t\t2F2B8B4B24A64CC100CEF088 /* PaymentQueueController.swift in Sources */,\n\t\t\t\t2F2B8B4324A64CC100CEF088 /* SwiftyStoreKit+Types.swift in Sources */,\n\t\t\t\t2F2B8B4F24A64CC100CEF088 /* InAppReceiptRefreshRequest.swift in Sources */,\n\t\t\t\t2F2B8B3324A64CC100CEF088 /* SKProductDiscount+LocalizedPrice.swift in Sources */,\n\t\t\t\t2F2B8B5B24A64CC100CEF088 /* ProductsInfoController.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tC4D74BB61C24CEC90071AD3E /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t2F2B8B3924A64CC100CEF088 /* InAppProductQueryRequest.swift in Sources */,\n\t\t\t\t2F2B8B6124A64CC100CEF088 /* PaymentsController.swift in Sources */,\n\t\t\t\t2F2B8B5524A64CC100CEF088 /* SKProduct+LocalizedPrice.swift in Sources */,\n\t\t\t\t2F2B8B3D24A64CC100CEF088 /* InAppReceipt.swift in Sources */,\n\t\t\t\t2F2B8B3524A64CC100CEF088 /* AppleReceiptValidator.swift in Sources */,\n\t\t\t\t2F2B8B6924A64CC100CEF088 /* RestorePurchasesController.swift in Sources */,\n\t\t\t\t2F2B8B4524A64CC100CEF088 /* CompleteTransactionsController.swift in Sources */,\n\t\t\t\t2F2B8B5D24A64CC100CEF088 /* OS.swift in Sources */,\n\t\t\t\t2F2B8B5124A64CC100CEF088 /* InAppReceiptVerificator.swift in Sources */,\n\t\t\t\t2F2B8B6524A64CC100CEF088 /* SwiftyStoreKit.swift in Sources */,\n\t\t\t\t2F2B8B4924A64CC100CEF088 /* PaymentQueueController.swift in Sources */,\n\t\t\t\t2F2B8B4124A64CC100CEF088 /* SwiftyStoreKit+Types.swift in Sources */,\n\t\t\t\t2F2B8B4D24A64CC100CEF088 /* InAppReceiptRefreshRequest.swift in Sources */,\n\t\t\t\t2F2B8B3124A64CC100CEF088 /* SKProductDiscount+LocalizedPrice.swift in Sources */,\n\t\t\t\t2F2B8B5924A64CC100CEF088 /* ProductsInfoController.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tC4FD39FD1C2954C10035CFF3 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t65F7DF841DCD4FC500835D30 /* AppDelegate.swift in Sources */,\n\t\t\t\t65F7DF881DCD4FC500835D30 /* ViewController.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\t654288001E79F75000F61800 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 54C0D52B1CF7404500F90BCE /* SwiftyStoreKit_tvOS */;\n\t\t\ttargetProxy = 654287FF1E79F75000F61800 /* PBXContainerItemProxy */;\n\t\t};\n\t\t658A08451E2EC5120074A98F /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 6502F62C1B985C40004E342D /* SwiftyStoreKit_iOS */;\n\t\t\ttargetProxy = 658A08441E2EC5120074A98F /* PBXContainerItemProxy */;\n\t\t};\n\t\t658A084E1E2EC83F0074A98F /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 6502F5FD1B985833004E342D /* SwiftyStoreKit_iOSDemo */;\n\t\t\ttargetProxy = 658A084D1E2EC83F0074A98F /* PBXContainerItemProxy */;\n\t\t};\n\t\t65F7DF911DCD524300835D30 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 6502F62C1B985C40004E342D /* SwiftyStoreKit_iOS */;\n\t\t\ttargetProxy = 65F7DF901DCD524300835D30 /* PBXContainerItemProxy */;\n\t\t};\n\t\tC4FD3A131C2954CD0035CFF3 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = C4D74BBA1C24CEC90071AD3E /* SwiftyStoreKit_macOS */;\n\t\t\ttargetProxy = C4FD3A121C2954CD0035CFF3 /* PBXContainerItemProxy */;\n\t\t};\n/* End PBXTargetDependency section */\n\n/* Begin PBXVariantGroup section */\n\t\t654287F41E79F5A000F61800 /* Main.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t654287F51E79F5A000F61800 /* Base */,\n\t\t\t);\n\t\t\tname = Main.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t65F7DF6A1DCD4DF000835D30 /* LaunchScreen.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t65F7DF6B1DCD4DF000835D30 /* Base */,\n\t\t\t);\n\t\t\tname = LaunchScreen.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t65F7DF6C1DCD4DF000835D30 /* Main.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t65F7DF6D1DCD4DF000835D30 /* Base */,\n\t\t\t);\n\t\t\tname = Main.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t65F7DF801DCD4FC500835D30 /* Main.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t65F7DF811DCD4FC500835D30 /* Base */,\n\t\t\t);\n\t\t\tname = Main.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\t54C0D5311CF7404500F90BCE /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=appletvos*]\" = \"\";\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEFINES_MODULE = YES;\n\t\t\t\tDEVELOPMENT_TEAM = M54ZVB688G;\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\tINFOPLIST_FILE = \"$(SRCROOT)/Sources/SwiftyStoreKit/Platforms/Info-tvOS.plist\";\n\t\t\t\tINSTALL_PATH = \"$(LOCAL_LIBRARY_DIR)/Frameworks\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks @loader_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.musevisions.tvOS.SwiftyStoreKit;\n\t\t\t\tPRODUCT_NAME = SwiftyStoreKit;\n\t\t\t\tSDKROOT = appletvos;\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = 3;\n\t\t\t\tTVOS_DEPLOYMENT_TARGET = 9.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\t54C0D5321CF7404500F90BCE /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=appletvos*]\" = \"\";\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEFINES_MODULE = YES;\n\t\t\t\tDEVELOPMENT_TEAM = M54ZVB688G;\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\tINFOPLIST_FILE = \"$(SRCROOT)/Sources/SwiftyStoreKit/Platforms/Info-tvOS.plist\";\n\t\t\t\tINSTALL_PATH = \"$(LOCAL_LIBRARY_DIR)/Frameworks\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks @loader_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.musevisions.tvOS.SwiftyStoreKit;\n\t\t\t\tPRODUCT_NAME = SwiftyStoreKit;\n\t\t\t\tSDKROOT = appletvos;\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Owholemodule\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = 3;\n\t\t\t\tTVOS_DEPLOYMENT_TARGET = 9.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\t6502F60E1B985833004E342D /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 9.0;\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.10;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\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\t6502F60F1B985833004E342D /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 9.0;\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.10;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tSDKROOT = iphoneos;\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\t6502F6111B985833004E342D /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;\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\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tINFOPLIST_FILE = \"$(SRCROOT)/SwiftyStoreKit-iOS-Demo/Info.plist\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 8.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.musevisions.iOS.SwiftyStoreDemo;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tTARGETED_DEVICE_FAMILY = 1;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t6502F6121B985833004E342D /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;\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\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tINFOPLIST_FILE = \"$(SRCROOT)/SwiftyStoreKit-iOS-Demo/Info.plist\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 8.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.musevisions.iOS.SwiftyStoreDemo;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Owholemodule\";\n\t\t\t\tTARGETED_DEVICE_FAMILY = 1;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t6502F6371B985C40004E342D /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tAPPLICATION_EXTENSION_API_ONLY = YES;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"\";\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\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\tINFOPLIST_FILE = \"$(SRCROOT)/Sources/SwiftyStoreKit/Platforms/Info-iOS.plist\";\n\t\t\t\tINSTALL_PATH = \"$(LOCAL_LIBRARY_DIR)/Frameworks\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 8.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks @loader_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.musevisions.iOS.SwiftyStoreKit;\n\t\t\t\tPRODUCT_NAME = SwiftyStoreKit;\n\t\t\t\tSKIP_INSTALL = YES;\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\t6502F6381B985C40004E342D /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tAPPLICATION_EXTENSION_API_ONLY = YES;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"\";\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\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\tINFOPLIST_FILE = \"$(SRCROOT)/Sources/SwiftyStoreKit/Platforms/Info-iOS.plist\";\n\t\t\t\tINSTALL_PATH = \"$(LOCAL_LIBRARY_DIR)/Frameworks\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 8.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks @loader_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.musevisions.iOS.SwiftyStoreKit;\n\t\t\t\tPRODUCT_NAME = SwiftyStoreKit;\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Owholemodule\";\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 = Release;\n\t\t};\n\t\t654287FA1E79F5A000F61800 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = \"App Icon & Top Shelf Image\";\n\t\t\t\tASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=appletvos*]\" = \"iPhone Developer\";\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tINFOPLIST_FILE = \"SwiftyStoreKit-tvOS-Demo/Info.plist\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.musevisions.iOS.SwiftyStoreDemo;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSDKROOT = appletvos;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;\n\t\t\t\tSWIFT_VERSION = 4.2;\n\t\t\t\tTARGETED_DEVICE_FAMILY = 3;\n\t\t\t\tTVOS_DEPLOYMENT_TARGET = 10.1;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t654287FB1E79F5A000F61800 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = \"App Icon & Top Shelf Image\";\n\t\t\t\tASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=appletvos*]\" = \"iPhone Developer\";\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tINFOPLIST_FILE = \"SwiftyStoreKit-tvOS-Demo/Info.plist\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.musevisions.iOS.SwiftyStoreDemo;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSDKROOT = appletvos;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Owholemodule\";\n\t\t\t\tSWIFT_VERSION = 4.2;\n\t\t\t\tTARGETED_DEVICE_FAMILY = 3;\n\t\t\t\tTVOS_DEPLOYMENT_TARGET = 10.1;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t658A08471E2EC5120074A98F /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\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_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tINFOPLIST_FILE = \"Tests/SwiftyStoreKitTests/Info-Tests.plist\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 10.2;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks @loader_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.musevisions.iOS.SwiftyStoreKitTests;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tSWIFT_SWIFT3_OBJC_INFERENCE = Default;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTEST_HOST = \"$(BUILT_PRODUCTS_DIR)/SwiftyStoreKit_iOSDemo.app/SwiftyStoreKit_iOSDemo\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t658A08481E2EC5120074A98F /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\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_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tINFOPLIST_FILE = \"Tests/SwiftyStoreKitTests/Info-Tests.plist\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 10.2;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks @loader_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.musevisions.iOS.SwiftyStoreKitTests;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Owholemodule\";\n\t\t\t\tSWIFT_SWIFT3_OBJC_INFERENCE = Default;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTEST_HOST = \"$(BUILT_PRODUCTS_DIR)/SwiftyStoreKit_iOSDemo.app/SwiftyStoreKit_iOSDemo\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tA61BF4DB2481F4970017D9BC /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tAPPLICATION_EXTENSION_API_ONLY = YES;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"\";\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\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\tINFOPLIST_FILE = \"$(SRCROOT)/Sources/SwiftyStoreKit/Platforms/Info-watchOS.plist\";\n\t\t\t\tINSTALL_PATH = \"$(LOCAL_LIBRARY_DIR)/Frameworks\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 8.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks @loader_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.musevisions.iOS.SwiftyStoreKit;\n\t\t\t\tPRODUCT_NAME = SwiftyStoreKit;\n\t\t\t\tSDKROOT = watchos;\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t\tSUPPORTED_PLATFORMS = \"watchsimulator watchos\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = 4;\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\tA61BF4DC2481F4970017D9BC /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tAPPLICATION_EXTENSION_API_ONLY = YES;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"\";\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\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\tINFOPLIST_FILE = \"$(SRCROOT)/Sources/SwiftyStoreKit/Platforms/Info-watchOS.plist\";\n\t\t\t\tINSTALL_PATH = \"$(LOCAL_LIBRARY_DIR)/Frameworks\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 8.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks @loader_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.musevisions.iOS.SwiftyStoreKit;\n\t\t\t\tPRODUCT_NAME = SwiftyStoreKit;\n\t\t\t\tSDKROOT = watchos;\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t\tSUPPORTED_PLATFORMS = \"watchsimulator watchos\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Owholemodule\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = 4;\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\tC4D74BC01C24CECA0071AD3E /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"-\";\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\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\tFRAMEWORK_VERSION = A;\n\t\t\t\tINFOPLIST_FILE = \"$(SRCROOT)/Sources/SwiftyStoreKit/Platforms/Info-macOS.plist\";\n\t\t\t\tINSTALL_PATH = \"$(LOCAL_LIBRARY_DIR)/Frameworks\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/../Frameworks @loader_path/Frameworks\";\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.10;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.musevisions.macOS.SwiftyStoreKit;\n\t\t\t\tPRODUCT_NAME = SwiftyStoreKit;\n\t\t\t\tSDKROOT = macosx;\n\t\t\t\tSKIP_INSTALL = YES;\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\tC4D74BC11C24CECA0071AD3E /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"-\";\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\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\tFRAMEWORK_VERSION = A;\n\t\t\t\tINFOPLIST_FILE = \"$(SRCROOT)/Sources/SwiftyStoreKit/Platforms/Info-macOS.plist\";\n\t\t\t\tINSTALL_PATH = \"$(LOCAL_LIBRARY_DIR)/Frameworks\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/../Frameworks @loader_path/Frameworks\";\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.10;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.musevisions.macOS.SwiftyStoreKit;\n\t\t\t\tPRODUCT_NAME = SwiftyStoreKit;\n\t\t\t\tSDKROOT = macosx;\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Owholemodule\";\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\tC4FD3A0E1C2954C10035CFF3 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCODE_SIGN_IDENTITY = \"-\";\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tINFOPLIST_FILE = \"$(SRCROOT)/SwiftyStoreKit-macOS-Demo/Info.plist\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/../Frameworks\";\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.10;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.musevisions.OSX.SwiftyStoreDemo;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSDKROOT = macosx;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tC4FD3A0F1C2954C10035CFF3 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCODE_SIGN_IDENTITY = \"-\";\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tINFOPLIST_FILE = \"$(SRCROOT)/SwiftyStoreKit-macOS-Demo/Info.plist\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/../Frameworks\";\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.10;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.musevisions.OSX.SwiftyStoreDemo;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\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/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t54C0D5331CF7404500F90BCE /* Build configuration list for PBXNativeTarget \"SwiftyStoreKit_tvOS\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t54C0D5311CF7404500F90BCE /* Debug */,\n\t\t\t\t54C0D5321CF7404500F90BCE /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t6502F5F91B985833004E342D /* Build configuration list for PBXProject \"SwiftyStoreKit\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t6502F60E1B985833004E342D /* Debug */,\n\t\t\t\t6502F60F1B985833004E342D /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t6502F6101B985833004E342D /* Build configuration list for PBXNativeTarget \"SwiftyStoreKit_iOSDemo\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t6502F6111B985833004E342D /* Debug */,\n\t\t\t\t6502F6121B985833004E342D /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t6502F6361B985C40004E342D /* Build configuration list for PBXNativeTarget \"SwiftyStoreKit_iOS\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t6502F6371B985C40004E342D /* Debug */,\n\t\t\t\t6502F6381B985C40004E342D /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t654287FC1E79F5A000F61800 /* Build configuration list for PBXNativeTarget \"SwiftyStoreKit_tvOSDemo\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t654287FA1E79F5A000F61800 /* Debug */,\n\t\t\t\t654287FB1E79F5A000F61800 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t658A08461E2EC5120074A98F /* Build configuration list for PBXNativeTarget \"SwiftyStoreKitTests\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t658A08471E2EC5120074A98F /* Debug */,\n\t\t\t\t658A08481E2EC5120074A98F /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tA61BF4DA2481F4970017D9BC /* Build configuration list for PBXNativeTarget \"SwiftyStoreKit_watchOS\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tA61BF4DB2481F4970017D9BC /* Debug */,\n\t\t\t\tA61BF4DC2481F4970017D9BC /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tC4D74BC21C24CECA0071AD3E /* Build configuration list for PBXNativeTarget \"SwiftyStoreKit_macOS\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tC4D74BC01C24CECA0071AD3E /* Debug */,\n\t\t\t\tC4D74BC11C24CECA0071AD3E /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tC4FD3A0D1C2954C10035CFF3 /* Build configuration list for PBXNativeTarget \"SwiftyStoreKit_macOSDemo\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tC4FD3A0E1C2954C10035CFF3 /* Debug */,\n\t\t\t\tC4FD3A0F1C2954C10035CFF3 /* 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 = 6502F5F61B985833004E342D /* Project object */;\n}\n"
  },
  {
    "path": "SwiftyStoreKit.xcodeproj/xcshareddata/xcschemes/SwiftyStoreKit-iOS-Demo.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1160\"\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 = \"6502F5FD1B985833004E342D\"\n               BuildableName = \"SwiftyStoreKit_iOSDemo.app\"\n               BlueprintName = \"SwiftyStoreKit_iOSDemo\"\n               ReferencedContainer = \"container:SwiftyStoreKit.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      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"6502F5FD1B985833004E342D\"\n            BuildableName = \"SwiftyStoreKit_iOSDemo.app\"\n            BlueprintName = \"SwiftyStoreKit_iOSDemo\"\n            ReferencedContainer = \"container:SwiftyStoreKit.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <Testables>\n         <TestableReference\n            skipped = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"658A083D1E2EC5120074A98F\"\n               BuildableName = \"SwiftyStoreKitTests.xctest\"\n               BlueprintName = \"SwiftyStoreKitTests\"\n               ReferencedContainer = \"container:SwiftyStoreKit.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"6502F5FD1B985833004E342D\"\n            BuildableName = \"SwiftyStoreKit_iOSDemo.app\"\n            BlueprintName = \"SwiftyStoreKit_iOSDemo\"\n            ReferencedContainer = \"container:SwiftyStoreKit.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"6502F5FD1B985833004E342D\"\n            BuildableName = \"SwiftyStoreKit_iOSDemo.app\"\n            BlueprintName = \"SwiftyStoreKit_iOSDemo\"\n            ReferencedContainer = \"container:SwiftyStoreKit.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": "SwiftyStoreKit.xcodeproj/xcshareddata/xcschemes/SwiftyStoreKit-iOS.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1160\"\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 = \"6502F62C1B985C40004E342D\"\n               BuildableName = \"SwiftyStoreKit.framework\"\n               BlueprintName = \"SwiftyStoreKit_iOS\"\n               ReferencedContainer = \"container:SwiftyStoreKit.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <Testables>\n      </Testables>\n   </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 = \"6502F62C1B985C40004E342D\"\n            BuildableName = \"SwiftyStoreKit.framework\"\n            BlueprintName = \"SwiftyStoreKit_iOS\"\n            ReferencedContainer = \"container:SwiftyStoreKit.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"6502F62C1B985C40004E342D\"\n            BuildableName = \"SwiftyStoreKit.framework\"\n            BlueprintName = \"SwiftyStoreKit_iOS\"\n            ReferencedContainer = \"container:SwiftyStoreKit.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": "SwiftyStoreKit.xcodeproj/xcshareddata/xcschemes/SwiftyStoreKit-macOS-Demo.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1160\"\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 = \"C4FD3A001C2954C10035CFF3\"\n               BuildableName = \"SwiftyStoreKit_macOSDemo.app\"\n               BlueprintName = \"SwiftyStoreKit_macOSDemo\"\n               ReferencedContainer = \"container:SwiftyStoreKit.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      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"C4FD3A001C2954C10035CFF3\"\n            BuildableName = \"SwiftyStoreKit_macOSDemo.app\"\n            BlueprintName = \"SwiftyStoreKit_macOSDemo\"\n            ReferencedContainer = \"container:SwiftyStoreKit.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <Testables>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"C4FD3A001C2954C10035CFF3\"\n            BuildableName = \"SwiftyStoreKit_macOSDemo.app\"\n            BlueprintName = \"SwiftyStoreKit_macOSDemo\"\n            ReferencedContainer = \"container:SwiftyStoreKit.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"C4FD3A001C2954C10035CFF3\"\n            BuildableName = \"SwiftyStoreKit_macOSDemo.app\"\n            BlueprintName = \"SwiftyStoreKit_macOSDemo\"\n            ReferencedContainer = \"container:SwiftyStoreKit.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": "SwiftyStoreKit.xcodeproj/xcshareddata/xcschemes/SwiftyStoreKit-macOS.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1160\"\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 = \"C4D74BBA1C24CEC90071AD3E\"\n               BuildableName = \"SwiftyStoreKit.framework\"\n               BlueprintName = \"SwiftyStoreKit_macOS\"\n               ReferencedContainer = \"container:SwiftyStoreKit.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <Testables>\n      </Testables>\n   </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 = \"C4D74BBA1C24CEC90071AD3E\"\n            BuildableName = \"SwiftyStoreKit.framework\"\n            BlueprintName = \"SwiftyStoreKit_macOS\"\n            ReferencedContainer = \"container:SwiftyStoreKit.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"C4D74BBA1C24CEC90071AD3E\"\n            BuildableName = \"SwiftyStoreKit.framework\"\n            BlueprintName = \"SwiftyStoreKit_macOS\"\n            ReferencedContainer = \"container:SwiftyStoreKit.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": "SwiftyStoreKit.xcodeproj/xcshareddata/xcschemes/SwiftyStoreKit-tvOS-Demo.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1160\"\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 = \"654287ED1E79F5A000F61800\"\n               BuildableName = \"SwiftyStoreKit_tvOSDemo.app\"\n               BlueprintName = \"SwiftyStoreKit_tvOSDemo\"\n               ReferencedContainer = \"container:SwiftyStoreKit.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      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"654287ED1E79F5A000F61800\"\n            BuildableName = \"SwiftyStoreKit_tvOSDemo.app\"\n            BlueprintName = \"SwiftyStoreKit_tvOSDemo\"\n            ReferencedContainer = \"container:SwiftyStoreKit.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <Testables>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"654287ED1E79F5A000F61800\"\n            BuildableName = \"SwiftyStoreKit_tvOSDemo.app\"\n            BlueprintName = \"SwiftyStoreKit_tvOSDemo\"\n            ReferencedContainer = \"container:SwiftyStoreKit.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"654287ED1E79F5A000F61800\"\n            BuildableName = \"SwiftyStoreKit_tvOSDemo.app\"\n            BlueprintName = \"SwiftyStoreKit_tvOSDemo\"\n            ReferencedContainer = \"container:SwiftyStoreKit.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": "SwiftyStoreKit.xcodeproj/xcshareddata/xcschemes/SwiftyStoreKit-tvOS.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1160\"\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 = \"54C0D52B1CF7404500F90BCE\"\n               BuildableName = \"SwiftyStoreKit.framework\"\n               BlueprintName = \"SwiftyStoreKit_tvOS\"\n               ReferencedContainer = \"container:SwiftyStoreKit.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <Testables>\n      </Testables>\n   </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 = \"54C0D52B1CF7404500F90BCE\"\n            BuildableName = \"SwiftyStoreKit.framework\"\n            BlueprintName = \"SwiftyStoreKit_tvOS\"\n            ReferencedContainer = \"container:SwiftyStoreKit.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"54C0D52B1CF7404500F90BCE\"\n            BuildableName = \"SwiftyStoreKit.framework\"\n            BlueprintName = \"SwiftyStoreKit_tvOS\"\n            ReferencedContainer = \"container:SwiftyStoreKit.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": "SwiftyStoreKit.xcodeproj/xcshareddata/xcschemes/SwiftyStoreKitTests.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1160\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\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 = \"658A083D1E2EC5120074A98F\"\n               BuildableName = \"SwiftyStoreKitTests.xctest\"\n               BlueprintName = \"SwiftyStoreKitTests\"\n               ReferencedContainer = \"container:SwiftyStoreKit.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n   </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": "SwiftyStoreKit.xcodeproj/xcshareddata/xcschemes/SwiftyStoreKit_watchOS.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1160\"\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 = \"A61BF4C42481F4970017D9BC\"\n               BuildableName = \"SwiftyStoreKit.framework\"\n               BlueprintName = \"SwiftyStoreKit_watchOS\"\n               ReferencedContainer = \"container:SwiftyStoreKit.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <Testables>\n      </Testables>\n   </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   </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 = \"A61BF4C42481F4970017D9BC\"\n            BuildableName = \"SwiftyStoreKit.framework\"\n            BlueprintName = \"SwiftyStoreKit_watchOS\"\n            ReferencedContainer = \"container:SwiftyStoreKit.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": "Tests/SwiftyStoreKitTests/CompleteTransactionsControllerTests.swift",
    "content": "//\n// CompleteTransactionsControllerTests.swift\n// SwiftyStoreKit\n//\n// Copyright (c) 2017 Andrea Bizzotto (bizz84@gmail.com)\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\nimport XCTest\nimport StoreKit\n@testable import SwiftyStoreKit\n\nclass CompleteTransactionsControllerTests: XCTestCase {\n\n    func testProcessTransactions_when_atomically_oneRestoredTransaction_then_finishesTransaction_callsCallback_noRemainingTransactions() {\n\n        let productIdentifier = \"com.SwiftyStoreKit.product1\"\n        let testProduct = TestProduct(productIdentifier: productIdentifier)\n\n        let transaction = TestPaymentTransaction(payment: SKPayment(product: testProduct), transactionState: .restored)\n\n        var callbackCalled = false\n        let completeTransactions = CompleteTransactions(atomically: true) { purchases in\n            callbackCalled = true\n            XCTAssertEqual(purchases.count, 1)\n            let purchase = purchases.first!\n            XCTAssertEqual(purchase.productId, productIdentifier)\n        }\n\n        let completeTransactionsController = makeCompleteTransactionsController(completeTransactions: completeTransactions)\n\n        let spy = PaymentQueueSpy()\n\n        let remainingTransactions = completeTransactionsController.processTransactions([transaction], on: spy)\n\n        XCTAssertEqual(remainingTransactions.count, 0)\n\n        XCTAssertTrue(callbackCalled)\n\n        XCTAssertEqual(spy.finishTransactionCalledCount, 1)\n    }\n\n    func testProcessTransactions_when_atomically_oneFailedTransaction_then_finishesTransaction_callsCallback_noRemainingTransactions_noNeedsFinishTransactions() {\n        \n        let productIdentifier = \"com.SwiftyStoreKit.product1\"\n        let testProduct = TestProduct(productIdentifier: productIdentifier)\n        \n        let transaction = TestPaymentTransaction(payment: SKPayment(product: testProduct), transactionState: .failed)\n        \n        var callbackCalled = false\n        let completeTransactions = CompleteTransactions(atomically: true) { purchases in\n            callbackCalled = true\n            XCTAssertEqual(purchases.count, 1)\n            let purchase = purchases.first!\n            XCTAssertFalse(purchase.needsFinishTransaction)\n            XCTAssertEqual(purchase.productId, productIdentifier)\n        }\n        \n        let completeTransactionsController = makeCompleteTransactionsController(completeTransactions: completeTransactions)\n        \n        let spy = PaymentQueueSpy()\n        \n        let remainingTransactions = completeTransactionsController.processTransactions([transaction], on: spy)\n        \n        XCTAssertEqual(remainingTransactions.count, 0)\n        \n        XCTAssertTrue(callbackCalled)\n        \n        XCTAssertEqual(spy.finishTransactionCalledCount, 1)\n    }\n\n    func testProcessTransactions_when_notAtomically_oneFailedTransaction_then_finishesTransaction_callsCallback_noRemainingTransactions_noNeedsFinishTransactions() {\n        \n        let productIdentifier = \"com.SwiftyStoreKit.product1\"\n        let testProduct = TestProduct(productIdentifier: productIdentifier)\n        \n        let transaction = TestPaymentTransaction(payment: SKPayment(product: testProduct), transactionState: .failed)\n        \n        var callbackCalled = false\n        let completeTransactions = CompleteTransactions(atomically: false) { purchases in\n            callbackCalled = true\n            XCTAssertEqual(purchases.count, 1)\n            let purchase = purchases.first!\n            XCTAssertFalse(purchase.needsFinishTransaction)\n            XCTAssertEqual(purchase.productId, productIdentifier)\n        }\n        \n        let completeTransactionsController = makeCompleteTransactionsController(completeTransactions: completeTransactions)\n        \n        let spy = PaymentQueueSpy()\n        \n        let remainingTransactions = completeTransactionsController.processTransactions([transaction], on: spy)\n        \n        XCTAssertEqual(remainingTransactions.count, 0)\n        \n        XCTAssertTrue(callbackCalled)\n        \n        XCTAssertEqual(spy.finishTransactionCalledCount, 1)\n    }\n\n    func testProcessTransactions_when_atomically_oneTransactionForEachState_then_finishesTransactions_callsCallback_onePurchasingTransactionRemaining() {\n\n        let transactions = [\n            makeTestPaymentTransaction(productIdentifier: \"com.SwiftyStoreKit.product1\", transactionState: .purchased),\n            makeTestPaymentTransaction(productIdentifier: \"com.SwiftyStoreKit.product2\", transactionState: .failed),\n            makeTestPaymentTransaction(productIdentifier: \"com.SwiftyStoreKit.product3\", transactionState: .restored),\n            makeTestPaymentTransaction(productIdentifier: \"com.SwiftyStoreKit.product4\", transactionState: .deferred),\n            makeTestPaymentTransaction(productIdentifier: \"com.SwiftyStoreKit.product5\", transactionState: .purchasing)\n        ]\n\n        var callbackCalled = false\n        let completeTransactions = CompleteTransactions(atomically: true) { purchases in\n            callbackCalled = true\n            XCTAssertEqual(purchases.count, 4)\n\n            for i in 0..<4 {\n                XCTAssertEqual(purchases[i].productId, transactions[i].payment.productIdentifier)\n            }\n        }\n\n        let completeTransactionsController = makeCompleteTransactionsController(completeTransactions: completeTransactions)\n\n        let spy = PaymentQueueSpy()\n\n        let remainingTransactions = completeTransactionsController.processTransactions(transactions, on: spy)\n\n        XCTAssertEqual(remainingTransactions.count, 1)\n\n        XCTAssertTrue(callbackCalled)\n\n        XCTAssertEqual(spy.finishTransactionCalledCount, 4)\n    }\n\n    func testProcessTransactions_when_atomically_zeroTransactions_then_noFinishedTransactions_noCallback_noTransactionsRemaining() {\n\n        let transactions: [TestPaymentTransaction] = []\n\n        let completeTransactions = CompleteTransactions(atomically: true) { _ in\n            XCTFail(\"Callback should not be called\")\n        }\n\n        let completeTransactionsController = makeCompleteTransactionsController(completeTransactions: completeTransactions)\n\n        let spy = PaymentQueueSpy()\n\n        let remainingTransactions = completeTransactionsController.processTransactions(transactions, on: spy)\n\n        XCTAssertEqual(remainingTransactions.count, 0)\n\n        XCTAssertEqual(spy.finishTransactionCalledCount, 0)\n    }\n\n    func testProcessTransactions_when_atomically_onePurchasingTransaction_then_noFinishedTransactions_noCallback_oneTransactionsRemaining() {\n\n        let productIdentifier = \"com.SwiftyStoreKit.product1\"\n        let testProduct = TestProduct(productIdentifier: productIdentifier)\n\n        let transaction = TestPaymentTransaction(payment: SKPayment(product: testProduct), transactionState: .purchasing)\n\n        let completeTransactions = CompleteTransactions(atomically: true) { _ in\n            XCTFail(\"Callback should not be called\")\n        }\n\n        let completeTransactionsController = makeCompleteTransactionsController(completeTransactions: completeTransactions)\n\n        let spy = PaymentQueueSpy()\n\n        let remainingTransactions = completeTransactionsController.processTransactions([transaction], on: spy)\n\n        XCTAssertEqual(remainingTransactions.count, 1)\n\n        XCTAssertEqual(spy.finishTransactionCalledCount, 0)\n    }\n    \n    func makeTestPaymentTransaction(productIdentifier: String, transactionState: SKPaymentTransactionState) -> TestPaymentTransaction {\n\n        let testProduct = TestProduct(productIdentifier: productIdentifier)\n        return TestPaymentTransaction(payment: SKPayment(product: testProduct), transactionState: transactionState)\n    }\n\n    func makeCompleteTransactionsController(completeTransactions: CompleteTransactions?) -> CompleteTransactionsController {\n\n        let completeTransactionsController = CompleteTransactionsController()\n\n        completeTransactionsController.completeTransactions = completeTransactions\n\n        return completeTransactionsController\n    }\n\n}\n"
  },
  {
    "path": "Tests/SwiftyStoreKitTests/InAppReceiptTests.swift",
    "content": "//\n//  InAppReceiptTests.swift\n//  SwiftyStoreKit\n//\n//  Created by Andrea Bizzotto on 08/05/2017.\n// Copyright (c) 2017 Andrea Bizzotto (bizz84@gmail.com)\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\nimport XCTest\nimport SwiftyStoreKit\n\nprivate extension TimeInterval {\n    var millisecondsNSString: NSString {\n        return String(format: \"%.0f\", self * 1000) as NSString\n    }\n}\n\nextension ReceiptItem: Equatable {\n\n    init(productId: String, purchaseDate: Date, subscriptionExpirationDate: Date? = nil, cancellationDate: Date? = nil, isTrialPeriod: Bool = false, isInIntroOfferPeriod: Bool = false, isUpgraded: Bool = false) {\n        self.init(productId: productId, quantity: 1, transactionId: UUID().uuidString, originalTransactionId: UUID().uuidString, purchaseDate: purchaseDate, originalPurchaseDate: purchaseDate, webOrderLineItemId: UUID().uuidString, subscriptionExpirationDate: subscriptionExpirationDate, cancellationDate: cancellationDate, isTrialPeriod: isTrialPeriod, isInIntroOfferPeriod: isInIntroOfferPeriod, isUpgraded: isUpgraded)\n        self.productId = productId\n        self.quantity = 1\n        self.purchaseDate = purchaseDate\n        self.originalPurchaseDate = purchaseDate\n        self.subscriptionExpirationDate = subscriptionExpirationDate\n        self.cancellationDate = cancellationDate\n        self.transactionId = UUID().uuidString\n        self.originalTransactionId = UUID().uuidString\n        self.webOrderLineItemId = UUID().uuidString\n        self.isTrialPeriod = isTrialPeriod\n        self.isInIntroOfferPeriod = isInIntroOfferPeriod\n        self.isUpgraded = isUpgraded\n    }\n\n    var receiptInfo: NSDictionary {\n        var result: [String: AnyObject] = [\n            \"product_id\": productId as NSString,\n            \"quantity\": String(quantity) as NSString,\n            \"purchase_date_ms\": purchaseDate.timeIntervalSince1970.millisecondsNSString,\n            \"original_purchase_date_ms\": originalPurchaseDate.timeIntervalSince1970.millisecondsNSString,\n            \"is_trial_period\": (isTrialPeriod ? \"1\" : \"0\") as NSString,\n            \"transaction_id\": transactionId as NSString,\n            \"original_transaction_id\": originalTransactionId as NSString\n        ]\n        if let subscriptionExpirationDate = subscriptionExpirationDate {\n            result[\"expires_date_ms\"] = subscriptionExpirationDate.timeIntervalSince1970.millisecondsNSString\n        }\n        if let cancellationDate = cancellationDate {\n            result[\"cancellation_date_ms\"] = cancellationDate.timeIntervalSince1970.millisecondsNSString\n            result[\"cancellation_date\"] = cancellationDate as NSDate\n        }\n        return NSDictionary(dictionary: result)\n    }\n    \n    public static func == (lhs: ReceiptItem, rhs: ReceiptItem) -> Bool {\n        return\n            lhs.productId == rhs.productId &&\n            lhs.quantity == rhs.quantity &&\n            lhs.purchaseDate == rhs.purchaseDate &&\n            lhs.originalPurchaseDate == rhs.originalPurchaseDate &&\n            lhs.subscriptionExpirationDate == rhs.subscriptionExpirationDate &&\n            lhs.cancellationDate == rhs.cancellationDate &&\n            lhs.isTrialPeriod == rhs.isTrialPeriod\n    }\n}\n\nextension VerifySubscriptionResult: Equatable {\n\n    public static func == (lhs: VerifySubscriptionResult, rhs: VerifySubscriptionResult) -> Bool {\n        switch (lhs, rhs) {\n        case (.notPurchased, .notPurchased): return true\n        case (.purchased(let lhsExpiryDate, let lhsReceiptItem), .purchased(let rhsExpiryDate, let rhsReceiptItem)):\n            return lhsExpiryDate == rhsExpiryDate && lhsReceiptItem == rhsReceiptItem\n        case (.expired(let lhsExpiryDate, let lhsReceiptItem), .expired(let rhsExpiryDate, let rhsReceiptItem)):\n            return lhsExpiryDate == rhsExpiryDate && lhsReceiptItem == rhsReceiptItem\n        default: return false\n        }\n    }\n}\n\nextension VerifyPurchaseResult: Equatable {\n    \n    public static func == (lhs: VerifyPurchaseResult, rhs: VerifyPurchaseResult) -> Bool {\n        switch (lhs, rhs) {\n        case (.notPurchased, .notPurchased): return true\n        case (.purchased(let lhsReceiptItem), .purchased(let rhsReceiptItem)):\n            return lhsReceiptItem == rhsReceiptItem\n        default: return false\n        }\n    }\n}\n\n// swiftlint: disable file_length\nclass InAppReceiptTests: XCTestCase {\n\n    // MARK: Verify Purchase\n    func testVerifyPurchase_when_noPurchases_then_resultIsNotPurchased() {\n        let receiptRequestDate = makeDateAtMidnight(year: 2017, month: 5, day: 14)\n        let productId = \"product1\"\n        let receipt = makeReceipt(items: [], requestDate: receiptRequestDate)\n\n        let verifyPurchaseResult = SwiftyStoreKit.verifyPurchase(productId: productId, inReceipt: receipt)\n\n        XCTAssertEqual(verifyPurchaseResult, .notPurchased)\n    }\n    \n    func testVerifyPurchase_when_onePurchase_then_resultIsPurchased() {\n        let receiptRequestDate = makeDateAtMidnight(year: 2017, month: 5, day: 14)\n        let productId = \"product1\"\n        let item = ReceiptItem(productId: productId, purchaseDate: receiptRequestDate, subscriptionExpirationDate: nil, cancellationDate: nil, isTrialPeriod: false)\n        let receipt = makeReceipt(items: [item], requestDate: receiptRequestDate)\n\n        let verifyPurchaseResult = SwiftyStoreKit.verifyPurchase(productId: productId, inReceipt: receipt)\n\n        XCTAssertEqual(verifyPurchaseResult, .purchased(item: item))\n    }\n    \n    func testVerifyPurchase_when_oneCancelledPurchase_then_resultIsNotPurchased() {\n        let receiptRequestDate = makeDateAtMidnight(year: 2017, month: 5, day: 14)\n        let productId = \"product1\"\n        let item = ReceiptItem(productId: productId, purchaseDate: receiptRequestDate, subscriptionExpirationDate: nil, cancellationDate: receiptRequestDate, isTrialPeriod: false)\n        let receipt = makeReceipt(items: [item], requestDate: receiptRequestDate)\n\n        let verifyPurchaseResult = SwiftyStoreKit.verifyPurchase(productId: productId, inReceipt: receipt)\n\n        XCTAssertEqual(verifyPurchaseResult, .notPurchased)\n    }\n\n    // MARK: Verify Subscription, single receipt item tests\n    // auto-renewable, not purchased\n    func testVerifyAutoRenewableSubscription_when_noSubscriptions_then_resultIsNotPurchased() {\n        let receiptRequestDate = makeDateAtMidnight(year: 2017, month: 5, day: 14)\n        let productId = \"product1\"\n        let receipt = makeReceipt(items: [], requestDate: receiptRequestDate)\n\n        let verifySubscriptionResult = SwiftyStoreKit.verifySubscription(ofType: .autoRenewable, productId: productId, inReceipt: receipt)\n\n        let expectedSubscriptionResult = VerifySubscriptionResult.notPurchased\n        XCTAssertEqual(verifySubscriptionResult, expectedSubscriptionResult)\n    }\n\n    // auto-renewable, expired\n    func testVerifyAutoRenewableSubscription_when_oneExpiredSubscription_then_resultIsExpired() {\n        let receiptRequestDate = makeDateAtMidnight(year: 2017, month: 5, day: 15)\n        let productId = \"product1\"\n        let isTrialPeriod = false\n        let purchaseDate = makeDateAtMidnight(year: 2017, month: 5, day: 14)\n        let expirationDate = purchaseDate.addingTimeInterval(60 * 60)\n        let item = ReceiptItem(productId: productId, purchaseDate: purchaseDate, subscriptionExpirationDate: expirationDate, cancellationDate: nil, isTrialPeriod: isTrialPeriod)\n        let receipt = makeReceipt(items: [item], requestDate: receiptRequestDate)\n\n        let verifySubscriptionResult = SwiftyStoreKit.verifySubscription(ofType: .autoRenewable, productId: productId, inReceipt: receipt)\n\n        let expectedSubscriptionResult = VerifySubscriptionResult.expired(expiryDate: expirationDate, items: [item])\n        XCTAssertEqual(verifySubscriptionResult, expectedSubscriptionResult)\n    }\n\n    // auto-renewable, purchased\n    func testVerifyAutoRenewableSubscription_when_oneNonExpiredSubscription_then_resultIsPurchased() {\n        let receiptRequestDate = makeDateAtMidnight(year: 2017, month: 5, day: 14)\n        let productId = \"product1\"\n        let isTrialPeriod = false\n        let purchaseDate = receiptRequestDate\n        let expirationDate = purchaseDate.addingTimeInterval(60 * 60)\n        let item = ReceiptItem(productId: productId, purchaseDate: purchaseDate, subscriptionExpirationDate: expirationDate, cancellationDate: nil, isTrialPeriod: isTrialPeriod)\n        let receipt = makeReceipt(items: [item], requestDate: receiptRequestDate)\n\n        let verifySubscriptionResult = SwiftyStoreKit.verifySubscription(ofType: .autoRenewable, productId: productId, inReceipt: receipt)\n\n        let expectedSubscriptionResult = VerifySubscriptionResult.purchased(expiryDate: expirationDate, items: [item])\n        XCTAssertEqual(verifySubscriptionResult, expectedSubscriptionResult)\n    }\n\n    // auto-renewable, cancelled\n    func testVerifyAutoRenewableSubscription_when_oneCancelledSubscription_then_resultIsNotPurchased() {\n        let receiptRequestDate = makeDateAtMidnight(year: 2017, month: 5, day: 14)\n        let productId = \"product1\"\n        let isTrialPeriod = false\n        let purchaseDate = receiptRequestDate\n        let expirationDate = purchaseDate.addingTimeInterval(60 * 60)\n        let cancelledDate = purchaseDate.addingTimeInterval(30 * 60)\n        let item = ReceiptItem(productId: productId, purchaseDate: purchaseDate, subscriptionExpirationDate: expirationDate, cancellationDate: cancelledDate, isTrialPeriod: isTrialPeriod)\n        let receipt = makeReceipt(items: [item], requestDate: receiptRequestDate)\n\n        let verifySubscriptionResult = SwiftyStoreKit.verifySubscription(ofType: .autoRenewable, productId: productId, inReceipt: receipt)\n\n        let expectedSubscriptionResult = VerifySubscriptionResult.notPurchased\n        XCTAssertEqual(verifySubscriptionResult, expectedSubscriptionResult)\n    }\n\n    // non-renewing, non purchased\n    func testVerifyNonRenewingSubscription_when_noSubscriptions_then_resultIsNotPurchased() {\n        let receiptRequestDate = makeDateAtMidnight(year: 2017, month: 5, day: 14)\n        let productId = \"product1\"\n        let receipt = makeReceipt(items: [], requestDate: receiptRequestDate)\n\n        let verifySubscriptionResult = SwiftyStoreKit.verifySubscription(ofType: .nonRenewing(validDuration: 60 * 60), productId: productId, inReceipt: receipt)\n\n        let expectedSubscriptionResult = VerifySubscriptionResult.notPurchased\n        XCTAssertEqual(verifySubscriptionResult, expectedSubscriptionResult)\n    }\n\n    // non-renewing, expired\n    func testVerifyNonRenewingSubscription_when_oneExpiredSubscription_then_resultIsExpired() {\n        let receiptRequestDate = makeDateAtMidnight(year: 2017, month: 5, day: 15)\n        let productId = \"product1\"\n        let isTrialPeriod = false\n        let purchaseDate = makeDateAtMidnight(year: 2017, month: 5, day: 14)\n        let duration: TimeInterval = 60 * 60\n        let expirationDate = purchaseDate.addingTimeInterval(duration)\n\n        let item = ReceiptItem(productId: productId, purchaseDate: purchaseDate, subscriptionExpirationDate: nil, cancellationDate: nil, isTrialPeriod: isTrialPeriod)\n        let receipt = makeReceipt(items: [item], requestDate: receiptRequestDate)\n\n        let verifySubscriptionResult = SwiftyStoreKit.verifySubscription(ofType: .nonRenewing(validDuration: duration), productId: productId, inReceipt: receipt)\n\n        let expectedSubscriptionResult = VerifySubscriptionResult.expired(expiryDate: expirationDate, items: [item])\n        XCTAssertEqual(verifySubscriptionResult, expectedSubscriptionResult)\n    }\n\n    // non-renewing, purchased\n    func testVerifyNonRenewingSubscription_when_oneNonExpiredSubscription_then_resultIsPurchased() {\n        let receiptRequestDate = makeDateAtMidnight(year: 2017, month: 5, day: 14)\n        let productId = \"product1\"\n        let isTrialPeriod = false\n        let purchaseDate = receiptRequestDate\n        let duration: TimeInterval = 60 * 60\n        let expirationDate = purchaseDate.addingTimeInterval(duration)\n\n        let item = ReceiptItem(productId: productId, purchaseDate: purchaseDate, subscriptionExpirationDate: nil, cancellationDate: nil, isTrialPeriod: isTrialPeriod)\n        let receipt = makeReceipt(items: [item], requestDate: receiptRequestDate)\n\n        let verifySubscriptionResult = SwiftyStoreKit.verifySubscription(ofType: .nonRenewing(validDuration: duration), productId: productId, inReceipt: receipt)\n\n        let expectedSubscriptionResult = VerifySubscriptionResult.purchased(expiryDate: expirationDate, items: [item])\n        XCTAssertEqual(verifySubscriptionResult, expectedSubscriptionResult)\n    }\n\n    // non-renewing, cancelled\n    func testVerifyNonRenewingSubscription_when_oneCancelledSubscription_then_resultIsNotPurchased() {\n        let receiptRequestDate = makeDateAtMidnight(year: 2017, month: 5, day: 14)\n        let productId = \"product1\"\n        let isTrialPeriod = false\n        let purchaseDate = receiptRequestDate\n        let duration: TimeInterval = 60 * 60\n        let cancelledDate = purchaseDate.addingTimeInterval(30 * 60)\n        let item = ReceiptItem(productId: productId, purchaseDate: purchaseDate, subscriptionExpirationDate: nil, cancellationDate: cancelledDate, isTrialPeriod: isTrialPeriod)\n        let receipt = makeReceipt(items: [item], requestDate: receiptRequestDate)\n\n        let verifySubscriptionResult = SwiftyStoreKit.verifySubscription(ofType: .nonRenewing(validDuration: duration), productId: productId, inReceipt: receipt)\n\n        let expectedSubscriptionResult = VerifySubscriptionResult.notPurchased\n        XCTAssertEqual(verifySubscriptionResult, expectedSubscriptionResult)\n    }\n\n    // MARK: Verify Subscription, multiple receipt item tests\n    func testVerifyAutoRenewableSubscription_when_twoSubscriptions_sameProductId_mostRecentNonExpired_then_resultIsPurchased_itemsSorted() {\n        let receiptRequestDate = makeDateAtMidnight(year: 2017, month: 5, day: 14)\n\n        let productId = \"product1\"\n        let isTrialPeriod = false\n\n        let olderPurchaseDate = makeDateAtMidnight(year: 2017, month: 5, day: 12)\n        let olderExpirationDate = olderPurchaseDate.addingTimeInterval(60 * 60)\n        let olderItem = ReceiptItem(productId: productId,\n                               purchaseDate: olderPurchaseDate,\n                               subscriptionExpirationDate: olderExpirationDate,\n                               cancellationDate: nil,\n                               isTrialPeriod: isTrialPeriod)\n\n        let newerPurchaseDate = makeDateAtMidnight(year: 2017, month: 5, day: 14)\n        let newerExpirationDate = newerPurchaseDate.addingTimeInterval(60 * 60)\n        let newerItem = ReceiptItem(productId: productId,\n                                    purchaseDate: newerPurchaseDate,\n                                    subscriptionExpirationDate: newerExpirationDate,\n                                    cancellationDate: nil,\n                                    isTrialPeriod: isTrialPeriod)\n\n        let receipt = makeReceipt(items: [olderItem, newerItem], requestDate: receiptRequestDate)\n\n        let verifySubscriptionResult = SwiftyStoreKit.verifySubscription(ofType: .autoRenewable, productId: productId, inReceipt: receipt)\n\n        let expectedSubscriptionResult = VerifySubscriptionResult.purchased(expiryDate: newerExpirationDate, items: [newerItem, olderItem])\n        XCTAssertEqual(verifySubscriptionResult, expectedSubscriptionResult)\n    }\n\n    func testVerifyAutoRenewableSubscription_when_twoSubscriptions_sameProductId_bothExpired_then_resultIsExpired_itemsSorted() {\n        let receiptRequestDate = makeDateAtMidnight(year: 2017, month: 5, day: 14)\n        \n        let productId = \"product1\"\n        let isTrialPeriod = false\n        \n        let olderPurchaseDate = makeDateAtMidnight(year: 2017, month: 5, day: 12)\n        let olderExpirationDate = olderPurchaseDate.addingTimeInterval(60 * 60)\n        let olderItem = ReceiptItem(productId: productId,\n                                    purchaseDate: olderPurchaseDate,\n                                    subscriptionExpirationDate: olderExpirationDate,\n                                    cancellationDate: nil,\n                                    isTrialPeriod: isTrialPeriod)\n        \n        let newerPurchaseDate = makeDateAtMidnight(year: 2017, month: 5, day: 13)\n        let newerExpirationDate = newerPurchaseDate.addingTimeInterval(60 * 60)\n        let newerItem = ReceiptItem(productId: productId,\n                                    purchaseDate: newerPurchaseDate,\n                                    subscriptionExpirationDate: newerExpirationDate,\n                                    cancellationDate: nil,\n                                    isTrialPeriod: isTrialPeriod)\n        \n        let receipt = makeReceipt(items: [olderItem, newerItem], requestDate: receiptRequestDate)\n        \n        let verifySubscriptionResult = SwiftyStoreKit.verifySubscription(ofType: .autoRenewable, productId: productId, inReceipt: receipt)\n        \n        let expectedSubscriptionResult = VerifySubscriptionResult.expired(expiryDate: newerExpirationDate, items: [newerItem, olderItem])\n        XCTAssertEqual(verifySubscriptionResult, expectedSubscriptionResult)\n    }\n    \n    // MARK: Verify Subscriptions, multiple receipt item tests\n    func testVerifyAutoRenewableSubscriptions_when_threeSubscriptions_twoMatchingProductIds_mostRecentNonExpired_then_resultIsPurchased_itemsSorted() {\n        let receiptRequestDate = makeDateAtMidnight(year: 2017, month: 5, day: 14)\n        \n        let productId1 = \"product1\"\n        let productId2 = \"product2\"\n        let productIds = Set([ productId1, productId2 ])\n        let isTrialPeriod = false\n        \n        let olderPurchaseDate = makeDateAtMidnight(year: 2017, month: 5, day: 12)\n        let olderExpirationDate = olderPurchaseDate.addingTimeInterval(60 * 60)\n        let olderItem = ReceiptItem(productId: productId1,\n                                    purchaseDate: olderPurchaseDate,\n                                    subscriptionExpirationDate: olderExpirationDate,\n                                    cancellationDate: nil,\n                                    isTrialPeriod: isTrialPeriod)\n        \n        let newerPurchaseDate = makeDateAtMidnight(year: 2017, month: 5, day: 14)\n        let newerExpirationDate = newerPurchaseDate.addingTimeInterval(60 * 60)\n        let newerItem = ReceiptItem(productId: productId2,\n                                    purchaseDate: newerPurchaseDate,\n                                    subscriptionExpirationDate: newerExpirationDate,\n                                    cancellationDate: nil,\n                                    isTrialPeriod: isTrialPeriod)\n        \n        let otherPurchaseDate = makeDateAtMidnight(year: 2017, month: 5, day: 15)\n        let otherExpirationDate = otherPurchaseDate.addingTimeInterval(60 * 60)\n        let otherItem = ReceiptItem(productId: \"otherProduct\",\n                                    purchaseDate: otherPurchaseDate,\n                                    subscriptionExpirationDate: otherExpirationDate,\n                                    cancellationDate: nil,\n                                    isTrialPeriod: isTrialPeriod)\n        \n        let receipt = makeReceipt(items: [olderItem, newerItem, otherItem], requestDate: receiptRequestDate)\n        \n        let verifySubscriptionResult = SwiftyStoreKit.verifySubscriptions(ofType: .autoRenewable, productIds: productIds, inReceipt: receipt)\n        \n        let expectedSubscriptionResult = VerifySubscriptionResult.purchased(expiryDate: newerExpirationDate, items: [newerItem, olderItem])\n        XCTAssertEqual(verifySubscriptionResult, expectedSubscriptionResult)\n    }\n    \n    // MARK: Get Distinct Purchase Identifiers, empty receipt item tests\n    func testGetDistinctPurchaseIds_when_noReceipt_then_resultIsNil() {\n        let receiptRequestDate = makeDateAtMidnight(year: 2017, month: 5, day: 14)\n        let receipt = makeReceipt(items: [], requestDate: receiptRequestDate)\n\n        let getdistinctProductIdsResult = SwiftyStoreKit.getDistinctPurchaseIds(ofType: .autoRenewable, inReceipt: receipt)\n        XCTAssertNil(getdistinctProductIdsResult)\n    }\n    \n    // MARK: Get Distinct Purchase Identifiers, multiple receipt item tests\n    func testGetDistinctPurchaseIds_when_Receipt_then_resultIsNotNil() {\n        let receiptRequestDateOne = makeDateAtMidnight(year: 2020, month: 2, day: 20)\n        let purchaseDateOne = makeDateAtMidnight(year: 2020, month: 2, day: 1)\n        let purchaseDateTwo = makeDateAtMidnight(year: 2020, month: 1, day: 1)\n        \n        let productId1 = \"product1\"\n        let productId2 = \"product2\"\n        \n        let product1 = ReceiptItem(productId: productId1, purchaseDate: purchaseDateOne)\n        let product2 = ReceiptItem(productId: productId2, purchaseDate: purchaseDateTwo)\n        \n        let receipt = makeReceipt(items: [product1, product2], requestDate: receiptRequestDateOne)\n\n        let getdistinctProductIdsResult = SwiftyStoreKit.getDistinctPurchaseIds(ofType: .autoRenewable, inReceipt: receipt)\n                \n        XCTAssertNotNil(getdistinctProductIdsResult)\n    }\n    \n    // MARK: Get Distinct Purchase Identifiers, multiple non unique product identifiers tests\n    func testGetDistinctPurchaseIds_when_nonUniqueIdentifiers_then_resultIsUnique() {\n        let receiptRequestDateOne = makeDateAtMidnight(year: 2020, month: 2, day: 20)\n        let purchaseDateOne = makeDateAtMidnight(year: 2020, month: 2, day: 1)\n        let purchaseDateTwo = makeDateAtMidnight(year: 2020, month: 2, day: 2)\n        let purchaseDateThree = makeDateAtMidnight(year: 2020, month: 2, day: 3)\n        let purchaseDateFour = makeDateAtMidnight(year: 2020, month: 2, day: 4)\n\n        let productId1 = \"product1\"\n        let productId2 = \"product2\"\n        let productId3 = \"product1\"\n        let productId4 = \"product2\"\n\n        let product1 = ReceiptItem(productId: productId1, purchaseDate: purchaseDateOne)\n        let product2 = ReceiptItem(productId: productId2, purchaseDate: purchaseDateTwo)\n        let product3 = ReceiptItem(productId: productId3, purchaseDate: purchaseDateThree)\n        let product4 = ReceiptItem(productId: productId4, purchaseDate: purchaseDateFour)\n\n        let receipt = makeReceipt(items: [product1, product2, product3, product4], requestDate: receiptRequestDateOne)\n\n        let getdistinctProductIdsResult = SwiftyStoreKit.getDistinctPurchaseIds(ofType: .autoRenewable, inReceipt: receipt)\n        let expectedProductIdsResult = Set([productId1, productId2, productId3, productId4])\n        XCTAssertEqual(getdistinctProductIdsResult, expectedProductIdsResult)\n    }\n\n    // MARK: Helper methods\n    func makeReceipt(items: [ReceiptItem], requestDate: Date) -> [String: AnyObject] {\n        let receiptInfos = items.map { $0.receiptInfo }\n\n        // Creating this with NSArray results in __NSSingleObjectArrayI which fails the cast to [String: AnyObject]\n        let array = NSMutableArray()\n        array.addObjects(from: receiptInfos)\n\n        return [\n            //\"latest_receipt\": [:],\n            \"status\": \"200\" as NSString,\n            \"environment\": \"Sandbox\" as NSString,\n            \"receipt\": NSDictionary(dictionary: [\n                \"request_date_ms\": requestDate.timeIntervalSince1970.millisecondsNSString,\n                \"in_app\": array // non renewing\n            ]),\n            \"latest_receipt_info\": array // autoRenewable\n        ]\n    }\n\n    func makeDateAtMidnight(year: Int, month: Int, day: Int) -> Date {\n        var dateComponents = DateComponents()\n        dateComponents.day = day\n        dateComponents.month = month\n        dateComponents.year = year\n        let calendar = Calendar(identifier: .gregorian)\n        return calendar.date(from: dateComponents)!\n    }\n}\n"
  },
  {
    "path": "Tests/SwiftyStoreKitTests/InAppReceiptVerificatorTests.swift",
    "content": "//\n//  InAppReceiptVerificatorTests.swift\n//  SwiftyStoreKit\n//\n//  Created by Andrea Bizzotto on 17/05/2017.\n// Copyright (c) 2017 Andrea Bizzotto (bizz84@gmail.com)\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\nimport XCTest\n@testable import SwiftyStoreKit\n\nclass TestReceiptValidator: ReceiptValidator {\n    var validateCalled = false\n    func validate(receiptData: Data, completion: @escaping (VerifyReceiptResult) -> Void) {\n        validateCalled = true\n        completion(.success(receipt: [:]))\n    }\n}\n\nclass TestInAppReceiptRefreshRequest: InAppReceiptRefreshRequest {\n    \n    override func start() {\n        // do nothing\n    }\n}\n\nextension VerifyReceiptResult: Equatable {\n    \n    static public func == (lhs: VerifyReceiptResult, rhs: VerifyReceiptResult) -> Bool {\n        switch (lhs, rhs) {\n        case (.success, .success): return true\n        case (.error(let lhsError), .error(let rhsError)): return lhsError == rhsError\n        default: return false\n        }\n    }\n}\n\nextension ReceiptError: Equatable {\n    \n    static public func == (lhs: ReceiptError, rhs: ReceiptError) -> Bool {\n        switch (lhs, rhs) {\n        case (.noReceiptData, .noReceiptData): return true\n        case (.noRemoteData, .noRemoteData): return true\n        case (.requestBodyEncodeError, .requestBodyEncodeError): return true\n        case (.networkError, .networkError): return true\n        case (.jsonDecodeError, .jsonDecodeError): return true\n        case (.receiptInvalid, .receiptInvalid): return true\n        default: return false\n        }\n    }\n}\n\nclass InAppReceiptVerificatorTests: XCTestCase {\n    \n    // MARK: refresh tests (no receipt url or no receipt data)\n    func testVerifyReceipt_when_appStoreReceiptURLIsNil_then_callsRefresh() {\n        \n        let validator = TestReceiptValidator()\n        let verificator = InAppReceiptVerificator(appStoreReceiptURL: nil)\n        \n        var refreshCalled = false\n        let request = verificator.verifyReceipt(using: validator, forceRefresh: false, refresh: { (properties, callback) -> InAppReceiptRefreshRequest in\n            \n            refreshCalled = true\n            return TestInAppReceiptRefreshRequest(receiptProperties: properties, callback: callback)\n            \n        }, completion: { _ in\n            \n        })\n        XCTAssertNotNil(request)\n        XCTAssertTrue(refreshCalled)\n    }\n\n    func testVerifyReceipt_when_appStoreReceiptURLIsNotNil_noReceiptData_then_callsRefresh() {\n        \n        let testReceiptURL = makeReceiptURL()\n        \n        let validator = TestReceiptValidator()\n        let verificator = InAppReceiptVerificator(appStoreReceiptURL: testReceiptURL)\n        \n        var refreshCalled = false\n        let request = verificator.verifyReceipt(using: validator, forceRefresh: false, refresh: { (properties, callback) -> InAppReceiptRefreshRequest in\n            \n            refreshCalled = true\n            return TestInAppReceiptRefreshRequest(receiptProperties: properties, callback: callback)\n            \n        }, completion: { _ in\n            \n        })\n        XCTAssertNotNil(request)\n        XCTAssertTrue(refreshCalled)\n    }\n    \n    func testVerifyReceipt_when_appStoreReceiptURLIsNotNil_hasReceiptData_forceRefreshIsTrue_then_callsRefresh() {\n        \n        let testReceiptURL = makeReceiptURL()\n        writeReceiptData(to: testReceiptURL)\n        \n        let validator = TestReceiptValidator()\n        let verificator = InAppReceiptVerificator(appStoreReceiptURL: testReceiptURL)\n        \n        var refreshCalled = false\n        let request = verificator.verifyReceipt(using: validator, forceRefresh: true, refresh: { (properties, callback) -> InAppReceiptRefreshRequest in\n            \n            refreshCalled = true\n            return TestInAppReceiptRefreshRequest(receiptProperties: properties, callback: callback)\n            \n        }, completion: { _ in\n            \n        })\n        XCTAssertNotNil(request)\n        XCTAssertTrue(refreshCalled)\n    }\n\n    func testVerifyReceipt_when_appStoreReceiptURLIsNil_refreshCallbackError_then_errorNetworkError() {\n        \n        let validator = TestReceiptValidator()\n        let verificator = InAppReceiptVerificator(appStoreReceiptURL: nil)\n        let refreshError = NSError(domain: \"\", code: 0, userInfo: nil)\n        \n        let request = verificator.verifyReceipt(using: validator, forceRefresh: false, refresh: { (properties, callback) -> InAppReceiptRefreshRequest in\n            \n            callback(.error(e: refreshError))\n            return TestInAppReceiptRefreshRequest(receiptProperties: properties, callback: callback)\n            \n        }, completion: { result in\n            \n            XCTAssertEqual(result, VerifyReceiptResult.error(error: ReceiptError.networkError(error: refreshError)))\n        })\n        XCTAssertNotNil(request)\n    }\n\n    func testVerifyReceipt_when_appStoreReceiptURLIsNil_refreshCallbackSuccess_receiptDataNotWritten_then_errorNoReceiptData_validateNotCalled() {\n        \n        let validator = TestReceiptValidator()\n        let verificator = InAppReceiptVerificator(appStoreReceiptURL: nil)\n        \n        let request = verificator.verifyReceipt(using: validator, forceRefresh: false, refresh: { (properties, callback) -> InAppReceiptRefreshRequest in\n            \n            callback(.success)\n            return TestInAppReceiptRefreshRequest(receiptProperties: properties, callback: callback)\n\n        }, completion: { result in\n\n            XCTAssertEqual(result, VerifyReceiptResult.error(error: ReceiptError.noReceiptData))\n        })\n        XCTAssertNotNil(request)\n        XCTAssertFalse(validator.validateCalled)\n    }\n\n    func testVerifyReceipt_when_appStoreReceiptURLIsNil_noReceiptData_refreshCallbackSuccess_receiptDataWritten_then_errorNoReceiptData_validateNotCalled() {\n        \n        let testReceiptURL = makeReceiptURL()\n        \n        let validator = TestReceiptValidator()\n        let verificator = InAppReceiptVerificator(appStoreReceiptURL: nil)\n        \n        let request = verificator.verifyReceipt(using: validator, forceRefresh: false, refresh: { (properties, callback) -> InAppReceiptRefreshRequest in\n            \n            writeReceiptData(to: testReceiptURL)\n            callback(.success)\n            return TestInAppReceiptRefreshRequest(receiptProperties: properties, callback: callback)\n            \n        }, completion: { result in\n            \n            XCTAssertEqual(result, VerifyReceiptResult.error(error: ReceiptError.noReceiptData))\n        })\n        XCTAssertNotNil(request)\n        XCTAssertFalse(validator.validateCalled)\n        removeReceiptData(at: testReceiptURL)\n    }\n    \n    func testVerifyReceipt_when_appStoreReceiptURLIsNotNil_noReceiptData_refreshCallbackSuccess_receiptDataWritten_then_validateIsCalled() {\n        \n        let testReceiptURL = makeReceiptURL()\n        \n        let validator = TestReceiptValidator()\n        let verificator = InAppReceiptVerificator(appStoreReceiptURL: testReceiptURL)\n        \n        let request = verificator.verifyReceipt(using: validator, forceRefresh: false, refresh: { (properties, callback) -> InAppReceiptRefreshRequest in\n            \n            writeReceiptData(to: testReceiptURL)\n            callback(.success)\n            return TestInAppReceiptRefreshRequest(receiptProperties: properties, callback: callback)\n            \n        }, completion: { _ in\n            \n        })\n        XCTAssertNil(request)\n        XCTAssertTrue(validator.validateCalled)\n        removeReceiptData(at: testReceiptURL)\n    }\n    \n    // MARK: non-refresh tests (receipt url and data are set)\n    func testVerifyReceipt_when_appStoreReceiptURLIsNotNil_hasReceiptData_forceRefreshIsFalse_then_refreshNotCalled_validateIsCalled() {\n        \n        let testReceiptURL = makeReceiptURL()\n        writeReceiptData(to: testReceiptURL)\n\n        let validator = TestReceiptValidator()\n        let verificator = InAppReceiptVerificator(appStoreReceiptURL: testReceiptURL)\n        \n        let request = verificator.verifyReceipt(using: validator, forceRefresh: false, refresh: { (properties, callback) -> InAppReceiptRefreshRequest in\n            \n            XCTFail(\"refresh should not be called if we already have a receipt\")\n            return TestInAppReceiptRefreshRequest(receiptProperties: properties, callback: callback)\n            \n        }, completion: { _ in\n            \n        })\n        XCTAssertNil(request)\n        XCTAssertTrue(validator.validateCalled)\n        removeReceiptData(at: testReceiptURL)\n    }\n    \n    // MARK: Helpers\n    func makeReceiptURL() -> URL {\n        \n        guard let testFolderURL = try? FileManager.default.url(for: .documentDirectory, in: .allDomainsMask, appropriateFor: nil, create: false) else {\n            fatalError(\"Invalid test folder\")\n        }\n        return testFolderURL.appendingPathComponent(\"receipt.data\")\n    }\n    \n    func writeReceiptData(to url: URL) {\n        \n        guard let testReceiptData = NSData(base64Encoded: \"encrypted-receipt\", options: .ignoreUnknownCharacters) else {\n            fatalError(\"Invalid receipt data\")\n        }\n        try? testReceiptData.write(to: url)\n    }\n    \n    func removeReceiptData(at url: URL) {\n        try? FileManager.default.removeItem(at: url)\n    }\n\n}\n"
  },
  {
    "path": "Tests/SwiftyStoreKitTests/Info-Tests.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": "Tests/SwiftyStoreKitTests/PaymentQueueControllerTests.swift",
    "content": "//\n// PaymentQueueControllerTests.swift\n// SwiftyStoreKit\n//\n// Copyright (c) 2017 Andrea Bizzotto (bizz84@gmail.com)\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\n// swiftlint:disable function_body_length\n\nimport XCTest\nimport StoreKit\n@testable import SwiftyStoreKit\n\nclass PaymentQueueControllerTests: XCTestCase {\n\n    // MARK: init/deinit\n    func testInit_registersAsObserver() {\n\n        let spy = PaymentQueueSpy()\n\n        let paymentQueueController = PaymentQueueController(paymentQueue: spy)\n\n        XCTAssertTrue(spy.observer === paymentQueueController)\n    }\n\n    func testDeinit_removesObserver() {\n\n        let spy = PaymentQueueSpy()\n\n        _ = PaymentQueueController(paymentQueue: spy)\n\n        XCTAssertNil(spy.observer)\n    }\n\n    // MARK: Start payment\n\n    func testStartTransaction_QueuesOnePayment() {\n\n        let spy = PaymentQueueSpy()\n\n        let paymentQueueController = PaymentQueueController(paymentQueue: spy)\n\n        let payment = makeTestPayment(productIdentifier: \"com.SwiftyStoreKit.product1\") { _ in }\n\n        paymentQueueController.completeTransactions(CompleteTransactions(atomically: true) { _ in })\n\n        paymentQueueController.startPayment(payment)\n\n        XCTAssertEqual(spy.payments.count, 1)\n    }\n\n    // MARK: SKPaymentTransactionObserver callbacks\n    func testPaymentQueue_when_oneTransactionForEachState_onePayment_oneRestorePurchases_oneCompleteTransactions_then_correctCallbacksCalled() {\n\n        // setup\n        let spy = PaymentQueueSpy()\n\n        let paymentQueueController = PaymentQueueController(paymentQueue: spy)\n\n        let purchasedProductIdentifier = \"com.SwiftyStoreKit.product1\"\n        let failedProductIdentifier = \"com.SwiftyStoreKit.product2\"\n        let restoredProductIdentifier = \"com.SwiftyStoreKit.product3\"\n        let deferredProductIdentifier = \"com.SwiftyStoreKit.product4\"\n        let purchasingProductIdentifier = \"com.SwiftyStoreKit.product5\"\n\n        let transactions = [\n            makeTestPaymentTransaction(productIdentifier: purchasedProductIdentifier, transactionState: .purchased),\n            makeTestPaymentTransaction(productIdentifier: failedProductIdentifier, transactionState: .failed),\n            makeTestPaymentTransaction(productIdentifier: restoredProductIdentifier, transactionState: .restored),\n            makeTestPaymentTransaction(productIdentifier: deferredProductIdentifier, transactionState: .deferred),\n            makeTestPaymentTransaction(productIdentifier: purchasingProductIdentifier, transactionState: .purchasing)\n            ]\n\n        var paymentCallbackCalled = false\n        let testPayment = makeTestPayment(productIdentifier: purchasedProductIdentifier) { result in\n            paymentCallbackCalled = true\n            if case .purchased(let product) = result {\n                XCTAssertEqual(product.productId, purchasedProductIdentifier)\n            } else {\n                XCTFail(\"expected purchased callback with product id\")\n            }\n        }\n\n        var restorePurchasesCallbackCalled = false\n        let restorePurchases = RestorePurchases(atomically: true) { results in\n            restorePurchasesCallbackCalled = true\n            XCTAssertEqual(results.count, 1)\n            let first = results.first!\n            if case .restored(let restoredPayment) = first {\n                XCTAssertEqual(restoredPayment.productId, restoredProductIdentifier)\n            } else {\n                XCTFail(\"expected restored callback with product\")\n            }\n        }\n\n        var completeTransactionsCallbackCalled = false\n        let completeTransactions = CompleteTransactions(atomically: true) { purchases in\n            completeTransactionsCallbackCalled = true\n            XCTAssertEqual(purchases.count, 2)\n            XCTAssertEqual(purchases[0].productId, failedProductIdentifier)\n            XCTAssertEqual(purchases[1].productId, deferredProductIdentifier)\n        }\n\n        // run\n        paymentQueueController.completeTransactions(completeTransactions)\n\n        paymentQueueController.startPayment(testPayment)\n\n        paymentQueueController.restorePurchases(restorePurchases)\n\n        paymentQueueController.paymentQueue(SKPaymentQueue(), updatedTransactions: transactions)\n        paymentQueueController.paymentQueueRestoreCompletedTransactionsFinished(SKPaymentQueue())\n\n        // verify\n        XCTAssertTrue(paymentCallbackCalled)\n        XCTAssertTrue(restorePurchasesCallbackCalled)\n        XCTAssertTrue(completeTransactionsCallbackCalled)\n    }\n\n    func testPaymentQueue_when_oneTransactionForEachState_onePayment_noRestorePurchases_oneCompleteTransactions_then_correctCallbacksCalled() {\n\n        // setup\n        let spy = PaymentQueueSpy()\n\n        let paymentQueueController = PaymentQueueController(paymentQueue: spy)\n\n        let purchasedProductIdentifier = \"com.SwiftyStoreKit.product1\"\n        let failedProductIdentifier = \"com.SwiftyStoreKit.product2\"\n        let restoredProductIdentifier = \"com.SwiftyStoreKit.product3\"\n        let deferredProductIdentifier = \"com.SwiftyStoreKit.product4\"\n        let purchasingProductIdentifier = \"com.SwiftyStoreKit.product5\"\n\n        let transactions = [\n            makeTestPaymentTransaction(productIdentifier: purchasedProductIdentifier, transactionState: .purchased),\n            makeTestPaymentTransaction(productIdentifier: failedProductIdentifier, transactionState: .failed),\n            makeTestPaymentTransaction(productIdentifier: restoredProductIdentifier, transactionState: .restored),\n            makeTestPaymentTransaction(productIdentifier: deferredProductIdentifier, transactionState: .deferred),\n            makeTestPaymentTransaction(productIdentifier: purchasingProductIdentifier, transactionState: .purchasing)\n            ]\n\n        var paymentCallbackCalled = false\n        let testPayment = makeTestPayment(productIdentifier: purchasedProductIdentifier) { result in\n            paymentCallbackCalled = true\n            if case .purchased(let payment) = result {\n                XCTAssertEqual(payment.productId, purchasedProductIdentifier)\n            } else {\n                XCTFail(\"expected purchased callback with product id\")\n            }\n        }\n\n        var completeTransactionsCallbackCalled = false\n        let completeTransactions = CompleteTransactions(atomically: true) { payments in\n            completeTransactionsCallbackCalled = true\n            XCTAssertEqual(payments.count, 3)\n            XCTAssertEqual(payments[0].productId, failedProductIdentifier)\n            XCTAssertEqual(payments[1].productId, restoredProductIdentifier)\n            XCTAssertEqual(payments[2].productId, deferredProductIdentifier)\n        }\n\n        // run\n        paymentQueueController.completeTransactions(completeTransactions)\n\n        paymentQueueController.startPayment(testPayment)\n\n        paymentQueueController.paymentQueue(SKPaymentQueue(), updatedTransactions: transactions)\n        paymentQueueController.paymentQueueRestoreCompletedTransactionsFinished(SKPaymentQueue())\n\n        // verify\n        XCTAssertTrue(paymentCallbackCalled)\n        XCTAssertTrue(completeTransactionsCallbackCalled)\n    }\n\n    func testPaymentQueue_when_oneTransactionForEachState_noPayments_oneRestorePurchases_oneCompleteTransactions_then_correctCallbacksCalled() {\n\n        // setup\n        let spy = PaymentQueueSpy()\n\n        let paymentQueueController = PaymentQueueController(paymentQueue: spy)\n\n        let purchasedProductIdentifier = \"com.SwiftyStoreKit.product1\"\n        let failedProductIdentifier = \"com.SwiftyStoreKit.product2\"\n        let restoredProductIdentifier = \"com.SwiftyStoreKit.product3\"\n        let deferredProductIdentifier = \"com.SwiftyStoreKit.product4\"\n        let purchasingProductIdentifier = \"com.SwiftyStoreKit.product5\"\n\n        let transactions = [\n            makeTestPaymentTransaction(productIdentifier: purchasedProductIdentifier, transactionState: .purchased),\n            makeTestPaymentTransaction(productIdentifier: failedProductIdentifier, transactionState: .failed),\n            makeTestPaymentTransaction(productIdentifier: restoredProductIdentifier, transactionState: .restored),\n            makeTestPaymentTransaction(productIdentifier: deferredProductIdentifier, transactionState: .deferred),\n            makeTestPaymentTransaction(productIdentifier: purchasingProductIdentifier, transactionState: .purchasing)\n            ]\n\n        var restorePurchasesCallbackCalled = false\n        let restorePurchases = RestorePurchases(atomically: true) { results in\n            restorePurchasesCallbackCalled = true\n            XCTAssertEqual(results.count, 1)\n            let first = results.first!\n            if case .restored(let restoredPayment) = first {\n                XCTAssertEqual(restoredPayment.productId, restoredProductIdentifier)\n            } else {\n                XCTFail(\"expected restored callback with product\")\n            }\n        }\n\n        var completeTransactionsCallbackCalled = false\n        let completeTransactions = CompleteTransactions(atomically: true) { payments in\n            completeTransactionsCallbackCalled = true\n            XCTAssertEqual(payments.count, 3)\n            XCTAssertEqual(payments[0].productId, purchasedProductIdentifier)\n            XCTAssertEqual(payments[1].productId, failedProductIdentifier)\n            XCTAssertEqual(payments[2].productId, deferredProductIdentifier)\n        }\n\n        // run\n        paymentQueueController.completeTransactions(completeTransactions)\n\n        paymentQueueController.restorePurchases(restorePurchases)\n\n        paymentQueueController.paymentQueue(SKPaymentQueue(), updatedTransactions: transactions)\n        paymentQueueController.paymentQueueRestoreCompletedTransactionsFinished(SKPaymentQueue())\n\n        // verify\n        XCTAssertTrue(restorePurchasesCallbackCalled)\n        XCTAssertTrue(completeTransactionsCallbackCalled)\n    }\n    \n    // MARK: shouldAddStorePayment tests\n    func testPaymentQueue_when_shouldAddStorePaymentHandlerIsNil_then_shouldAddStorePaymentReturnsFalse() {\n        \n        let spy = PaymentQueueSpy()\n        \n        let paymentQueueController = PaymentQueueController(paymentQueue: spy)\n        \n        paymentQueueController.shouldAddStorePaymentHandler = nil\n        \n        XCTAssertFalse(paymentQueueController.paymentQueue(SKPaymentQueue(), shouldAddStorePayment: SKPayment(), for: SKProduct()))\n    }\n\n    func testPaymentQueue_when_shouldAddStorePaymentHandlerReturnsTrue_then_shouldAddStorePaymentReturnsTrue() {\n        \n        let spy = PaymentQueueSpy()\n        \n        let paymentQueueController = PaymentQueueController(paymentQueue: spy)\n        \n        paymentQueueController.shouldAddStorePaymentHandler = { payment, product in\n            return true\n        }\n        \n        XCTAssertTrue(paymentQueueController.paymentQueue(SKPaymentQueue(), shouldAddStorePayment: SKPayment(), for: SKProduct()))\n    }\n\n    func testPaymentQueue_when_shouldAddStorePaymentHandlerReturnsFalse_then_shouldAddStorePaymentReturnsFalse() {\n        \n        let spy = PaymentQueueSpy()\n        \n        let paymentQueueController = PaymentQueueController(paymentQueue: spy)\n        \n        paymentQueueController.shouldAddStorePaymentHandler = { payment, product in\n            return false\n        }\n        \n        XCTAssertFalse(paymentQueueController.paymentQueue(SKPaymentQueue(), shouldAddStorePayment: SKPayment(), for: SKProduct()))\n    }\n\n    // MARK: Helpers\n    func makeTestPaymentTransaction(productIdentifier: String, transactionState: SKPaymentTransactionState) -> TestPaymentTransaction {\n\n        let testProduct = TestProduct(productIdentifier: productIdentifier)\n        return TestPaymentTransaction(payment: SKPayment(product: testProduct), transactionState: transactionState)\n    }\n\n    func makeTestPayment(productIdentifier: String, quantity: Int = 1, atomically: Bool = true, callback: @escaping (TransactionResult) -> Void) -> Payment {\n\n        let testProduct = TestProduct(productIdentifier: productIdentifier)\n        return Payment(product: testProduct, paymentDiscount: nil, quantity: quantity, atomically: atomically, applicationUsername: \"\", simulatesAskToBuyInSandbox: false, callback: callback)\n    }\n}\n"
  },
  {
    "path": "Tests/SwiftyStoreKitTests/PaymentQueueSpy.swift",
    "content": "//\n//  PaymentQueueSpy.swift\n//  SwiftyStoreKit\n//\n//  Created by Andrea Bizzotto on 17/01/2017.\n//  Copyright © 2017 musevisions. All rights reserved.\n//\n\nimport SwiftyStoreKit\nimport StoreKit\n\nclass PaymentQueueSpy: PaymentQueue {\n\n    weak var observer: SKPaymentTransactionObserver?\n\n    var payments: [SKPayment] = []\n\n    var restoreCompletedTransactionCalledCount = 0\n\n    var finishTransactionCalledCount = 0\n\n    func add(_ observer: SKPaymentTransactionObserver) {\n\n        self.observer = observer\n    }\n    func remove(_ observer: SKPaymentTransactionObserver) {\n\n        if self.observer === observer {\n            self.observer = nil\n        }\n    }\n\n    func add(_ payment: SKPayment) {\n\n        payments.append(payment)\n    }\n\n    func restoreCompletedTransactions(withApplicationUsername username: String?) {\n\n        restoreCompletedTransactionCalledCount += 1\n    }\n\n    func finishTransaction(_ transaction: SKPaymentTransaction) {\n\n        finishTransactionCalledCount += 1\n    }\n    \n    func start(_ downloads: [SKDownload]) {\n        \n    }\n    \n    func pause(_ downloads: [SKDownload]) {\n        \n    }\n    \n    func resume(_ downloads: [SKDownload]) {\n        \n    }\n    \n    func cancel(_ downloads: [SKDownload]) {\n        \n    }\n}\n"
  },
  {
    "path": "Tests/SwiftyStoreKitTests/PaymentTransactionObserverFake.swift",
    "content": "//\n//  PaymentTransactionObserverFake.swift\n//  SwiftyStoreKit\n//\n//  Created by Andrea Bizzotto on 17/01/2017.\n//  Copyright © 2017 musevisions. All rights reserved.\n//\n\n#if os(iOS)\n\nimport UIKit\n\nclass PaymentTransactionObserverFake: NSObject {\n\n}\n\n#endif\n"
  },
  {
    "path": "Tests/SwiftyStoreKitTests/PaymentsControllerTests.swift",
    "content": "//\n// PaymentsControllerTests.swift\n// SwiftyStoreKit\n//\n// Copyright (c) 2017 Andrea Bizzotto (bizz84@gmail.com)\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\nimport XCTest\nimport StoreKit\n@testable import SwiftyStoreKit\n\nclass PaymentsControllerTests: XCTestCase {\n\n    func testInsertPayment_hasPayment() {\n\n        let payment = makeTestPayment(productIdentifier: \"com.SwiftyStoreKit.product1\") { _ in }\n\n        let paymentsController = makePaymentsController(appendPayments: [payment])\n\n        XCTAssertTrue(paymentsController.hasPayment(payment))\n    }\n\n    func testProcessTransaction_when_onePayment_transactionStatePurchased_then_removesPayment_finishesTransaction_callsCallback() {\n\n        let productIdentifier = \"com.SwiftyStoreKit.product1\"\n        let testProduct = TestProduct(productIdentifier: productIdentifier)\n\n        var callbackCalled = false\n        let payment = makeTestPayment(product: testProduct) { result in\n\n            callbackCalled = true\n            if case .purchased(let payment) = result {\n                XCTAssertEqual(payment.productId, productIdentifier)\n                XCTAssertEqual(payment.quantity, 1)\n            } else {\n                XCTFail(\"expected purchased callback with product id\")\n            }\n        }\n\n        let paymentsController = makePaymentsController(appendPayments: [payment])\n\n        let transaction = TestPaymentTransaction(payment: SKPayment(product: testProduct), transactionState: .purchased)\n\n        let spy = PaymentQueueSpy()\n\n        let remainingTransactions = paymentsController.processTransactions([transaction], on: spy)\n\n        XCTAssertEqual(remainingTransactions.count, 0)\n\n        XCTAssertFalse(paymentsController.hasPayment(payment))\n\n        XCTAssertTrue(callbackCalled)\n\n        XCTAssertEqual(spy.finishTransactionCalledCount, 1)\n    }\n\n    func testProcessTransaction_when_onePayment_transactionStateFailed_then_removesPayment_finishesTransaction_callsCallback() {\n\n        let productIdentifier = \"com.SwiftyStoreKit.product1\"\n        let testProduct = TestProduct(productIdentifier: productIdentifier)\n\n        var callbackCalled = false\n        let payment = makeTestPayment(product: testProduct) { result in\n\n            callbackCalled = true\n            if case .failed = result {\n\n            } else {\n                XCTFail(\"expected failed callback with error\")\n            }\n        }\n\n        let paymentsController = makePaymentsController(appendPayments: [payment])\n\n        let transaction = TestPaymentTransaction(payment: SKPayment(product: testProduct), transactionState: .failed)\n\n        let spy = PaymentQueueSpy()\n\n        let remainingTransactions = paymentsController.processTransactions([transaction], on: spy)\n\n        XCTAssertEqual(remainingTransactions.count, 0)\n\n        XCTAssertFalse(paymentsController.hasPayment(payment))\n\n        XCTAssertTrue(callbackCalled)\n\n        XCTAssertEqual(spy.finishTransactionCalledCount, 1)\n    }\n\n    func testProcessTransaction_when_twoPaymentsSameId_firstTransactionStatePurchased_secondTransactionStateFailed_then_removesPayments_finishesTransactions_callsCallbacks() {\n\n        let productIdentifier = \"com.SwiftyStoreKit.product1\"\n        let testProduct1 = TestProduct(productIdentifier: productIdentifier)\n\n        var callback1Called = false\n        let payment1 = makeTestPayment(product: testProduct1) { result in\n\n            callback1Called = true\n            if case .purchased(let payment) = result {\n                XCTAssertEqual(payment.productId, productIdentifier)\n            } else {\n                XCTFail(\"expected purchased callback with product id\")\n            }\n        }\n\n        let testProduct2 = TestProduct(productIdentifier: productIdentifier)\n\n        var callback2Called = false\n        let payment2 = makeTestPayment(product: testProduct2) { result in\n            callback2Called = true\n            if case .failed = result {\n\n            } else {\n                XCTFail(\"expected failed callback with error\")\n            }\n        }\n\n        let paymentsController = makePaymentsController(appendPayments: [payment1, payment2])\n\n        let transaction1 = TestPaymentTransaction(payment: SKPayment(product: testProduct1), transactionState: .purchased)\n        let transaction2 = TestPaymentTransaction(payment: SKPayment(product: testProduct2), transactionState: .failed)\n\n        let spy = PaymentQueueSpy()\n\n        let remainingTransactions = paymentsController.processTransactions([transaction1, transaction2], on: spy)\n\n        XCTAssertEqual(remainingTransactions.count, 0)\n\n        XCTAssertFalse(paymentsController.hasPayment(payment1))\n        XCTAssertFalse(paymentsController.hasPayment(payment2))\n\n        XCTAssertTrue(callback1Called)\n        XCTAssertTrue(callback2Called)\n\n        XCTAssertEqual(spy.finishTransactionCalledCount, 2)\n    }\n\n    func testProcessTransaction_when_twoPaymentsSameId_firstPayment_transactionStatePurchased_then_removesFirstPayment_finishesTransaction_callsCallback() {\n\n        let productIdentifier = \"com.SwiftyStoreKit.product1\"\n        let testProduct1 = TestProduct(productIdentifier: productIdentifier)\n\n        var callback1Called = false\n        let payment1 = makeTestPayment(product: testProduct1) { result in\n\n            callback1Called = true\n            if case .purchased(let payment) = result {\n                XCTAssertEqual(payment.productId, productIdentifier)\n            } else {\n                XCTFail(\"expected purchased callback with product id\")\n            }\n        }\n\n        let testProduct2 = TestProduct(productIdentifier: productIdentifier)\n        let payment2 = makeTestPayment(product: testProduct2) { _ in\n\n            XCTFail(\"unexpected callback for second payment\")\n        }\n\n        let paymentsController = makePaymentsController(appendPayments: [payment1, payment2])\n\n        let transaction1 = TestPaymentTransaction(payment: SKPayment(product: testProduct1), transactionState: .purchased)\n\n        let spy = PaymentQueueSpy()\n\n        let remainingTransactions = paymentsController.processTransactions([transaction1], on: spy)\n\n        XCTAssertEqual(remainingTransactions.count, 0)\n\n        // First one removed, but second one with same identifier still there\n        XCTAssertTrue(paymentsController.hasPayment(payment2))\n\n        XCTAssertTrue(callback1Called)\n\n        XCTAssertEqual(spy.finishTransactionCalledCount, 1)\n    }\n    \n    func testProcessTransaction_when_onePayment_transactionStatePurchased_quantityIs2_then_removesPayment_finishesTransaction_callsCallback_correctQuantity() {\n        \n        let productIdentifier = \"com.SwiftyStoreKit.product1\"\n        let quantity = 2\n        let testProduct = TestProduct(productIdentifier: productIdentifier)\n        \n        var callbackCalled = false\n        let payment = makeTestPayment(product: testProduct) { result in\n            \n            callbackCalled = true\n            if case .purchased(let payment) = result {\n                XCTAssertEqual(payment.productId, productIdentifier)\n                XCTAssertEqual(payment.quantity, quantity)\n            } else {\n                XCTFail(\"expected purchased callback with product id\")\n            }\n        }\n        \n        let paymentsController = makePaymentsController(appendPayments: [payment])\n        \n        let skPayment = SKMutablePayment(product: testProduct)\n        skPayment.quantity = quantity\n        let transaction = TestPaymentTransaction(payment: skPayment, transactionState: .purchased)\n        \n        let spy = PaymentQueueSpy()\n        \n        let remainingTransactions = paymentsController.processTransactions([transaction], on: spy)\n        \n        XCTAssertEqual(remainingTransactions.count, 0)\n        \n        XCTAssertFalse(paymentsController.hasPayment(payment))\n        \n        XCTAssertTrue(callbackCalled)\n        \n        XCTAssertEqual(spy.finishTransactionCalledCount, 1)\n    }\n\n    func makePaymentsController(appendPayments payments: [Payment]) -> PaymentsController {\n\n        let paymentsController = PaymentsController()\n\n        payments.forEach { paymentsController.append($0) }\n\n        return paymentsController\n    }\n\n    func makeTestPayment(product: SKProduct, atomically: Bool = true, callback: @escaping (TransactionResult) -> Void) -> Payment {\n\n        return Payment(product: product, paymentDiscount: nil, quantity: 1, atomically: atomically, applicationUsername: \"\", simulatesAskToBuyInSandbox: false, callback: callback)\n    }\n\n    func makeTestPayment(productIdentifier: String, atomically: Bool = true, callback: @escaping (TransactionResult) -> Void) -> Payment {\n\n        let product = TestProduct(productIdentifier: productIdentifier)\n        return makeTestPayment(product: product, atomically: atomically, callback: callback)\n\n    }\n}\n"
  },
  {
    "path": "Tests/SwiftyStoreKitTests/ProductsInfoControllerTests.swift",
    "content": "//\n// ProductsInfoControllerTests.swift\n// SwiftyStoreKit\n//\n// Copyright (c) 2017 Andrea Bizzotto (bizz84@gmail.com)\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\nimport XCTest\nimport Foundation\n@testable import SwiftyStoreKit\n\nclass TestInAppProductRequest: InAppProductRequest {\n    \n    var hasCompleted: Bool\n    var cachedResults: RetrieveResults?\n    \n    private let productIds: Set<String>\n    private let callback: InAppProductRequestCallback\n\n    init(productIds: Set<String>, callback: @escaping InAppProductRequestCallback) {\n        self.productIds = productIds\n        self.callback = callback\n        self.hasCompleted = false\n    }\n    \n    func start() {\n\n    }\n    func cancel() {\n        \n    }\n    \n    func fireCallback() {\n        callback(RetrieveResults(retrievedProducts: [], invalidProductIDs: [], error: nil))\n    }\n}\n\nclass TestInAppProductRequestBuilder: InAppProductRequestBuilder {\n    \n    var requests: [ TestInAppProductRequest ] = []\n    \n    func request(productIds: Set<String>, callback: @escaping InAppProductRequestCallback) -> InAppProductRequest {\n        let request = TestInAppProductRequest(productIds: productIds, callback: callback)\n        requests.append(request)\n        return request\n    }\n    \n    func fireCallbacks() {\n        requests.forEach {\n            $0.fireCallback()\n        }\n        requests = []\n    }\n}\n\nclass ProductsInfoControllerTests: XCTestCase {\n    \n    let sampleProductIdentifiers: Set<String> = [\"com.iap.purchase1\"]\n    // Set of in app purchases to ask in different threads\n    let testProducts: Set<String> = [\"com.iap.purchase01\",\n                                     \"com.iap.purchase02\",\n                                     \"com.iap.purchase03\",\n                                     \"com.iap.purchase04\",\n                                     \"com.iap.purchase05\",\n                                     \"com.iap.purchase06\",\n                                     \"com.iap.purchase07\",\n                                     \"com.iap.purchase08\",\n                                     \"com.iap.purchase09\",\n                                     \"com.iap.purchase10\"]\n\n    func testRetrieveProductsInfo_when_calledOnce_then_completionCalledOnce() {\n        \n        let requestBuilder = TestInAppProductRequestBuilder()\n        let productInfoController = ProductsInfoController(inAppProductRequestBuilder: requestBuilder)\n        \n        var completionCount = 0\n        productInfoController.retrieveProductsInfo(sampleProductIdentifiers) { _ in\n            completionCount += 1\n        }\n        requestBuilder.fireCallbacks()\n        \n        XCTAssertEqual(completionCount, 1)\n    }\n\n    func testRetrieveProductsInfo_when_calledTwiceConcurrently_then_eachCompletionCalledOnce() {\n        \n        let requestBuilder = TestInAppProductRequestBuilder()\n        let productInfoController = ProductsInfoController(inAppProductRequestBuilder: requestBuilder)\n        \n        var completionCount = 0\n        productInfoController.retrieveProductsInfo(sampleProductIdentifiers) { _ in\n            completionCount += 1\n        }\n        productInfoController.retrieveProductsInfo(sampleProductIdentifiers) { _ in\n            completionCount += 1\n        }\n        requestBuilder.fireCallbacks()\n\n        XCTAssertEqual(completionCount, 2)\n    }\n    func testRetrieveProductsInfo_when_calledTwiceNotConcurrently_then_eachCompletionCalledOnce() {\n        \n        let requestBuilder = TestInAppProductRequestBuilder()\n        let productInfoController = ProductsInfoController(inAppProductRequestBuilder: requestBuilder)\n        \n        var completionCount = 0\n        productInfoController.retrieveProductsInfo(sampleProductIdentifiers) { _ in\n            completionCount += 1\n        }\n        requestBuilder.fireCallbacks()\n        XCTAssertEqual(completionCount, 1)\n        \n        productInfoController.retrieveProductsInfo(sampleProductIdentifiers) { _ in\n            completionCount += 1\n        }\n        requestBuilder.fireCallbacks()\n        XCTAssertEqual(completionCount, 2)\n    }\n  \n  func testRetrieveProductsInfo_when_calledConcurrentlyInDifferentThreads_then_eachcompletionCalledOnce_noCrashes() {\n    let requestBuilder = TestInAppProductRequestBuilder()\n    let productInfoController = ProductsInfoController(inAppProductRequestBuilder: requestBuilder)\n    \n    var completionCallbackCount = 0\n    \n    // Create the expectation not to let the test finishes before the other threads complete\n    let expectation = XCTestExpectation(description: \"Expect downloads of product informations\")\n    \n    // Create the dispatch group to let the test verifies the assert only when\n    // everything else finishes.\n    let group = DispatchGroup()\n    \n    // Dispatch a request for every product in a different thread\n    for product in testProducts {\n      DispatchQueue.global().async {\n        group.enter()\n        productInfoController.retrieveProductsInfo([product]) { _ in\n          completionCallbackCount += 1\n          group.leave()\n        }\n      }\n    }\n    DispatchQueue.global().asyncAfter(deadline: .now()+0.1) {\n      requestBuilder.fireCallbacks()\n    }\n    // Fullfil the expectation when every thread finishes\n    group.notify(queue: DispatchQueue.global()) {\n      \n      XCTAssertEqual(completionCallbackCount, self.testProducts.count)\n      expectation.fulfill()\n    }\n    \n    wait(for: [expectation], timeout: 10.0)\n  }\n}\n"
  },
  {
    "path": "Tests/SwiftyStoreKitTests/RestorePurchasesControllerTests.swift",
    "content": "//\n// RestorePurchasesControllerTests.swift\n// SwiftyStoreKit\n//\n// Copyright (c) 2017 Andrea Bizzotto (bizz84@gmail.com)\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\nimport XCTest\nimport StoreKit\n@testable import SwiftyStoreKit\n\nclass RestorePurchasesControllerTests: XCTestCase {\n\n    func testProcessTransactions_when_oneRestoredTransaction_then_finishesTransaction_callsCallback_noRemainingTransactions() {\n\n        let productIdentifier = \"com.SwiftyStoreKit.product1\"\n        let testProduct = TestProduct(productIdentifier: productIdentifier)\n\n        let transaction = TestPaymentTransaction(payment: SKPayment(product: testProduct), transactionState: .restored)\n\n        var callbackCalled = false\n        let restorePurchases = RestorePurchases(atomically: true) { results in\n            callbackCalled = true\n            XCTAssertEqual(results.count, 1)\n            let restored = results.first!\n            if case .restored(let restoredPurchase) = restored {\n                XCTAssertEqual(restoredPurchase.productId, productIdentifier)\n            } else {\n                XCTFail(\"expected restored callback with product\")\n            }\n        }\n\n        let restorePurchasesController = makeRestorePurchasesController(restorePurchases: restorePurchases)\n\n        let spy = PaymentQueueSpy()\n\n        let remainingTransactions = restorePurchasesController.processTransactions([transaction], on: spy)\n        restorePurchasesController.restoreCompletedTransactionsFinished()\n\n        XCTAssertEqual(remainingTransactions.count, 0)\n\n        XCTAssertTrue(callbackCalled)\n\n        XCTAssertEqual(spy.finishTransactionCalledCount, 1)\n    }\n\n    func testProcessTransactions_when_twoRestoredTransactions_oneFailedTransaction_onePurchasedTransaction_then_finishesTwoTransactions_callsCallback_twoRemainingTransaction() {\n\n        let productIdentifier1 = \"com.SwiftyStoreKit.product1\"\n        let testProduct1 = TestProduct(productIdentifier: productIdentifier1)\n        let transaction1 = TestPaymentTransaction(payment: SKPayment(product: testProduct1), transactionState: .restored)\n\n        let productIdentifier2 = \"com.SwiftyStoreKit.product2\"\n        let testProduct2 = TestProduct(productIdentifier: productIdentifier2)\n        let transaction2 = TestPaymentTransaction(payment: SKPayment(product: testProduct2), transactionState: .restored)\n\n        let productIdentifier3 = \"com.SwiftyStoreKit.product3\"\n        let testProduct3 = TestProduct(productIdentifier: productIdentifier3)\n        let transaction3 = TestPaymentTransaction(payment: SKPayment(product: testProduct3), transactionState: .failed)\n\n        let productIdentifier4 = \"com.SwiftyStoreKit.product4\"\n        let testProduct4 = TestProduct(productIdentifier: productIdentifier4)\n        let transaction4 = TestPaymentTransaction(payment: SKPayment(product: testProduct4), transactionState: .purchased)\n\n        let transactions = [transaction1, transaction2, transaction3, transaction4]\n\n        var callbackCalled = false\n        let restorePurchases = RestorePurchases(atomically: true) { results in\n            callbackCalled = true\n            XCTAssertEqual(results.count, 2)\n            let first = results.first!\n            if case .restored(let restoredPurchase) = first {\n                XCTAssertEqual(restoredPurchase.productId, productIdentifier1)\n            } else {\n                XCTFail(\"expected restored callback with product\")\n            }\n            let last = results.last!\n            if case .restored(let restoredPurchase) = last {\n                XCTAssertEqual(restoredPurchase.productId, productIdentifier2)\n            } else {\n                XCTFail(\"expected restored callback with product\")\n            }\n        }\n\n        let restorePurchasesController = makeRestorePurchasesController(restorePurchases: restorePurchases)\n\n        let spy = PaymentQueueSpy()\n\n        let remainingTransactions = restorePurchasesController.processTransactions(transactions, on: spy)\n        restorePurchasesController.restoreCompletedTransactionsFinished()\n\n        XCTAssertEqual(remainingTransactions.count, 2)\n\n        XCTAssertTrue(callbackCalled)\n\n        XCTAssertEqual(spy.finishTransactionCalledCount, 2)\n    }\n\n    func testRestoreCompletedTransactionsFailed_callsCallbackWithError() {\n\n        var callbackCalled = false\n        let restorePurchases = RestorePurchases(atomically: true) { results in\n            callbackCalled = true\n\n            XCTAssertEqual(results.count, 1)\n            let first = results.first!\n            if case .failed = first {\n\n            } else {\n                XCTFail(\"expected failed callback with error\")\n            }\n        }\n\n        let restorePurchasesController = makeRestorePurchasesController(restorePurchases: restorePurchases)\n\n        let error = NSError(domain: \"SwiftyStoreKit\", code: 0, userInfo: nil)\n\n        restorePurchasesController.restoreCompletedTransactionsFailed(withError: error)\n\n        XCTAssertTrue(callbackCalled)\n    }\n\n    func testRestoreCompletedTransactionsFinished_callsCallbackWithNoTransactions() {\n\n        var callbackCalled = false\n        let restorePurchases = RestorePurchases(atomically: true) { results in\n            callbackCalled = true\n\n            XCTAssertEqual(results.count, 0)\n        }\n        let restorePurchasesController = makeRestorePurchasesController(restorePurchases: restorePurchases)\n\n        restorePurchasesController.restoreCompletedTransactionsFinished()\n\n        XCTAssertTrue(callbackCalled)\n    }\n\n    func makeRestorePurchasesController(restorePurchases: RestorePurchases?) -> RestorePurchasesController {\n\n        let restorePurchasesController = RestorePurchasesController()\n\n        restorePurchasesController.restorePurchases = restorePurchases\n\n        return restorePurchasesController\n    }\n}\n"
  },
  {
    "path": "Tests/SwiftyStoreKitTests/TestPaymentTransaction.swift",
    "content": "//\n// TestPaymentTransaction.swift\n// SwiftyStoreKit\n//\n// Copyright (c) 2017 Andrea Bizzotto (bizz84@gmail.com)\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\nimport StoreKit\n\n// swiftlint:disable variable_name\n\nclass TestPaymentTransaction: SKPaymentTransaction {\n\n    let _transactionState: SKPaymentTransactionState\n    let _payment: SKPayment\n\n    init(payment: SKPayment, transactionState: SKPaymentTransactionState) {\n        _transactionState = transactionState\n        _payment = payment\n    }\n\n    override var payment: SKPayment {\n        return _payment\n    }\n\n    override var transactionState: SKPaymentTransactionState {\n        return _transactionState\n    }\n}\n"
  },
  {
    "path": "Tests/SwiftyStoreKitTests/TestProduct.swift",
    "content": "//\n// TestProduct.swift\n// SwiftyStoreKit\n//\n// Copyright (c) 2017 Andrea Bizzotto (bizz84@gmail.com)\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\nimport StoreKit\n\n// swiftlint:disable variable_name\n\nclass TestProduct: SKProduct {\n\n    var _productIdentifier: String = \"\"\n\n    override var productIdentifier: String {\n        return _productIdentifier\n    }\n\n    init(productIdentifier: String) {\n        _productIdentifier = productIdentifier\n        super.init()\n    }\n}\n"
  },
  {
    "path": "scripts/build.sh",
    "content": "#!/bin/bash\nbold=$(tput bold)\nnormal=$(tput sgr0)\n\necho \"${bold}/*****************************/\"\necho \"/* Build: SwiftyStoreKit_iOS */\"\necho \"/*****************************/${normal}\"\nset -o pipefail && xcodebuild -project SwiftyStoreKit.xcodeproj -target SwiftyStoreKit_iOS | tee xcodebuild.log | xcpretty\n\necho \"\"\necho \"${bold}/*******************************/\"\necho \"/* Build: SwiftyStoreKit_macOS */\"\necho \"/*******************************/${normal}\"\nset -o pipefail && xcodebuild -project SwiftyStoreKit.xcodeproj -target SwiftyStoreKit_macOS | tee xcodebuild.log | xcpretty\n\necho \"\"\necho \"${bold}/******************************/\"\necho \"/* Build: SwiftyStoreKit_tvOS */\"\necho \"/******************************/${normal}\"\nset -o pipefail && xcodebuild -project SwiftyStoreKit.xcodeproj -target SwiftyStoreKit_tvOS | tee xcodebuild.log | xcpretty\n\necho \"\"\necho \"${bold}/******************************/\"\necho \"/* Build: SwiftyStoreKit_watchOS */\"\necho \"/******************************/${normal}\"\nset -o pipefail && xcodebuild -project SwiftyStoreKit.xcodeproj -target SwiftyStoreKit_watchOS | tee xcodebuild.log | xcpretty\n\necho \"\"\necho \"${bold}/****************************/\"\necho \"/* Run: SwiftyStoreKitTests */\"\necho \"/****************************/${normal}\"\nset -o pipefail && xcodebuild test -project SwiftyStoreKit.xcodeproj -scheme SwiftyStoreKitTests -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 6,OS=12.0' | tee xcodebuild.log | xcpretty\n"
  },
  {
    "path": "scripts/install_swiftlint.sh",
    "content": "#!/bin/bash\n\n# Installs the SwiftLint package.\n# Tries to get the precompiled .pkg file from Github, but if that\n# fails just recompiles from source.\n\nset -e\n\nSWIFTLINT_PKG_PATH=\"/tmp/SwiftLint.pkg\"\nSWIFTLINT_PKG_URL=\"https://github.com/realm/SwiftLint/releases/download/0.39.2/SwiftLint.pkg\"\n\nwget --output-document=$SWIFTLINT_PKG_PATH $SWIFTLINT_PKG_URL\n\nif [ -f $SWIFTLINT_PKG_PATH ]; then\n  echo \"SwiftLint package exists! Installing it...\"\n  sudo installer -pkg $SWIFTLINT_PKG_PATH -target /\nelse\n  echo \"SwiftLint package doesn't exist. Compiling from source...\" &&\n  git clone https://github.com/realm/SwiftLint.git /tmp/SwiftLint &&\n  cd /tmp/SwiftLint &&\n  git submodule update --init --recursive &&\n  sudo make install\nfi\n"
  }
]